use crate::interface::PyGeomDriver;
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList};
use pyo3::PyTypeInfo;
#[pyclass(subclass)]
pub struct EngineMixin {
driver: Option<PyGeomDriver>,
}
#[pymethods]
impl EngineMixin {
#[new]
pub fn new(_molecule: PyObject) -> PyResult<Self> {
Ok(EngineMixin { driver: None })
}
pub fn set_driver(&mut self, driver: &PyGeomDriver) {
self.driver = Some(driver.clone());
}
pub fn calc_new(&mut self, coords: Vec<f64>, dirname: &str) -> PyResult<PyObject> {
let mut driver = self.driver.as_mut().unwrap().pointer.lock().unwrap();
let result = driver.calc_new(&coords, dirname);
Python::with_gil(|py| {
let numpy = py.import("numpy")?;
let energy = result.energy;
let gradient = numpy.call_method1("array", (PyList::new(py, result.gradient)?,))?;
let dict = PyDict::new(py);
dict.set_item("energy", energy)?;
dict.set_item("gradient", gradient)?;
Ok(dict.into())
})
}
}
pub fn get_pyo3_engine_cls() -> PyResult<PyObject> {
Python::with_gil(|py| {
let base_type = py.import("geometric.engine")?.getattr("Engine")?;
let engine_mixin_type = EngineMixin::type_object(py);
let locals = PyDict::new(py);
locals.set_item("Engine", base_type)?;
locals.set_item("EngineMixin", engine_mixin_type)?;
let pyo3_engine_type =
py.eval(c"type('PyO3Engine', (EngineMixin, Engine), {})", None, Some(&locals))?;
Ok(pyo3_engine_type.into())
})
}
pub fn init_pyo3_molecule(elem: &[&str], xyzs: &[Vec<f64>]) -> PyResult<PyObject> {
Python::with_gil(|py| {
let molecule_cls = py.import("geometric.molecule")?.getattr("Molecule")?;
let molecule_instance = molecule_cls.call0()?;
let numpy = py.import("numpy")?;
let xyzs = xyzs
.iter()
.map(|xyz| {
let arr = numpy.call_method1("array", (PyList::new(py, xyz)?,))?;
let arr = arr.call_method1("reshape", (-1, 3))?;
Ok(arr)
})
.collect::<PyResult<Vec<_>>>()?;
molecule_instance.setattr("elem", elem)?;
molecule_instance.setattr("xyzs", xyzs)?;
Ok(molecule_instance.into())
})
}
pub fn molecule_build_topology(
molecule: &PyObject,
kwargs: Option<&Bound<'_, PyDict>>,
) -> PyResult<()> {
Python::with_gil(|py| {
molecule.call_method(py, "build_topology", (), kwargs)?;
Ok(())
})
}