use crate::Model;
use crate::error::{Result, TbError};
use crate::find_R;
use ndarray::prelude::*;
use ndarray::*;
use num_complex::Complex;
use std::f64::consts::PI;
fn gcd(mut a: usize, mut b: usize) -> usize {
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
pub trait MagneticField {
fn add_magnetic_field(&self, mag_dir: usize, expand: [usize; 2], phi: isize) -> Result<Self>
where
Self: Sized;
}
impl MagneticField for Model {
fn add_magnetic_field(&self, mag_dir: usize, expand: [usize; 2], phi: isize) -> Result<Self> {
if mag_dir >= self.dim_r() && !(self.dim_r() == 2 && mag_dir == 2) {
return Err(TbError::InvalidDirection {
index: mag_dir,
dim: self.dim_r(),
});
}
if expand[0] == 0 || expand[1] == 0 {
return Err(TbError::InvalidSupercellSize(0));
}
let total_area_cells = expand[0] * expand[1];
if phi != 0 {
let gcd_val = gcd(phi.abs() as usize, total_area_cells);
if gcd_val > 1 {
let reduced_p = phi / (gcd_val as isize);
let reduced_q = total_area_cells / gcd_val;
println!(
"提示: 每个原胞的磁通量为 {}/{} Φ₀, 互质约化为 {}/{} Φ₀。",
phi, total_area_cells, reduced_p, reduced_q
);
} else {
println!("提示: 每个原胞的磁通量为 {}/{} Φ₀。", phi, total_area_cells);
}
}
let perp_dirs: [usize; 2] = match self.dim_r() {
3 => match mag_dir {
0 => [1, 2],
1 => [2, 0], 2 => [0, 1],
_ => unreachable!(),
},
2 => match mag_dir {
2 => [0, 1], _ => {
return Err(TbError::InvalidDirection {
index: mag_dir,
dim: 2,
});
} },
_ => {
return Err(TbError::InvalidDimension {
dim: self.dim_r(),
supported: vec![2, 3],
});
}
};
let mut u_matrix = Array2::<f64>::eye(self.dim_r());
u_matrix[[perp_dirs[0], perp_dirs[0]]] = expand[0] as f64;
u_matrix[[perp_dirs[1], perp_dirs[1]]] = expand[1] as f64;
let super_model = self.make_supercell(&u_matrix)?;
let d1 = perp_dirs[0];
let d2 = perp_dirs[1];
let norb = super_model.norb();
let spin = super_model.spin;
let tot_orb = if spin { norb * 2 } else { norb };
let mut new_ham = super_model.ham.clone();
if phi != 0 {
for iR in 0..super_model.hamR.nrows() {
let R_vec = super_model.hamR.row(iR);
let m1 = R_vec[d1] as f64;
let m2 = R_vec[d2] as f64;
let mut ham_slice = new_ham.slice_mut(s![iR, .., ..]);
for i in 0..tot_orb {
let spatial_i = i % norb;
let u1_i = super_model.orb[[spatial_i, d1]];
let u2_i = super_model.orb[[spatial_i, d2]];
for j in 0..tot_orb {
let hop = ham_slice[[i, j]];
if hop.norm() < 1e-12 {
continue;
}
let spatial_j = j % norb;
let u1_j = super_model.orb[[spatial_j, d1]];
let u2_j = super_model.orb[[spatial_j, d2]];
let v1_j = u1_j + m1;
let v2_j = u2_j + m2;
let phase_val = 2.0
* PI
* (phi as f64)
* ((u1_i + v1_j) / 2.0 * (v2_j - u2_i) - m1 * v2_j);
let peierls = Complex::new(phase_val.cos(), phase_val.sin());
ham_slice[[i, j]] = hop * peierls;
}
}
}
}
if spin && phi != 0 {
let area = if self.dim_r() == 3 {
let L1 = super_model.lat.row(d1);
let L2 = super_model.lat.row(d2);
let cross_x = L1[1] * L2[2] - L1[2] * L2[1];
let cross_y = L1[2] * L2[0] - L1[0] * L2[2];
let cross_z = L1[0] * L2[1] - L1[1] * L2[0];
(cross_x.powi(2) + cross_y.powi(2) + cross_z.powi(2)).sqrt()
} else {
let L1 = super_model.lat.row(0);
let L2 = super_model.lat.row(1);
(L1[0] * L2[1] - L1[1] * L2[0]).abs()
};
const PHI0: f64 = 4.135667662e-15; let area_m2 = area * 1e-20; let B_tesla = (phi as f64) * PHI0 / area_m2;
const MU_B: f64 = 5.7883818012e-5; let g = 2.0;
let zeeman_energy = g * MU_B * B_tesla;
let zero_R = Array1::<isize>::zeros(super_model.dim_r());
let index0 = find_R(&super_model.hamR, &zero_R).unwrap();
let mut ham0 = new_ham.slice_mut(s![index0, .., ..]);
for i in 0..norb {
match mag_dir {
0 => {
ham0[[i, i + norb]] += zeeman_energy / 2.0;
ham0[[i + norb, i]] += zeeman_energy / 2.0;
}
1 => {
ham0[[i, i + norb]] += Complex::new(0.0, -zeeman_energy / 2.0);
ham0[[i + norb, i]] += Complex::new(0.0, zeeman_energy / 2.0);
}
2 => {
ham0[[i, i]] += zeeman_energy / 2.0;
ham0[[i + norb, i + norb]] -= zeeman_energy / 2.0;
}
_ => unreachable!(),
}
}
}
let mut new_model = super_model;
new_model.ham = new_ham;
Ok(new_model)
}
}