use std::collections::HashMap;
use super::super::point_group::{iter_trans_mat_basis, iter_unimodular_trans_mat};
use super::super::rotation_type::identify_rotation_type;
use super::super::space_group::match_origin_shift;
use crate::base::{Operations, UnimodularLinear, UnimodularTransformation, project_rotations};
use crate::search::is_layer_block_form;
pub fn integral_normalizer_2_1(
prim_operations: &Operations,
prim_generators: &Operations,
epsilon: f64,
) -> Vec<UnimodularTransformation> {
let prim_rotations = project_rotations(prim_operations);
let prim_rotation_generators = project_rotations(prim_generators);
let rotation_types = prim_rotations
.iter()
.map(identify_rotation_type)
.collect::<Vec<_>>();
let mut conjugators = vec![];
for trans_mat_basis in
iter_trans_mat_basis(prim_rotations, rotation_types, prim_rotation_generators)
{
for prim_trans_mat in iter_unimodular_trans_mat(trans_mat_basis) {
if !is_layer_block_form(&prim_trans_mat) {
continue;
}
if let Some(mut origin_shift) =
match_origin_shift(prim_operations, &prim_trans_mat, prim_generators, epsilon)
{
if let Some(exact_s_z) =
layer_exact_s_z(prim_operations, &prim_trans_mat, prim_generators, epsilon)
{
origin_shift[2] = prim_trans_mat[(2, 2)] as f64 * exact_s_z;
}
conjugators.push(UnimodularTransformation::new(prim_trans_mat, origin_shift));
break;
}
}
}
conjugators
}
fn layer_exact_s_z(
prim_layer_operations: &Operations,
trans_mat: &UnimodularLinear,
db_prim_generators: &Operations,
epsilon: f64,
) -> Option<f64> {
let new_prim_operations = UnimodularTransformation::from_linear(*trans_mat)
.transform_operations(prim_layer_operations);
let mut hm_translations = HashMap::new();
for op in new_prim_operations.iter() {
hm_translations.insert(op.rotation, op.translation);
}
let mut chosen: Option<f64> = None;
for db_op in db_prim_generators.iter() {
if db_op.rotation[(2, 2)] != -1 {
continue;
}
let target_t = hm_translations.get(&db_op.rotation)?;
let s_z = (target_t[2] - db_op.translation[2]) / 2.0;
match chosen {
None => chosen = Some(s_z),
Some(prev) => debug_assert!(
(prev - s_z - (prev - s_z).round()).abs() < epsilon.max(1e-6),
"c-flipping generators disagree on s_z (prev={}, new={})",
prev,
s_z
),
}
}
chosen
}