1use super::*;
3
4use std::ptr::null;
5pub struct XtbEnvironment {
10 env: xtb_TEnvironment,
12}
13
14impl XtbEnvironment {
15 pub fn new() -> Self {
17 unsafe { assert_eq!(XTB_API_VERSION, xtb_getAPIVersion() as u32) };
18
19 Self {
20 env: unsafe { xtb_newEnvironment() },
21 }
22 }
23
24 pub fn check_error(&self) -> Result<()> {
26 let ret = unsafe { xtb_checkEnvironment(self.env) };
27 if ret != 0 {
28 unsafe { xtb_showEnvironment(self.env, null()) };
30 bail!("Error occured in the API with return code {}!", ret);
31 }
32 Ok(())
33 }
34
35 fn set_verbosity(&self, verbosity: u32) -> Result<()> {
37 unsafe {
38 xtb_setVerbosity(self.env, verbosity as i32);
39 }
40 self.check_error()?;
41 Ok(())
42 }
43
44 pub fn set_output_verbose(&self) -> Result<()> {
46 self.set_verbosity(XTB_VERBOSITY_FULL)
47 }
48
49 pub fn set_output_minimal(&self) -> Result<()> {
51 self.set_verbosity(XTB_VERBOSITY_MINIMAL)
52 }
53
54 pub fn set_output_muted(&self) -> Result<()> {
56 self.set_verbosity(XTB_VERBOSITY_MUTED)
57 }
58}
59pub struct XtbMolecule {
64 mol: xtb_TMolecule,
65}
66
67impl XtbMolecule {
68 pub fn create<'a>(
72 env: &XtbEnvironment,
73 attyp: &[i32],
74 coord: &[f64],
75 charge: f64,
76 uhf: i32,
77 lattice: impl Into<Option<&'a [f64; 9]>>,
78 periodic: impl Into<Option<&'a [bool; 3]>>,
79 ) -> Result<Self> {
80 let mol = unsafe {
81 let natoms = attyp.len() as i32;
82 let env = env.env;
83 let attyp = attyp.as_ptr();
84 let coord = coord.as_ptr();
85 let lattice = lattice.into().map_or(null(), |x| x.as_ptr());
86 let periodic = periodic.into().map_or(null(), |x| x.as_ptr());
87 xtb_newMolecule(env, &natoms, attyp, coord, &charge, &uhf, lattice, periodic)
88 };
89 env.check_error()?;
90 let mol = Self { mol };
91
92 Ok(mol)
93 }
94
95 pub fn update(&self, env: &XtbEnvironment, coord: &[f64], lattice: Option<&[f64; 9]>) -> Result<()> {
97 unsafe {
98 let env = env.env;
99 let mol = self.mol;
100 let coord = coord.as_ptr();
101 let lattice = lattice.map_or(null(), |x| x.as_ptr());
102 xtb_updateMolecule(env, mol, coord, lattice);
103 }
104 env.check_error()?;
105
106 Ok(())
107 }
108}
109#[derive(Clone, Debug, Copy, PartialEq)]
114pub enum XtbMethod {
115 GFN2xTB,
117 GFN1xTB,
119 GFN0xTB,
121 GFNFF,
123}
124
125pub struct XtbCalculator {
127 calc: xtb_TCalculator,
128}
129
130impl XtbCalculator {
131 pub fn new() -> Self {
133 Self {
134 calc: unsafe { xtb_newCalculator() },
135 }
136 }
137
138 pub fn load_parametrization(&self, mol: &XtbMolecule, env: &XtbEnvironment, method: XtbMethod) -> Result<()> {
140 unsafe {
141 let calc = self.calc;
142 let mol = mol.mol;
143 let env = env.env;
144 match method {
145 XtbMethod::GFNFF => xtb_loadGFNFF(env, mol, calc, std::ptr::null_mut()),
146 XtbMethod::GFN0xTB => xtb_loadGFN0xTB(env, mol, calc, std::ptr::null_mut()),
147 XtbMethod::GFN1xTB => xtb_loadGFN1xTB(env, mol, calc, std::ptr::null_mut()),
148 XtbMethod::GFN2xTB => xtb_loadGFN2xTB(env, mol, calc, std::ptr::null_mut()),
149 _ => unimplemented!(),
150 }
151 }
152 env.check_error()?;
153 Ok(())
154 }
155
156 pub fn set_max_iterations(&self, env: &XtbEnvironment, n: usize) {
162 unsafe {
163 xtb_setMaxIter(env.env, self.calc, n as i32);
164 }
165 }
166
167 pub fn set_electronic_temperature(&self, env: &XtbEnvironment, temp: f64) {
169 unsafe {
170 xtb_setElectronicTemp(env.env, self.calc, temp);
171 }
172 }
173
174 pub fn set_accuracy(&self, env: &XtbEnvironment, acc: f64) {
176 unsafe {
177 xtb_setAccuracy(env.env, self.calc, acc);
178 }
179 }
180
181 pub fn single_point(&self, mol: &XtbMolecule, env: &XtbEnvironment) -> Result<XtbResults> {
184 let mut res = XtbResults::new();
185 unsafe {
186 let calc = self.calc;
187 let mol = mol.mol;
188 let res = res.res;
189 let env = env.env;
190 xtb_singlepoint(env, mol, calc, res);
191 }
192 env.check_error()?;
193 Ok(res)
194 }
195}
196pub struct XtbResults {
201 res: xtb_TResults,
202}
203
204impl XtbResults {
205 fn new() -> Self {
207 Self {
208 res: unsafe { xtb_newResults() },
209 }
210 }
211
212 pub fn get_energy(&self, env: &XtbEnvironment) -> Result<f64> {
214 let mut energy = std::f64::NAN;
215 unsafe {
216 xtb_getEnergy(env.env, self.res, &mut energy);
217 }
218 env.check_error()?;
219 Ok(energy)
220 }
221
222 pub fn get_dipole(&self, env: &XtbEnvironment) -> Result<[f64; 3]> {
224 let mut dipole = [std::f64::NAN; 3];
225 unsafe {
226 xtb_getDipole(env.env, self.res, dipole.as_mut_ptr());
227 }
228 env.check_error()?;
229 Ok(dipole)
230 }
231
232 pub fn get_gradient(&self, env: &XtbEnvironment, gradient: &mut [f64]) -> Result<()> {
234 unsafe {
235 xtb_getGradient(env.env, self.res, gradient.as_mut_ptr());
236 }
237 env.check_error()?;
238 Ok(())
239 }
240
241 pub fn get_bond_orders(&self, env: &XtbEnvironment, bond_orders: &mut [f64]) -> Result<()> {
243 unsafe {
244 xtb_getBondOrders(env.env, self.res, bond_orders.as_mut_ptr());
245 }
246 env.check_error()?;
247 Ok(())
248 }
249
250 pub fn get_charges(&self, env: &XtbEnvironment, charges: &mut [f64]) -> Result<()> {
252 unsafe {
253 xtb_getCharges(env.env, self.res, charges.as_mut_ptr());
254 }
255 env.check_error()?;
256 Ok(())
257 }
258
259 pub fn get_virial(&self, env: &XtbEnvironment, virial: &mut [f64]) -> Result<()> {
261 unsafe {
262 xtb_getVirial(env.env, self.res, virial.as_mut_ptr());
263 }
264 env.check_error()?;
265 Ok(())
266 }
267
268 pub fn get_nao(&self, env: &XtbEnvironment) -> Result<usize> {
270 let mut nao = 0;
271 unsafe {
272 xtb_getNao(env.env, self.res, &mut nao);
273 }
274 env.check_error()?;
275 Ok(nao as usize)
276 }
277
278 pub fn get_orbital_eigenvalues(&self, env: &XtbEnvironment, emo: &mut [f64]) -> Result<()> {
280 unsafe {
281 xtb_getOrbitalEigenvalues(env.env, self.res, emo.as_mut_ptr());
282 }
283 env.check_error()?;
284 Ok(())
285 }
286
287 pub fn get_orbital_occupations(&self, env: &XtbEnvironment, focc: &mut [f64]) -> Result<()> {
289 unsafe {
290 xtb_getOrbitalOccupations(env.env, self.res, focc.as_mut_ptr());
291 }
292 env.check_error()?;
293 Ok(())
294 }
295
296 pub fn get_orbital_coefficients(&self, env: &XtbEnvironment, forb: &mut [f64]) -> Result<()> {
298 unsafe {
299 xtb_getOrbitalCoefficients(env.env, self.res, forb.as_mut_ptr());
300 }
301 env.check_error()?;
302 Ok(())
303 }
304}
305macro_rules! impl_xtb_drop {
309 ($obj:ident, $xtb_del:ident, $res:ident) => {
310 impl Drop for $obj {
311 fn drop(&mut self) {
312 if !self.$res.is_null() {
313 unsafe { $xtb_del(&mut self.$res) }
314 }
315 assert!(self.$res.is_null());
316 }
317 }
318 };
319}
320
321impl_xtb_drop!(XtbEnvironment, xtb_delEnvironment, env);
322impl_xtb_drop!(XtbMolecule, xtb_delMolecule, mol);
323impl_xtb_drop!(XtbResults, xtb_delResults, res);
324impl_xtb_drop!(XtbCalculator, xtb_delCalculator, calc);
325