#[allow(unused_imports)]
#[macro_use]
extern crate approx;
pub mod base;
pub mod data;
pub mod identify;
pub mod math;
pub mod search; pub mod utils;
mod symmetrize;
use crate::base::{
AngleTolerance, Cell, MagneticCell, MagneticMoment, MagneticOperations, MoyoError, Operations,
OriginShift, RotationMagneticMomentAction,
};
use crate::data::{
HallNumber, Number, Setting, UNINumber, arithmetic_crystal_class_entry, hall_symbol_entry,
};
use crate::identify::{MagneticSpaceGroup, SpaceGroup};
use crate::search::{
iterative_magnetic_symmetry_search, iterative_symmetry_search,
magnetic_operations_in_magnetic_cell, operations_in_cell,
};
use crate::symmetrize::{StandardizedCell, StandardizedMagneticCell, orbits_in_cell};
use nalgebra::Matrix3;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MoyoDataset {
pub number: Number,
pub hall_number: HallNumber,
pub hm_symbol: String,
pub operations: Operations,
pub orbits: Vec<usize>,
pub wyckoffs: Vec<char>,
pub site_symmetry_symbols: Vec<String>,
pub std_cell: Cell,
pub std_linear: Matrix3<f64>,
pub std_origin_shift: OriginShift,
pub std_rotation_matrix: Matrix3<f64>,
pub pearson_symbol: String,
pub prim_std_cell: Cell,
pub prim_std_linear: Matrix3<f64>,
pub prim_std_origin_shift: OriginShift,
pub mapping_std_prim: Vec<usize>,
pub symprec: f64,
pub angle_tolerance: AngleTolerance,
}
impl MoyoDataset {
pub fn new(
cell: &Cell,
symprec: f64,
angle_tolerance: AngleTolerance,
setting: Setting,
) -> Result<Self, MoyoError> {
let (prim_cell, symmetry_search, symprec, angle_tolerance) =
iterative_symmetry_search(cell, symprec, angle_tolerance)?;
let operations = operations_in_cell(&prim_cell, &symmetry_search.operations);
let epsilon = symprec / prim_cell.cell.lattice.volume().powf(1.0 / 3.0);
let space_group = SpaceGroup::new(&symmetry_search.operations, setting, epsilon)?;
let std_cell = StandardizedCell::new(
&prim_cell.cell,
&symmetry_search.operations,
&symmetry_search.permutations,
&space_group,
symprec,
epsilon,
true, )?;
let orbits = orbits_in_cell(
prim_cell.cell.num_atoms(),
&symmetry_search.permutations,
&prim_cell.site_mapping,
);
let mapping_std_prim = prim_cell.site_mapping.clone();
let mut std_prim_wyckoffs = vec![None; prim_cell.cell.num_atoms()];
for (i, wyckoff) in std_cell.wyckoffs.iter().enumerate() {
let j = std_cell.site_mapping[i];
if std_prim_wyckoffs[j].is_none() {
std_prim_wyckoffs[j] = Some(wyckoff.clone());
}
}
let wyckoffs: Option<Vec<_>> = mapping_std_prim
.iter()
.map(|&i| std_prim_wyckoffs[i].clone())
.collect();
let wyckoffs = wyckoffs.ok_or(MoyoError::WyckoffPositionAssignmentError)?;
let prim_cell_linear_inv = prim_cell.linear.map(|e| e as f64).try_inverse().unwrap();
let std_linear = prim_cell_linear_inv * std_cell.transformation.linear_as_f64();
let std_origin_shift = prim_cell_linear_inv * std_cell.transformation.origin_shift;
let prim_std_linear = prim_cell_linear_inv * std_cell.prim_transformation.linear_as_f64();
let prim_std_origin_shift =
prim_cell_linear_inv * std_cell.prim_transformation.origin_shift;
let hall_symbol = hall_symbol_entry(space_group.hall_number).unwrap();
let arithmetic_entry =
arithmetic_crystal_class_entry(hall_symbol.arithmetic_number).unwrap();
let bravais_class = arithmetic_entry.bravais_class;
let pearson_symbol = format!("{}{}", bravais_class.to_string(), std_cell.cell.num_atoms());
Ok(Self {
number: space_group.number,
hall_number: space_group.hall_number,
hm_symbol: hall_symbol.hm_short.to_string(),
operations,
std_cell: std_cell.cell,
std_linear,
std_origin_shift,
std_rotation_matrix: std_cell.rotation_matrix,
pearson_symbol,
prim_std_cell: std_cell.prim_cell,
prim_std_linear,
prim_std_origin_shift,
mapping_std_prim,
orbits,
wyckoffs: wyckoffs.iter().map(|w| w.letter).collect(),
site_symmetry_symbols: wyckoffs
.iter()
.map(|w| w.site_symmetry.to_string())
.collect(),
symprec,
angle_tolerance,
})
}
pub fn num_operations(&self) -> usize {
self.operations.len()
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MoyoMagneticDataset<M: MagneticMoment> {
pub uni_number: UNINumber,
pub magnetic_operations: MagneticOperations,
pub orbits: Vec<usize>,
pub std_mag_cell: MagneticCell<M>,
pub std_linear: Matrix3<f64>,
pub std_origin_shift: OriginShift,
pub std_rotation_matrix: Matrix3<f64>,
pub prim_std_mag_cell: MagneticCell<M>,
pub prim_std_linear: Matrix3<f64>,
pub prim_std_origin_shift: OriginShift,
pub mapping_std_prim: Vec<usize>,
pub symprec: f64,
pub angle_tolerance: AngleTolerance,
pub mag_symprec: f64,
}
impl<M: MagneticMoment> MoyoMagneticDataset<M> {
pub fn new(
magnetic_cell: &MagneticCell<M>,
symprec: f64,
angle_tolerance: AngleTolerance,
mag_symprec: Option<f64>,
action: RotationMagneticMomentAction,
) -> Result<Self, MoyoError> {
let (prim_mag_cell, magnetic_symmetry_search, symprec, angle_tolerance, mag_symprec) =
iterative_magnetic_symmetry_search(
magnetic_cell,
symprec,
angle_tolerance,
mag_symprec,
action,
)?;
let magnetic_operations = magnetic_operations_in_magnetic_cell(
&prim_mag_cell,
&magnetic_symmetry_search.magnetic_operations,
);
let epsilon = symprec
/ prim_mag_cell
.magnetic_cell
.cell
.lattice
.volume()
.powf(1.0 / 3.0);
let magnetic_space_group =
MagneticSpaceGroup::new(&magnetic_symmetry_search.magnetic_operations, epsilon)?;
let std_mag_cell = StandardizedMagneticCell::new(
&prim_mag_cell,
&magnetic_symmetry_search,
&magnetic_space_group,
symprec,
mag_symprec,
epsilon,
action,
true, )?;
let mapping_std_prim = prim_mag_cell.site_mapping.clone();
let orbits = orbits_in_cell(
prim_mag_cell.magnetic_cell.num_atoms(),
&magnetic_symmetry_search.permutations,
&mapping_std_prim,
);
let prim_mag_cell_linear_inv = prim_mag_cell
.linear
.map(|e| e as f64)
.try_inverse()
.unwrap();
let std_linear = prim_mag_cell_linear_inv * std_mag_cell.transformation.linear_as_f64();
let std_origin_shift = prim_mag_cell_linear_inv * std_mag_cell.transformation.origin_shift;
let prim_std_linear =
prim_mag_cell_linear_inv * std_mag_cell.prim_transformation.linear_as_f64();
let prim_std_origin_shift =
prim_mag_cell_linear_inv * std_mag_cell.prim_transformation.origin_shift;
Ok(Self {
uni_number: magnetic_space_group.uni_number,
magnetic_operations,
orbits,
std_mag_cell: std_mag_cell.mag_cell,
std_linear,
std_origin_shift,
std_rotation_matrix: std_mag_cell.rotation_matrix,
prim_std_mag_cell: std_mag_cell.prim_mag_cell,
prim_std_linear,
prim_std_origin_shift,
mapping_std_prim,
symprec,
angle_tolerance,
mag_symprec,
})
}
pub fn num_magnetic_operations(&self) -> usize {
self.magnetic_operations.len()
}
}