1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//! Safe Rust wrapper for [cuEST](https://developer.nvidia.com/cuest) (CUDA
//! Electronic Structure Toolkit) built on [cudarc].
//!
//! This crate wraps the raw [`cuest_ffi`] bindings into a safe API: cuEST
//! handles become owned Rust objects, user-allocated workspaces are managed
//! internally, every return code is checked, and device buffers are tied to
//! the cudarc stream the cuEST handle was created on.
//!
//! This crate is not an official NVIDIA project. cuEST itself is proprietary
//! NVIDIA software and is not distributed with this crate.
//!
//! # Design notes
//!
//! - A [`CuestContext`] wraps a user-supplied `Arc<CudaStream>`. The stream is
//! bound once at `cuestCreate` (cuEST has no per-call streams), so every
//! device buffer passed to a compute call must live on that stream; this is
//! checked at runtime and reported as [`CuestError::Rust`] otherwise.
//! - Objects keep their dependencies alive (an [`Arc`](std::sync::Arc)-based
//! keep-alive, not lifetime parameters), so cuEST's destruction order is
//! enforced by normal `Drop` order.
//! - Device buffers for inputs are taken as `&impl DevicePtr<f64>` (any
//! [`CudaSlice`](cudarc::driver::CudaSlice),
//! [`CudaView`](cudarc::driver::CudaView) or
//! [`CudaViewMut`](cudarc::driver::CudaViewMut)); outputs are either
//! auto-allocated or written into an `&mut impl DevicePtrMut<f64>` (`*_into`
//! methods). No synchronization is performed inside compute methods — the
//! work is stream-ordered, as with cudarc itself.
//! - All calls are error-checked; a failing cuEST status becomes
//! [`CuestError::Status`]. Buffer sizes the cuEST C API cannot validate (the
//! caller contract) are validated here instead.
//! - The `unsafe` blocks are cuEST FFI calls (justified by owned handles, the
//! cuEST call contracts, and the validations above) and one uninitialized
//! scratch allocation (cuEST workspace buffers, matching the C samples'
//! `cudaMalloc`).
//!
//! # Example
//!
//! ```no_run
//! use cuest_cudarc::prelude::*;
//! use cuest_cudarc::cudarc::driver::CudaContext;
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let stream = CudaContext::new(0)?.default_stream();
//! let context = CuestContext::new(&stream)?;
//!
//! // H2 at 1.4 Bohr (0.7408 Angstrom), STO-3G, on one atom each.
//! let xyz = Xyz::parse(
//! "2
//! H2
//! H 0.0 0.0 0.0
//! H 0.0 0.0 0.7408
//! ",
//! )?;
//!
//! let spec = CuestShellSpec::new(0, true, vec![3.42525091, 0.62391373, 0.16885540], vec![
//! 0.15432897, 0.53532814, 0.44463454,
//! ])?
//! .normalized(1.0)?;
//! let shells: Vec<CuestAOShell> =
//! (0..xyz.len()).map(|_| CuestAOShell::new(&context, &spec)).collect::<Result<_, _>>()?;
//! let basis = CuestAOBasis::new(&context, &[&shells[0..1], &shells[1..2]])?;
//!
//! let pair_list = CuestAOPairList::from_xyz(&basis, &xyz, 1.0e-14)?;
//! let plan = CuestOeIntPlan::new(&basis, &pair_list)?;
//!
//! let s = plan.overlap()?; // CudaSlice<f64>, nao x nao, on `stream`
//! let t = plan.kinetic()?;
//! # Ok(())
//! # }
//! ```
//!
//! # Loading modes
//!
//! The loading mode is selected through this crate's features (matching
//! `cuest-ffi`):
//!
//! - **Dynamic loading** (default, `dynamic_loading` feature): the cuEST shared
//! library is loaded at runtime; set `CUEST_DYLOAD` or see
//! [`cuest_ffi::ffi_dynamic`] for the search order.
//! - **Static linking** (`--no-default-features`): links `libcuest` at build
//! time (`CUEST_LIB_DIR` overrides the search path).
//!
//! # Thread safety
//!
//! cuEST documents no thread-safety guarantees beyond the usage model of one
//! handle per stream. The types in this crate are therefore `Send` (they can
//! be moved between threads) but **not** `Sync`: a given handle (and any
//! object derived from it) must be used from one thread at a time. The
//! underlying CUDA stream is the real serialization point.
//!
//! # Escape hatch
//!
//! The raw bindings are re-exported as [`cuest_ffi`] for API surface this
//! crate does not wrap yet; every object also exposes its raw handle
//! (`raw_handle()`).
// Deliberate: the shared per-object state (`Arc<...Inner>`) holds a raw cuEST
// handle and is therefore neither `Send` nor `Sync`; the public wrapper types
// add a documented `unsafe impl Send` instead (see "Thread safety" above).
pub
pub
/// The cudarc version this crate was built against.
pub use cudarc;
/// The raw cuEST FFI bindings this crate builds on (escape hatch).
pub use cuest_ffi;
pub use crateCuestAOBasis;
pub use crate;
pub use crateCuestError;
pub use crate;
pub use crateCuestAOPairList;
pub use crate;
pub use crateXyz;
/// Common imports.