autopcet 1.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.
- autopcet-1.1.0/CHANGELOG.md +56 -0
- autopcet-1.1.0/LICENSE +21 -0
- autopcet-1.1.0/MANIFEST.in +10 -0
- autopcet-1.1.0/PKG-INFO +531 -0
- autopcet-1.1.0/README.md +499 -0
- autopcet-1.1.0/autopcet/__init__.py +179 -0
- autopcet-1.1.0/autopcet/_types.py +23 -0
- autopcet-1.1.0/autopcet/ase_io.py +485 -0
- autopcet-1.1.0/autopcet/cli/__init__.py +7 -0
- autopcet-1.1.0/autopcet/cli/_io.py +56 -0
- autopcet-1.1.0/autopcet/cli/align_average.py +196 -0
- autopcet-1.1.0/autopcet/cli/calc_keff.py +82 -0
- autopcet-1.1.0/autopcet/cli/scan_da_distance.py +178 -0
- autopcet-1.1.0/autopcet/cli/scan_proton_coord.py +116 -0
- autopcet-1.1.0/autopcet/constants.py +64 -0
- autopcet-1.1.0/autopcet/edl.py +198 -0
- autopcet-1.1.0/autopcet/fgh.py +63 -0
- autopcet-1.1.0/autopcet/gaussian_io.py +238 -0
- autopcet-1.1.0/autopcet/kappa.py +335 -0
- autopcet-1.1.0/autopcet/plotting/__init__.py +109 -0
- autopcet-1.1.0/autopcet/plotting/_mpl.py +99 -0
- autopcet-1.1.0/autopcet/plotting/analysis.py +251 -0
- autopcet-1.1.0/autopcet/plotting/averaging.py +82 -0
- autopcet-1.1.0/autopcet/plotting/potentials.py +379 -0
- autopcet-1.1.0/autopcet/plotting/states.py +207 -0
- autopcet-1.1.0/autopcet/plotting/style.py +103 -0
- autopcet-1.1.0/autopcet/plotting/sweeps.py +151 -0
- autopcet-1.1.0/autopcet/potentials.py +221 -0
- autopcet-1.1.0/autopcet/py.typed +0 -0
- autopcet-1.1.0/autopcet/rates.py +327 -0
- autopcet-1.1.0/autopcet/reporting.py +94 -0
- autopcet-1.1.0/autopcet/structure.py +211 -0
- autopcet-1.1.0/autopcet/utils.py +39 -0
- autopcet-1.1.0/autopcet.egg-info/PKG-INFO +531 -0
- autopcet-1.1.0/autopcet.egg-info/SOURCES.txt +149 -0
- autopcet-1.1.0/autopcet.egg-info/dependency_links.txt +1 -0
- autopcet-1.1.0/autopcet.egg-info/entry_points.txt +5 -0
- autopcet-1.1.0/autopcet.egg-info/requires.txt +13 -0
- autopcet-1.1.0/autopcet.egg-info/top_level.txt +1 -0
- autopcet-1.1.0/examples/example1_basic_usage/double_well_potentials.dat +22 -0
- autopcet-1.1.0/examples/example1_basic_usage/example1_basic_usage.py +88 -0
- autopcet-1.1.0/examples/example1_basic_usage/reference_output.txt +25 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/example2_Y356-Y731.py +206 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/p_R_umbrella_A.dat +82 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R2.42_potential.dat +49 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R2.52_potential.dat +49 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R2.62_potential.dat +49 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R2.72_potential.dat +49 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R2.82_potential.dat +49 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R2.92_potential.dat +49 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R3.02_potential.dat +73 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/proton_potentials/R3.12_potential.dat +73 -0
- autopcet-1.1.0/examples/example2_Y356-Y731/reference_output.txt +11 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/electrochem_reference_output.txt +17 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/example3_BIP_KIE_electrochemical.py +254 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/example3_BIP_KIE_photochemical.py +201 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/photochem_reference_output.txt +17 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.37A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.42A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.47A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.52A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.57A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.62A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.67A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.72A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.77A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.82A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Oxidized_BIP_2.87A.csv +26 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.37A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.42A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.47A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.52A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.57A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.62A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.67A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.72A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.77A.csv +25 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.82A.csv +27 -0
- autopcet-1.1.0/examples/example3_BIP_KIE/proton_potentials/Reduced_BIP_2.87A.csv +27 -0
- autopcet-1.1.0/examples/example4_CoTPP/CoTPP_reference_output.txt +299 -0
- autopcet-1.1.0/examples/example4_CoTPP/example4_CoTPP.py +371 -0
- autopcet-1.1.0/examples/example4_CoTPP/graphene_DOS_norm_gauss.csv +4001 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.057_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.057_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.157_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.157_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.207_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.207_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.257_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.257_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.307_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.307_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.357_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.357_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.379_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.379_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.407_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.407_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.457_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.457_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.507_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.507_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.557_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.557_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.607_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.607_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.657_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.657_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.757_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.757_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.857_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.857_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.957_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_3.957_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_4.057_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_4.057_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_4.157_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_4.157_R.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_4.257_P.csv +257 -0
- autopcet-1.1.0/examples/example4_CoTPP/proton_potentials/rDA_4.257_R.csv +257 -0
- autopcet-1.1.0/examples/example5_RNR_nonadiabaticity/Y356_Y731_config2_env.dat +28 -0
- autopcet-1.1.0/examples/example5_RNR_nonadiabaticity/Y356_Y731_config2_gas.dat +28 -0
- autopcet-1.1.0/examples/example5_RNR_nonadiabaticity/example5_nonadiabaticity_Y356-Y731.py +104 -0
- autopcet-1.1.0/examples/example5_RNR_nonadiabaticity/reference_output_env.txt +7 -0
- autopcet-1.1.0/examples/example5_RNR_nonadiabaticity/reference_output_gas.txt +7 -0
- autopcet-1.1.0/examples/example6_ORCA_ASE/example6_orca_ase.py +237 -0
- autopcet-1.1.0/pyproject.toml +129 -0
- autopcet-1.1.0/setup.cfg +4 -0
- autopcet-1.1.0/tests/conftest.py +94 -0
- autopcet-1.1.0/tests/data/donor_acceptor.xyz +5 -0
- autopcet-1.1.0/tests/data/freq_hpmodes.log +34 -0
- autopcet-1.1.0/tests/data/product.xyz +8 -0
- autopcet-1.1.0/tests/data/reactant.xyz +8 -0
- autopcet-1.1.0/tests/data/reference_average.xyz +8 -0
- autopcet-1.1.0/tests/data/reference_average_mismatched_acceptor.xyz +8 -0
- autopcet-1.1.0/tests/data/reference_product_aligned.xyz +8 -0
- autopcet-1.1.0/tests/data/reference_reactant_aligned.xyz +8 -0
- autopcet-1.1.0/tests/example1_data.py +29 -0
- autopcet-1.1.0/tests/test_ase_io.py +421 -0
- autopcet-1.1.0/tests/test_cli.py +390 -0
- autopcet-1.1.0/tests/test_double_well.py +64 -0
- autopcet-1.1.0/tests/test_edl_model.py +130 -0
- autopcet-1.1.0/tests/test_examples.py +167 -0
- autopcet-1.1.0/tests/test_fgh.py +44 -0
- autopcet-1.1.0/tests/test_gaussian_io.py +160 -0
- autopcet-1.1.0/tests/test_kappa_coupling.py +189 -0
- autopcet-1.1.0/tests/test_pcet.py +370 -0
- autopcet-1.1.0/tests/test_plotting.py +718 -0
- autopcet-1.1.0/tests/test_potentials_and_utils.py +221 -0
- autopcet-1.1.0/tests/test_reporting.py +129 -0
- autopcet-1.1.0/tests/test_structure.py +197 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [1.1.0] - 2026-09-18
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Support for Python 3.12 and 3.13 alongside 3.14. The declared floor moves
|
|
12
|
+
from `>=3.14` to `>=3.12`, and CI tests all three.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- `import autopcet` raised `NameError` on Python 3.12 and 3.13. Annotations
|
|
17
|
+
naming an import made only under `if TYPE_CHECKING:` are evaluated eagerly
|
|
18
|
+
before 3.14, which defers them under PEP 649; every module doing so now
|
|
19
|
+
carries `from __future__ import annotations`. Moving those imports out of the
|
|
20
|
+
type-checking block would have made `ase` and `matplotlib` mandatory, so the
|
|
21
|
+
`TC004` lint rule guards the pattern instead.
|
|
22
|
+
|
|
23
|
+
## [1.0.0] - 2026-09-18
|
|
24
|
+
|
|
25
|
+
First public release.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- Vibronically nonadiabatic PCET rate constants from diabatic proton
|
|
30
|
+
potentials, with proton vibrational states solved on a Fourier grid
|
|
31
|
+
Hamiltonian (`autopcet.fgh`) and golden-rule rate matrices summed over pairs
|
|
32
|
+
of reactant and product vibronic states (`PCET`).
|
|
33
|
+
- Kinetic isotope effects from the same rate machinery
|
|
34
|
+
(`kinetic_isotope_effect`).
|
|
35
|
+
- Nonadiabaticity analysis after Georgievskii and Stuchebrukhov
|
|
36
|
+
(`KappaCoupling`).
|
|
37
|
+
- An electrical double layer model of the interfacial potential drop for
|
|
38
|
+
electrochemical PCET (`make_edl_model`).
|
|
39
|
+
- Analytic and tabulated proton potentials, including Morse, inverted Morse and
|
|
40
|
+
Gaussian forms, with polynomial and B-spline fitting of scan data
|
|
41
|
+
(`autopcet.potentials`).
|
|
42
|
+
- Readers for Gaussian output and, through the optional `ase` extra, scan and
|
|
43
|
+
vibrational drivers for any ASE calculator (`autopcet.gaussian_io`,
|
|
44
|
+
`autopcet.ase_io`).
|
|
45
|
+
- Structure alignment and averaging helpers for donor-acceptor geometries
|
|
46
|
+
(`autopcet.structure`).
|
|
47
|
+
- Four console scripts: `autopcet-align-average`, `autopcet-keff`,
|
|
48
|
+
`autopcet-scan-da` and `autopcet-scan-proton`.
|
|
49
|
+
- An optional matplotlib layer under the `plotting` extra
|
|
50
|
+
(`autopcet.plotting`). Importing the package, or the subpackage, never
|
|
51
|
+
requires matplotlib; only calling a plotting function does.
|
|
52
|
+
- Inline type annotations, exported through `py.typed`.
|
|
53
|
+
- Six worked examples with committed reference output, under `examples/`.
|
|
54
|
+
|
|
55
|
+
[1.1.0]: https://github.com/LouieSlocombe/autopcet/compare/v1.0.0...v1.1.0
|
|
56
|
+
[1.0.0]: https://github.com/LouieSlocombe/autopcet/releases/tag/v1.0.0
|
autopcet-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Louie Slocombe
|
|
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,10 @@
|
|
|
1
|
+
# The tests read fixtures from tests/data, and test_examples.py runs the
|
|
2
|
+
# scripts under examples/ against their committed reference output. Both have
|
|
3
|
+
# to travel with the sdist for its test suite to be runnable.
|
|
4
|
+
include CHANGELOG.md
|
|
5
|
+
|
|
6
|
+
graft tests
|
|
7
|
+
graft examples
|
|
8
|
+
|
|
9
|
+
global-exclude *.py[cod]
|
|
10
|
+
prune **/__pycache__
|
autopcet-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autopcet
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Automated proton-coupled electron transfer (PCET) tooling.
|
|
5
|
+
Author-email: Louie Slocombe <louies@hotmail.co.uk>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/LouieSlocombe/autopcet
|
|
8
|
+
Project-URL: Issues, https://github.com/LouieSlocombe/autopcet/issues
|
|
9
|
+
Project-URL: Repository, https://github.com/LouieSlocombe/autopcet
|
|
10
|
+
Keywords: chemistry,electron-transfer,pcet,proton-transfer
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: numba>=0.67
|
|
22
|
+
Requires-Dist: numpy>=2.5.2
|
|
23
|
+
Requires-Dist: scipy>=1.14
|
|
24
|
+
Provides-Extra: ase
|
|
25
|
+
Requires-Dist: ase>=3.23; extra == "ase"
|
|
26
|
+
Provides-Extra: examples
|
|
27
|
+
Requires-Dist: autopcet[plotting]; extra == "examples"
|
|
28
|
+
Requires-Dist: pandas>=2.2; extra == "examples"
|
|
29
|
+
Provides-Extra: plotting
|
|
30
|
+
Requires-Dist: matplotlib>=3.10; extra == "plotting"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# autopcet
|
|
34
|
+
|
|
35
|
+
Automated proton-coupled electron transfer (PCET) rate calculations in Python.
|
|
36
|
+
|
|
37
|
+
The library computes vibronically nonadiabatic PCET rate constants from
|
|
38
|
+
diabatic proton potentials: it solves for the proton vibrational states with a
|
|
39
|
+
Fourier grid Hamiltonian (FGH) method, builds the golden-rule rate matrices
|
|
40
|
+
over pairs of reactant/product vibronic states (`PCET`), and evaluates
|
|
41
|
+
kinetic isotope effects (KIEs). It also provides a nonadiabaticity analysis
|
|
42
|
+
following Georgievskii and Stuchebrukhov (`KappaCoupling`) and an electrical
|
|
43
|
+
double layer (EDL) model of the interfacial potential drop for
|
|
44
|
+
electrochemical PCET (`make_edl_model`). Everything it computes can be drawn
|
|
45
|
+
with `autopcet.plotting`, an optional matplotlib layer described under
|
|
46
|
+
[Plotting](#plotting).
|
|
47
|
+
|
|
48
|
+
## Requirements
|
|
49
|
+
|
|
50
|
+
- Python 3.12 or newer
|
|
51
|
+
- pip 25.1 or newer (for dependency groups)
|
|
52
|
+
|
|
53
|
+
NumPy, SciPy, and Numba are installed automatically as dependencies.
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
Create an isolated environment and install the package:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m venv .venv
|
|
61
|
+
source .venv/bin/activate
|
|
62
|
+
python -m pip install --upgrade pip
|
|
63
|
+
python -m pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
On Windows PowerShell, activate the environment with
|
|
67
|
+
`.venv\Scripts\Activate.ps1` instead.
|
|
68
|
+
|
|
69
|
+
`autopcet.plotting` needs matplotlib, the examples additionally use pandas,
|
|
70
|
+
and ASE powers both the in-process scan runners in `autopcet.ase_io` and the
|
|
71
|
+
structure-file reading of the `autopcet-*` command-line helpers; install them
|
|
72
|
+
through the optional extras:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python -m pip install -e ".[plotting]"
|
|
76
|
+
python -m pip install -e ".[examples]"
|
|
77
|
+
python -m pip install -e ".[ase]"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
(`examples` includes `plotting`.) Importing `autopcet` itself never needs any
|
|
81
|
+
of them.
|
|
82
|
+
|
|
83
|
+
For development, install the dev dependency group as well:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
python -m pip install --group dev -e .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If you prefer Conda, `build_tools/environment.yml` creates the base environment:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
conda env create -f build_tools/environment.yml
|
|
93
|
+
conda activate autopcet
|
|
94
|
+
python -m pip install --group dev -e .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Quick start
|
|
98
|
+
|
|
99
|
+
Fit tabulated diabatic proton potentials, set up the golden-rule rate model,
|
|
100
|
+
and compute rate constants and the KIE:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from autopcet import PCET, MASS_DEUTERON, MASS_PROTON, fit_poly8
|
|
104
|
+
|
|
105
|
+
# rp, reactant_energies, product_energies: 1D arrays holding the tabulated
|
|
106
|
+
# diabatic proton potentials
|
|
107
|
+
reactant_potential = fit_poly8(rp, reactant_energies)
|
|
108
|
+
product_potential = fit_poly8(rp, product_energies)
|
|
109
|
+
|
|
110
|
+
system = PCET(
|
|
111
|
+
reactant_potential,
|
|
112
|
+
product_potential,
|
|
113
|
+
reaction_free_energy=-0.50,
|
|
114
|
+
reorganization_energy=1.00,
|
|
115
|
+
electronic_coupling=0.0434,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
rate_h = system.calculate(MASS_PROTON, temperature=298)
|
|
119
|
+
rate_d = system.calculate(MASS_DEUTERON, temperature=298)
|
|
120
|
+
print(f"k(H) = {rate_h:.2e} s^-1, KIE = {rate_h / rate_d:.2f}")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Once `calculate` has run, the per-state results are plain attributes:
|
|
124
|
+
`populations`, `overlaps`, `pair_free_energies`, `pair_activation_energies`,
|
|
125
|
+
`rate_contributions`, and `total_rate_constant`. The thermodynamic parameters
|
|
126
|
+
are attributes too, so a sweep just reassigns one and calls `calculate` again
|
|
127
|
+
with `reuse_states=True` to keep the proton states it already solved for.
|
|
128
|
+
`temperature_sweep` and `driving_force_sweep` do exactly that over a grid --
|
|
129
|
+
one FGH solve for the whole sweep -- and `kinetic_isotope_effect` returns
|
|
130
|
+
`k(H) / k(D)` in one call.
|
|
131
|
+
|
|
132
|
+
A rate constant computed at one proton donor-acceptor distance is usually
|
|
133
|
+
averaged over the distribution of distances the mode samples.
|
|
134
|
+
`donor_acceptor_distribution` builds the harmonic `P(R)` from the effective
|
|
135
|
+
force constant that `autopcet-keff` reports:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from scipy.integrate import simpson
|
|
139
|
+
|
|
140
|
+
from autopcet import donor_acceptor_distribution
|
|
141
|
+
|
|
142
|
+
# distances: the grid k(R) was evaluated on; force_constant in atomic units
|
|
143
|
+
distribution = donor_acceptor_distribution(distances, 2.58, 0.0443, temperature=298)
|
|
144
|
+
distribution /= simpson(distribution, x=distances)
|
|
145
|
+
average_rate = simpson(distribution * rates, x=distances)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
To quantify the (non)adiabaticity of a reaction from the same inputs:
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from autopcet import KappaCoupling, MASS_PROTON
|
|
152
|
+
|
|
153
|
+
# potentials tabulated on a 2^n grid, electronic coupling in eV
|
|
154
|
+
system = KappaCoupling(rp, reactant_energies, product_energies, electronic_coupling)
|
|
155
|
+
system.calculate(MASS_PROTON)
|
|
156
|
+
|
|
157
|
+
print(system.tau_electron, system.tau_proton, system.adiabaticity, system.kappa)
|
|
158
|
+
print(system.v_semiclassical, system.v_nonadiabatic, system.v_adiabatic)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Units and naming
|
|
162
|
+
|
|
163
|
+
Energies are in electronvolts, lengths in ångström, and particle masses in
|
|
164
|
+
electron masses (atomic units), unless a name says otherwise. Unit conversions
|
|
165
|
+
are exported as named constants (`KCAL_TO_EV`, `HARTREE_TO_EV`,
|
|
166
|
+
`ANGSTROM_TO_BOHR`, ...), as are the physical constants (`BOLTZMANN`, `HBAR`,
|
|
167
|
+
`MASS_PROTON`, `MASS_DEUTERON`, ...).
|
|
168
|
+
|
|
169
|
+
## Plotting
|
|
170
|
+
|
|
171
|
+
`autopcet.plotting` draws the quantities above in a consistent house style. It
|
|
172
|
+
needs matplotlib, from the `plotting` extra, and is imported explicitly --
|
|
173
|
+
`import autopcet` itself never pulls matplotlib in:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
import matplotlib.pyplot as plt
|
|
177
|
+
|
|
178
|
+
from autopcet.plotting import (
|
|
179
|
+
figure_of,
|
|
180
|
+
plot_proton_states,
|
|
181
|
+
plot_state_pair_map,
|
|
182
|
+
use_style,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
use_style()
|
|
186
|
+
|
|
187
|
+
# the two diabats with their vibrational states, one panel each
|
|
188
|
+
reactant_axes, _ = plot_proton_states(system, n_states=6)
|
|
189
|
+
figure_of(reactant_axes).savefig("proton_states.png")
|
|
190
|
+
|
|
191
|
+
# which pairs of vibronic states actually carry the rate constant
|
|
192
|
+
ax = plot_state_pair_map(system, "contribution")
|
|
193
|
+
figure_of(ax).savefig("state_pairs.png")
|
|
194
|
+
plt.close("all")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Every function takes an optional axes to draw on and returns the axes it drew,
|
|
198
|
+
so figures compose. None of them saves, shows, or closes a figure, and none
|
|
199
|
+
sets an axis limit that was not read off the data -- placing and saving the
|
|
200
|
+
figure stays yours.
|
|
201
|
+
|
|
202
|
+
What it can draw:
|
|
203
|
+
|
|
204
|
+
| Function | Figure |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| `plot_proton_states`, `plot_state_ladder` | diabatic potentials with their vibrational states |
|
|
207
|
+
| `plot_isotope_states` | proton and deuteron states on shared axes |
|
|
208
|
+
| `plot_potential_family` | one proton potential per donor-acceptor distance |
|
|
209
|
+
| `plot_potential_fit` | a fitted potential against the data, with residuals |
|
|
210
|
+
| `plot_state_pair_map`, `plot_state_pair_grid` | the (u, v) matrices as annotated heat maps |
|
|
211
|
+
| `plot_populations` | Boltzmann populations of the reactant states |
|
|
212
|
+
| `plot_arrhenius`, `plot_kie_vs_temperature` | rate constant and KIE against temperature |
|
|
213
|
+
| `plot_rate_vs_driving_force` | the Marcus curve, marking $`-\lambda`$ |
|
|
214
|
+
| `plot_thermal_average` | $`k(R)`$, $`P(R)`$, and the product that decides the average |
|
|
215
|
+
| `plot_crossing`, `plot_diabats_and_adiabats` | the `KappaCoupling` nonadiabaticity analysis |
|
|
216
|
+
| `plot_edl_profile` | the interfacial potential drop of an EDL model |
|
|
217
|
+
| `plot_distance_scan`, `plot_proton_scan` | the raw energies off an ASE scan |
|
|
218
|
+
|
|
219
|
+
The sweeps behind the temperature and driving-force figures are ordinary
|
|
220
|
+
library functions, so they work without matplotlib:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
import numpy as np
|
|
224
|
+
|
|
225
|
+
from autopcet import temperature_sweep
|
|
226
|
+
from autopcet.plotting import plot_arrhenius
|
|
227
|
+
|
|
228
|
+
temperatures = np.linspace(250, 400, 16)
|
|
229
|
+
plot_arrhenius(temperatures, temperature_sweep(system, temperatures))
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
A sweep leaves the system holding the results of its last point, as any
|
|
233
|
+
`calculate` call does; the input it assigns is put back before it returns.
|
|
234
|
+
|
|
235
|
+
Colours, sizes, and the axis labels come from `autopcet.plotting.style`.
|
|
236
|
+
`use_style()` sets them globally, `style_context()` only for a block, and both
|
|
237
|
+
take overrides:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from autopcet.plotting import style_context
|
|
241
|
+
|
|
242
|
+
with style_context(**{"axes.labelsize": 18}):
|
|
243
|
+
...
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Reporting
|
|
247
|
+
|
|
248
|
+
The same state-pair matrices go out as text through `autopcet.reporting`, which
|
|
249
|
+
needs no matplotlib:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
import sys
|
|
253
|
+
|
|
254
|
+
from autopcet import write_contribution_table
|
|
255
|
+
|
|
256
|
+
# every pair's population, |S_uv|^2, free energy, activation energy, and share
|
|
257
|
+
# of the total rate constant
|
|
258
|
+
write_contribution_table(sys.stdout, system, n_states=4)
|
|
259
|
+
|
|
260
|
+
with open("contributions.log", "w") as log:
|
|
261
|
+
write_contribution_table(log, system, label="H", n_states=4)
|
|
262
|
+
write_contribution_table(log, system_d, label="D", n_states=4)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`format_contribution_table` returns the same block as a string, and
|
|
266
|
+
`contribution_percentages` returns just the percentage matrix.
|
|
267
|
+
`plot_state_pair_map` draws these numbers instead; the one difference is that
|
|
268
|
+
the map shows `|S_uv|`, which reads better on a linear colour scale, where the
|
|
269
|
+
table prints the `|S_uv|^2` that actually enters the rate.
|
|
270
|
+
|
|
271
|
+
## Examples
|
|
272
|
+
|
|
273
|
+
The `examples/` directory contains worked calculations, each with its input
|
|
274
|
+
data and a reference output to compare against:
|
|
275
|
+
|
|
276
|
+
1. `example1_basic_usage` — rate constant, vibronic-state analysis, and H/D
|
|
277
|
+
KIE for a first-principles double-well potential.
|
|
278
|
+
2. `example2_Y356-Y731` — rate constants as a function of the proton
|
|
279
|
+
donor-acceptor distance for the RNR Y356-Y731 interface, thermally averaged
|
|
280
|
+
over an umbrella-sampled P(R) distribution.
|
|
281
|
+
3. `example3_BIP_KIE` — electrochemical and photochemical KIEs for a
|
|
282
|
+
benzimidazole-phenol (BIP) system, one script each
|
|
283
|
+
(`example3_BIP_KIE_electrochemical.py` and `..._photochemical.py`). They
|
|
284
|
+
share a directory, so every file each writes is tagged with its own name.
|
|
285
|
+
4. `example4_CoTPP` — heterogeneous electrochemical PCET for CoTPP on
|
|
286
|
+
graphene, combining the EDL model with a density-of-states average.
|
|
287
|
+
5. `example5_RNR_nonadiabaticity` — vibronic couplings and nonadiabaticity
|
|
288
|
+
analysis for the RNR Y356-Y731 interface, in the gas phase
|
|
289
|
+
(`--config gas`) or in the protein environment (`--config env`).
|
|
290
|
+
6. `example6_ORCA_ASE` — the whole workflow run in-process through ASE with
|
|
291
|
+
ORCA: donor-acceptor scan, proton endpoint optimizations, proton
|
|
292
|
+
potentials, effective mode, rate constant, and KIE. Unlike the others it
|
|
293
|
+
needs a working ORCA installation (pass its path with `--orca`) and your
|
|
294
|
+
own reactant/product structures.
|
|
295
|
+
|
|
296
|
+
Run an example from inside its own directory, e.g.:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
cd examples/example1_basic_usage
|
|
300
|
+
python example1_basic_usage.py
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Example 5 takes the configuration to run as an argument, and writes a separate
|
|
304
|
+
set of figures for each:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
cd examples/example5_RNR_nonadiabaticity
|
|
308
|
+
python example5_nonadiabaticity_Y356-Y731.py --config gas
|
|
309
|
+
python example5_nonadiabaticity_Y356-Y731.py --config env
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The reference outputs were generated with the NumPy and SciPy versions current
|
|
313
|
+
at the time; results can drift in the third significant digit across releases.
|
|
314
|
+
`tests/test_examples.py` re-runs examples 1 and 5 and compares them at a
|
|
315
|
+
relative tolerance.
|
|
316
|
+
|
|
317
|
+
## Command-line tools
|
|
318
|
+
|
|
319
|
+
Installing the package also installs four helpers that prepare the Gaussian
|
|
320
|
+
inputs a calculation like the ones above starts from. They wrap
|
|
321
|
+
`autopcet.structure` and `autopcet.gaussian_io`, so anything they do is also
|
|
322
|
+
available from Python. Reading structure files in formats other than xyz needs
|
|
323
|
+
ASE, from the `ase` extra. Every one of them takes `--help`.
|
|
324
|
+
|
|
325
|
+
The four run in the order below, which is the order a proton potential is built
|
|
326
|
+
in.
|
|
327
|
+
|
|
328
|
+
### 1. Scan the proton donor-acceptor distance
|
|
329
|
+
|
|
330
|
+
`autopcet-scan-da` takes the fully optimized reactant and product structures --
|
|
331
|
+
the atoms must appear in the same order in both -- and writes, for each
|
|
332
|
+
donor-acceptor distance $`R`$, a pair of Gaussian inputs that reoptimize the two
|
|
333
|
+
states with $`R`$ frozen:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
autopcet-scan-da -r reac.xyz -p prod.xyz -D 0 -A 2 --start 2.4 --stop 2.8 --points 9
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`-D` and `-A` are the 0-based indices of the proton donor and acceptor. Charges
|
|
340
|
+
and multiplicities default to a neutral singlet reactant and a +1 doublet
|
|
341
|
+
product; `--reactant-charge` and friends override them. This assumes the two
|
|
342
|
+
diabatic electronic states differ only in the charge of the whole system, as
|
|
343
|
+
they do in homogeneous electrochemical PCET or in photoexcited PCET with an
|
|
344
|
+
external photoreceptor.
|
|
345
|
+
|
|
346
|
+
`--template` points at a file holding your own Gaussian header, in place of the
|
|
347
|
+
built-in B3LYP/6-31+G(d,p) one. It is formatted with `{state}`, `{charge}`, and
|
|
348
|
+
`{multiplicity}`.
|
|
349
|
+
|
|
350
|
+
> [!NOTE]
|
|
351
|
+
> Set `Nosymm` in these constrained optimizations. Without it Gaussian rotates
|
|
352
|
+
> the molecule and the later steps will not work.
|
|
353
|
+
|
|
354
|
+
### 2. Align and average the structures
|
|
355
|
+
|
|
356
|
+
`autopcet-align-average` overlays the reactant and product so the proton donor
|
|
357
|
+
and acceptor are superimposed along Z with their midpoint at the origin, rotates
|
|
358
|
+
the product about that axis to minimize the RMSD to the reactant, and averages
|
|
359
|
+
the two geometries:
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
autopcet-align-average -r reac.xyz -p prod.xyz --r-donor 1 --r-acceptor 2 --p-donor 1 --p-acceptor 2
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
These indices are 1-based, as printed by most quantum chemistry programs. The
|
|
366
|
+
aligned intermediates are written alongside their inputs, and the average goes
|
|
367
|
+
to `AVERAGE_STRUCTURE.xyz` unless `-o` says otherwise.
|
|
368
|
+
|
|
369
|
+
From the averaged structure, optimize the proton on the donor for the reactant
|
|
370
|
+
and on the acceptor for the product, with every other nucleus frozen. With
|
|
371
|
+
Gaussian, set that frozen optimization up by hand; with an ASE calculator,
|
|
372
|
+
`optimize_proton` does it in-process (see
|
|
373
|
+
[Running the scans with an ASE calculator](#running-the-scans-with-an-ase-calculator)).
|
|
374
|
+
|
|
375
|
+
### 3. Scan the proton along its transfer axis
|
|
376
|
+
|
|
377
|
+
`autopcet-scan-proton` builds the axis through the two optimized proton
|
|
378
|
+
positions and writes a Gaussian single point for each point along it. Run it
|
|
379
|
+
once per state:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
autopcet-scan-proton -r averaged_optH_reac.xyz -p averaged_optH_prod.xyz -H 1 --state reactant --charge 0 --multiplicity 1
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`-H` is the 0-based index of the transferring proton. The scan spans 1.7 times
|
|
386
|
+
the distance between the two equilibrium proton positions, and never less than
|
|
387
|
+
1 Å, so that the proton comes close to both the donor and the acceptor.
|
|
388
|
+
|
|
389
|
+
### 4. Effective donor-acceptor force constant
|
|
390
|
+
|
|
391
|
+
`autopcet-keff` projects the normal modes of a Gaussian frequency job onto the
|
|
392
|
+
donor-acceptor axis and prints the effective force constant (a.u.), reduced mass
|
|
393
|
+
(amu), and frequency (cm<sup>-1</sup>) of the donor-acceptor mode:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
autopcet-keff --log freq.log -D 0 -A 1
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
The force constant is what `donor_acceptor_distribution` needs to build the
|
|
400
|
+
$`P(R)`$ the rate constant is thermally averaged over.
|
|
401
|
+
|
|
402
|
+
> [!NOTE]
|
|
403
|
+
> Run the frequency job with `#P` and `freq=HPmodes`. The parser reads the
|
|
404
|
+
> high-precision normal modes those settings print and will not work without
|
|
405
|
+
> them.
|
|
406
|
+
|
|
407
|
+
## Running the scans with an ASE calculator
|
|
408
|
+
|
|
409
|
+
Everything the helpers above prepare Gaussian inputs for can also run
|
|
410
|
+
in-process against any [ASE](https://ase-lib.org) calculator — ORCA, xTB, or
|
|
411
|
+
anything else implementing ASE's `Calculator` interface — through
|
|
412
|
+
`autopcet.ase_io`, installed with the `ase` extra. The diabatic electronic
|
|
413
|
+
states are selected through the calculator: configure one per state, carrying
|
|
414
|
+
that state's charge and multiplicity, and run each scan once per state.
|
|
415
|
+
|
|
416
|
+
Everything that moves atoms — `run_da_scan`, `optimize_proton`,
|
|
417
|
+
`run_vibrations` — needs forces, so a calculator that runs an external program
|
|
418
|
+
has to be told to compute the gradient. For ORCA that means `EnGrad` in
|
|
419
|
+
`orcasimpleinput`: without it ORCA writes no `.engrad` file, ASE reports no
|
|
420
|
+
forces, and the scan stops on its first step. `run_proton_scan` and
|
|
421
|
+
`read_scan_energies` need energies only.
|
|
422
|
+
|
|
423
|
+
```python
|
|
424
|
+
from ase.calculators.orca import ORCA, OrcaProfile
|
|
425
|
+
from ase.io import read
|
|
426
|
+
|
|
427
|
+
from autopcet import (
|
|
428
|
+
effective_mode_from_vibrations,
|
|
429
|
+
optimize_proton,
|
|
430
|
+
run_da_scan,
|
|
431
|
+
run_proton_scan,
|
|
432
|
+
run_vibrations,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
profile = OrcaProfile(command="/opt/orca/orca")
|
|
436
|
+
reactant_calc = ORCA(
|
|
437
|
+
profile=profile,
|
|
438
|
+
directory="reac",
|
|
439
|
+
charge=0,
|
|
440
|
+
mult=1,
|
|
441
|
+
orcasimpleinput="B3LYP def2-SVP TightSCF EnGrad",
|
|
442
|
+
# ASE replaces its whole default block, so set the memory here too
|
|
443
|
+
orcablocks="%pal nprocs 8 end\n%maxcore 3000",
|
|
444
|
+
)
|
|
445
|
+
# ... and a product_calc with that state's charge and multiplicity
|
|
446
|
+
|
|
447
|
+
# 1. reoptimize the state on a grid of frozen donor-acceptor distances
|
|
448
|
+
scan = run_da_scan(read("reac.xyz"), 0, 2, reactant_calc, [2.4, 2.5, 2.6])
|
|
449
|
+
|
|
450
|
+
# 2. align and average with autopcet.structure as before, then optimize the
|
|
451
|
+
# proton endpoints with the rest of the frame frozen
|
|
452
|
+
endpoint = optimize_proton(averaged, 1, reactant_calc)
|
|
453
|
+
|
|
454
|
+
# 3. the proton potential along the transfer axis, on the same grid the
|
|
455
|
+
# command-line helper writes; feeds PCET directly
|
|
456
|
+
potential = run_proton_scan(reactant_endpoint, product_endpoint, 1, reactant_calc)
|
|
457
|
+
pcet = PCET((potential.offsets, potential.relative_energies), ...)
|
|
458
|
+
|
|
459
|
+
# 4. the effective donor-acceptor mode, in place of autopcet-keff
|
|
460
|
+
mode = effective_mode_from_vibrations(
|
|
461
|
+
run_vibrations(equilibrium, reactant_calc), donor=0, acceptor=2
|
|
462
|
+
)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Every grid point reuses the calculator's `directory`, so each job overwrites
|
|
466
|
+
the last one's files. Give a scan its own per-point directory if you want to
|
|
467
|
+
keep them, or to reuse a converged wavefunction as the next point's guess.
|
|
468
|
+
|
|
469
|
+
`examples/example6_ORCA_ASE` walks the full pipeline. For jobs run elsewhere —
|
|
470
|
+
on a cluster, say — keep writing inputs with `autopcet-scan-proton` and skip
|
|
471
|
+
the manual energy table afterwards: `read_scan_energies(directory, state)`
|
|
472
|
+
walks the numbered directories the helper created and reads the finished
|
|
473
|
+
outputs in any format ASE recognizes, Gaussian logs and ORCA outputs included.
|
|
474
|
+
Name each job's output after its input, so grid point `03` of a reactant scan
|
|
475
|
+
holds `reactant_sp.out` (or `.log`, `.xyz`, `.traj`) beside its `reactant_sp.gjf`.
|
|
476
|
+
|
|
477
|
+
> [!NOTE]
|
|
478
|
+
> Point `OrcaProfile` at the full path of your ORCA binary. On desktop Linux a
|
|
479
|
+
> bare `orca` on the PATH is usually the GNOME screen reader, not ORCA.
|
|
480
|
+
|
|
481
|
+
> [!NOTE]
|
|
482
|
+
> ASE warns `Geometry optimization did not converge!` for every ORCA gradient
|
|
483
|
+
> single point, reading the gradient header as the start of a relaxation, and
|
|
484
|
+
> prints a caution about reading `.engrad` files from optimizations. Both are
|
|
485
|
+
> artefacts of ASE's ORCA reader and say nothing about your calculation.
|
|
486
|
+
|
|
487
|
+
## Development
|
|
488
|
+
|
|
489
|
+
Run the complete local checks:
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
ruff check .
|
|
493
|
+
ruff format --check .
|
|
494
|
+
mypy
|
|
495
|
+
pytest
|
|
496
|
+
python -m build
|
|
497
|
+
python -m twine check dist/*
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Ruff can apply safe lint and formatting changes with:
|
|
501
|
+
|
|
502
|
+
```bash
|
|
503
|
+
ruff check --fix .
|
|
504
|
+
ruff format .
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
Install the Git hooks once, then pre-commit will run the fast checks before
|
|
508
|
+
each commit:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
pre-commit install
|
|
512
|
+
pre-commit run --all-files
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## Project layout
|
|
516
|
+
|
|
517
|
+
```text
|
|
518
|
+
.
|
|
519
|
+
├── .github/workflows/ci.yml # automated quality and packaging checks
|
|
520
|
+
├── autopcet/ # the installable, typed package
|
|
521
|
+
│ ├── cli/ # the autopcet-* command-line helpers
|
|
522
|
+
│ └── plotting/ # optional matplotlib figures (plotting extra)
|
|
523
|
+
├── build_tools/ # optional Conda setup
|
|
524
|
+
├── examples/ # worked examples with reference outputs
|
|
525
|
+
├── tests/ # behavior-focused tests
|
|
526
|
+
└── pyproject.toml # project metadata and tool configuration
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## License
|
|
530
|
+
|
|
531
|
+
Released under the [MIT License](https://github.com/LouieSlocombe/autopcet/blob/main/LICENSE).
|