firecode 1.5.3__tar.gz → 2.0.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 (118) hide show
  1. {firecode-1.5.3 → firecode-2.0.0}/.coveragerc +8 -2
  2. {firecode-1.5.3 → firecode-2.0.0}/.github/workflows/test.yml +10 -4
  3. {firecode-1.5.3 → firecode-2.0.0}/.gitignore +2 -1
  4. {firecode-1.5.3 → firecode-2.0.0}/.pre-commit-config.yaml +11 -11
  5. {firecode-1.5.3 → firecode-2.0.0}/CHANGELOG.md +37 -6
  6. firecode-2.0.0/PKG-INFO +151 -0
  7. firecode-2.0.0/README.md +120 -0
  8. {firecode-1.5.3 → firecode-2.0.0}/firecode/__main__.py +61 -49
  9. firecode-2.0.0/firecode/algebra.py +54 -0
  10. firecode-2.0.0/firecode/ase_manipulations.py +1533 -0
  11. {firecode-1.5.3 → firecode-2.0.0}/firecode/atropisomer_module.py +71 -98
  12. firecode-2.0.0/firecode/calculators/ase_uma.py +78 -0
  13. firecode-2.0.0/firecode/calculators/solvation_delta_calc.py +246 -0
  14. firecode-1.5.3/firecode/calculators/_xtb.py → firecode-2.0.0/firecode/calculators/xtb.py +131 -389
  15. firecode-2.0.0/firecode/context_managers.py +178 -0
  16. firecode-2.0.0/firecode/dispatcher.py +331 -0
  17. {firecode-1.5.3 → firecode-2.0.0}/firecode/embedder.py +684 -705
  18. {firecode-1.5.3 → firecode-2.0.0}/firecode/embedder_options.py +221 -223
  19. {firecode-1.5.3 → firecode-2.0.0}/firecode/embeds.py +94 -238
  20. firecode-2.0.0/firecode/ensemble.py +297 -0
  21. {firecode-1.5.3 → firecode-2.0.0}/firecode/graph_manipulations.py +14 -28
  22. {firecode-1.5.3 → firecode-2.0.0}/firecode/hypermolecule_class.py +93 -152
  23. firecode-2.0.0/firecode/interfaces/crest.py +457 -0
  24. firecode-2.0.0/firecode/interfaces/goat.py +415 -0
  25. firecode-2.0.0/firecode/md/equilibration.py +277 -0
  26. firecode-2.0.0/firecode/md/packmol.py +359 -0
  27. firecode-2.0.0/firecode/modify_settings.py +128 -0
  28. {firecode-1.5.3 → firecode-2.0.0}/firecode/multiembed.py +24 -17
  29. {firecode-1.5.3 → firecode-2.0.0}/firecode/operators.py +388 -247
  30. firecode-2.0.0/firecode/optimization_methods.py +330 -0
  31. {firecode-1.5.3 → firecode-2.0.0}/firecode/parameters.py +1 -1
  32. {firecode-1.5.3 → firecode-2.0.0}/firecode/pka.py +74 -79
  33. {firecode-1.5.3 → firecode-2.0.0}/firecode/profiler.py +2 -1
  34. {firecode-1.5.3 → firecode-2.0.0}/firecode/pt.py +7 -6
  35. {firecode-1.5.3 → firecode-2.0.0}/firecode/quotes.json +5 -1
  36. {firecode-1.5.3 → firecode-2.0.0}/firecode/quotes.py +2 -2
  37. {firecode-1.5.3 → firecode-2.0.0}/firecode/rdkit_tools.py +81 -49
  38. {firecode-1.5.3 → firecode-2.0.0}/firecode/reactive_atoms_classes.py +193 -116
  39. firecode-2.0.0/firecode/references.py +40 -0
  40. firecode-2.0.0/firecode/settings.py +67 -0
  41. firecode-2.0.0/firecode/solvents.py +226 -0
  42. firecode-2.0.0/firecode/standalone_optimizer.py +770 -0
  43. firecode-2.0.0/firecode/tests/C2H4.xyz +8 -0
  44. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/conftest.py +6 -1
  45. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_multiembed/embed_multiembed.txt +1 -1
  46. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_trimolecular/embed_trimolecular.txt +2 -2
  47. firecode-2.0.0/firecode/tests/operator_crest_search/operator_crest_search.txt +2 -0
  48. firecode-2.0.0/firecode/tests/operator_crest_search/salt.xyz +20 -0
  49. firecode-2.0.0/firecode/tests/operator_equilibrate/C2H4.xyz +8 -0
  50. firecode-2.0.0/firecode/tests/operator_equilibrate/operator_equilibrate.txt +2 -0
  51. firecode-2.0.0/firecode/tests/operator_fsm/anti_to_gauche.xyz +32 -0
  52. firecode-2.0.0/firecode/tests/operator_fsm/operator_fsm.txt +2 -0
  53. firecode-2.0.0/firecode/tests/operator_goat/.firecoderc +2 -0
  54. firecode-2.0.0/firecode/tests/operator_goat/H2O.xyz +5 -0
  55. firecode-2.0.0/firecode/tests/operator_goat/operator_goat.txt +2 -0
  56. firecode-2.0.0/firecode/tests/operator_neb/anti_to_gauche.xyz +32 -0
  57. firecode-2.0.0/firecode/tests/operator_neb/operator_neb.txt +2 -0
  58. firecode-2.0.0/firecode/tests/operator_pka/HCOOH.xyz +7 -0
  59. firecode-2.0.0/firecode/tests/operator_pka/Me2NH2+.xyz +13 -0
  60. firecode-2.0.0/firecode/tests/operator_pka/Me3N.xyz +15 -0
  61. firecode-2.0.0/firecode/tests/operator_pka/operator_pka.txt +4 -0
  62. firecode-2.0.0/firecode/tests/operator_racerts/operator_racerts.txt +4 -0
  63. firecode-2.0.0/firecode/tests/operator_racerts/taut_TS.xyz +11 -0
  64. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/operator_rdkit_search/operator_rdkit_search.txt +1 -1
  65. firecode-2.0.0/firecode/tests/operator_saddle/operator_saddle.txt +2 -0
  66. firecode-2.0.0/firecode/tests/operator_saddle/propane_ts.xyz +13 -0
  67. firecode-2.0.0/firecode/tests/operator_scan+neb/operator_scan+neb.txt +2 -0
  68. firecode-2.0.0/firecode/tests/operator_scan+neb/taut.xyz +11 -0
  69. firecode-2.0.0/firecode/tests/operator_scan_dihedral/operator_scan_dihedral.txt +2 -0
  70. firecode-2.0.0/firecode/tests/test_suite.py +304 -0
  71. firecode-2.0.0/firecode/thermochemistry.py +670 -0
  72. {firecode-1.5.3 → firecode-2.0.0}/firecode/torsion_module.py +378 -346
  73. firecode-2.0.0/firecode/typing_.py +19 -0
  74. {firecode-1.5.3 → firecode-2.0.0}/firecode/units.py +16 -0
  75. {firecode-1.5.3 → firecode-2.0.0}/firecode/utils.py +255 -249
  76. {firecode-1.5.3 → firecode-2.0.0}/pixi.lock +803 -612
  77. {firecode-1.5.3 → firecode-2.0.0}/pyproject.toml +67 -14
  78. firecode-1.5.3/.ase/gui.py +0 -1
  79. firecode-1.5.3/PKG-INFO +0 -80
  80. firecode-1.5.3/README.md +0 -52
  81. firecode-1.5.3/firecode/algebra.py +0 -107
  82. firecode-1.5.3/firecode/ase_manipulations.py +0 -1324
  83. firecode-1.5.3/firecode/calculators/_ase_uma.py +0 -48
  84. firecode-1.5.3/firecode/calculators/_orca.py +0 -128
  85. firecode-1.5.3/firecode/mep_relaxer.py +0 -218
  86. firecode-1.5.3/firecode/modify_settings.py +0 -223
  87. firecode-1.5.3/firecode/numba_functions.py +0 -239
  88. firecode-1.5.3/firecode/optimization_methods.py +0 -817
  89. firecode-1.5.3/firecode/references.py +0 -18
  90. firecode-1.5.3/firecode/settings.py +0 -71
  91. firecode-1.5.3/firecode/solvents.py +0 -131
  92. firecode-1.5.3/firecode/standalone_optimizer.py +0 -482
  93. firecode-1.5.3/firecode/tests/embed_cyclical/C2H4.xyz +0 -8
  94. firecode-1.5.3/firecode/tests/operator_mtd_search/dimer.xyz +0 -12
  95. firecode-1.5.3/firecode/tests/operator_mtd_search/operator_mtd_search.txt +0 -2
  96. firecode-1.5.3/firecode/tests/scan_dihedral/scan_dihedral.txt +0 -2
  97. firecode-1.5.3/firecode/tests/scan_linear/dimer.xyz +0 -12
  98. firecode-1.5.3/firecode/tests/scan_linear/scan_linear.txt +0 -2
  99. firecode-1.5.3/firecode/tests/test_suite.py +0 -118
  100. {firecode-1.5.3 → firecode-2.0.0}/.readthedocs.yaml +0 -0
  101. {firecode-1.5.3 → firecode-2.0.0}/LICENSE +0 -0
  102. {firecode-1.5.3 → firecode-2.0.0}/MANIFEST.in +0 -0
  103. {firecode-1.5.3 → firecode-2.0.0}/firecode/__init__.py +0 -0
  104. {firecode-1.5.3 → firecode-2.0.0}/firecode/errors.py +0 -0
  105. {firecode-1.5.3/firecode/tests → firecode-2.0.0/firecode/tests/embed_chelotropic}/C2H4.xyz +0 -0
  106. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_chelotropic/HCOOOH.xyz +0 -0
  107. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_chelotropic/embed_chelotropic.txt +0 -0
  108. {firecode-1.5.3/firecode/tests/embed_chelotropic → firecode-2.0.0/firecode/tests/embed_cyclical}/C2H4.xyz +0 -0
  109. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_cyclical/embed_cyclical.txt +0 -0
  110. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_multiembed/HCOOH.xyz +0 -0
  111. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_string/CH3Cl.xyz +0 -0
  112. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_string/HCOOH.xyz +0 -0
  113. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_string/embed_string.txt +0 -0
  114. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_trimolecular/CH3Cl.xyz +0 -0
  115. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/embed_trimolecular/HCOOH.xyz +0 -0
  116. {firecode-1.5.3 → firecode-2.0.0}/firecode/tests/operator_rdkit_search/butane.xyz +0 -0
  117. {firecode-1.5.3/firecode/tests/scan_dihedral → firecode-2.0.0/firecode/tests/operator_scan_dihedral}/C2F2H4.xyz +0 -0
  118. {firecode-1.5.3 → firecode-2.0.0}/icon.ico +0 -0
@@ -1,6 +1,12 @@
1
1
  [run]
2
2
  source = prism_pruner
3
- omit = prism_pruner/__main__.py
3
+ omit =
4
+ firecode/__main__.py
5
+ */.pixi/*
6
+ */tests/*
7
+ # */venv/*
8
+ # setup.py
9
+ # */__pycache__/*
4
10
 
5
11
  [report]
6
12
  exclude_lines =
@@ -20,4 +26,4 @@ exclude_lines =
20
26
  if __name__ == .__main__.:
21
27
 
22
28
  # Don't complain if an ellipsis isn't run (typically in an abstractmethod):
23
- ^\s*\.\.\.
29
+ ^\s*\.\.\.
@@ -6,6 +6,7 @@ on:
6
6
  branches:
7
7
  - main
8
8
  - feature/**
9
+ - bug/**
9
10
 
10
11
  jobs:
11
12
  test:
@@ -18,7 +19,7 @@ jobs:
18
19
  runs-on: ${{ matrix.os }}
19
20
 
20
21
  steps:
21
- - uses: actions/checkout@v5
22
+ - uses: actions/checkout@v6
22
23
 
23
24
  # - uses: actions/setup-python@v6
24
25
  # with:
@@ -38,9 +39,14 @@ jobs:
38
39
  # - run: pixi run types
39
40
  - run: pixi run -e dev test_cov
40
41
 
42
+ - run: pixi run -e dev coverage report
43
+
44
+ - run: head -5 coverage.xml
45
+
41
46
  - name: Upload Coverage to Codecov
42
- uses: codecov/codecov-action@v4
47
+ uses: codecov/codecov-action@v5
43
48
  with:
44
49
  files: ./coverage.xml
45
- env:
46
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
50
+ token: ${{ secrets.CODECOV_TOKEN }}
51
+ verbose: true
52
+ disable_search: true
@@ -4,8 +4,9 @@ site/
4
4
  .vscode/
5
5
  .mypy_cache/
6
6
  firecode.egg-info/
7
- docs/
8
7
 
9
8
  firecode/calculators/uma-s-1p1.pt
9
+ firecode/calculators/uma-s-1p2.pt
10
+ firecode/calculators/esen_sm_conserving_all.pt
10
11
  coverage.xml
11
12
  .coverage
@@ -12,7 +12,7 @@ repos:
12
12
  hooks:
13
13
  - id: ruff
14
14
  name: ruff-format
15
- stages: [pre-commit, pre-push]
15
+ stages: [pre-commit]
16
16
  language: system
17
17
  entry: pixi run fmt
18
18
  types: [python]
@@ -20,24 +20,24 @@ repos:
20
20
 
21
21
  - id: ruff
22
22
  name: ruff-check
23
- stages: [pre-commit, pre-push]
23
+ stages: [pre-commit]
24
24
  language: system
25
25
  entry: pixi run lint
26
26
  types: [python]
27
27
  pass_filenames: false
28
28
 
29
- # - id: Mypy
30
- # name: mypy
31
- # stages: [pre-commit, pre-push]
32
- # language: system
33
- # entry: pixi run types
34
- # types: [python]
35
- # pass_filenames: false
29
+ - id: Mypy
30
+ name: mypy
31
+ stages: [pre-commit]
32
+ language: system
33
+ entry: pixi run types
34
+ types: [python]
35
+ pass_filenames: false
36
36
 
37
37
  - id: pytest
38
38
  name: pytest
39
- stages: [pre-commit, pre-push]
39
+ stages: [pre-push]
40
40
  language: system
41
- entry: pixi run -e dev pytest -s -m codecov
41
+ entry: pixi run -e dev test_cov
42
42
  types: [python]
43
43
  pass_filenames: false
@@ -1,10 +1,41 @@
1
1
 
2
- <!-- - Introduced compatibility of SADDLE and NEB keywords for scan> runs with both 2 indices (distance scans) and 4 indices (distance scans) -->
3
-
4
- <!-- - ... mep_relax> BETA
5
- - ... IMAGES kw, also implement it for neb>-->
6
- <!-- FINALSPLEVEL keyword? -->
7
- <!-- add documentation: SCRAMBLECHECK kw, fsm>, neb>, rdkit_search>, standalone optimizer-->
2
+ <!-- add documentation: SCRAMBLECHECK kw, fsm>, neb>, rdkit_search>, standalone optimizer, non-inline constraints-->
3
+ <!-- add number of active constraints printout for parallel multithread functions -->
4
+
5
+
6
+ ## FIRECODE 2.0.0 🔥 (WIP)
7
+ - Restructured and expanded solvent module.
8
+ - Implemented vibrational analysis via ASE including quasi-RRHO thermochemistry to get free energies.
9
+ - Added Sella dependency to perform saddle points optimization with the `saddle>` operator.
10
+ - Added FREQ keyword, computing free energies at the end of embedding or refine runs.
11
+ - Added `freq>` operator for standalone frequency analysis on any ensemble.
12
+ - Added T (temperature, in K), T_C (temperature, in °C), P (pressure, in atm), and C (concentration, in mol/L) keywords.
13
+ - Updated CREST interface to version 3 of the program (see [paper](https://doi.org/10.1063/5.0197592) and [documentation](https://crest-lab.github.io/crest-docs/))
14
+ - Added delta solvation implementation for gas-phase ML models, providing energies _and_ forces via TBLITE in the geometry optimization loop. Activate with environmental variable FIRECODE_SOLV_IMPLEM_FOR_ML="opt"
15
+ - Dropped support for native XTB calculator, and XTB-pyhton interface, since TBLITE is the modern successor.
16
+ - Added basic [racerts](https://github.com/digital-chemistry-laboratory/racerts) interface ("rdkit_search>" operator, alias of "racerts>").
17
+ - Removed PROCS keyword.
18
+ - Removed force field pre-optimization and related keywords (FFCALC, FFLEVEL)
19
+ - Added basic interface to ORCA's [GOAT](https://onlinelibrary.wiley.com/doi/abs/10.1002/anie.202500393) via the `goat>` operator (GFN2-xTB level with GFN-FF uphill steps).
20
+ - Renamed "CRESTNCI" keyword to "NCI" to cater for both CREST and GOAT.
21
+ - Significant restructuring of some core code organization (interfaces, context_manager.py, settings.py)
22
+ - Separated interfaces with external programs in "interfaces".
23
+ - Added the use of environmental variables throughout the codebase. Defaults in settings.py, specific context managers in utils.py.
24
+ - Environment variables in settings.py can now be overridden by a local `.firecoderc` with key=value pairs in the same folder as the input file.
25
+ - Added automated [packmol](https://github.com/m3g/packmol) solvator interface (`packmol>` operator, **preview**!).
26
+ <!-- - Added MD equilibration of solvated boxes (`equilibrate>`) -->
27
+
28
+ ## FIRECODE 1.6.0 🔥 (March 11 2026)
29
+ - Refreshed constraints handling in operators.
30
+ - Added non-inline constraints specification after a molecule line. Syntax: "B/A/D i1 i2 [i3] [i4] [auto/value]"
31
+ - These constraints can be fixed (default, same as uppercase in-line constraints) or temporary (like "interactions", i.e. "D 1 2 3 4 fixed=false")
32
+ - Clearer, more explicit printouts for all constraints at any step.
33
+ - the mtd>/mtd_search> operator now has more explicit synonyms: crest> and crest_search>
34
+ - Added tests for the crest_search>, neb> and fsm> operators, as well as a "neb> scan>" chain.
35
+ - Updated documentation: usage and operators (`neb>`, `fsm>`, `rdkit_search>`, `crest_search>`, ...) as well as keywords (general vs. legacy).
36
+ - Type annotated the whole codebase(!).
37
+ - Removed molecular bending and RIGID keyword.
38
+ - Removed standalone ORCA calculator (can use ASE in the future, but throws NotImplementedError for now.)
8
39
 
9
40
  ## FIRECODE 1.5.3 🔥 (February 19 2026)
10
41
  - Fixes a bug with reactive_atoms_classes_dict and embedder.options.charge.
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: firecode
3
+ Version: 2.0.0
4
+ Summary: FIRECODE: Filtering Refiner and Embedder for Conformationally Dense Ensembles
5
+ Author-email: Nicolò Tampellini <nicolo.tampellini@yale.edu>
6
+ License-Expression: LGPL-3.0-or-later
7
+ License-File: LICENSE
8
+ Requires-Python: <3.13,>=3.12
9
+ Requires-Dist: ase
10
+ Requires-Dist: inquirerpy
11
+ Requires-Dist: matplotlib
12
+ Requires-Dist: mlfsm
13
+ Requires-Dist: networkx
14
+ Requires-Dist: numpy
15
+ Requires-Dist: prettytable
16
+ Requires-Dist: prism-pruner
17
+ Requires-Dist: psutil
18
+ Requires-Dist: racerts>=0.1.6
19
+ Requires-Dist: rdkit>=2025.9.3
20
+ Requires-Dist: rich
21
+ Requires-Dist: scipy
22
+ Requires-Dist: sella>=2.4.2
23
+ Provides-Extra: aimnet2
24
+ Requires-Dist: aimnet[ase]; extra == 'aimnet2'
25
+ Provides-Extra: full
26
+ Requires-Dist: aimnet[ase]; extra == 'full'
27
+ Requires-Dist: fairchem-core; extra == 'full'
28
+ Provides-Extra: uma
29
+ Requires-Dist: fairchem-core; extra == 'uma'
30
+ Description-Content-Type: text/markdown
31
+
32
+
33
+ # FIRECODE - Filtering Refiner and Embedder for Conformationally Dense Ensembles
34
+
35
+ <div align="center">
36
+
37
+ [![License: GNU LGPL v3](https://img.shields.io/github/license/ntampellini/firecode)](https://opensource.org/licenses/LGPL-3.0)
38
+ ![Python Version](https://img.shields.io/badge/Python-3.12-blue)
39
+ [![Powered by: Pixi](https://img.shields.io/badge/Powered_by-Pixi-facc15)](https://pixi.sh)
40
+ ![Size](https://img.shields.io/github/languages/code-size/ntampellini/firecode)
41
+ ![Lines](https://sloc.xyz/github/ntampellini/firecode/)
42
+ [![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/ntampellini/firecode)](https://www.codefactor.io/repository/github/ntampellini/firecode)
43
+ [![codecov](https://codecov.io/gh/ntampellini/FIRECODE/graph/badge.svg?token=D9TM6S33D8)](https://codecov.io/gh/ntampellini/FIRECODE)
44
+
45
+ [![PyPI](https://img.shields.io/pypi/v/firecode)](https://pypi.org/project/firecode/)
46
+ [![Wheel](https://img.shields.io/pypi/wheel/firecode)](https://pypi.org/project/firecode/)
47
+ [![Documentation Status](https://readthedocs.org/projects/firecode/badge/?version=latest)](https://firecode.readthedocs.io/en/latest/?badge=latest)
48
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/firecode)
49
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
50
+
51
+ ![Twitter](https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2Fntampellini_&label=%40ntampellini_&link=https%3A%2F%2Ftwitter.com%2Fntampellini_)
52
+
53
+ </div>
54
+
55
+ <p align="center">
56
+
57
+ <img src="docs/images/logo.png" alt="FIRECODE logo" class="center" width="500"/>
58
+
59
+ </p>
60
+
61
+ FIRECODE is a computational chemistry workflow driver and hub for the generation, optimization and refinement of conformational ensembles, including transition state and thermochemical utilities.
62
+
63
+
64
+
65
+ <!-- It runs flexible workflows for conformer generation (via [CREST](https://github.com/crest-lab/crest), [RDKit](https://github.com/rdkit/rdkit)), double-ended TS search ([NEB](https://ase-lib.org/ase/neb.html) via [ASE](https://github.com/rosswhitfield/ase), [ML-FSM](https://github.com/thegomeslab/ML-FSM)), and (constrained) ensemble optimization through popular calculators like [XTB](https://github.com/grimme-lab/xtb), [TBLITE](https://github.com/tblite/tblite), [ORCA](https://www.orcasoftware.de/tutorials_orca/), and Pytorch Neural Network models ([AIMNET2](https://github.com/isayevlab/AIMNet2), [UMA](https://huggingface.co/facebook/UMA)) via [ASE](https://github.com/rosswhitfield/ase).
66
+
67
+ Conformational pruning is performed with the now standalone [PRISM Pruner](https://github.com/ntampellini/prism_pruner).
68
+
69
+ As a legacy feature from [TSCoDe](https://github.com/ntampellini/TSCoDe), FIRECODE can also assemble non-covalent adducts from conformational ensembles (embedding) programmatically. -->
70
+
71
+ ## Calculators
72
+
73
+ - [xTB](https://github.com/grimme-lab/xtb) *(native)*
74
+ - [tblite](https://github.com/tblite/tblite) *(via [ASE](https://github.com/rosswhitfield/ase))*
75
+ - [AIMNET2](https://github.com/isayevlab/AIMNet2) *(via [ASE](https://github.com/rosswhitfield/ase))*
76
+ - [UMA](https://huggingface.co/facebook/UMA) *(via [ASE](https://github.com/rosswhitfield/ase))*
77
+
78
+ ## Interfaces / utilities
79
+
80
+ - [CREST](https://github.com/crest-lab/crest) *(conformational search)*
81
+ - [GOAT](https://onlinelibrary.wiley.com/doi/abs/10.1002/anie.202500393) *(conformational search)*
82
+ - [racerts](https://github.com/digital-chemistry-laboratory/racerts) *(conformational search)*
83
+ - [ETKDG](https://pubs.acs.org/doi/10.1021/acs.jcim.0c00025) *(via [rdkit](https://github.com/rdkit/rdkit), conformational search)*
84
+ - [TSCoDe](https://github.com/ntampellini/TSCoDe) *(conformational embedding)*
85
+ - [prism_pruner](https://github.com/ntampellini/prism_pruner) *(conformational pruning)*
86
+ - [ML-FSM](https://pubs.acs.org/doi/10.1021/acs.jcim.0c00025) *(two-ended TS search)*
87
+ - [Sella](https://github.com/zadorlab/sella) *(saddle point optimization)*
88
+ <!-- - [packmol](https://github.com/m3g/packmol) *(explicit solvation)* -->
89
+
90
+ ...plus frequency calculation, NEB optimization, and more are all implemented in the code in a calculator-agnostic way.
91
+
92
+ ## Installation
93
+
94
+ The package is distributed via `pip`, and the use of [`uv`](https://docs.astral.sh/uv/) is highly recommended. The default installation is minimalistic, and torch/GPU support requires dedicated installs:
95
+
96
+ ```python
97
+ uv pip install firecode # XTB, TBLITE, ORCA
98
+ uv pip install firecode[aimnet2] # + AIMNET2
99
+ uv pip install firecode[uma] # + UMA/OMOL
100
+ uv pip install firecode[full] # + AIMNET2, UMA/OMOL
101
+ ```
102
+
103
+ More installation details in the documentation.
104
+
105
+ ## Usage
106
+
107
+ Installation exposes the main program working on a plain text file as well as a standalone optimizer.
108
+
109
+ ```
110
+ 🔥 firecode [-h] [-s] [-t] input.txt [-n NAME] [-p]
111
+
112
+ positional arguments:
113
+ inpufile.txt Input filename, can be any text file.
114
+
115
+ optional arguments:
116
+ -h, --help Show this help message and exit.
117
+ -s, --setup Guided setup of the calculation settings.
118
+ -n, --name NAME Specify a custom name for the run.
119
+ -cl,--command_line Read instructions from the command line instead of from an input file.
120
+ -p, --profile Profile the run through cProfiler.
121
+ ```
122
+
123
+ ```
124
+ 🔥 firecode_opt [-h] [-i] [-t TEMPERATURE] [-c CALCULATOR] [-m METHOD] [-s SOLVENT] [-o] [-f] [--ts] [--irc] [--cfile CFILE] [-n] [--debug]
125
+ filenames [filenames ...]
126
+
127
+ positional arguments:
128
+ filenames Input filename(s), in .xyz format
129
+
130
+ options:
131
+ -h, --help show this help message and exit
132
+ -i, --interactive Set options interactively.
133
+ -t TEMPERATURE, --temperature TEMPERATURE
134
+ Temperature, in degrees Celsius.
135
+ -c CALCULATOR, --calculator CALCULATOR
136
+ Calculator (default UMA).
137
+ -m METHOD, --method METHOD
138
+ Method (default OMOL for UMA).
139
+ -s SOLVENT, --solvent SOLVENT
140
+ Solvent (default ch2cl2).
141
+ -o, --opt Optimize the geometry.
142
+ -f, --freq Perform vibrational analysis.
143
+ --ts, --saddle Optimize to a TS.
144
+ --irc Run an IRC calculation.
145
+ --cfile CFILE Uses a constraint file.
146
+ -n, --newfile Write optimized structure to a new file (*_opt.xyz).
147
+ --debug Does not delete optimization data.
148
+ ```
149
+
150
+ ## Documentation
151
+ Documentation on how to install and use the program can be found on [readthedocs](https://firecode.readthedocs.io/en/latest/index.html).
@@ -0,0 +1,120 @@
1
+
2
+ # FIRECODE - Filtering Refiner and Embedder for Conformationally Dense Ensembles
3
+
4
+ <div align="center">
5
+
6
+ [![License: GNU LGPL v3](https://img.shields.io/github/license/ntampellini/firecode)](https://opensource.org/licenses/LGPL-3.0)
7
+ ![Python Version](https://img.shields.io/badge/Python-3.12-blue)
8
+ [![Powered by: Pixi](https://img.shields.io/badge/Powered_by-Pixi-facc15)](https://pixi.sh)
9
+ ![Size](https://img.shields.io/github/languages/code-size/ntampellini/firecode)
10
+ ![Lines](https://sloc.xyz/github/ntampellini/firecode/)
11
+ [![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/ntampellini/firecode)](https://www.codefactor.io/repository/github/ntampellini/firecode)
12
+ [![codecov](https://codecov.io/gh/ntampellini/FIRECODE/graph/badge.svg?token=D9TM6S33D8)](https://codecov.io/gh/ntampellini/FIRECODE)
13
+
14
+ [![PyPI](https://img.shields.io/pypi/v/firecode)](https://pypi.org/project/firecode/)
15
+ [![Wheel](https://img.shields.io/pypi/wheel/firecode)](https://pypi.org/project/firecode/)
16
+ [![Documentation Status](https://readthedocs.org/projects/firecode/badge/?version=latest)](https://firecode.readthedocs.io/en/latest/?badge=latest)
17
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/firecode)
18
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
19
+
20
+ ![Twitter](https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2Fntampellini_&label=%40ntampellini_&link=https%3A%2F%2Ftwitter.com%2Fntampellini_)
21
+
22
+ </div>
23
+
24
+ <p align="center">
25
+
26
+ <img src="docs/images/logo.png" alt="FIRECODE logo" class="center" width="500"/>
27
+
28
+ </p>
29
+
30
+ FIRECODE is a computational chemistry workflow driver and hub for the generation, optimization and refinement of conformational ensembles, including transition state and thermochemical utilities.
31
+
32
+
33
+
34
+ <!-- It runs flexible workflows for conformer generation (via [CREST](https://github.com/crest-lab/crest), [RDKit](https://github.com/rdkit/rdkit)), double-ended TS search ([NEB](https://ase-lib.org/ase/neb.html) via [ASE](https://github.com/rosswhitfield/ase), [ML-FSM](https://github.com/thegomeslab/ML-FSM)), and (constrained) ensemble optimization through popular calculators like [XTB](https://github.com/grimme-lab/xtb), [TBLITE](https://github.com/tblite/tblite), [ORCA](https://www.orcasoftware.de/tutorials_orca/), and Pytorch Neural Network models ([AIMNET2](https://github.com/isayevlab/AIMNet2), [UMA](https://huggingface.co/facebook/UMA)) via [ASE](https://github.com/rosswhitfield/ase).
35
+
36
+ Conformational pruning is performed with the now standalone [PRISM Pruner](https://github.com/ntampellini/prism_pruner).
37
+
38
+ As a legacy feature from [TSCoDe](https://github.com/ntampellini/TSCoDe), FIRECODE can also assemble non-covalent adducts from conformational ensembles (embedding) programmatically. -->
39
+
40
+ ## Calculators
41
+
42
+ - [xTB](https://github.com/grimme-lab/xtb) *(native)*
43
+ - [tblite](https://github.com/tblite/tblite) *(via [ASE](https://github.com/rosswhitfield/ase))*
44
+ - [AIMNET2](https://github.com/isayevlab/AIMNet2) *(via [ASE](https://github.com/rosswhitfield/ase))*
45
+ - [UMA](https://huggingface.co/facebook/UMA) *(via [ASE](https://github.com/rosswhitfield/ase))*
46
+
47
+ ## Interfaces / utilities
48
+
49
+ - [CREST](https://github.com/crest-lab/crest) *(conformational search)*
50
+ - [GOAT](https://onlinelibrary.wiley.com/doi/abs/10.1002/anie.202500393) *(conformational search)*
51
+ - [racerts](https://github.com/digital-chemistry-laboratory/racerts) *(conformational search)*
52
+ - [ETKDG](https://pubs.acs.org/doi/10.1021/acs.jcim.0c00025) *(via [rdkit](https://github.com/rdkit/rdkit), conformational search)*
53
+ - [TSCoDe](https://github.com/ntampellini/TSCoDe) *(conformational embedding)*
54
+ - [prism_pruner](https://github.com/ntampellini/prism_pruner) *(conformational pruning)*
55
+ - [ML-FSM](https://pubs.acs.org/doi/10.1021/acs.jcim.0c00025) *(two-ended TS search)*
56
+ - [Sella](https://github.com/zadorlab/sella) *(saddle point optimization)*
57
+ <!-- - [packmol](https://github.com/m3g/packmol) *(explicit solvation)* -->
58
+
59
+ ...plus frequency calculation, NEB optimization, and more are all implemented in the code in a calculator-agnostic way.
60
+
61
+ ## Installation
62
+
63
+ The package is distributed via `pip`, and the use of [`uv`](https://docs.astral.sh/uv/) is highly recommended. The default installation is minimalistic, and torch/GPU support requires dedicated installs:
64
+
65
+ ```python
66
+ uv pip install firecode # XTB, TBLITE, ORCA
67
+ uv pip install firecode[aimnet2] # + AIMNET2
68
+ uv pip install firecode[uma] # + UMA/OMOL
69
+ uv pip install firecode[full] # + AIMNET2, UMA/OMOL
70
+ ```
71
+
72
+ More installation details in the documentation.
73
+
74
+ ## Usage
75
+
76
+ Installation exposes the main program working on a plain text file as well as a standalone optimizer.
77
+
78
+ ```
79
+ 🔥 firecode [-h] [-s] [-t] input.txt [-n NAME] [-p]
80
+
81
+ positional arguments:
82
+ inpufile.txt Input filename, can be any text file.
83
+
84
+ optional arguments:
85
+ -h, --help Show this help message and exit.
86
+ -s, --setup Guided setup of the calculation settings.
87
+ -n, --name NAME Specify a custom name for the run.
88
+ -cl,--command_line Read instructions from the command line instead of from an input file.
89
+ -p, --profile Profile the run through cProfiler.
90
+ ```
91
+
92
+ ```
93
+ 🔥 firecode_opt [-h] [-i] [-t TEMPERATURE] [-c CALCULATOR] [-m METHOD] [-s SOLVENT] [-o] [-f] [--ts] [--irc] [--cfile CFILE] [-n] [--debug]
94
+ filenames [filenames ...]
95
+
96
+ positional arguments:
97
+ filenames Input filename(s), in .xyz format
98
+
99
+ options:
100
+ -h, --help show this help message and exit
101
+ -i, --interactive Set options interactively.
102
+ -t TEMPERATURE, --temperature TEMPERATURE
103
+ Temperature, in degrees Celsius.
104
+ -c CALCULATOR, --calculator CALCULATOR
105
+ Calculator (default UMA).
106
+ -m METHOD, --method METHOD
107
+ Method (default OMOL for UMA).
108
+ -s SOLVENT, --solvent SOLVENT
109
+ Solvent (default ch2cl2).
110
+ -o, --opt Optimize the geometry.
111
+ -f, --freq Perform vibrational analysis.
112
+ --ts, --saddle Optimize to a TS.
113
+ --irc Run an IRC calculation.
114
+ --cfile CFILE Uses a constraint file.
115
+ -n, --newfile Write optimized structure to a new file (*_opt.xyz).
116
+ --debug Does not delete optimization data.
117
+ ```
118
+
119
+ ## Documentation
120
+ Documentation on how to install and use the program can be found on [readthedocs](https://firecode.readthedocs.io/en/latest/index.html).
@@ -14,24 +14,31 @@ GNU General Public License for more details.
14
14
 
15
15
  https://github.com/ntampellini/firecode
16
16
 
17
- Nicolo' Tampellini - nicolo.tampellini@yale.edu
17
+ Nicolo' Tampellini - ntamp@mit.edu
18
18
 
19
19
  """
20
20
 
21
21
  import argparse
22
22
  import os
23
23
  import sys
24
+ from io import TextIOWrapper
24
25
 
25
26
  from rich.traceback import install
26
27
 
27
28
  install(show_locals=True)
28
29
 
29
30
 
30
- def main():
31
- usage = """\n\n 🔥 python -m firecode [-h] [-s] [-t] input.txt [-n NAME] [-p]
32
- 🔥 python -m firecode -cl "refine> mtd> mol.xyz"
33
- 🔥 python -m firecode -c
34
- 🔥 python -m firecode -o mol.xyz
31
+ def main() -> None:
32
+ # Redirect stdout and stderr to handle encoding errors
33
+ sys.stdout = TextIOWrapper(
34
+ sys.stdout.buffer, encoding="utf-8", errors="replace", write_through=True
35
+ )
36
+
37
+ sys.stderr = TextIOWrapper(
38
+ sys.stdout.buffer, encoding="utf-8", errors="replace", write_through=True
39
+ )
40
+
41
+ usage = """\n\n 🔥 firecode [-h] [-s] [-t] input.txt [-n NAME] [-p]
35
42
 
36
43
  positional arguments:
37
44
  inpufile.txt Input filename, can be any text file.
@@ -39,12 +46,9 @@ def main():
39
46
  optional arguments:
40
47
  -h, --help Show this help message and exit.
41
48
  -s, --setup Guided setup of the calculation settings.
42
- -t, --test Perform some tests to check the software setup.
43
49
  -n, --name NAME Specify a custom name for the run.
44
50
  -cl,--command_line Read instructions from the command line instead of from an input file.
45
- -c, --cite Print citation links.
46
51
  -p, --profile Profile the run through cProfiler.
47
- -o, --optimize FILE Run a standalone structure optimization tool.
48
52
 
49
53
  """
50
54
 
@@ -52,9 +56,6 @@ def main():
52
56
  parser.add_argument(
53
57
  "-s", "--setup", help="Guided setup of the calculation settings.", action="store_true"
54
58
  )
55
- parser.add_argument(
56
- "-t", "--test", help="Perform some tests to check the software setup.", action="store_true"
57
- )
58
59
  parser.add_argument(
59
60
  "-cl",
60
61
  "--command_line",
@@ -71,13 +72,6 @@ def main():
71
72
  parser.add_argument(
72
73
  "-n", "--name", help="Specify a custom name for the run.", action="store", required=False
73
74
  )
74
- parser.add_argument(
75
- "-c",
76
- "--cite",
77
- help="Print the appropriate document links for citation purposes.",
78
- action="store_true",
79
- required=False,
80
- )
81
75
  parser.add_argument(
82
76
  "-p",
83
77
  "--profile",
@@ -85,21 +79,13 @@ def main():
85
79
  action="store_true",
86
80
  required=False,
87
81
  )
88
- parser.add_argument(
89
- "-o",
90
- "--optimize",
91
- help="Run a standalone structure optimization tool.",
92
- action="store",
93
- required=False,
94
- nargs="+",
95
- )
96
82
 
97
83
  args = parser.parse_args()
98
84
 
99
- if (
100
- not (args.test or args.setup or args.command_line or args.optimize)
101
- ) and args.inputfile is None:
102
- parser.error("One of the following arguments are required: inputfile, -t, -s, -o.\n")
85
+ env_variables_handling()
86
+
87
+ if (not (args.setup or args.command_line)) and args.inputfile is None:
88
+ parser.error("One of the following arguments are required: inputfile, -t, -s.\n")
103
89
 
104
90
  if args.setup:
105
91
  from firecode.modify_settings import run_setup
@@ -107,24 +93,6 @@ def main():
107
93
  run_setup()
108
94
  sys.exit(0)
109
95
 
110
- if args.cite:
111
- print(
112
- "No citation link is available for FIRECODE yet. You can link to the code on https://www.github.com/ntampellini/firecode"
113
- )
114
- sys.exit(0)
115
-
116
- if args.test:
117
- from firecode.tests import run_tests
118
-
119
- run_tests()
120
- sys.exit(0)
121
-
122
- if args.optimize:
123
- from firecode.standalone_optimizer import main
124
-
125
- main(args.optimize)
126
- sys.exit(0)
127
-
128
96
  if args.command_line:
129
97
  filename = "input_firecode.txt"
130
98
  with open(filename, "w") as f:
@@ -149,5 +117,49 @@ def main():
149
117
  # run the program
150
118
 
151
119
 
120
+ def env_variables_handling() -> None:
121
+ """Handles global environment variables and associated processes.
122
+
123
+ Priority should be given to handling env vars with locally-scoped
124
+ context managers, if possible (see the env_override function).
125
+ """
126
+ from pathlib import Path
127
+ from shutil import rmtree
128
+
129
+ # remove compilation cache for jax: we might be running on different
130
+ # hardware from the last firecode run, and that might result in nasty
131
+ # compatibility issues with stale compilation of the jax library.
132
+ jax_comp_cache_dir = Path.home() / ".cache/sella/jax_cache"
133
+ rmtree(str(jax_comp_cache_dir), ignore_errors=True)
134
+
135
+ # export "FIRECODE_*" environment variables
136
+ from firecode.settings import ENV_VARS
137
+
138
+ for key, value in ENV_VARS.items():
139
+ os.environ.setdefault(key, value)
140
+
141
+ # override/add from global .firecoderc
142
+ if Path("~/.firecoderc").exists():
143
+ set_env_vars_from_file("~/.firecoderc")
144
+
145
+ # override/add from local .firecoderc
146
+ if ".firecoderc" in os.listdir(os.getcwd()):
147
+ set_env_vars_from_file(".firecoderc")
148
+
149
+
150
+ def set_env_vars_from_file(filename: str) -> None:
151
+ """Set environment variable from a text file."""
152
+ with open(filename, "r") as f:
153
+ lines = f.readlines()
154
+
155
+ print(f"--> Setting environment variables from {filename}")
156
+ for line in lines:
157
+ key, value = line.split("=")
158
+ key = key.strip().upper()
159
+ value = value.strip()
160
+ os.environ[key] = value
161
+ print(f" {key}={value}")
162
+
163
+
152
164
  if __name__ == "__main__":
153
165
  main()
@@ -0,0 +1,54 @@
1
+ """FIRECODE: Filtering Refiner and Embedder for Conformationally Dense Ensembles
2
+ Copyright (C) 2021-2026 Nicolò Tampellini
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ """
15
+
16
+ import numpy as np
17
+ from prism_pruner.algebra import normalize
18
+ from scipy.spatial.distance import cdist
19
+
20
+ from firecode.typing_ import Array1D_float, Array2D_float
21
+
22
+
23
+ def point_angle(p1: Array1D_float, p2: Array1D_float, p3: Array1D_float) -> float:
24
+ """Returns the planar angle between three points in space, in degrees."""
25
+ return np.arccos(np.clip(normalize(p1 - p2) @ normalize(p3 - p2), -1.0, 1.0)) * 180 / np.pi # type: ignore[no-any-return]
26
+
27
+
28
+ def align_vec_pair(ref: Array2D_float, tgt: Array2D_float) -> Array2D_float:
29
+ """ref, tgt: iterables of two 3D vectors each
30
+
31
+ return: rotation matrix that when applied to tgt,
32
+ optimally aligns it to ref
33
+ """
34
+ B = np.zeros((3, 3))
35
+ for i in range(3):
36
+ for k in range(3):
37
+ tot = 0
38
+ for j in range(2):
39
+ tot += ref[j][i] * tgt[j][k]
40
+ B[i, k] = tot
41
+
42
+ u, s, vh = np.linalg.svd(B)
43
+
44
+ # Correct improper rotation if necessary (as in Kabsch algorithm)
45
+ if np.linalg.det(u @ vh) < 0:
46
+ s[-1] = -s[-1]
47
+ u[:, -1] = -u[:, -1]
48
+
49
+ return np.ascontiguousarray(np.dot(u, vh))
50
+
51
+
52
+ def count_clashes(coords: Array2D_float) -> int:
53
+ """Returns the number of atomic distances between 0 and 0.5 Å."""
54
+ return int(np.count_nonzero((cdist(coords, coords) < 0.5) & (cdist(coords, coords) > 0)))