use crate::cell::Cell;
use crate::debug;
use crate::primitive::{prm_get_primitive, Primitive};
use crate::refinement::{ref_get_exact_structure_and_symmetry, ExactStructure};
use crate::spacegroup::{spa_search_spacegroup, Spacegroup};
const REDUCE_RATE_OUTER: f64 = 0.9;
const NUM_ATTEMPT_OUTER: i32 = 10;
const REDUCE_RATE: f64 = 0.95;
const ANGLE_REDUCE_RATE: f64 = 0.95;
const NUM_ATTEMPT: i32 = 20;
pub struct DataContainer {
pub spacegroup: Option<Spacegroup>,
pub primitive: Option<Primitive>,
pub exact_structure: Option<ExactStructure>,
}
pub fn det_determine_all(
cell: &Cell,
hall_number: i32,
symprec: f64,
angle_symprec: f64,
) -> Option<DataContainer> {
if hall_number > 530 {
return None;
}
let mut tolerance = symprec;
for _ in 0..NUM_ATTEMPT_OUTER {
if let Some(mut container) =
get_spacegroup_and_primitive(cell, hall_number, tolerance, angle_symprec)
{
let exstr = {
let sg = container.spacegroup.as_mut().unwrap();
let prim = container.primitive.as_ref().unwrap();
let prim_cell = prim.cell.as_ref().unwrap();
ref_get_exact_structure_and_symmetry(
sg,
prim_cell,
cell,
&prim.mapping_table,
prim.tolerance,
)
};
if let Some(exstr) = exstr {
container.exact_structure = Some(exstr);
return Some(container);
}
debug::debug_print(format_args!(
"spglib: ref_get_exact_structure_and_symmetry failed.\n"
));
}
tolerance *= REDUCE_RATE_OUTER;
}
None
}
fn get_spacegroup_and_primitive(
cell: &Cell,
hall_number: i32,
symprec: f64,
angle_symprec: f64,
) -> Option<DataContainer> {
debug::debug_print(format_args!(
"get_spacegroup_and_primitive (tolerance = {}):\n",
symprec
));
let mut tolerance = symprec;
let mut angle_tolerance = angle_symprec;
for attempt in 0..NUM_ATTEMPT {
let primitive = prm_get_primitive(cell, tolerance, angle_tolerance);
if let Some(primitive) = primitive {
debug::debug_print(format_args!("primitive lattice\n"));
let prim_tol = primitive.tolerance;
let prim_angle_tol = primitive.angle_tolerance;
let spacegroup = spa_search_spacegroup(
&primitive,
hall_number,
prim_tol,
prim_angle_tol,
);
if let Some(spacegroup) = spacegroup {
return Some(DataContainer {
spacegroup: Some(spacegroup),
primitive: Some(primitive),
exact_structure: None,
});
}
}
debug::debug_print(format_args!(
"spglib: Attempt {} tolerance = {} failed.\n",
attempt, tolerance
));
tolerance *= REDUCE_RATE;
if angle_tolerance > 0.0 {
angle_tolerance *= ANGLE_REDUCE_RATE;
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cell::Cell;
use crate::mathfunc::Mat3;
#[test]
fn test_det_hall_number_out_of_range() {
let cell = Cell::new(1, crate::cell::TensorRank::NoSpin);
let result = det_determine_all(&cell, 999, 1e-5, -1.0);
assert!(result.is_none());
}
}