Skip to content

Commit

Permalink
iterative magnetic symmetry search
Browse files Browse the repository at this point in the history
  • Loading branch information
lan496 committed Jan 11, 2025
1 parent 0d277ab commit 0720ea5
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 57 deletions.
2 changes: 1 addition & 1 deletion moyo/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use operation::{
Rotations, Translation,
};
pub use permutation::Permutation;
pub use tolerance::AngleTolerance;
pub use tolerance::{AngleTolerance, MagneticSymmetryTolerances, SymmetryTolerances};
pub use transformation::{Linear, OriginShift};

pub use cell::orbits_from_permutations;
Expand Down
2 changes: 2 additions & 0 deletions moyo/src/base/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub enum MoyoError {
PrimitiveCellError,
#[error("Primitive symmetry search failed")]
PrimitiveSymmetrySearchError,
#[error("Primitive magnetic symmetry search failed")]
PrimitiveMagneticSymmetrySearchError,
#[error("Bravais group search failed")]
BravaisGroupSearchError,
#[error("Geometric crystal class identification failed")]
Expand Down
126 changes: 91 additions & 35 deletions moyo/src/base/tolerance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use log::debug;
use std::fmt::Debug;

use super::error::MoyoError;

Expand All @@ -15,63 +16,118 @@ pub enum AngleTolerance {
Default,
}

pub struct ToleranceHandler {
pub trait Tolerances {
fn increase_tolerances(&self, stride: f64) -> Self;
fn reduce_tolerances(&self, stride: f64) -> Self;
}

#[derive(Debug, Clone)]
pub struct SymmetryTolerances {
pub symprec: f64,
pub angle_tolerance: AngleTolerance,
stride: f64,
prev_error: Option<MoyoError>,
}

impl ToleranceHandler {
pub fn new(symprec: f64, angle_tolerance: AngleTolerance) -> Self {
impl Tolerances for SymmetryTolerances {
fn increase_tolerances(&self, stride: f64) -> Self {
let symprec = self.symprec * stride;
let angle_tolerance = if let AngleTolerance::Radian(angle) = self.angle_tolerance {
AngleTolerance::Radian(angle * stride)
} else {
AngleTolerance::Default
};
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.reduce_tolerance(),
fn reduce_tolerances(&self, stride: f64) -> Self {
let symprec = self.symprec / stride;
let angle_tolerance = if let AngleTolerance::Radian(angle) = self.angle_tolerance {
AngleTolerance::Radian(angle / stride)
} else {
AngleTolerance::Default
};
Self {
symprec,
angle_tolerance,
}
}
}

#[derive(Debug, Clone)]
pub struct MagneticSymmetryTolerances {
pub symprec: f64,
pub angle_tolerance: AngleTolerance,
pub mag_symprec: f64,
}

fn increase_tolerance(&self) -> (f64, AngleTolerance) {
let symprec = self.symprec * self.stride;
impl Tolerances for MagneticSymmetryTolerances {
fn increase_tolerances(&self, stride: f64) -> Self {
let symprec = self.symprec * stride;
let angle_tolerance = if let AngleTolerance::Radian(angle) = self.angle_tolerance {
AngleTolerance::Radian(angle * self.stride)
AngleTolerance::Radian(angle * stride)
} else {
AngleTolerance::Default
};
debug!(
"Increase tolerance to symprec={}, angle_tolerance={:?}",
symprec, angle_tolerance
);
(symprec, angle_tolerance)
let mag_symprec = self.mag_symprec * stride;
Self {
symprec,
angle_tolerance,
mag_symprec,
}
}

fn reduce_tolerance(&self) -> (f64, AngleTolerance) {
let symprec = self.symprec / self.stride;
fn reduce_tolerances(&self, stride: f64) -> Self {
let symprec = self.symprec / stride;
let angle_tolerance = if let AngleTolerance::Radian(angle) = self.angle_tolerance {
AngleTolerance::Radian(angle / self.stride)
AngleTolerance::Radian(angle / stride)
} else {
AngleTolerance::Default
};
debug!(
"Reduce tolerance to symprec={}, angle_tolerance={:?}",
symprec, angle_tolerance
);
(symprec, angle_tolerance)
let mag_symprec = self.mag_symprec / stride;
Self {
symprec,
angle_tolerance,
mag_symprec,
}
}
}

pub struct ToleranceHandler<T: Tolerances> {
pub tolerances: T,
stride: f64,
prev_error: Option<MoyoError>,
}

impl<T: Tolerances + Debug> ToleranceHandler<T> {
pub fn new(tolerances: T) -> Self {
Self {
tolerances,
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.tolerances = match err {
MoyoError::TooSmallToleranceError => {
let new_tolerances = self.tolerances.increase_tolerances(self.stride);
debug!("Increase tolerances: {:?}", new_tolerances);
new_tolerances
}
_ => {
let new_tolerances = self.tolerances.reduce_tolerances(self.stride);
debug!("Reduce tolerances: {:?}", new_tolerances);
new_tolerances
}
}
}
}
82 changes: 61 additions & 21 deletions moyo/src/search/symmetry_search.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::primitive_cell::{PrimitiveCell, PrimitiveMagneticCell};
use super::primitive_symmetry_search::{PrimitiveMagneticSymmetrySearch, PrimitiveSymmetrySearch};
use crate::base::{
AngleTolerance, Cell, MagneticCell, MagneticMoment, MoyoError, ToleranceHandler,
AngleTolerance, Cell, MagneticCell, MagneticMoment, MagneticSymmetryTolerances, MoyoError,
RotationMagneticMomentAction, SymmetryTolerances, ToleranceHandler,
};

use log::debug;
Expand All @@ -14,26 +15,28 @@ pub fn iterative_symmetry_search(
symprec: f64,
angle_tolerance: AngleTolerance,
) -> Result<(PrimitiveCell, PrimitiveSymmetrySearch, f64, AngleTolerance), MoyoError> {
let mut current_symprec = symprec;
let mut current_angle_tolerance = angle_tolerance;
let mut tolerances = SymmetryTolerances {
symprec,
angle_tolerance,
};

for _ in 0..MAX_TOLERANCE_HANDLER_TRIALS {
let mut tolerance_handler = ToleranceHandler::new(current_symprec, current_angle_tolerance);
let mut tolerance_handler = ToleranceHandler::new(tolerances);

for _ in 0..MAX_SYMMETRY_SEARCH_TRIALS {
match PrimitiveCell::new(cell, tolerance_handler.symprec) {
match PrimitiveCell::new(cell, tolerance_handler.tolerances.symprec) {
Ok(prim_cell) => {
match PrimitiveSymmetrySearch::new(
&prim_cell.cell,
tolerance_handler.symprec,
tolerance_handler.angle_tolerance,
tolerance_handler.tolerances.symprec,
tolerance_handler.tolerances.angle_tolerance,
) {
Ok(symmetry_search) => {
return Ok((
prim_cell,
symmetry_search,
tolerance_handler.symprec,
tolerance_handler.angle_tolerance,
tolerance_handler.tolerances.symprec,
tolerance_handler.tolerances.angle_tolerance,
));
}
Err(err) => tolerance_handler.update(err),
Expand All @@ -44,22 +47,19 @@ pub fn iterative_symmetry_search(
}

// When the maximum number of symmetry search trials is reached, restart ToleranceHandler to try larger strides
current_symprec = tolerance_handler.symprec;
current_angle_tolerance = tolerance_handler.angle_tolerance;
debug!(
"Restart ToleranceHandler with symprec={}, angle_tolerance={:?}",
current_symprec, current_angle_tolerance
);
tolerances = tolerance_handler.tolerances.clone();
debug!("Restart ToleranceHandler with {:?}", tolerances);
}
debug!("Reach the maximum number of symmetry search trials");
Err(MoyoError::PrimitiveSymmetrySearchError)
}

pub fn iterative_magnetic_symmetry_search<M: MagneticMoment>(
cell: &MagneticCell<M>,
pub fn iterative_magnetic_symmetry_search<M: MagneticMoment + Clone>(
magnetic_cell: &MagneticCell<M>,
symprec: f64,
angle_tolerance: AngleTolerance,
mag_symprec: Option<f64>,
action: RotationMagneticMomentAction,
) -> Result<
(
PrimitiveMagneticCell<M>,
Expand All @@ -70,9 +70,49 @@ pub fn iterative_magnetic_symmetry_search<M: MagneticMoment>(
),
MoyoError,
> {
let mut current_symprec = symprec;
let mut current_angle_tolerance = angle_tolerance;
let mut current_mag_symprec = mag_symprec.unwrap_or(symprec);
let mut tolerances = MagneticSymmetryTolerances {
symprec,
angle_tolerance,
mag_symprec: mag_symprec.unwrap_or(symprec),
};

todo!()
for _ in 0..MAX_TOLERANCE_HANDLER_TRIALS {
let mut tolerance_handler = ToleranceHandler::new(tolerances);

for _ in 0..MAX_SYMMETRY_SEARCH_TRIALS {
match PrimitiveMagneticCell::new(
&magnetic_cell,
tolerance_handler.tolerances.symprec,
tolerance_handler.tolerances.mag_symprec,
) {
Ok(prim_mag_cell) => {
match PrimitiveMagneticSymmetrySearch::new(
&prim_mag_cell.magnetic_cell,
tolerance_handler.tolerances.symprec,
tolerance_handler.tolerances.angle_tolerance,
tolerance_handler.tolerances.mag_symprec,
action,
) {
Ok(magnetic_symmetry_search) => {
return Ok((
prim_mag_cell,
magnetic_symmetry_search,
tolerance_handler.tolerances.symprec,
tolerance_handler.tolerances.angle_tolerance,
tolerance_handler.tolerances.mag_symprec,
));
}
Err(err) => tolerance_handler.update(err),
}
}
Err(err) => tolerance_handler.update(err),
}
}

// When the maximum number of symmetry search trials is reached, restart ToleranceHandler to try larger strides
tolerances = tolerance_handler.tolerances.clone();
debug!("Restart ToleranceHandler with {:?}", tolerances);
}
debug!("Reach the maximum number of symmetry search trials");
Err(MoyoError::PrimitiveMagneticSymmetrySearchError)
}

0 comments on commit 0720ea5

Please sign in to comment.