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//}