sparta-chem 0.2.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.
Files changed (34) hide show
  1. sparta_chem-0.2.0/.gitignore +47 -0
  2. sparta_chem-0.2.0/LICENSE +21 -0
  3. sparta_chem-0.2.0/PKG-INFO +393 -0
  4. sparta_chem-0.2.0/README.md +367 -0
  5. sparta_chem-0.2.0/pyproject.toml +64 -0
  6. sparta_chem-0.2.0/sparta/__init__.py +21 -0
  7. sparta_chem-0.2.0/sparta/calculation/__init__.py +5 -0
  8. sparta_chem-0.2.0/sparta/calculation/ase_calc.py +59 -0
  9. sparta_chem-0.2.0/sparta/calculation/base.py +39 -0
  10. sparta_chem-0.2.0/sparta/calculation/reference.py +94 -0
  11. sparta_chem-0.2.0/sparta/calculation/xtb_calc.py +106 -0
  12. sparta_chem-0.2.0/sparta/cheminformatics.py +550 -0
  13. sparta_chem-0.2.0/sparta/cli.py +414 -0
  14. sparta_chem-0.2.0/sparta/initial_generation/__init__.py +13 -0
  15. sparta_chem-0.2.0/sparta/initial_generation/bounds_matrix.py +305 -0
  16. sparta_chem-0.2.0/sparta/initial_generation/dg_optimizer.py +262 -0
  17. sparta_chem-0.2.0/sparta/iterative_alignment/__init__.py +34 -0
  18. sparta_chem-0.2.0/sparta/iterative_alignment/force_propagation.py +478 -0
  19. sparta_chem-0.2.0/sparta/iterative_alignment/idpp.py +141 -0
  20. sparta_chem-0.2.0/sparta/iterative_alignment/optimization.py +987 -0
  21. sparta_chem-0.2.0/sparta/metal_bonds.py +179 -0
  22. sparta_chem-0.2.0/sparta/reaction.py +407 -0
  23. sparta_chem-0.2.0/tests/__init__.py +0 -0
  24. sparta_chem-0.2.0/tests/conftest.py +88 -0
  25. sparta_chem-0.2.0/tests/test_barrier_api.py +284 -0
  26. sparta_chem-0.2.0/tests/test_bounds_matrix.py +159 -0
  27. sparta_chem-0.2.0/tests/test_calculation.py +464 -0
  28. sparta_chem-0.2.0/tests/test_cheminformatics.py +372 -0
  29. sparta_chem-0.2.0/tests/test_dg_optimizer.py +143 -0
  30. sparta_chem-0.2.0/tests/test_force_propagation.py +372 -0
  31. sparta_chem-0.2.0/tests/test_idpp.py +163 -0
  32. sparta_chem-0.2.0/tests/test_metal_bonds.py +142 -0
  33. sparta_chem-0.2.0/tests/test_optimization.py +420 -0
  34. sparta_chem-0.2.0/tests/test_reaction.py +342 -0
@@ -0,0 +1,47 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ *.so
7
+ *.egg
8
+ *.egg-info/
9
+ dist/
10
+ build/
11
+ .eggs/
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ ENV/
17
+
18
+ # uv
19
+ .python-version
20
+
21
+ # Testing
22
+ .pytest_cache/
23
+ .coverage
24
+ .coverage.*
25
+ htmlcov/
26
+
27
+ # Jupyter
28
+ .ipynb_checkpoints/
29
+ *.ipynb
30
+
31
+ # Claude Code
32
+ .claude/
33
+
34
+ # IDEs
35
+ .vscode/
36
+ .idea/
37
+ *.swp
38
+ *.swo
39
+ *~
40
+
41
+ # OS
42
+ .DS_Store
43
+ Thumbs.db
44
+
45
+ # Conformer output (workflow script)
46
+ conformers/
47
+ *_results.csv
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nicholas Casetti
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.
@@ -0,0 +1,393 @@
1
+ Metadata-Version: 2.5
2
+ Name: sparta-chem
3
+ Version: 0.2.0
4
+ Summary: Steric Path Alignment for Reactive Transformation Assessment
5
+ Project-URL: Homepage, https://github.com/ncasetti7/sparta
6
+ Project-URL: Repository, https://github.com/ncasetti7/sparta
7
+ Project-URL: Issues, https://github.com/ncasetti7/sparta/issues
8
+ Author-email: Nicholas Casetti <ncasetti@mit.edu>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: cheminformatics,chemistry,computational-chemistry,reaction-path,transition-state
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: ase>=3.26.0
22
+ Requires-Dist: numpy>=1.24
23
+ Requires-Dist: rdkit>=2025.9.1
24
+ Requires-Dist: scipy>=1.16.2
25
+ Description-Content-Type: text/markdown
26
+
27
+ <p align="center">
28
+ <img src="sparta_logo.png" alt="SPARTA logo" width="400"/>
29
+ </p>
30
+
31
+ # SPARTA
32
+
33
+ **S**teric **P**ath **A**lignment for **R**eactive **T**ransformation **A**ssessment
34
+
35
+ SPARTA generates reactant-product conformer pairs and iteratively aligns them using an Image-Dependent Pair Potential (IDPP) nudged-elastic-band (NEB) path optimization.
36
+
37
+ Path generation and alignment are purely geometric and need no electronic-structure program. Evaluating electronic energies along the aligned path gives a barrier estimate that acts as a fast proxy for kinetic feasibility, at a small fraction of the cost of locating a transition state. SPARTA will use any calculator you give it; see [Electronic energies](#electronic-energies).
38
+
39
+ ---
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install sparta-chem
45
+ ```
46
+
47
+ The import name is `sparta`:
48
+
49
+ ```python
50
+ from sparta import Reaction
51
+ ```
52
+
53
+ | Requirement | Minimum version |
54
+ |-------------|----------------|
55
+ | Python | 3.11 |
56
+ | numpy | 1.24 |
57
+ | scipy | 1.16 |
58
+ | rdkit | 2025.9.1 |
59
+ | ase | 3.26 |
60
+
61
+ ---
62
+
63
+ ## Python API
64
+
65
+ ### Quick start
66
+
67
+ ```python
68
+ from sparta import Reaction, XTBCalculation, run_sparta
69
+
70
+ rxn = Reaction(
71
+ reactant_smiles="[C:1]([H:2])([H:3])([H:4])[H:5].[F:6][F:7]",
72
+ product_smiles="[C:1]([H:2])([H:3])([H:4])[F:6].[H:5][F:7]",
73
+ )
74
+
75
+ rxn = run_sparta(rxn, calculator=XTBCalculation())
76
+ print(rxn.barrier_kcal) # SPARTA barrier, kcal/mol
77
+ ```
78
+
79
+ `run_sparta` is the whole pipeline in one call. It scans stretch factors from
80
+ 1.0 to 2.0, aligns one endpoint pair at each, evaluates electronic energies
81
+ along the path, and keeps the factor giving the lowest barrier.
82
+
83
+ Both SMILES must be **fully atom-mapped, including hydrogens**, and the two
84
+ mappings must cover the same set of map numbers, that correspondence is what
85
+ defines which bonds change. Hydrogens have to be written as explicit mapped
86
+ atoms (`[C:1]([H:2])...`) rather than left implicit (`[CH4:1]`): SPARTA parses
87
+ with `removeHs=False`, so an implicit hydrogen is not an atom and will be
88
+ missing from the generated geometry.
89
+
90
+ ### Geometric scoring only
91
+
92
+ Without a calculator nothing electronic is computed, and the result carries
93
+ the IDPP score alone. This is the cheaper, purely geometric mode:
94
+
95
+ ```python
96
+ from sparta import Reaction, generate_initial_conformers, run_iterative_alignment
97
+
98
+ rxn = Reaction(reactant_smiles=..., product_smiles=..., stretch_factors=[1.3, 1.5, 1.8])
99
+ rxn = generate_initial_conformers(rxn)
100
+ rxn = run_iterative_alignment(rxn)
101
+
102
+ print(rxn.aligned_results[0]["score"]) # IDPP score, not an energy
103
+ ```
104
+
105
+ Each function returns the reaction, so these also chain:
106
+ `Reaction(...).generate_initial_conformers().run_iterative_alignment()`.
107
+
108
+ ### Accessing results
109
+
110
+ ```python
111
+ # aligned_results is sorted by score (ascending, lower is better)
112
+ best = rxn.aligned_results[0]
113
+
114
+ print(best["score"]) # float: max interior IDPP energy
115
+ print(best["reactant_coords"]) # np.ndarray (n_atoms, 3)
116
+ print(best["product_coords"]) # np.ndarray (n_atoms, 3)
117
+ print(best["images"]) # list of ase.Atoms, full NEB path
118
+ print(best["energies"]) # list of float, per-image IDPP energies
119
+ print(best["seed"]) # int
120
+ print(best["stretch_factor"]) # float
121
+ print(best["conformer_idx"]) # int: index into rxn.top_k_conformers
122
+
123
+ # present only when a calculator was supplied
124
+ print(best["barrier_kcal"]) # SPARTA barrier, kcal/mol
125
+ print(best["electronic_energies"]) # list of float, per interior image
126
+ print(best["peak_image_idx"]) # index of the highest-energy image
127
+ print(rxn.barrier_kcal) # same as aligned_results[0]["barrier_kcal"]
128
+ print(rxn.reference_energy) # relaxed reactant reference, Hartree
129
+ ```
130
+
131
+ Two different quantities live here and they are not interchangeable:
132
+
133
+ | | meaning | units |
134
+ |---|---|---|
135
+ | `score` | highest interior **IDPP** energy, purely geometric | IDPP |
136
+ | `barrier_kcal` | highest interior **electronic** energy minus the relaxed reactant reference | kcal/mol |
137
+
138
+ `aligned_results` is sorted by `barrier_kcal` when a calculator was given, and
139
+ by `score` otherwise, so `aligned_results[0]` is always the best result by
140
+ whichever metric was available.
141
+
142
+ The reactant reference relaxes each connected fragment separately and sums the
143
+ energies. Optimizing a multi-fragment reactant as one unit would fold an
144
+ arbitrary inter-fragment interaction into every barrier.
145
+
146
+ All intermediate conformers are also available:
147
+
148
+ ```python
149
+ rxn.all_conformers # every generated conformer pair, sorted by initial NEB score
150
+ rxn.top_k_conformers # the top-k subset passed to iterative alignment
151
+ ```
152
+
153
+ ### Electronic energies
154
+
155
+ The IDPP score is geometric. To obtain an electronic barrier, evaluate single-point energies on the images of the aligned path with a calculator of your choice.
156
+
157
+ SPARTA ships an `XTBCalculation` wrapper for convenience, which shells out to the [xtb](https://github.com/grimme-lab/xtb) executable. **xtb is not a Python dependency and is not installed by pip**, install it separately and make sure it is on `PATH`, or pass an explicit path via `xtb_cmd`. Nothing else in SPARTA requires it.
158
+
159
+ ```python
160
+ from sparta.calculation import XTBCalculation
161
+
162
+ calc = XTBCalculation(charge=0, multiplicity=1) # or xtb_cmd="/path/to/xtb"
163
+ # XTBCalculation also takes `timeout` (seconds, default 120)
164
+ energies = [calc.energy(img) for img in best["images"]]
165
+ ```
166
+
167
+ `ASECalculation` wraps any ASE calculator, which covers most machine-learned potentials:
168
+
169
+ ```python
170
+ from sparta.calculation import ASECalculation
171
+
172
+ calc = ASECalculation(ase_calculator) # also takes `fmax`, `max_steps`
173
+ ```
174
+
175
+ Any object exposing the same `energy(atoms)` interface works in their place, so the path code never needs to know what is underneath.
176
+
177
+ ### `Reaction` parameters
178
+
179
+ | Parameter | Type | Default | Description |
180
+ |-----------|------|---------|-------------|
181
+ | `reactant_smiles` | `str` |, | Atom-mapped SMILES for the reactant(s) |
182
+ | `product_smiles` | `str` |, | Atom-mapped SMILES for the product(s) |
183
+ | `charge` | `int` | auto | Total charge; inferred from the SMILES when omitted |
184
+ | `multiplicity` | `int` | auto | Spin multiplicity; inferred from the SMILES when omitted |
185
+ | `n_conformers` | `int` | `10` | Conformers per (seed, stretch_factor) combination |
186
+ | `n_seeds` | `int` | `1` | Number of random seeds (0 … n_seeds−1) |
187
+ | `stretch_factors` | `float` or `list` | `1.5` | Stretch factor(s) applied to changing bond targets in the bounds matrix |
188
+ | `top_k` | `int` | `5` | Number of best initial conformers to carry into iterative alignment |
189
+ | `n_images` | `int` | `15` | NEB images (including endpoints) |
190
+ | `filter_dihedrals` | `bool` | `True` | Restrict optimization to dihedrals near the reaction center |
191
+ | `k_nearest_dihedrals` | `int` | `3` | Bond-distance cutoff for dihedral filtering |
192
+ | `cutoff` | `float` | `10.0` | Neighbor-pair cutoff (Å) for overlap evaluation |
193
+ | `rotation` | `bool` | `True` | Include fragment rotations |
194
+ | `translation` | `bool` | auto | Include fragment translations (default: `True` when multiple fragments exist) |
195
+
196
+ ### `generate_initial_conformers` parameters
197
+
198
+ | Parameter | Default | Description |
199
+ |-----------|---------|-------------|
200
+ | `n_workers` | `1` | Conformer pairs generated and scored in parallel |
201
+ | `calculator` | `None` | Optional `Calculation`; when given, initial scoring uses it instead of the IDPP energy |
202
+
203
+ ### `run_iterative_alignment` parameters
204
+
205
+ | Parameter | Default | Description |
206
+ |-----------|---------|-------------|
207
+ | `neb_fmax` | `0.001` | Force convergence criterion for each inner NEB run |
208
+ | `neb_steps` | `200` | Maximum steps per inner NEB run |
209
+ | `propagation_threshold` | `0.0001` | Stop when max propagated endpoint force < this value |
210
+ | `propagation_step_size` | `2.0` | Initial endpoint adjustment step size (Å) |
211
+ | `max_iterations` | `40` | Maximum NEB + propagation iterations per conformer |
212
+ | `objective` | `"peak"` | Which IDPP quantity to minimize: `"peak"` the highest interior image, `"total"` the sum. Not the electronic barrier |
213
+ | `d_power` | `4` | IDPP distance weighting exponent |
214
+ | `backtrack_fmax` | `None` | Force criterion for the cheap NEB runs during endpoint stepping; falls back to `neb_fmax` |
215
+ | `backtrack_steps` | `None` | Step cap for those runs; falls back to `neb_steps` |
216
+ | `n_workers` | `1` | Conformers aligned in parallel |
217
+ | `calculator` | `None` | Optional `Calculation` for electronic energies along the path |
218
+ | `sp_images` | `"all"` | `"all"` evaluates every interior image; `"peak"` evaluates only the image the IDPP path puts highest, which is cheaper but assumes the two peaks coincide |
219
+ | `verbose` | `False` | Print per-iteration progress |
220
+
221
+ ### Choosing a stretch factor automatically
222
+
223
+ A single stretch factor is not optimal for every reaction. `find_optimal_stretch_factor` scans upward until the score stops improving and leaves the best result on the reaction object:
224
+
225
+ ```python
226
+ from sparta import find_optimal_stretch_factor
227
+
228
+ rxn = find_optimal_stretch_factor(rxn, start=1.0, step=0.1, max_stretch=3.0)
229
+ ```
230
+
231
+ | Parameter | Default | Description |
232
+ |-----------|---------|-------------|
233
+ | `start` | `1.0` | First stretch factor tried |
234
+ | `step` | `0.1` | Increment between factors |
235
+ | `max_stretch` | `3.0` | Upper bound on the factor |
236
+ | `patience` | `3` | Stop after this many consecutive factors fail to improve. `1` stops at the first, which is cheap but leaves gains behind when the score is not monotonic |
237
+ | `calculator` | `None` | When given, factors are ranked by electronic barrier rather than IDPP score |
238
+ | `rank_by` | `"auto"` | `"auto"` ranks by barrier when a calculator is present and by IDPP score otherwise; `"idpp"` forces geometric ranking |
239
+ | `sp_images` | `"all"` | As for `run_iterative_alignment` |
240
+
241
+ It also accepts every alignment parameter of `run_iterative_alignment`.
242
+
243
+ ### Getting the barrier for an aligned reaction
244
+
245
+ If a reaction has already been aligned, `sparta_barrier` returns its barrier in
246
+ kcal/mol, computing the electronic energies only if they are not already there:
247
+
248
+ ```python
249
+ from sparta import sparta_barrier
250
+
251
+ barrier = sparta_barrier(rxn, calculator=XTBCalculation())
252
+ ```
253
+
254
+ ### Reproducing the published results
255
+
256
+ The defaults of `run_sparta` are the published settings. Stated explicitly:
257
+
258
+ ```python
259
+ from sparta import Reaction, XTBCalculation, run_sparta
260
+
261
+ rxn = Reaction(
262
+ reactant_smiles=...,
263
+ product_smiles=...,
264
+ n_conformers=30, # per stretch factor
265
+ n_seeds=1,
266
+ )
267
+
268
+ rxn = run_sparta(
269
+ rxn,
270
+ calculator=XTBCalculation(),
271
+ stretch_factors=None, # scan 1.0 to 2.0 in steps of 0.1
272
+ patience=3, # stop after 3 factors without improvement
273
+ )
274
+ ```
275
+
276
+ `run_sparta` sets `top_k=1`, so one endpoint pair per stretch factor carries
277
+ through to alignment. The reported barriers used g-xTB; `XTBCalculation`
278
+ invokes whichever xtb build is on `PATH`, and GFN2 and g-xTB give different
279
+ numbers for the same reaction.
280
+
281
+ To evaluate a fixed set of factors instead of scanning, pass them:
282
+ `run_sparta(rxn, calc, stretch_factors=[1.0, 1.1, ..., 2.0])`.
283
+
284
+ ---
285
+
286
+ ## Command line
287
+
288
+ Installing the package provides a `sparta` command that processes a CSV of reactions and writes a results CSV.
289
+
290
+ ### Input file format
291
+
292
+ A CSV with at minimum these two columns:
293
+
294
+ ```
295
+ reactant_smiles,product_smiles
296
+ [C:1]([H:2])([H:3])([H:4])[H:5].[F:6][F:7],[C:1]([H:2])([H:3])([H:4])[F:6].[H:5][F:7]
297
+ [C:1]([H:3])([H:4])=[C:2]([H:5])[H:6].[H:7][Cl:8],[C:1]([H:3])([H:4])([H:7])[C:2]([H:5])([H:6])[Cl:8]
298
+ ```
299
+
300
+ As above, every atom carries a map number and hydrogens are explicit.
301
+
302
+ Additional columns are preserved in the output.
303
+
304
+ ### Basic usage
305
+
306
+ ```bash
307
+ # Defaults
308
+ sparta reactions.csv
309
+
310
+ # Specify output file
311
+ sparta reactions.csv -o results.csv
312
+
313
+ # Override hyperparameters via flags
314
+ sparta reactions.csv \
315
+ --n-conformers 10 --n-seeds 3 \
316
+ --stretch-factors 1.3 1.5 1.8 \
317
+ --top-k 5 --idpp-objective peak
318
+
319
+ # Load hyperparameters from a JSON config
320
+ sparta reactions.csv --config config.json
321
+
322
+ # Compute SPARTA barriers rather than geometric scores alone
323
+ sparta reactions.csv --calculator xtb
324
+
325
+ # Save the best aligned conformer pair as XYZ files
326
+ sparta reactions.csv --save-conformers --conformer-dir ./conformers
327
+ ```
328
+
329
+ ### Config file format
330
+
331
+ CLI flags override config file values. All keys are optional.
332
+
333
+ ```json
334
+ {
335
+ "n_conformers": 10,
336
+ "n_seeds": 3,
337
+ "stretch_factors": [1.3, 1.5, 1.8],
338
+ "top_k": 5,
339
+ "n_images": 15,
340
+ "neb_fmax": 0.001,
341
+ "neb_steps": 200,
342
+ "propagation_threshold": 0.0001,
343
+ "propagation_step_size": 2.0,
344
+ "max_iterations": 40,
345
+ "objective": "peak",
346
+ "d_power": 4
347
+ }
348
+ ```
349
+
350
+ ### Output
351
+
352
+ The output CSV contains all original columns plus:
353
+
354
+ | Column | Description |
355
+ |--------|-------------|
356
+ | `status` | `ok`, `no_results`, or `error: <message>` |
357
+ | `best_score` | IDPP score of the best aligned conformer (lower = better) |
358
+ | `all_scores` | Semicolon-separated scores for all aligned conformers |
359
+ | `barrier_kcal` | SPARTA barrier in kcal/mol, present when `--calculator` is not `none` |
360
+
361
+ ### All CLI flags
362
+
363
+ ```
364
+ positional arguments:
365
+ input CSV file with reactant_smiles and product_smiles columns
366
+
367
+ options:
368
+ -o, --output FILE Output CSV (default: <input>_results.csv)
369
+ -c, --config FILE JSON config file for hyperparameters
370
+
371
+ --n-conformers INT Conformers per (seed, stretch_factor) [default: 10]
372
+ --n-seeds INT Number of random seeds [default: 1]
373
+ --stretch-factors SF [...] Stretch factor(s) [default: 1.5]
374
+ --top-k INT Top-k conformers to align [default: 5]
375
+ --n-images INT NEB images [default: 15]
376
+
377
+ --neb-fmax FLOAT NEB force convergence [default: 0.001]
378
+ --neb-steps INT Max NEB steps per run [default: 200]
379
+ --propagation-threshold F Endpoint force convergence [default: 0.0001]
380
+ --propagation-step-size F Initial endpoint step size Å [default: 2.0]
381
+ --max-iterations INT Max NEB+propagation iterations [default: 40]
382
+ --d-power INT IDPP distance exponent [default: 4]
383
+
384
+ --save-conformers Save best XYZ conformer pair per reaction
385
+ --conformer-dir DIR Directory for XYZ files [default: conformers]
386
+ --verbose Print per-conformer optimization progress
387
+ ```
388
+
389
+ ---
390
+
391
+ ## License
392
+
393
+ MIT, see [LICENSE](LICENSE).