fastesp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastesp-0.1.0/LICENSE +21 -0
- fastesp-0.1.0/PKG-INFO +214 -0
- fastesp-0.1.0/README.md +186 -0
- fastesp-0.1.0/fastesp/__init__.py +42 -0
- fastesp-0.1.0/fastesp/basis.py +303 -0
- fastesp-0.1.0/fastesp/cli.py +326 -0
- fastesp-0.1.0/fastesp/esp.py +296 -0
- fastesp-0.1.0/fastesp/ints.py +158 -0
- fastesp-0.1.0/fastesp/molden.py +169 -0
- fastesp-0.1.0/fastesp/native/build_pairs.cpp +425 -0
- fastesp-0.1.0/fastesp/native/esp_gpu.cu +326 -0
- fastesp-0.1.0/fastesp/py.typed +0 -0
- fastesp-0.1.0/fastesp/table.py +316 -0
- fastesp-0.1.0/fastesp.egg-info/PKG-INFO +214 -0
- fastesp-0.1.0/fastesp.egg-info/SOURCES.txt +21 -0
- fastesp-0.1.0/fastesp.egg-info/dependency_links.txt +1 -0
- fastesp-0.1.0/fastesp.egg-info/entry_points.txt +2 -0
- fastesp-0.1.0/fastesp.egg-info/requires.txt +8 -0
- fastesp-0.1.0/fastesp.egg-info/top_level.txt +1 -0
- fastesp-0.1.0/pyproject.toml +49 -0
- fastesp-0.1.0/setup.cfg +4 -0
- fastesp-0.1.0/tests/test_integrals.py +111 -0
- fastesp-0.1.0/tests/test_pipeline.py +178 -0
fastesp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zidong Shu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
fastesp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastesp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Exact electrostatic potential from a Gaussian-basis wavefunction, evaluated analytically and solved on the GPU
|
|
5
|
+
Author: Zidong Shu
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ZidongS/fastesp
|
|
8
|
+
Project-URL: Repository, https://github.com/ZidongS/fastesp
|
|
9
|
+
Project-URL: Issues, https://github.com/ZidongS/fastesp/issues
|
|
10
|
+
Keywords: computational-chemistry,electrostatic-potential,ESP,wavefunction,gaussian-basis,cuda,gpu,multiwfn,orca,molden
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: C++
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: numpy>=1.22
|
|
22
|
+
Requires-Dist: scipy>=1.8
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
25
|
+
Provides-Extra: bench
|
|
26
|
+
Requires-Dist: matplotlib>=3.5; extra == "bench"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# fastesp
|
|
30
|
+
|
|
31
|
+
**Exact electrostatic potential from a Gaussian-basis wavefunction — evaluated
|
|
32
|
+
analytically, and solved on the GPU.**
|
|
33
|
+
|
|
34
|
+
`fastesp` computes
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
V(C) = sum_A Z_A/|C - R_A| - sum_{mu nu} P_{mu nu} < mu | 1/|r - C| | nu >
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
at an arbitrary set of points, without any real-space quadrature. The one-electron
|
|
41
|
+
Coulomb integrals are evaluated in closed form (Hermite / McMurchie–Davidson
|
|
42
|
+
expansion of the Gaussian product, Boys functions for the 1/r operator), so the
|
|
43
|
+
result is exact to machine precision. It is a drop-in faster and more accurate
|
|
44
|
+
replacement for the "electrostatic potential at a set of points" function of
|
|
45
|
+
Multiwfn (menu `5 → 12 → 100`).
|
|
46
|
+
|
|
47
|
+
## Benchmark
|
|
48
|
+
|
|
49
|
+
54-atom protein fragment, ORCA wB97M-D3BJ/def2-TZVPPD (1450 spherical / 1634
|
|
50
|
+
Cartesian functions), points on the union of the Bondi vdW spheres. Multiwfn
|
|
51
|
+
8 CPU threads vs one RTX 5090, measured with `benchmarks/benchmark.py` under
|
|
52
|
+
SLURM on a dedicated node.
|
|
53
|
+
|
|
54
|
+
| points | Multiwfn 1 thr | Multiwfn 8 thr | fastesp (1 GPU) | speedup |
|
|
55
|
+
|---|---|---|---|---|
|
|
56
|
+
| 300 | 206.07 s | 26.29 s | 0.269 s | **98x** |
|
|
57
|
+
| 3000 | 2061 s\* | 258.57 s | 0.479 s | **539x** |
|
|
58
|
+
| 30000 | 20607 s\* | 2586 s\* | 2.456 s | **>1000x** |
|
|
59
|
+
|
|
60
|
+
\* extrapolated; Multiwfn is linear in the point count at 86.2–87.6 ms/point.
|
|
61
|
+
The part that replaces Multiwfn's integration is **0.030 ms/point vs 87.6** —
|
|
62
|
+
a **2900x** speedup — because the table build is point-independent.
|
|
63
|
+
|
|
64
|
+
Accuracy at the identical 300 points:
|
|
65
|
+
|
|
66
|
+
| | |
|
|
67
|
+
|---|---|
|
|
68
|
+
| max abs difference vs Multiwfn | 1.75e-7 a.u. = **4.8e-3 mV** |
|
|
69
|
+
| max abs difference vs unscreened analytic evaluation | 1.3e-11 a.u. |
|
|
70
|
+
| primitive integrals vs independent quadrature | 6.6e-14 (relative) |
|
|
71
|
+
| electron density vs Multiwfn at the same points | 4.3e-12 (9e-10 relative) |
|
|
72
|
+
|
|
73
|
+
The 1.75e-7 a.u. gap is **Multiwfn's** quadrature error, and this is pinned down
|
|
74
|
+
by three measurements: (1) the electron density — a pure basis evaluation on
|
|
75
|
+
Multiwfn's side — agrees to 9e-10 relative, so both programs read the
|
|
76
|
+
wavefunction identically; (2) Multiwfn's answer is bit-for-bit unchanged when
|
|
77
|
+
its Becke grid is swept from 75×434 (1.8e6 points) to 200×2354 (2.5e7 points);
|
|
78
|
+
(3) its three internal ESP engines (`iESPcode` 1/2/3) agree exactly with each
|
|
79
|
+
other. See `benchmarks/check_density_mwfn.py` and
|
|
80
|
+
`benchmarks/mwfn_grid_convergence.py`.
|
|
81
|
+
|
|
82
|
+
## Install
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install fastesp # NumPy reference (exact, no toolchain needed)
|
|
86
|
+
fastesp build-native # optional: compile the C++/CUDA backends
|
|
87
|
+
fastesp selftest # validate the analytic integrals
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The native backends are compiled into `~/.cache/fastesp` (override with
|
|
91
|
+
`FASTESP_CACHE`) and need `g++` (with OpenMP) and, for the GPU path, `nvcc`.
|
|
92
|
+
`pip install` alone already gives exact results — just slower.
|
|
93
|
+
|
|
94
|
+
## Use
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# ESP at the points in pts.txt (Bohr, one "x y z" per line)
|
|
98
|
+
fastesp esp mol.molden.input --points pts.txt -o esp.txt
|
|
99
|
+
fastesp esp mol.molden.input --points pts.txt --backend numpy # force reference
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
backend : cuda
|
|
104
|
+
basis : 1634 Cartesian functions, 2080 primitives
|
|
105
|
+
pair table : 0.2600 s (point-independent)
|
|
106
|
+
ESP kernel : 0.0089 s
|
|
107
|
+
ESP range : -2.2055 .. +1.9854 V
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
As a library:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
import numpy as np
|
|
114
|
+
from fastesp import read_molden, Basis, build_table
|
|
115
|
+
|
|
116
|
+
wfn = read_molden("mol.molden.input")
|
|
117
|
+
basis = Basis(wfn)
|
|
118
|
+
dens = basis.density_matrix_cartesian()
|
|
119
|
+
|
|
120
|
+
table = build_table(wfn, basis, dens, points_bohr) # point-independent tables
|
|
121
|
+
esp = table.esp() # Hartree/e
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`examples/vdw_surface_esp.py` shows the full production workflow: sample the
|
|
125
|
+
Bondi vdW surface of a molecule and evaluate the ESP on it.
|
|
126
|
+
|
|
127
|
+
## How it works
|
|
128
|
+
|
|
129
|
+
For a pair of primitive Cartesian Gaussians, the product is one Gaussian times a
|
|
130
|
+
polynomial. Expanding about the Gaussian product centre `P` in Hermite Gaussians
|
|
131
|
+
`L_t` gives the exact closed form
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
g_A^a g_B^b = K sum_t E_t L_t(r - P)
|
|
135
|
+
int L_t(r')/|R - r'| dr' = (-1)^|t| (d/dR)^t F(R), F(R) = (2 pi / p) F_0(p R^2)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
and `(d/dR)^t F` is expanded exactly by the one-dimensional recurrence
|
|
139
|
+
`a[t+1][j] = -a[t][j] + (t-2j+2) a[t][j-1]`.
|
|
140
|
+
|
|
141
|
+
The structural step that makes this fast: **everything except `R = C - P` is
|
|
142
|
+
independent of the sampling point.** Contracting the E-coefficients, the `(-1)^|t|`
|
|
143
|
+
signs and the `(2p)^m` factors over the Cartesian components and over the
|
|
144
|
+
primitive pairs — weighted by the density matrix — yields, once per primitive
|
|
145
|
+
pair, a sparse table `G[alpha, m]` such that
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
I_pair(C) = K * sum_{alpha,m} G[alpha,m] * R^alpha * F_m(p R^2)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Per point that is one Boys evaluation, a short monomial schedule and one dot
|
|
152
|
+
product — a shape that maps directly onto GPU threads. The `O(N_pairs)` table
|
|
153
|
+
build is independent of the point set (and of how many points there are), so it
|
|
154
|
+
is done once and reused; only the `O(N_pairs x N_points)` evaluation runs per
|
|
155
|
+
point set.
|
|
156
|
+
|
|
157
|
+
Screening uses the rigorous bound `|I_pair| <= K * int|rho_pair| / d`, with
|
|
158
|
+
`int|rho_pair|` obtained from the `|He_n|` moment products computed at build time.
|
|
159
|
+
The builder also prints the sum rule `Tr(P S) = N_elec` as a sanity check on the
|
|
160
|
+
basis it just read.
|
|
161
|
+
|
|
162
|
+
### MOLDEN conventions
|
|
163
|
+
|
|
164
|
+
The MOLDEN format does not pin these down. All three were determined from the
|
|
165
|
+
file itself and are verified by `Tr(P S) = N_elec` and `max|C^T S C - I|`:
|
|
166
|
+
|
|
167
|
+
1. **Primitive normalisation.** ORCA writes GTO coefficients that already
|
|
168
|
+
include `N_s = (2 alpha/pi)^{3/4} (4 alpha)^{l/2}` — the radial prefactor
|
|
169
|
+
*without* the angular `(2l-1)!!` factor of a fully normalised Cartesian
|
|
170
|
+
Gaussian. Verified against every single-primitive p/d/f shell in the test
|
|
171
|
+
file to 8 digits.
|
|
172
|
+
2. **Angular ordering.** The spherical functions are the real solid harmonics in
|
|
173
|
+
MOLDEN order `m = 0, +1, -1, +2, -2, ...` (`fastesp/basis.py`, `_POLY`).
|
|
174
|
+
3. **Cartesian ↔ spherical transform.** Rows are S-orthonormalised so that
|
|
175
|
+
`T S T^T = I`.
|
|
176
|
+
|
|
177
|
+
If you have a wavefunction whose conventions differ, `Basis` +
|
|
178
|
+
`overlap_matrix` will show it: `Tr(P S)` will not reproduce the MOLDEN
|
|
179
|
+
occupancy sum.
|
|
180
|
+
|
|
181
|
+
## Repository layout
|
|
182
|
+
|
|
183
|
+
| path | role |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `fastesp/molden.py` | MOLDEN reader |
|
|
186
|
+
| `fastesp/basis.py` | Cartesian basis, conventions, density matrix |
|
|
187
|
+
| `fastesp/ints.py` | exact primitive-pair Coulomb integrals |
|
|
188
|
+
| `fastesp/esp.py` | contracted pair tables + NumPy ESP |
|
|
189
|
+
| `fastesp/table.py` | table construction, binary I/O, evaluation |
|
|
190
|
+
| `fastesp/cli.py` | `fastesp` console script |
|
|
191
|
+
| `fastesp/native/build_pairs.cpp` | OpenMP table builder (fast path) |
|
|
192
|
+
| `fastesp/native/esp_gpu.cu` | CUDA solver |
|
|
193
|
+
| `tests/` | integral and end-to-end validation |
|
|
194
|
+
| `benchmarks/` | head-to-head benchmark and cross-checks |
|
|
195
|
+
|
|
196
|
+
## Limitations
|
|
197
|
+
|
|
198
|
+
* Only the vacuum wavefunction ESP is implemented. Adding external point charges
|
|
199
|
+
(e.g. a CPCM reaction field) is a one-line addition to the nuclear term.
|
|
200
|
+
* `l = 4` (g) solid harmonics are tabulated but unverified — the test file has no
|
|
201
|
+
g functions.
|
|
202
|
+
* The GPU solver is fp64 throughout; there is headroom for a mixed-precision
|
|
203
|
+
build if needed.
|
|
204
|
+
* Tested against ORCA-generated MOLDEN files; other writers may use different
|
|
205
|
+
conventions (see above).
|
|
206
|
+
|
|
207
|
+
## Citation
|
|
208
|
+
|
|
209
|
+
If you use this in published work, please cite the repository
|
|
210
|
+
(https://github.com/ZidongS/fastesp).
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT — see `LICENSE`.
|
fastesp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# fastesp
|
|
2
|
+
|
|
3
|
+
**Exact electrostatic potential from a Gaussian-basis wavefunction — evaluated
|
|
4
|
+
analytically, and solved on the GPU.**
|
|
5
|
+
|
|
6
|
+
`fastesp` computes
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
V(C) = sum_A Z_A/|C - R_A| - sum_{mu nu} P_{mu nu} < mu | 1/|r - C| | nu >
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
at an arbitrary set of points, without any real-space quadrature. The one-electron
|
|
13
|
+
Coulomb integrals are evaluated in closed form (Hermite / McMurchie–Davidson
|
|
14
|
+
expansion of the Gaussian product, Boys functions for the 1/r operator), so the
|
|
15
|
+
result is exact to machine precision. It is a drop-in faster and more accurate
|
|
16
|
+
replacement for the "electrostatic potential at a set of points" function of
|
|
17
|
+
Multiwfn (menu `5 → 12 → 100`).
|
|
18
|
+
|
|
19
|
+
## Benchmark
|
|
20
|
+
|
|
21
|
+
54-atom protein fragment, ORCA wB97M-D3BJ/def2-TZVPPD (1450 spherical / 1634
|
|
22
|
+
Cartesian functions), points on the union of the Bondi vdW spheres. Multiwfn
|
|
23
|
+
8 CPU threads vs one RTX 5090, measured with `benchmarks/benchmark.py` under
|
|
24
|
+
SLURM on a dedicated node.
|
|
25
|
+
|
|
26
|
+
| points | Multiwfn 1 thr | Multiwfn 8 thr | fastesp (1 GPU) | speedup |
|
|
27
|
+
|---|---|---|---|---|
|
|
28
|
+
| 300 | 206.07 s | 26.29 s | 0.269 s | **98x** |
|
|
29
|
+
| 3000 | 2061 s\* | 258.57 s | 0.479 s | **539x** |
|
|
30
|
+
| 30000 | 20607 s\* | 2586 s\* | 2.456 s | **>1000x** |
|
|
31
|
+
|
|
32
|
+
\* extrapolated; Multiwfn is linear in the point count at 86.2–87.6 ms/point.
|
|
33
|
+
The part that replaces Multiwfn's integration is **0.030 ms/point vs 87.6** —
|
|
34
|
+
a **2900x** speedup — because the table build is point-independent.
|
|
35
|
+
|
|
36
|
+
Accuracy at the identical 300 points:
|
|
37
|
+
|
|
38
|
+
| | |
|
|
39
|
+
|---|---|
|
|
40
|
+
| max abs difference vs Multiwfn | 1.75e-7 a.u. = **4.8e-3 mV** |
|
|
41
|
+
| max abs difference vs unscreened analytic evaluation | 1.3e-11 a.u. |
|
|
42
|
+
| primitive integrals vs independent quadrature | 6.6e-14 (relative) |
|
|
43
|
+
| electron density vs Multiwfn at the same points | 4.3e-12 (9e-10 relative) |
|
|
44
|
+
|
|
45
|
+
The 1.75e-7 a.u. gap is **Multiwfn's** quadrature error, and this is pinned down
|
|
46
|
+
by three measurements: (1) the electron density — a pure basis evaluation on
|
|
47
|
+
Multiwfn's side — agrees to 9e-10 relative, so both programs read the
|
|
48
|
+
wavefunction identically; (2) Multiwfn's answer is bit-for-bit unchanged when
|
|
49
|
+
its Becke grid is swept from 75×434 (1.8e6 points) to 200×2354 (2.5e7 points);
|
|
50
|
+
(3) its three internal ESP engines (`iESPcode` 1/2/3) agree exactly with each
|
|
51
|
+
other. See `benchmarks/check_density_mwfn.py` and
|
|
52
|
+
`benchmarks/mwfn_grid_convergence.py`.
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install fastesp # NumPy reference (exact, no toolchain needed)
|
|
58
|
+
fastesp build-native # optional: compile the C++/CUDA backends
|
|
59
|
+
fastesp selftest # validate the analytic integrals
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The native backends are compiled into `~/.cache/fastesp` (override with
|
|
63
|
+
`FASTESP_CACHE`) and need `g++` (with OpenMP) and, for the GPU path, `nvcc`.
|
|
64
|
+
`pip install` alone already gives exact results — just slower.
|
|
65
|
+
|
|
66
|
+
## Use
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# ESP at the points in pts.txt (Bohr, one "x y z" per line)
|
|
70
|
+
fastesp esp mol.molden.input --points pts.txt -o esp.txt
|
|
71
|
+
fastesp esp mol.molden.input --points pts.txt --backend numpy # force reference
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
backend : cuda
|
|
76
|
+
basis : 1634 Cartesian functions, 2080 primitives
|
|
77
|
+
pair table : 0.2600 s (point-independent)
|
|
78
|
+
ESP kernel : 0.0089 s
|
|
79
|
+
ESP range : -2.2055 .. +1.9854 V
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
As a library:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import numpy as np
|
|
86
|
+
from fastesp import read_molden, Basis, build_table
|
|
87
|
+
|
|
88
|
+
wfn = read_molden("mol.molden.input")
|
|
89
|
+
basis = Basis(wfn)
|
|
90
|
+
dens = basis.density_matrix_cartesian()
|
|
91
|
+
|
|
92
|
+
table = build_table(wfn, basis, dens, points_bohr) # point-independent tables
|
|
93
|
+
esp = table.esp() # Hartree/e
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`examples/vdw_surface_esp.py` shows the full production workflow: sample the
|
|
97
|
+
Bondi vdW surface of a molecule and evaluate the ESP on it.
|
|
98
|
+
|
|
99
|
+
## How it works
|
|
100
|
+
|
|
101
|
+
For a pair of primitive Cartesian Gaussians, the product is one Gaussian times a
|
|
102
|
+
polynomial. Expanding about the Gaussian product centre `P` in Hermite Gaussians
|
|
103
|
+
`L_t` gives the exact closed form
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
g_A^a g_B^b = K sum_t E_t L_t(r - P)
|
|
107
|
+
int L_t(r')/|R - r'| dr' = (-1)^|t| (d/dR)^t F(R), F(R) = (2 pi / p) F_0(p R^2)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
and `(d/dR)^t F` is expanded exactly by the one-dimensional recurrence
|
|
111
|
+
`a[t+1][j] = -a[t][j] + (t-2j+2) a[t][j-1]`.
|
|
112
|
+
|
|
113
|
+
The structural step that makes this fast: **everything except `R = C - P` is
|
|
114
|
+
independent of the sampling point.** Contracting the E-coefficients, the `(-1)^|t|`
|
|
115
|
+
signs and the `(2p)^m` factors over the Cartesian components and over the
|
|
116
|
+
primitive pairs — weighted by the density matrix — yields, once per primitive
|
|
117
|
+
pair, a sparse table `G[alpha, m]` such that
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
I_pair(C) = K * sum_{alpha,m} G[alpha,m] * R^alpha * F_m(p R^2)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Per point that is one Boys evaluation, a short monomial schedule and one dot
|
|
124
|
+
product — a shape that maps directly onto GPU threads. The `O(N_pairs)` table
|
|
125
|
+
build is independent of the point set (and of how many points there are), so it
|
|
126
|
+
is done once and reused; only the `O(N_pairs x N_points)` evaluation runs per
|
|
127
|
+
point set.
|
|
128
|
+
|
|
129
|
+
Screening uses the rigorous bound `|I_pair| <= K * int|rho_pair| / d`, with
|
|
130
|
+
`int|rho_pair|` obtained from the `|He_n|` moment products computed at build time.
|
|
131
|
+
The builder also prints the sum rule `Tr(P S) = N_elec` as a sanity check on the
|
|
132
|
+
basis it just read.
|
|
133
|
+
|
|
134
|
+
### MOLDEN conventions
|
|
135
|
+
|
|
136
|
+
The MOLDEN format does not pin these down. All three were determined from the
|
|
137
|
+
file itself and are verified by `Tr(P S) = N_elec` and `max|C^T S C - I|`:
|
|
138
|
+
|
|
139
|
+
1. **Primitive normalisation.** ORCA writes GTO coefficients that already
|
|
140
|
+
include `N_s = (2 alpha/pi)^{3/4} (4 alpha)^{l/2}` — the radial prefactor
|
|
141
|
+
*without* the angular `(2l-1)!!` factor of a fully normalised Cartesian
|
|
142
|
+
Gaussian. Verified against every single-primitive p/d/f shell in the test
|
|
143
|
+
file to 8 digits.
|
|
144
|
+
2. **Angular ordering.** The spherical functions are the real solid harmonics in
|
|
145
|
+
MOLDEN order `m = 0, +1, -1, +2, -2, ...` (`fastesp/basis.py`, `_POLY`).
|
|
146
|
+
3. **Cartesian ↔ spherical transform.** Rows are S-orthonormalised so that
|
|
147
|
+
`T S T^T = I`.
|
|
148
|
+
|
|
149
|
+
If you have a wavefunction whose conventions differ, `Basis` +
|
|
150
|
+
`overlap_matrix` will show it: `Tr(P S)` will not reproduce the MOLDEN
|
|
151
|
+
occupancy sum.
|
|
152
|
+
|
|
153
|
+
## Repository layout
|
|
154
|
+
|
|
155
|
+
| path | role |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `fastesp/molden.py` | MOLDEN reader |
|
|
158
|
+
| `fastesp/basis.py` | Cartesian basis, conventions, density matrix |
|
|
159
|
+
| `fastesp/ints.py` | exact primitive-pair Coulomb integrals |
|
|
160
|
+
| `fastesp/esp.py` | contracted pair tables + NumPy ESP |
|
|
161
|
+
| `fastesp/table.py` | table construction, binary I/O, evaluation |
|
|
162
|
+
| `fastesp/cli.py` | `fastesp` console script |
|
|
163
|
+
| `fastesp/native/build_pairs.cpp` | OpenMP table builder (fast path) |
|
|
164
|
+
| `fastesp/native/esp_gpu.cu` | CUDA solver |
|
|
165
|
+
| `tests/` | integral and end-to-end validation |
|
|
166
|
+
| `benchmarks/` | head-to-head benchmark and cross-checks |
|
|
167
|
+
|
|
168
|
+
## Limitations
|
|
169
|
+
|
|
170
|
+
* Only the vacuum wavefunction ESP is implemented. Adding external point charges
|
|
171
|
+
(e.g. a CPCM reaction field) is a one-line addition to the nuclear term.
|
|
172
|
+
* `l = 4` (g) solid harmonics are tabulated but unverified — the test file has no
|
|
173
|
+
g functions.
|
|
174
|
+
* The GPU solver is fp64 throughout; there is headroom for a mixed-precision
|
|
175
|
+
build if needed.
|
|
176
|
+
* Tested against ORCA-generated MOLDEN files; other writers may use different
|
|
177
|
+
conventions (see above).
|
|
178
|
+
|
|
179
|
+
## Citation
|
|
180
|
+
|
|
181
|
+
If you use this in published work, please cite the repository
|
|
182
|
+
(https://github.com/ZidongS/fastesp).
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
MIT — see `LICENSE`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""fastesp -- exact electrostatic potential from a Gaussian-basis wavefunction.
|
|
2
|
+
|
|
3
|
+
The electron part of the ESP at a point C is
|
|
4
|
+
|
|
5
|
+
V_el(C) = -sum_{mu nu} P_{mu nu} < mu | 1/|r - C| | nu >
|
|
6
|
+
|
|
7
|
+
evaluated *analytically*: the Gaussian product is expanded in Hermite Gaussians
|
|
8
|
+
(McMurchie-Davidson) and the potential of each Hermite Gaussian is a closed-form
|
|
9
|
+
derivative of the Boys function. No real-space quadrature is involved, so the
|
|
10
|
+
result is exact to machine precision.
|
|
11
|
+
|
|
12
|
+
Quick start::
|
|
13
|
+
|
|
14
|
+
from fastesp import read_molden, Basis, build_table
|
|
15
|
+
|
|
16
|
+
wfn = read_molden("mol.molden.input")
|
|
17
|
+
basis = Basis(wfn)
|
|
18
|
+
density = basis.density_matrix_cartesian()
|
|
19
|
+
table = build_table(wfn, basis, density, points_bohr)
|
|
20
|
+
esp = table.esp() # (n_points,) in Hartree/e
|
|
21
|
+
|
|
22
|
+
See :mod:`fastesp.cli` (console script ``fastesp``) for the compiled C++/CUDA
|
|
23
|
+
backends, which are orders of magnitude faster on large point sets.
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from .basis import Basis, cart_order, overlap_matrix
|
|
28
|
+
from .esp import ESPEngine
|
|
29
|
+
from .ints import boys, primitive_pair_integral
|
|
30
|
+
from .molden import Wavefunction, read_molden
|
|
31
|
+
from .table import (PairTable, basis_payload, build_table, write_basis_payload)
|
|
32
|
+
|
|
33
|
+
__version__ = "0.1.0"
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"Wavefunction", "read_molden",
|
|
37
|
+
"Basis", "cart_order", "overlap_matrix",
|
|
38
|
+
"boys", "primitive_pair_integral",
|
|
39
|
+
"PairTable", "build_table",
|
|
40
|
+
"basis_payload", "write_basis_payload",
|
|
41
|
+
"__version__",
|
|
42
|
+
]
|