use crate::types::{AlignedMatrix, MolecularBatch};
#[derive(Debug, Clone, PartialEq)]
pub struct BondOrderResult {
pub bond_orders: AlignedMatrix<f64>,
pub valencies: Vec<f64>,
pub active_charges: Vec<f64>,
pub self_charges: Vec<f64>,
pub free_valencies: Vec<f64>,
}
#[allow(clippy::needless_range_loop)]
pub fn compute_bond_orders(
batch: &MolecularBatch,
density: &AlignedMatrix<f64>,
) -> BondOrderResult {
let natoms = batch.natoms;
let mut bond_orders = AlignedMatrix::zeroed(natoms, natoms);
let mut valencies = vec![0.0; natoms];
let mut active_charges = vec![0.0; natoms];
let mut self_charges = vec![0.0; natoms];
let mut free_valencies = vec![0.0; natoms];
for a in 0..natoms {
let la = batch.orbital_offsets[a];
let norbs_a = batch.basis_types[a].num_orbitals();
let lla = la + norbs_a;
let mut sum_diag = 0.0;
for mu in la..lla {
sum_diag += density.get(mu, mu);
}
let mut self_term = 0.0;
for mu in la..lla {
for nu in la..lla {
let p = density.get(mu, nu);
self_term += p * p;
}
}
let va = 2.0 * sum_diag - self_term;
valencies[a] = va;
for b in (a + 1)..natoms {
let lb = batch.orbital_offsets[b];
let norbs_b = batch.basis_types[b].num_orbitals();
let llb = lb + norbs_b;
let mut b_ab = 0.0;
for mu in la..lla {
for nu in lb..llb {
let p = density.get(mu, nu);
b_ab += p * p;
}
}
bond_orders.set(a, b, b_ab);
bond_orders.set(b, a, b_ab);
}
}
for a in 0..natoms {
let mut aq = 0.0;
for b in 0..natoms {
if a != b {
aq += bond_orders.get(a, b);
}
}
active_charges[a] = aq;
free_valencies[a] = valencies[a] - aq;
self_charges[a] = (valencies[a] - aq) * 0.5;
}
BondOrderResult {
bond_orders,
valencies,
active_charges,
self_charges,
free_valencies,
}
}