diff --git a/moyo/src/base.rs b/moyo/src/base.rs index dff1c6e..7728282 100644 --- a/moyo/src/base.rs +++ b/moyo/src/base.rs @@ -15,5 +15,5 @@ pub use transformation::{Linear, OriginShift}; pub use cell::orbits_from_permutations; #[allow(unused_imports)] pub use operation::traverse; -pub use tolerance::EPS; +pub use tolerance::{ToleranceHandler, EPS}; pub use transformation::{Transformation, UnimodularLinear, UnimodularTransformation}; diff --git a/moyo/src/base/tolerance.rs b/moyo/src/base/tolerance.rs index b5b4be6..50718fa 100644 --- a/moyo/src/base/tolerance.rs +++ b/moyo/src/base/tolerance.rs @@ -1,7 +1,74 @@ +use log::warn; + +use super::error::MoyoError; + +pub const EPS: f64 = 1e-8; + +const INITIAL_SYMMETRY_SEARCH_STRIDE: f64 = 2.0; + #[derive(Debug, Copy, Clone)] pub enum AngleTolerance { Radian(f64), Default, } -pub const EPS: f64 = 1e-8; +pub struct ToleranceHandler { + pub symprec: f64, + pub angle_tolerance: AngleTolerance, + stride: f64, + prev_error: Option, +} + +impl ToleranceHandler { + pub fn new(symprec: f64, angle_tolerance: AngleTolerance) -> Self { + Self { + symprec, + angle_tolerance, + stride: INITIAL_SYMMETRY_SEARCH_STRIDE, + prev_error: None, + } + } + + pub fn update(&mut self, err: MoyoError) { + // Update stride + if !self.prev_error.is_none() && self.prev_error != Some(err) { + self.stride = self.stride.sqrt() + } + self.prev_error = Some(err); + + // Update tolerances + (self.symprec, self.angle_tolerance) = match err { + MoyoError::TooSmallToleranceError => self.increase_tolerance(), + MoyoError::TooLargeToleranceError => self.reduce_tolerance(), + _ => (self.symprec, self.angle_tolerance), + } + } + + fn increase_tolerance(&self) -> (f64, AngleTolerance) { + let symprec = self.symprec * self.stride; + let angle_tolerance = if let AngleTolerance::Radian(angle) = self.angle_tolerance { + AngleTolerance::Radian(angle * self.stride) + } else { + AngleTolerance::Default + }; + warn!( + "Increase tolerance to symprec={}, angle_tolerance={:?}", + symprec, angle_tolerance + ); + (symprec, angle_tolerance) + } + + fn reduce_tolerance(&self) -> (f64, AngleTolerance) { + let symprec = self.symprec / self.stride; + let angle_tolerance = if let AngleTolerance::Radian(angle) = self.angle_tolerance { + AngleTolerance::Radian(angle / self.stride) + } else { + AngleTolerance::Default + }; + warn!( + "Reduce tolerance to symprec={}, angle_tolerance={:?}", + symprec, angle_tolerance + ); + (symprec, angle_tolerance) + } +} diff --git a/moyo/src/lib.rs b/moyo/src/lib.rs index ac4ad9f..1c41f42 100644 --- a/moyo/src/lib.rs +++ b/moyo/src/lib.rs @@ -9,10 +9,11 @@ pub mod math; pub mod search; pub mod symmetrize; -use log::warn; use nalgebra::Matrix3; -use crate::base::{AngleTolerance, Cell, MoyoError, Operations, OriginShift, Transformation}; +use crate::base::{ + AngleTolerance, Cell, MoyoError, Operations, OriginShift, ToleranceHandler, Transformation, +}; use crate::data::{HallNumber, Number, Setting}; use crate::identify::SpaceGroup; use crate::search::{PrimitiveCell, PrimitiveSymmetrySearch}; @@ -154,111 +155,40 @@ impl MoyoDataset { } const MAX_SYMMETRY_SEARCH_TRIALS: usize = 16; -const INITIAL_SYMMETRY_SEARCH_STRIDE: f64 = 2.0; fn iterative_symmetry_search( cell: &Cell, symprec: f64, angle_tolerance: AngleTolerance, ) -> Result<(PrimitiveCell, PrimitiveSymmetrySearch, f64, AngleTolerance), MoyoError> { - let mut symprec = symprec; - let mut angle_tolerance = angle_tolerance; - let mut stride: f64 = INITIAL_SYMMETRY_SEARCH_STRIDE; - let mut prev_error: Option = None; - - fn _increase_tolerance( - symprec: f64, - angle_tolerance: AngleTolerance, - stride: f64, - ) -> (f64, AngleTolerance) { - let symprec = symprec * stride; - let angle_tolerance = if let AngleTolerance::Radian(angle) = angle_tolerance { - AngleTolerance::Radian(angle * stride) - } else { - AngleTolerance::Default - }; - warn!( - "Increase tolerance to symprec={}, angle_tolerance={:?}", - symprec, angle_tolerance - ); - (symprec, angle_tolerance) - } - - fn _reduce_tolerance( - symprec: f64, - angle_tolerance: AngleTolerance, - stride: f64, - ) -> (f64, AngleTolerance) { - let symprec = symprec / stride; - let angle_tolerance = if let AngleTolerance::Radian(angle) = angle_tolerance { - AngleTolerance::Radian(angle / stride) - } else { - AngleTolerance::Default - }; - warn!( - "Reduce tolerance to symprec={}, angle_tolerance={:?}", - symprec, angle_tolerance - ); - (symprec, angle_tolerance) - } - - fn _update_stride( - err: MoyoError, - prev_error: Option, - stride: f64, - ) -> (Option, f64) { - let stride = if !prev_error.is_none() && prev_error != Some(err) { - stride.sqrt() - } else { - stride - }; - (Some(err), stride) - } - - fn handle_tolerance_error( - err: MoyoError, - prev_error: Option, - stride: f64, - symprec: f64, - angle_tolerance: AngleTolerance, - ) -> (Option, f64, f64, AngleTolerance) { - let (new_error, new_stride) = _update_stride(err, prev_error, stride); - let (new_symprec, new_angle_tolerance) = match err { - MoyoError::TooSmallToleranceError => { - _increase_tolerance(symprec, angle_tolerance, new_stride) - } - MoyoError::TooLargeToleranceError => { - _reduce_tolerance(symprec, angle_tolerance, new_stride) - } - _ => (symprec, angle_tolerance), - }; - (new_error, new_stride, new_symprec, new_angle_tolerance) - } + let mut tolerance_handler = ToleranceHandler::new(symprec, angle_tolerance); for _ in 0..MAX_SYMMETRY_SEARCH_TRIALS { - match PrimitiveCell::new(cell, symprec) { + match PrimitiveCell::new(cell, tolerance_handler.symprec) { Ok(prim_cell) => { - match PrimitiveSymmetrySearch::new(&prim_cell.cell, symprec, angle_tolerance) { + match PrimitiveSymmetrySearch::new( + &prim_cell.cell, + tolerance_handler.symprec, + tolerance_handler.angle_tolerance, + ) { Ok(symmetry_search) => { - return Ok((prim_cell, symmetry_search, symprec, angle_tolerance)); + return Ok(( + prim_cell, + symmetry_search, + tolerance_handler.symprec, + tolerance_handler.angle_tolerance, + )); } Err(err @ MoyoError::TooSmallToleranceError) | Err(err @ MoyoError::TooLargeToleranceError) => { - (prev_error, stride, symprec, angle_tolerance) = handle_tolerance_error( - err, - prev_error, - stride, - symprec, - angle_tolerance, - ); + tolerance_handler.update(err); } Err(err) => return Err(err), } } Err(err @ MoyoError::TooSmallToleranceError) | Err(err @ MoyoError::TooLargeToleranceError) => { - (prev_error, stride, symprec, angle_tolerance) = - handle_tolerance_error(err, prev_error, stride, symprec, angle_tolerance); + tolerance_handler.update(err); } Err(err) => return Err(err), }