Skip to content

Commit

Permalink
Started impl of UHF
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinRJDagleish committed Jan 3, 2024
1 parent 006716a commit ee7c98c
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/calc_type/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ndarray_linalg::SolveH;
use std::ops::{Index, IndexMut};

pub(crate) mod rhf;
pub(crate) mod uhf;

pub(crate) enum CalcType {
RHF,
Expand Down
82 changes: 50 additions & 32 deletions src/calc_type/rhf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ pub fn calc_2e_int_matr(basis: &BasisSet) -> EriArr1 {
/// - direct vs. indirect SCF
#[allow(unused)]
pub(crate) fn rhf_scf_normal(
calc_sett: CalcSettings,
calc_sett: &CalcSettings,
exec_times: &mut ExecTimes,
basis: &BasisSet,
mol: &Molecule,
Expand Down Expand Up @@ -274,7 +274,7 @@ pub(crate) fn rhf_scf_normal(
(orb_ener, C_matr_MO) = F_matr_pr.eigh(UPLO::Upper).unwrap();
C_matr_AO = S_matr_inv_sqrt.dot(&C_matr_MO);

calc_P_matr(&mut P_matr, &C_matr_AO, basis.no_occ());
calc_P_matr_rhf(&mut P_matr, &C_matr_AO, basis.no_occ());
delta_P_matr = P_matr.clone();
} else {
/// direct or indirect scf
Expand Down Expand Up @@ -354,7 +354,7 @@ pub(crate) fn rhf_scf_normal(
}
E_scf_prev = E_scf_curr;
P_matr_old = P_matr.clone();
calc_P_matr(&mut P_matr, &C_matr_AO, basis.no_occ());
calc_P_matr_rhf(&mut P_matr, &C_matr_AO, basis.no_occ());
delta_P_matr = (&P_matr - &P_matr_old).to_owned();
}
}
Expand All @@ -373,7 +373,7 @@ pub(crate) fn rhf_scf_normal(
scf
}

fn calc_P_matr(P_matr: &mut Array2<f64>, C_matr: &Array2<f64>, no_occ: usize) {
fn calc_P_matr_rhf(P_matr: &mut Array2<f64>, C_matr: &Array2<f64>, no_occ: usize) {
let C_occ = C_matr.slice(s![.., ..no_occ]);
general_mat_mul(2.0_f64, &C_occ, &C_occ.t(), 0.0_f64, P_matr)
}
Expand Down Expand Up @@ -498,7 +498,7 @@ fn calc_rms_2_matr(matr1: &Array2<f64>, matr2: &Array2<f64>) -> f64 {
/ (matr1.len() as f64).sqrt()
}

fn inv_ssqrt(arr2: &Array2<f64>, uplo: UPLO) -> Array2<f64> {
pub(crate) fn inv_ssqrt(arr2: &Array2<f64>, uplo: UPLO) -> Array2<f64> {
let (e, v) = arr2.eigh(uplo).unwrap();
let e_inv_sqrt = Array1::from_iter(e.iter().map(|x| x.powf(-0.5)));
let e_inv_sqrt_diag = Array::from_diag(&e_inv_sqrt);
Expand Down Expand Up @@ -569,28 +569,46 @@ fn rhf_scf_linscal(
"Iter", "E_scf", "E_tot", "ΔE", "RMS(|FPS - SPF|)"
);
for scf_iter in 0..=calc_sett.max_scf_iter {
// 1. First new Fock matrix
calc_new_F_matr_dir_scf(&mut F_matr, &delta_P_matr, schwarz_est_matr.as_ref().unwrap(), basis);
// 2. Calc E_scf
let E_scf_curr = calc_E_scf(&P_matr, &H_core, &F_matr);
scf.E_tot_conv = E_scf_curr + V_nuc;

let delta_E = E_scf_curr - E_scf_prev;
println!(
"{:>3} {:>20.12} {:>20.12} {}",
scf_iter,
E_scf_curr,
scf.E_tot_conv,
fmt_f64(delta_E, 20, 8, 2),
);

// 3. Save old density matrix
P_matr_old = P_matr.clone();
// 4. Calculate new density matrix
P_matr = calc_new_P_matr_linscal_contravar(&P_matr, &F_matr, &S_matr, &S_matr_inv);
// 5. Calculate calculate ΔP matrix
delta_P_matr = (&P_matr - &P_matr_old).to_owned();
E_scf_prev = E_scf_curr;
if scf_iter == 0 {
let S_matr_inv_sqrt = inv_ssqrt(&S_matr, UPLO::Upper);
let F_matr_pr = S_matr_inv_sqrt.dot(&F_matr).dot(&S_matr_inv_sqrt);

let (orb_ener, C_matr_MO) = F_matr_pr.eigh(UPLO::Upper).unwrap();
let C_matr_AO = S_matr_inv_sqrt.dot(&C_matr_MO);

calc_P_matr_rhf(&mut P_matr, &C_matr_AO, basis.no_occ());
println!("Guess P_matr:\n {:12.6}", &P_matr);
println!("Eigenvalues of guess: {:12.6}", &P_matr.eigh(UPLO::Upper).unwrap().0);
delta_P_matr = P_matr.clone();
} else {
// 1. First new Fock matrix
calc_new_F_matr_dir_scf(
&mut F_matr,
&delta_P_matr,
schwarz_est_matr.as_ref().unwrap(),
basis,
);
// 2. Calc E_scf
let E_scf_curr = calc_E_scf(&P_matr, &H_core, &F_matr);
scf.E_tot_conv = E_scf_curr + V_nuc;

let delta_E = E_scf_curr - E_scf_prev;
println!(
"{:>3} {:>20.12} {:>20.12} {}",
scf_iter,
E_scf_curr,
scf.E_tot_conv,
fmt_f64(delta_E, 20, 8, 2),
);

// 3. Save old density matrix
P_matr_old = P_matr.clone();
// 4. Calculate new density matrix
P_matr = calc_new_P_matr_linscal_contravar(&P_matr, &F_matr, &S_matr, &S_matr_inv);
// 5. Calculate calculate ΔP matrix
delta_P_matr = (&P_matr - &P_matr_old).to_owned();
E_scf_prev = E_scf_curr;
}
}
}

Expand All @@ -602,7 +620,7 @@ fn calc_new_P_matr_linscal_contravar(
S_matr: &Array2<f64>,
S_matr_inv: &Array2<f64>,
) -> Array2<f64> {
const STEP_WIDTH: f64 = 0.0005;
const STEP_WIDTH: f64 = 0.000_001;

let energy_grad = calc_energy_gradient_p_matr(F_matr, P_matr_curr, S_matr);
P_matr_curr - STEP_WIDTH * S_matr_inv.dot(&energy_grad).dot(S_matr_inv)
Expand Down Expand Up @@ -665,7 +683,7 @@ mod tests {
};
let mut exec_times = ExecTimes::new();

let _scf = rhf_scf_normal(calc_sett, &mut exec_times, &basis, &mol);
let _scf = rhf_scf_normal(&calc_sett, &mut exec_times, &basis, &mol);
println!("{:?}", _scf);
}

Expand All @@ -686,7 +704,7 @@ mod tests {
};
let mut exec_times = ExecTimes::new();

let _scf = rhf_scf_normal(calc_sett, &mut exec_times, &basis, &mol);
let _scf = rhf_scf_normal(&calc_sett, &mut exec_times, &basis, &mol);
println!("{:?}", _scf);
}

Expand All @@ -707,10 +725,10 @@ mod tests {
};
let mut exec_times = ExecTimes::new();

let _scf = rhf_scf_normal(calc_sett, &mut exec_times, &basis, &mol);
let _scf = rhf_scf_normal(&calc_sett, &mut exec_times, &basis, &mol);
// println!("{:?}", _scf);
}

#[test]
fn test_rhf_dir_linscal() {
let mol = Molecule::new("data/xyz/water90.xyz", 0);
Expand Down
193 changes: 193 additions & 0 deletions src/calc_type/uhf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
use super::{CalcSettings, SCF};
use crate::{
basisset::BasisSet,
calc_type::{
rhf::{calc_1e_int_matrs, calc_2e_int_matr, inv_ssqrt},
DIIS,
},
mol_int_and_deriv::te_int::calc_schwarz_est_int,
molecule::Molecule,
};
use ndarray::{linalg::general_mat_mul, s, Array1, Array2};
use ndarray_linalg::{Eigh, UPLO};

fn uhf_scf_normal(
calc_sett: &CalcSettings,
exec_times: &mut crate::print_utils::ExecTimes,
mol: &Molecule,
basis: &BasisSet,
) -> SCF {
let mut is_scf_conv = false;
let mut scf = SCF::default();
let mut diis: Option<DIIS> = if calc_sett.use_diis {
Some(DIIS::new(
&calc_sett.diis_sett,
[basis.no_bf(), basis.no_bf()],
))
} else {
None
};

let no_elec_half = mol.no_elec() / 2;
let (n_alpha, n_beta) = if mol.no_elec() % 2 == 0 {
(no_elec_half, no_elec_half)
} else {
(no_elec_half + 1, no_elec_half)
};

let V_nuc: f64 = if mol.no_atoms() > 100 {
mol.calc_core_potential_par()
} else {
mol.calc_core_potential_ser()
};

println!("Calculating 1e integrals ...");
let (S_matr, H_core) = calc_1e_int_matrs(basis, mol);
println!("FINSIHED calculating 1e integrals ...");

let mut eri;
let schwarz_est_matr;
if calc_sett.use_direct_scf {
eri = None;

println!("Calculating Schwarz int estimates ...");
schwarz_est_matr = Some(calc_schwarz_est_int(basis));
println!("FINISHED Schwarz int estimates ...");
} else {
schwarz_est_matr = None;

println!("Calculating 2e integrals ...");
eri = Some(calc_2e_int_matr(basis));
println!("FINSIHED calculating 2e integrals ...");
}

let S_matr_inv_sqrt = inv_ssqrt(&S_matr, UPLO::Upper);

// Init matrices for SCF loop
let (mut orb_ener_alph, mut C_matr_MO_alph) = init_diag_F_matr(&H_core, &S_matr_inv_sqrt);
let mut C_matr_AO_alph = S_matr_inv_sqrt.dot(&C_matr_MO_alph);

let mut C_matr_MO_beta = C_matr_MO_alph.clone();
let mut C_matr_AO_beta = C_matr_AO_alph.clone();
let mut orb_ener_beta = orb_ener_alph.clone();

let mut E_scf_prev = 0.0;

let mut P_matr_alph;
build_P_matr_uhf(&mut P_matr_alph, &C_matr_AO_alph, n_alpha);
let mut P_matr_beta;
build_P_matr_uhf(&mut P_matr_beta, &C_matr_AO_beta, n_beta);
let mut P_matr_old_alph = P_matr_alph.clone();
let mut P_matr_old_beta = P_matr_beta.clone();

let mut F_matr_pr;

Check failure on line 83 in src/calc_type/uhf.rs

View workflow job for this annotation

GitHub Actions / Rust project

type annotations needed
let mut diis_str = "";

// Initial guess -> H_core
let mut F_matr_alph;
let mut F_matr_beta;

// for scf_iter in 1..=calc_sett.max_scf_iter {
// /// direct or indirect scf
// match eri {
// Some(ref eri) => {
// calc_new_F_matr_ind_scf(&mut F_matr, &H_core, &P_matr, eri);
// }
// None => {
// calc_new_F_matr_dir_scf(
// &mut F_matr,
// &delta_P_matr,
// schwarz_est_matr.as_ref().unwrap(),
// basis,
// );
// }
// }
// let E_scf_curr = calc_E_scf(&P_matr, &H_core, &F_matr);
// scf.E_tot_conv = E_scf_curr + V_nuc;
// let fps_comm = DIIS::calc_FPS_comm(&F_matr, &P_matr, &S_matr);
//
// F_matr_pr = S_matr_inv_sqrt.dot(&F_matr).dot(&S_matr_inv_sqrt);
//
// if calc_sett.use_diis {
// let repl_idx = (scf_iter - 1) % calc_sett.diis_sett.diis_max; // always start with 0
// let err_matr = S_matr_inv_sqrt.dot(&fps_comm).dot(&S_matr_inv_sqrt);
// diis.as_mut()
// .unwrap()
// .push_to_ring_buf(&F_matr_pr, &err_matr, repl_idx);
//
// if scf_iter >= calc_sett.diis_sett.diis_min {
// // println!("{:^120}", "*** ↓ Using DIIS ↓ ***");
// let err_set_len = std::cmp::min(calc_sett.diis_sett.diis_max, scf_iter);
// F_matr_pr = diis.as_ref().unwrap().run_DIIS(err_set_len);
// diis_str = "DIIS";
// }
// }
//
// (orb_ener, C_matr_MO) = F_matr_pr.eigh(UPLO::Upper).unwrap();
// C_matr_AO = S_matr_inv_sqrt.dot(&C_matr_MO);
//
// let delta_E = E_scf_curr - E_scf_prev;
// let rms_comm_val =
// (fps_comm.par_iter().map(|x| x * x).sum::<f64>() / fps_comm.len() as f64).sqrt();
// if SHOW_ALL_CONV_CRIT {
// let rms_p_val = calc_rms_2_matr(&P_matr, &P_matr_old.clone());
// println!(
// "{:>3} {:>20.12} {:>20.12} {:>20.12} {:>20.12} {:>20.12}",
// scf_iter, E_scf_curr, scf.E_tot_conv, rms_p_val, delta_E, rms_comm_val
// );
// } else {
// println!(
// "{:>3} {:>20.12} {:>20.12} {} {} {:>10} ",
// scf_iter,
// E_scf_curr,
// scf.E_tot_conv,
// fmt_f64(delta_E, 20, 8, 2),
// fmt_f64(rms_comm_val, 20, 8, 2),
// diis_str
// );
// diis_str = "";
// }
//
// if (delta_E.abs() < calc_sett.e_diff_thrsh)
// && (rms_comm_val < calc_sett.commu_conv_thrsh)
// {
// scf.tot_scf_iter = scf_iter;
// scf.E_scf_conv = E_scf_curr;
// scf.C_matr_conv = C_matr_AO.clone();
// scf.P_matr_conv = P_matr.clone();
// scf.orb_energies_conv = orb_ener.clone();
// println!("\nSCF CONVERGED!\n");
// is_scf_conv = true;
// break;
// } else if scf_iter == calc_sett.max_scf_iter {
// println!("\nSCF DID NOT CONVERGE!\n");
// break;
// }
// E_scf_prev = E_scf_curr;
// P_matr_old = P_matr.clone();
// calc_P_matr_rhf(&mut P_matr, &C_matr_AO, basis.no_occ());
// delta_P_matr = (&P_matr - &P_matr_old).to_owned();
//
// }

scf
}

fn init_diag_F_matr(
F_matr: &Array2<f64>,
S_matr_inv_sqrt: &Array2<f64>,
) -> (Array1<f64>, Array2<f64>) {
let F_matr_pr = S_matr_inv_sqrt.dot(F_matr).dot(S_matr_inv_sqrt);
let (orb_ener, C_matr) = F_matr_pr.eigh(UPLO::Upper).unwrap();
let C_matr = S_matr_inv_sqrt.dot(&C_matr);
(orb_ener, C_matr)
}

fn build_P_matr_uhf(P_matr_spin: &mut Array2<f64>, C_matr_MO_spin: &Array2<f64>, n_orb: usize) {
let C_occ = C_matr_MO_spin.slice(s![.., ..n_orb]);
general_mat_mul(1.0_f64, &C_occ, &C_occ.t(), 0.0_f64, P_matr_spin);
}

fn divmod(n: usize, d: usize) -> (usize, usize) {
(n / d, n % d)
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn main() {
},
};

let _scf = rhf_scf_normal(calc_sett, &mut exec_times, &basis, &mol);
let _scf = rhf_scf_normal(&calc_sett, &mut exec_times, &basis, &mol);
exec_times.stop("RHF noDIIS");


Expand Down
1 change: 0 additions & 1 deletion src/molecule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ impl Molecule {
Ok((z_vals, geom_matr, atoms, no_atoms))
}


pub(crate) fn calc_core_potential_ser(&self) -> f64 {
let mut core_potential = 0.0;
let coords = &self.geom.coords_matr;
Expand Down

0 comments on commit ee7c98c

Please sign in to comment.