rust_libcint/lib.rs
1//! # rust-libcint
2//!
3//! The `rust-libcint` crate provides wrappers for libcint (C).
4//!
5//! In order to use the crate, the libcint should be installed with the outcome library `libcint.so` stored in a reachable path by users.
6//!
7//! Please visit <https://github.com/sunqm/libcint> for more details about the installation and the usage of libcint
8//!
9//! The `CINTR2CDATA` struct groups all necessary data for using `libcint`.
10//! Various kinds of analytical Gaussian-type orbital (GTO) integrals provided by `libcint` are then wrapped as the methods defined on the `CINTR2CDATA` struct.
11//!
12//! Currently, only four kinds of integrals, including 1) the one-electron kinetic integral,
13//! 2) the one-electron nuclear attractive integral, 3) the one-electron overlap integral,
14//! and 4) the two-electron repulsive integral are available for both spheric and Cartesian GTOs.
15//! The other kinds of integrals are not yet ready in the current version.
16//!
17//! # Examples
18//!
19//!
20//! ```
21//! //=============================================================================
22//! // Prepare `atm`, `bas` and `env` with the same data structures of those used by `libcint`.
23//! // Refer to <https://github.com/sunqm/libcint/blob/master/doc/program_ref.pdf>
24//! // for the details of these data structures.
25//! //=============================================================================
26//! use rust_libcint::{CINTR2CDATA,CintType};
27//! let mut atm: Vec<Vec<i32>> = vec![];
28//! atm.push(vec![2,0,0,0,0,0]);
29//! atm.push(vec![4,3,0,0,0,0]);
30//! let mut natm = atm.len() as i32;
31//! let mut bas: Vec<Vec<i32>> = vec![];
32//! bas.push(vec![0,1,1,1,1,6,7,0]);
33//! bas.push(vec![0,2,1,1,1,8,9,0]);
34//! let mut nbas = bas.len() as i32;
35//! let mut env: Vec<f64> = vec![0.0,0.0,0.0,0.7,0.0,0.0,1.0,1.0,0.5,1.0];
36//! let mut cint_data = CINTR2CDATA::new();
37//! // Transfer `atm`, `bas`, and `env` to the raw pointers,
38//! // and organize them by the `CINTR2CDATA` structure.
39//! cint_data.initial_r2c(&atm,natm,&bas,nbas,env);
40//! //=============================================================================
41//! //The 2-electron repulsive integrals (ERIs) for spheric Gaussian-type orbitals
42//! //=============================================================================
43//! // The GTO functions considered here are shperic.
44//! // For Cartesian GTOs, replace `CintType::Spheric` by
45//! // `CintType::Cartesian` on the following line:
46//! cint_data.set_cint_type(CintType::Spheric);
47//! cint_data.cint2e_optimizer_rust();
48//! let buf = cint_data.cint_ijkl(0,1,1,0);
49//! let mut v1:f64=0.0;
50//! &buf.into_iter().for_each(|i| {v1 += i.abs()});
51//! println!("The reference data for cint2e ERIs: 0.5745411555937561; v1: {:18.16}; ",v1);
52//! //=============================================================================
53//! //The one-electron overlap integrals for spheric Gaussian-type orbitals
54//! //=============================================================================
55//! cint_data.cint_del_optimizer_rust();
56//! // The GTO functions considered here are shperic
57//! cint_data.set_cint_type(CintType::Spheric);
58//! cint_data.cint1e_ovlp_optimizer_rust();
59//! let buf = cint_data.cint_ijovlp(0,1);
60//! let mut v1:f64=0.0;
61//! &buf.into_iter().for_each(|i| {v1 += i.abs()});
62//! println!("The reference data for cint1e_ovlp: 0.7096366827378776; v1: {:18.16}; ",v1);
63//! //=============================================================================
64//! //The one-electron kinetic integrals for Cartesian Gaussian-type orbitals
65//! //=============================================================================
66//! cint_data.cint_del_optimizer_rust();
67//! // The GTO functions considered here are Cartesian
68//! cint_data.set_cint_type(CintType::Cartesian);
69//! cint_data.cint1e_kin_optimizer_rust();
70//! let buf = cint_data.cint_ijkin(0,1);
71//! let mut v1:f64=0.0;
72//! &buf.into_iter().for_each(|i| {v1 += i.abs()});
73//! println!("The reference data for cint1e_kin : 1.5780816190296618; v1: {:18.16}; ",v1);
74//! //=============================================================================
75//! //The one-electron nuclear attraction integrals for Cartesian Gaussian-type orbitals
76//! //=============================================================================
77//! cint_data.cint_del_optimizer_rust();
78//! // The GTO functions considered here are Cartesian
79//! cint_data.set_cint_type(CintType::Cartesian);
80//! cint_data.cint1e_nuc_optimizer_rust();
81//! let buf = cint_data.cint_ijnuc(0,1);
82//! let mut v1:f64=0.0;
83//! &buf.into_iter().for_each(|i| {v1 += i.abs()});
84//! println!("The reference data for cint1e_nuc : 4.0007622494430706; v1: {:18.16}; ",v1);
85//! //=============================================================================
86//! // Finally deallocate the memory by transferring the raw pointers back to RUST
87//! // i.e. Vec::from_raw_parts();
88//! //=============================================================================
89//! cint_data.final_c2r();
90//! ```
91
92#![allow(unused)]
93use std::os::raw::c_int;
94use std::mem::ManuallyDrop;
95
96mod cint;
97use crate::cint::{CINTOpt,CINTdel_optimizer};
98
99pub enum CintType {
100 Spheric,
101 Cartesian,
102 //Spinor, // Not yet included
103}
104
105pub struct CINTR2CDATA {
106 c_atm: (*mut i32, usize, usize),
107 c_bas: (*mut i32, usize, usize),
108 c_env: (*mut f64, usize, usize),
109 c_nbas: c_int,
110 c_natm: c_int,
111 c_opt: (*mut CINTOpt, usize, usize),
112 cint_type: CintType,
113}
114
115impl CINTR2CDATA {
116 /// create a new, empty CINTR2CDATA.
117 pub fn new() -> CINTR2CDATA {
118 CINTR2CDATA {
119 c_atm: (unsafe {std::ptr::null::<i32>() as *mut i32}, 0,0),
120 c_bas: (unsafe {std::ptr::null::<i32>() as *mut i32}, 0,0),
121 c_env: (unsafe {std::ptr::null::<f64>() as *mut f64}, 0,0),
122 c_opt: (unsafe {std::ptr::null::<CINTOpt>() as *mut CINTOpt}, 0,0),
123 c_nbas: 0 as c_int,
124 c_natm: 0 as c_int,
125 cint_type: CintType::Spheric,
126 }
127 }
128 pub fn set_cint_type(&mut self, ctype: CintType) {
129 self.cint_type = ctype;
130 }
131 ////
132 pub fn initial_r2c(&mut self,
133 atm: &Vec<Vec<i32>>, natm:i32,
134 bas: &Vec<Vec<i32>>, nbas:i32,
135 mut env: Vec<f64>) {
136 unsafe {
137 let r_atm = Vec::from_raw_parts(self.c_atm.0,self.c_atm.1,self.c_atm.2);
138 let r_bas = Vec::from_raw_parts(self.c_bas.0,self.c_bas.1,self.c_bas.2);
139 let r_env = Vec::from_raw_parts(self.c_env.0,self.c_env.1,self.c_env.2);
140 }
141 env.shrink_to_fit();
142 let mut env = ManuallyDrop::new(env);
143 self.c_env = (env.as_mut_ptr(), env.len(), env.capacity());
144
145 let mut bas_f: Vec<i32> = vec![];
146 &mut (0..bas.len()).for_each(|i| {
147 bas_f.extend(bas[i].clone());
148 });
149 bas_f.shrink_to_fit();
150 let mut bas_f = ManuallyDrop::new(bas_f);
151 self.c_bas = (bas_f.as_mut_ptr(), bas_f.len(), bas_f.capacity());
152
153 let mut atm_f: Vec<i32> = vec![];
154 &mut (0..atm.len()).for_each(|i| {
155 atm_f.extend(atm[i].clone());
156 });
157 atm_f.shrink_to_fit();
158 let mut atm_f = ManuallyDrop::new(atm_f);
159 self.c_atm = (atm_f.as_mut_ptr(), atm_f.len(), atm_f.capacity());
160
161 self.c_natm = natm as c_int;
162 self.c_nbas = nbas as c_int;
163
164 self.c_opt = (unsafe {std::ptr::null::<CINTOpt>() as *mut CINTOpt}, 0,0);
165 }
166 pub fn final_c2r(&mut self) {
167 println!("Transfer the ownership of the raw pointers in CINTR2CDATA to Rust");
168 unsafe {
169 let r_atm = Vec::from_raw_parts(self.c_atm.0,self.c_atm.1,self.c_atm.2);
170 let r_bas = Vec::from_raw_parts(self.c_bas.0,self.c_bas.1,self.c_bas.2);
171 let r_env = Vec::from_raw_parts(self.c_env.0,self.c_env.1,self.c_env.2);
172 }
173 self.cint_del_optimizer_rust();
174 }
175 pub fn cint_del_optimizer_rust(&mut self) {
176 unsafe{
177 CINTdel_optimizer(&mut self.c_opt.0);
178 }
179 }
180 pub fn cint2e_optimizer_rust(&mut self){
181 self.cint_del_optimizer_rust();
182 //self.cint_init_2e_optimizer_rust();
183 unsafe {
184 cint::cint2e_optimizer(&mut self.c_opt.0,
185 self.c_atm.0, self.c_natm,
186 self.c_bas.0, self.c_nbas,
187 self.c_env.0);
188 }
189 }
190 pub fn cint1e_ovlp_optimizer_rust(&mut self){
191 self.cint_del_optimizer_rust();
192 //self.cint_init_optimizer_rust();
193 unsafe {
194 cint::cint1e_ovlp_optimizer(&mut self.c_opt.0,
195 self.c_atm.0, self.c_natm,
196 self.c_bas.0, self.c_nbas,
197 self.c_env.0);
198 }
199 }
200 pub fn cint1e_nuc_optimizer_rust(&mut self){
201 self.cint_del_optimizer_rust();
202 //self.cint_init_optimizer_rust();
203 unsafe {
204 cint::cint1e_nuc_optimizer(&mut self.c_opt.0,
205 self.c_atm.0, self.c_natm,
206 self.c_bas.0, self.c_nbas,
207 self.c_env.0);
208 }
209 }
210 pub fn cint1e_kin_optimizer_rust(&mut self){
211 self.cint_del_optimizer_rust();
212 //self.cint_init_optimizer_rust();
213 unsafe {
214 cint::int1e_kin_optimizer(&mut self.c_opt.0,
215 self.c_atm.0, self.c_natm,
216 self.c_bas.0, self.c_nbas,
217 self.c_env.0);
218 }
219 }
220 pub fn cint_cgto_rust(&self, index: i32) -> i32 {
221 let mut dim: i32;
222 unsafe {
223 dim = match self.cint_type {
224 CintType::Spheric =>cint::CINTcgto_spheric(index as c_int, self.c_bas.0) as i32,
225 CintType::Cartesian=>cint::CINTcgto_cart(index as c_int, self.c_bas.0) as i32,
226 };
227 }
228 dim
229 }
230 pub fn cint_ijkl(&mut self, i:i32,j:i32,k:i32,l:i32) -> Vec<f64> {
231 let mut di = self.cint_cgto_rust(i);
232 let mut dj = self.cint_cgto_rust(j);
233 let mut dk = self.cint_cgto_rust(k);
234 let mut dl = self.cint_cgto_rust(l);
235
236 let mut shls: Vec<c_int> = vec![i as c_int,j as c_int,k as c_int,l as c_int];
237 shls.shrink_to_fit();
238 let mut shls = ManuallyDrop::new(shls);
239 let (c_shls,shls_len,shls_cap) = (shls.as_mut_ptr() as *mut c_int,shls.len(),shls.capacity());
240
241 let mut buf: Vec<f64> = [0.0f64].repeat((di*dj*dk*dl) as usize);
242 buf.shrink_to_fit();
243 let mut buf = ManuallyDrop::new(buf);
244 let (c_buf, buf_len, buf_cap) = (buf.as_mut_ptr() as *mut f64, buf.len(), buf.capacity());
245
246 let mut new_buf:Vec<f64>;
247 unsafe {
248 match self.cint_type {
249 CintType::Spheric => cint::cint2e_sph(c_buf, c_shls,
250 self.c_atm.0, self.c_natm,
251 self.c_bas.0,self.c_nbas,
252 self.c_env.0,
253 self.c_opt.0),
254 CintType::Cartesian => cint::cint2e_cart(c_buf, c_shls,
255 self.c_atm.0, self.c_natm,
256 self.c_bas.0,self.c_nbas,
257 self.c_env.0,
258 self.c_opt.0),
259 };
260 //println!("debug 1 {}", &c_buf.read());
261 let shls = Vec::from_raw_parts(c_shls, shls_len, shls_cap);
262 new_buf = Vec::from_raw_parts(c_buf, buf_len, buf_cap);
263 }
264 new_buf
265 }
266 pub fn cint_ijovlp(&mut self, i:i32,j:i32) -> Vec<f64> {
267 let mut di: i32 = self.cint_cgto_rust(i);
268 let mut dj: i32 = self.cint_cgto_rust(j);
269
270 let mut shls: Vec<c_int> = vec![i as c_int,j as c_int];
271 shls.shrink_to_fit();
272 let mut shls = ManuallyDrop::new(shls);
273 let (c_shls,shls_len,shls_cap) = (shls.as_mut_ptr() as *mut c_int,shls.len(),shls.capacity());
274
275 let mut buf: Vec<f64> = [0.0f64].repeat((di*dj) as usize);
276 buf.shrink_to_fit();
277 let mut buf = ManuallyDrop::new(buf);
278 let (c_buf, buf_len, buf_cap) = (buf.as_mut_ptr() as *mut f64, buf.len(), buf.capacity());
279
280 let mut new_buf:Vec<f64>;
281 unsafe {
282 match self.cint_type {
283 CintType::Spheric => cint::cint1e_ovlp_sph(
284 c_buf, c_shls,
285 self.c_atm.0, self.c_natm,
286 self.c_bas.0,self.c_nbas,
287 self.c_env.0,
288 self.c_opt.0),
289 CintType::Cartesian => cint::cint1e_ovlp_cart(
290 c_buf, c_shls,
291 self.c_atm.0, self.c_natm,
292 self.c_bas.0,self.c_nbas,
293 self.c_env.0,
294 self.c_opt.0),
295 };
296 let shls = Vec::from_raw_parts(c_shls, shls_len, shls_cap);
297 new_buf = Vec::from_raw_parts(c_buf, buf_len, buf_cap);
298 }
299 new_buf
300 }
301 pub fn cint_ijnuc(&mut self, i:i32,j:i32) -> Vec<f64> {
302 let mut di: i32 = self.cint_cgto_rust(i);
303 let mut dj: i32 = self.cint_cgto_rust(j);
304
305 let mut shls: Vec<c_int> = vec![i as c_int,j as c_int];
306 shls.shrink_to_fit();
307 let mut shls = ManuallyDrop::new(shls);
308 let (c_shls,shls_len,shls_cap) = (shls.as_mut_ptr() as *mut c_int,shls.len(),shls.capacity());
309
310 let mut buf: Vec<f64> = [0.0f64].repeat((di*dj) as usize);
311 buf.shrink_to_fit();
312 let mut buf = ManuallyDrop::new(buf);
313 let (c_buf, buf_len, buf_cap) = (buf.as_mut_ptr() as *mut f64, buf.len(), buf.capacity());
314
315 let mut new_buf:Vec<f64>;
316 unsafe {
317 match self.cint_type {
318 CintType::Spheric => cint::cint1e_nuc_sph(
319 c_buf, c_shls,
320 self.c_atm.0, self.c_natm,
321 self.c_bas.0,self.c_nbas,
322 self.c_env.0,
323 self.c_opt.0),
324 CintType::Cartesian => cint::cint1e_nuc_cart(
325 c_buf, c_shls,
326 self.c_atm.0, self.c_natm,
327 self.c_bas.0,self.c_nbas,
328 self.c_env.0,
329 self.c_opt.0),
330 };
331 let shls = Vec::from_raw_parts(c_shls, shls_len, shls_cap);
332 new_buf = Vec::from_raw_parts(c_buf, buf_len, buf_cap);
333 }
334 new_buf
335 }
336
337 pub fn cint_ijkin(&mut self, i:i32,j:i32) -> Vec<f64> {
338 let mut di: i32 = self.cint_cgto_rust(i);
339 let mut dj: i32 = self.cint_cgto_rust(j);
340
341 let mut shls: Vec<c_int> = vec![i as c_int,j as c_int];
342 shls.shrink_to_fit();
343 let mut shls = ManuallyDrop::new(shls);
344 let (c_shls,shls_len,shls_cap) = (shls.as_mut_ptr() as *mut c_int,shls.len(),shls.capacity());
345
346 let mut buf: Vec<f64> = [0.0f64].repeat((di*dj) as usize);
347 buf.shrink_to_fit();
348 let mut buf = ManuallyDrop::new(buf);
349 let (c_buf, buf_len, buf_cap) = (buf.as_mut_ptr() as *mut f64, buf.len(), buf.capacity());
350
351 let mut new_buf:Vec<f64>;
352 unsafe {
353 match self.cint_type {
354 CintType::Spheric => cint::cint1e_kin_sph(
355 c_buf, c_shls,
356 self.c_atm.0, self.c_natm,
357 self.c_bas.0,self.c_nbas,
358 self.c_env.0,
359 self.c_opt.0),
360 CintType::Cartesian => cint::cint1e_kin_cart(
361 c_buf, c_shls,
362 self.c_atm.0, self.c_natm,
363 self.c_bas.0,self.c_nbas,
364 self.c_env.0,
365 self.c_opt.0),
366 };
367 let shls = Vec::from_raw_parts(c_shls, shls_len, shls_cap);
368 new_buf = Vec::from_raw_parts(c_buf, buf_len, buf_cap);
369 }
370 new_buf
371 }
372}
373
374//pub fn cint2e_sph_rust(mut buf: Vec<f64>, mut shls: Vec<i32>,
375// c_atm: & *mut c_int, c_natm:c_int,
376// c_bas: & *mut c_int, c_nbas:c_int,
377// c_env: & *mut f64,
378// c_opt: & *mut CINTOpt) -> Vec<f64> {
379// //
380// buf.shrink_to_fit();
381// let mut buf = ManuallyDrop::new(buf);
382// let (c_buf, buf_len, buf_cap) = (buf.as_mut_ptr() as *mut f64, buf.len(), buf.capacity());
383//
384// shls.shrink_to_fit();
385// let mut shls = ManuallyDrop::new(shls);
386// let (c_shls,shls_len,shls_cap) = (shls.as_mut_ptr() as *mut c_int,shls.len(),shls.capacity());
387// let mut new_buf:Vec<f64>;
388// unsafe {
389// cint::cint2e_sph(c_buf, c_shls, *c_atm, c_natm, *c_bas, c_nbas, *c_env, *c_opt);
390// //println!("debug 1 {}", &c_buf.read());
391// let shls = Vec::from_raw_parts(c_shls, shls_len, shls_cap);
392// new_buf = Vec::from_raw_parts(c_buf, buf_len, buf_cap);
393// //println!("debug 2");
394// //vec![0.0,0.0]
395// }
396// new_buf
397//}
398//pub fn cint1e_ovlp_sph_rust(mut buf: Vec<f64>, mut shls: Vec<i32>,
399// c_atm: & *mut c_int, c_natm:c_int,
400// c_bas: & *mut c_int, c_nbas:c_int,
401// c_env: & *mut f64,
402// c_opt: & *mut CINTOpt) -> Vec<f64> {
403// //
404// buf.shrink_to_fit();
405// let mut buf = ManuallyDrop::new(buf);
406// let (c_buf, buf_len, buf_cap) = (buf.as_mut_ptr() as *mut f64, buf.len(), buf.capacity());
407//
408// shls.shrink_to_fit();
409// let mut shls = ManuallyDrop::new(shls);
410// let (c_shls,shls_len,shls_cap) = (shls.as_mut_ptr() as *mut c_int,shls.len(),shls.capacity());
411// let mut new_buf:Vec<f64>;
412// unsafe {
413// cint::cint1e_ovlp_sph(c_buf, c_shls, *c_atm, c_natm, *c_bas, c_nbas, *c_env, *c_opt);
414// let shls = Vec::from_raw_parts(c_shls, shls_len, shls_cap);
415// new_buf = Vec::from_raw_parts(c_buf, buf_len, buf_cap);
416// }
417// new_buf
418//}