use crate::ffi;
use crate::interface::*;
use std::ptr::null_mut;
use std::result::Result;
pub struct DFTD3GCP {
ptr: ffi::dftd3_gcp,
structure: DFTD3Structure,
}
impl Drop for DFTD3GCP {
fn drop(&mut self) {
unsafe { ffi::dftd3_delete_gcp(&mut self.ptr) };
}
}
impl DFTD3GCP {
pub fn new(
numbers: &[usize],
positions: &[f64],
lattice: Option<&[f64]>,
periodic: Option<&[bool]>,
method: &str,
basis: &str,
) -> Self {
Self::new_f(numbers, positions, lattice, periodic, method, basis).unwrap()
}
pub fn get_counterpoise(&self, eval_grad: bool) -> DFTD3Output {
self.get_counterpoise_f(eval_grad).unwrap()
}
pub fn get_natoms(&self) -> usize {
self.structure.get_natoms()
}
pub fn update(&mut self, positions: &[f64], lattice: Option<&[f64]>) {
self.structure.update(positions, lattice)
}
pub fn load_gcp_param(structure: DFTD3Structure, method: &str, basis: &str) -> Self {
Self::load_gcp_param_f(structure, method, basis).unwrap()
}
pub fn set_realspace_cutoff(&self, bas: f64, srb: f64) {
self.set_realspace_cutoff_f(bas, srb).unwrap()
}
pub fn new_f(
numbers: &[usize],
positions: &[f64],
lattice: Option<&[f64]>,
periodic: Option<&[bool]>,
method: &str,
basis: &str,
) -> Result<Self, DFTD3Error> {
let structure = DFTD3Structure::new_f(numbers, positions, lattice, periodic)?;
Self::load_gcp_param_f(structure, method, basis)
}
pub fn get_counterpoise_f(&self, eval_grad: bool) -> Result<DFTD3Output, DFTD3Error> {
let structure = &self.structure;
let natoms = structure.get_natoms();
let mut energy = 0.0;
let mut grad = match eval_grad {
true => Some(vec![0.0; 3 * natoms]),
false => None,
};
let mut sigma = match eval_grad {
true => Some(vec![0.0; 9]),
false => None,
};
let mut error = DFTD3Error::new();
unsafe {
ffi::dftd3_get_counterpoise(
error.get_c_ptr(),
structure.ptr,
self.ptr,
&mut energy,
grad.as_mut().map_or(null_mut(), |x| x.as_mut_ptr()),
sigma.as_mut().map_or(null_mut(), |x| x.as_mut_ptr()),
)
};
match error.check() {
true => Err(error),
false => Ok(DFTD3Output { energy, grad, sigma }),
}
}
pub fn load_gcp_param_f(
structure: DFTD3Structure,
method: &str,
basis: &str,
) -> Result<Self, DFTD3Error> {
let mut error = DFTD3Error::new();
let token_method = std::ffi::CString::new(method).unwrap();
let token_basis = std::ffi::CString::new(basis).unwrap();
let ptr = unsafe {
ffi::dftd3_load_gcp_param(
error.get_c_ptr(),
structure.ptr,
token_method.into_raw(),
token_basis.into_raw(),
)
};
match error.check() {
true => Err(error),
false => Ok(Self { ptr, structure }),
}
}
pub fn set_realspace_cutoff_f(&self, bas: f64, srb: f64) -> Result<(), DFTD3Error> {
let mut error = DFTD3Error::new();
unsafe { ffi::dftd3_set_gcp_realspace_cutoff(error.get_c_ptr(), self.ptr, bas, srb) };
match error.check() {
true => Err(error),
false => Ok(()),
}
}
}
pub fn get_counterpoise_f(
structure: &DFTD3Structure,
gcp: &DFTD3GCP,
) -> Result<(f64, Vec<f64>, Vec<f64>), DFTD3Error> {
let natoms = structure.get_natoms();
let mut energy = 0.0;
let mut grad = vec![0.0; 3 * natoms];
let mut sigma = vec![0.0; 9];
let mut error = DFTD3Error::new();
unsafe {
ffi::dftd3_get_counterpoise(
error.get_c_ptr(),
structure.ptr,
gcp.ptr,
&mut energy,
grad.as_mut_ptr(),
sigma.as_mut_ptr(),
)
};
match error.check() {
true => Err(error),
false => Ok((energy, grad, sigma)),
}
}
pub fn get_counterpoise(structure: &DFTD3Structure, gcp: &DFTD3GCP) -> (f64, Vec<f64>, Vec<f64>) {
get_counterpoise_f(structure, gcp).unwrap()
}