diff --git a/moyo/src/data.rs b/moyo/src/data.rs index 8f2a796..61400c0 100644 --- a/moyo/src/data.rs +++ b/moyo/src/data.rs @@ -13,6 +13,7 @@ pub use arithmetic_crystal_class::ArithmeticNumber; pub use centering::Centering; pub use hall_symbol::{HallSymbol, MagneticHallSymbol}; pub use hall_symbol_database::{hall_symbol_entry, HallNumber, HallSymbolEntry, Number}; +pub use magnetic_hall_symbol_database::{magnetic_hall_symbol_entry, MagneticHallSymbolEntry}; pub use magnetic_space_group::{ get_magnetic_space_group_type, ConstructType, UNINumber, NUM_MAGNETIC_SPACE_GROUP_TYPES, }; diff --git a/moyo/src/data/magnetic_hall_symbol_database.rs b/moyo/src/data/magnetic_hall_symbol_database.rs index 5bfbb79..d4a251c 100644 --- a/moyo/src/data/magnetic_hall_symbol_database.rs +++ b/moyo/src/data/magnetic_hall_symbol_database.rs @@ -1,4 +1,8 @@ -use super::magnetic_space_group::{UNINumber, NUM_MAGNETIC_SPACE_GROUP_TYPES}; +use super::hall_symbol_database::HallNumber; +use super::magnetic_space_group::{ + get_magnetic_space_group_type, ConstructType, UNINumber, NUM_MAGNETIC_SPACE_GROUP_TYPES, +}; +use super::setting::Setting; #[derive(Debug, Clone)] pub struct MagneticHallSymbolEntry { @@ -13,6 +17,19 @@ impl MagneticHallSymbolEntry { uni_number, } } + + pub fn construct_type(&self) -> ConstructType { + get_magnetic_space_group_type(self.uni_number) + .unwrap() + .construct_type + } + + pub fn reference_hall_number(&self) -> HallNumber { + let number = get_magnetic_space_group_type(self.uni_number) + .unwrap() + .number; + Setting::Standard.hall_number(number).unwrap() + } } pub fn magnetic_hall_symbol_entry(uni_number: UNINumber) -> Option { @@ -1679,7 +1696,7 @@ const MAGNETIC_HALL_SYMBOL_DATABASE: [MagneticHallSymbolEntry; NUM_MAGNETIC_SPAC #[cfg(test)] mod tests { use super::*; - use crate::data::hall_symbol::MagneticHallSymbol; + use crate::data::MagneticHallSymbol; fn iter_magnetic_hall_symbol_entry() -> impl Iterator { MAGNETIC_HALL_SYMBOL_DATABASE.iter() diff --git a/moyo/src/data/setting.rs b/moyo/src/data/setting.rs index 84c67f1..23dc4fa 100644 --- a/moyo/src/data/setting.rs +++ b/moyo/src/data/setting.rs @@ -1,4 +1,4 @@ -use super::hall_symbol_database::HallNumber; +use super::hall_symbol_database::{HallNumber, Number}; #[derive(Debug, Copy, Clone, PartialEq)] /// Preference for the setting of the space group. @@ -11,44 +11,49 @@ pub enum Setting { Standard, } +const SPGLIB_HALL_NUMBERS: [HallNumber; 230] = [ + 1, 2, 3, 6, 9, 18, 21, 30, 39, 57, 60, 63, 72, 81, 90, 108, 109, 112, 115, 116, 119, 122, 123, + 124, 125, 128, 134, 137, 143, 149, 155, 161, 164, 170, 173, 176, 182, 185, 191, 197, 203, 209, + 212, 215, 218, 221, 227, 228, 230, 233, 239, 245, 251, 257, 263, 266, 269, 275, 278, 284, 290, + 292, 298, 304, 310, 313, 316, 322, 334, 335, 337, 338, 341, 343, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 361, 363, 364, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 401, 402, 404, 406, 407, 408, 410, 412, 413, 414, 416, 418, 419, 420, + 422, 424, 425, 426, 428, 430, 431, 432, 433, 435, 436, 438, 439, 440, 441, 442, 443, 444, 446, + 447, 448, 449, 450, 452, 454, 455, 456, 457, 458, 460, 462, 463, 464, 465, 466, 467, 468, 469, + 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 495, 497, 498, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 514, 515, 516, 517, 518, 520, 521, 523, 524, 525, 527, 529, 530, +]; +const STANDARD_HALL_NUMBERS: [HallNumber; 230] = [ + 1, 2, 3, 6, 9, 18, 21, 30, 39, 57, 60, 63, 72, 81, 90, 108, 109, 112, 115, 116, 119, 122, 123, + 124, 125, 128, 134, 137, 143, 149, 155, 161, 164, 170, 173, 176, 182, 185, 191, 197, 203, 209, + 212, 215, 218, 221, 227, 229, 230, 234, 239, 245, 251, 257, 263, 266, 269, 275, 279, 284, 290, + 292, 298, 304, 310, 313, 316, 323, 334, 336, 337, 338, 341, 343, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 360, 362, 363, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, + 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 401, 403, 405, 406, 407, 409, 411, 412, 413, 415, 417, 418, 419, 421, + 423, 424, 425, 427, 429, 430, 431, 432, 433, 435, 436, 438, 439, 440, 441, 442, 443, 444, 446, + 447, 448, 449, 450, 452, 454, 455, 456, 457, 458, 460, 462, 463, 464, 465, 466, 467, 468, 469, + 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, + 489, 490, 491, 492, 493, 494, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, + 510, 511, 512, 513, 514, 515, 516, 517, 519, 520, 522, 523, 524, 526, 528, 529, 530, +]; + impl Setting { pub fn hall_numbers(&self) -> Vec { match self { Setting::HallNumber(hall_number) => vec![*hall_number], - Setting::Spglib => vec![ - 1, 2, 3, 6, 9, 18, 21, 30, 39, 57, 60, 63, 72, 81, 90, 108, 109, 112, 115, 116, - 119, 122, 123, 124, 125, 128, 134, 137, 143, 149, 155, 161, 164, 170, 173, 176, - 182, 185, 191, 197, 203, 209, 212, 215, 218, 221, 227, 228, 230, 233, 239, 245, - 251, 257, 263, 266, 269, 275, 278, 284, 290, 292, 298, 304, 310, 313, 316, 322, - 334, 335, 337, 338, 341, 343, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 361, 363, 364, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, 402, 404, 406, 407, 408, 410, 412, 413, - 414, 416, 418, 419, 420, 422, 424, 425, 426, 428, 430, 431, 432, 433, 435, 436, - 438, 439, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 452, 454, 455, 456, - 457, 458, 460, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, - 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 495, 497, 498, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 520, 521, 523, 524, 525, 527, - 529, 530, - ], - Setting::Standard => vec![ - 1, 2, 3, 6, 9, 18, 21, 30, 39, 57, 60, 63, 72, 81, 90, 108, 109, 112, 115, 116, - 119, 122, 123, 124, 125, 128, 134, 137, 143, 149, 155, 161, 164, 170, 173, 176, - 182, 185, 191, 197, 203, 209, 212, 215, 218, 221, 227, 229, 230, 234, 239, 245, - 251, 257, 263, 266, 269, 275, 279, 284, 290, 292, 298, 304, 310, 313, 316, 323, - 334, 336, 337, 338, 341, 343, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 360, 362, 363, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, - 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, 403, 405, 406, 407, 409, 411, 412, 413, - 415, 417, 418, 419, 421, 423, 424, 425, 427, 429, 430, 431, 432, 433, 435, 436, - 438, 439, 440, 441, 442, 443, 444, 446, 447, 448, 449, 450, 452, 454, 455, 456, - 457, 458, 460, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, - 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 493, 494, 496, 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 514, 515, 516, 517, 519, 520, 522, 523, 524, 526, 528, - 529, 530, - ], + Setting::Spglib => SPGLIB_HALL_NUMBERS.to_vec(), + Setting::Standard => STANDARD_HALL_NUMBERS.to_vec(), + } + } + + pub fn hall_number(&self, number: Number) -> Option { + match self { + Setting::HallNumber(_) => None, + Setting::Spglib => SPGLIB_HALL_NUMBERS.get(number as usize - 1).cloned(), + Setting::Standard => STANDARD_HALL_NUMBERS.get(number as usize - 1).cloned(), } } } diff --git a/moyo/src/identify/magnetic_space_group.rs b/moyo/src/identify/magnetic_space_group.rs index 536a336..5357cba 100644 --- a/moyo/src/identify/magnetic_space_group.rs +++ b/moyo/src/identify/magnetic_space_group.rs @@ -9,8 +9,8 @@ use crate::base::{ UnimodularTransformation, }; use crate::data::{ - get_magnetic_space_group_type, uni_number_range, ConstructType, MagneticHallSymbol, Setting, - UNINumber, + get_magnetic_space_group_type, hall_symbol_entry, magnetic_hall_symbol_entry, uni_number_range, + ConstructType, HallSymbol, MagneticHallSymbol, MagneticHallSymbolEntry, Setting, UNINumber, }; #[derive(Debug)] @@ -54,11 +54,11 @@ impl MagneticSpaceGroup { // TODO: - let mhs = MagneticHallSymbol::from_uni_number(uni_number) + let entry = magnetic_hall_symbol_entry(uni_number).unwrap(); + let mhs = MagneticHallSymbol::new(&entry.magnetic_hall_symbol) .ok_or(MoyoError::MagneticSpaceGroupTypeIdentificationError)?; let db_prim_mag_generators = mhs.primitive_generators(); - let db_ref_prim_generators = - Self::get_db_reference_space_group_primitive_generators(&mhs, &construct_type); + let db_ref_prim_generators = db_reference_space_group_primitive_generators(&entry); // The correction transformations keep the reference space group of `tmp_prim_mag_operations` // TODO: precompute the correction transformation matrices @@ -83,40 +83,6 @@ impl MagneticSpaceGroup { Err(MoyoError::MagneticSpaceGroupTypeIdentificationError) } - fn get_db_reference_space_group_primitive_generators( - mhs: &MagneticHallSymbol, - construct_type: &ConstructType, - ) -> Operations { - let db_prim_mag_operations = mhs.primitive_generators(); - match construct_type { - ConstructType::Type1 | ConstructType::Type2 | ConstructType::Type3 => { - // Reference space group: FSG - // -> Remove time-reversal parts - db_prim_mag_operations - .iter() - .map(|mops| mops.operation.clone()) - .collect() - } - ConstructType::Type4 => { - // Reference space group: XSG - // -> Remove anti-translation operation - let identity = Rotation::identity(); - db_prim_mag_operations - .iter() - .filter_map(|mops| { - // Here we assume the magnetic Hall symbol composes of XSG generators and one anti-translation operation - if mops.time_reversal { - assert_eq!(mops.operation.rotation, identity); - None - } else { - Some(mops.operation.clone()) - } - }) - .collect() - } - } - } - /// Search for origin_shift such that (trans_mat, origin_shift) transforms `prim_mag_operations` into /// TODO: unify with identify/space_group.rs::match_origin_shift fn match_origin_shift( @@ -252,6 +218,20 @@ fn family_space_group_from_magnetic_space_group( (fsg, is_type2) } +/// Return generators of the reference space group of magnetic space group `entry`. +/// This function assumes the magnetic Hall symbol is extended from the Hall symbol in the standard setting. +fn db_reference_space_group_primitive_generators(entry: &MagneticHallSymbolEntry) -> Operations { + let ref_hall_number = entry.reference_hall_number(); + let ref_hall_entry = hall_symbol_entry(ref_hall_number).unwrap(); + let identity = Rotation::identity(); + HallSymbol::new(&ref_hall_entry.hall_symbol) + .unwrap() + .primitive_generators() + .into_iter() + .filter(|ops| ops.rotation != identity) // In primitive, if rotation part is identity, it is a pure translation + .collect() +} + #[cfg(test)] mod tests { use rstest::rstest; @@ -259,7 +239,9 @@ mod tests { use super::*; use crate::base::Transformation; - use crate::data::{MagneticHallSymbol, NUM_MAGNETIC_SPACE_GROUP_TYPES}; + use crate::data::{ + magnetic_hall_symbol_entry, MagneticHallSymbol, NUM_MAGNETIC_SPACE_GROUP_TYPES, + }; fn get_prim_mag_operations(uni_number: UNINumber) -> MagneticOperations { let mhs = MagneticHallSymbol::from_uni_number(uni_number).unwrap(); @@ -299,6 +281,61 @@ mod tests { assert_eq!(construct_type_actual, construct_type); } + // Check generators of reference space group by two methods: + // 1. From the magnetic Hall symbol + // 2. From the Hall symbol with the corresponding Hall number + #[test_with_log] + fn test_db_reference_space_group_primitive_generators() { + for uni_number in 1..=NUM_MAGNETIC_SPACE_GROUP_TYPES { + let entry = magnetic_hall_symbol_entry(uni_number as UNINumber).unwrap(); + let actual = db_reference_space_group_primitive_generators(&entry); + + let mhs = MagneticHallSymbol::new(&entry.magnetic_hall_symbol).unwrap(); + let identity = Rotation::identity(); + let expect: Operations = match entry.construct_type() { + ConstructType::Type1 | ConstructType::Type2 => mhs + .primitive_generators() + .iter() + .filter_map(|mops| { + if mops.time_reversal || mops.operation.rotation == identity { + // Ignore 1' for Type2 + None + } else { + Some(mops.operation.clone()) + } + }) + .collect(), + ConstructType::Type3 => mhs + .primitive_generators() + .iter() + .map(|mops| mops.operation.clone()) // Ignore time-reversal parts + .collect(), + ConstructType::Type4 => mhs + .primitive_generators() + .iter() + .filter_map(|mops| { + if mops.operation.rotation == identity { + // Ignore anti-translation + None + } else { + Some(mops.operation.clone()) + } + }) + .collect(), + }; + assert_eq!(actual.len(), expect.len()); + let mut hm_translation = HashMap::new(); + for ops1 in actual.iter() { + hm_translation.insert(ops1.rotation.clone(), ops1.translation); + } + for ops2 in expect.iter() { + let translation1 = hm_translation.get(&ops2.rotation).unwrap(); + let diff = ops2.translation - translation1; + assert_relative_eq!(diff.map(|e| (e - e.round().abs())).max(), 0.0); + } + } + } + #[test_with_log] fn test_identify_magnetic_space_group() { // for uni_number in 1..=NUM_MAGNETIC_SPACE_GROUP_TYPES {