firecode 1.5.0__tar.gz → 1.5.1__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.
- {firecode-1.5.0 → firecode-1.5.1}/CHANGELOG.md +2 -1
- {firecode-1.5.0 → firecode-1.5.1}/PKG-INFO +8 -5
- {firecode-1.5.0 → firecode-1.5.1}/docs/examples.rst +7 -14
- firecode-1.5.1/docs/installation.rst +85 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/usage.rst +9 -13
- {firecode-1.5.0 → firecode-1.5.1}/firecode/ase_manipulations.py +50 -143
- {firecode-1.5.0 → firecode-1.5.1}/firecode/atropisomer_module.py +2 -1
- {firecode-1.5.0 → firecode-1.5.1}/firecode/calculators/_ase_uma.py +6 -2
- {firecode-1.5.0 → firecode-1.5.1}/firecode/calculators/_xtb.py +4 -3
- {firecode-1.5.0 → firecode-1.5.1}/firecode/embedder.py +6 -6
- {firecode-1.5.0 → firecode-1.5.1}/firecode/hypermolecule_class.py +1 -9
- {firecode-1.5.0 → firecode-1.5.1}/firecode/mep_relaxer.py +6 -4
- {firecode-1.5.0 → firecode-1.5.1}/firecode/operators.py +8 -38
- {firecode-1.5.0 → firecode-1.5.1}/firecode/optimization_methods.py +20 -12
- {firecode-1.5.0 → firecode-1.5.1}/firecode/quotes.json +21 -26
- firecode-1.5.0/firecode/smarts.py → firecode-1.5.1/firecode/rdkit_tools.py +109 -4
- {firecode-1.5.0 → firecode-1.5.1}/firecode/standalone_optimizer.py +3 -2
- {firecode-1.5.0 → firecode-1.5.1}/firecode/torsion_module.py +2 -2
- {firecode-1.5.0 → firecode-1.5.1}/firecode/utils.py +3 -51
- {firecode-1.5.0 → firecode-1.5.1}/pixi.lock +2 -2
- {firecode-1.5.0 → firecode-1.5.1}/pyproject.toml +14 -5
- firecode-1.5.0/docs/installation.rst +0 -104
- firecode-1.5.0/firecode/automep.py +0 -133
- firecode-1.5.0/firecode/explode_search.py +0 -218
- {firecode-1.5.0 → firecode-1.5.1}/.ase/gui.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/.gitignore +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/.readthedocs.yaml +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/LICENSE +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/MANIFEST.in +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/README.md +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/conf.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/atropo.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/complex_embed_cd.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/embeds.svg +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/intro_embed.PNG +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/logo.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/orbitals.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/peptide.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/peptide_chemdraw.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/plot.svg +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/qz_firecode.gif +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/images/trimolecular.png +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/index.rst +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/introduction.rst +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/license.rst +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/operators_keywords.rst +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/docs/requirements.txt +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/__init__.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/__main__.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/algebra.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/calculators/__init__.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/calculators/_orca.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/calculators/dummy_ase_calc.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/concurrent_test.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/embedder_options.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/embeds.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/errors.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/graph_manipulations.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/modify_settings.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/multiembed.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/numba_functions.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/parameters.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/pka.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/profiler.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/pt.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/quotes.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/reactive_atoms_classes.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/references.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/settings.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/solvents.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/C2H4.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/chelotropic/C2H4.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/chelotropic/HCOOOH.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/chelotropic/chelotropic.txt +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/cyclical/C2H4.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/cyclical/cyclical.txt +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/dihedral/C2F2H4.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/dihedral/dihedral.txt +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/string/CH3Cl.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/string/HCOOH.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/string/string.txt +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/trimolecular/CH3Cl.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/trimolecular/HCOOH.xyz +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests/trimolecular/trimolecular.txt +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/tests.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/firecode/units.py +0 -0
- {firecode-1.5.0 → firecode-1.5.1}/icon.ico +0 -0
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
- Removed openbabel dependency.
|
|
11
11
|
- Imports bugfixes.
|
|
12
12
|
- Restructured setup to use [Pixi](https://pixi.prefix.dev/latest/).
|
|
13
|
-
|
|
13
|
+
- Removed SMILES to 3D conversion.
|
|
14
|
+
<!-- add documentation: SCRAMBLECHECK kw, fsm>, neb>, rdkit_search>-->
|
|
14
15
|
|
|
15
16
|
## FIRECODE 1.4.0 🔥 (January 25 2026) - Big cleanup and reorganization!
|
|
16
17
|
- Similarity pruning is now done via the standalone [PRISM](https://github.com/ntampellini/prism_pruner) library.
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firecode
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: FIRECODE: Filtering Refiner and Embedder for Conformationally Dense Ensembles
|
|
5
5
|
Author-email: Nicolò Tampellini <nicolo.tampellini@yale.edu>
|
|
6
6
|
License-Expression: LGPL-3.0-or-later
|
|
7
7
|
License-File: LICENSE
|
|
8
8
|
Requires-Python: <3.13,>=3.10
|
|
9
9
|
Requires-Dist: ase
|
|
10
|
-
Requires-Dist: fairchem-core
|
|
11
|
-
Requires-Dist: importlib-metadata
|
|
12
10
|
Requires-Dist: inquirerpy
|
|
13
|
-
Requires-Dist: llvmlite
|
|
14
11
|
Requires-Dist: matplotlib
|
|
15
12
|
Requires-Dist: networkx
|
|
16
13
|
Requires-Dist: numpy
|
|
@@ -20,7 +17,13 @@ Requires-Dist: psutil
|
|
|
20
17
|
Requires-Dist: rdkit>=2025.9.3
|
|
21
18
|
Requires-Dist: rich
|
|
22
19
|
Requires-Dist: scipy
|
|
23
|
-
|
|
20
|
+
Provides-Extra: aimnet2
|
|
21
|
+
Requires-Dist: aimnet[ase]; extra == 'aimnet2'
|
|
22
|
+
Provides-Extra: full
|
|
23
|
+
Requires-Dist: aimnet[ase]; extra == 'full'
|
|
24
|
+
Requires-Dist: fairchem-core; extra == 'full'
|
|
25
|
+
Provides-Extra: uma
|
|
26
|
+
Requires-Dist: fairchem-core; extra == 'uma'
|
|
24
27
|
Description-Content-Type: text/markdown
|
|
25
28
|
|
|
26
29
|
|
|
@@ -11,13 +11,13 @@ For detailed descriptions of the operators and keywords present in the inputs, s
|
|
|
11
11
|
|
|
12
12
|
Work is in progress to expand this section with more examples.
|
|
13
13
|
|
|
14
|
-
1.
|
|
15
|
-
|
|
14
|
+
1. Conformational search and refinement
|
|
15
|
+
+++++++++++++++++++++++++++++++++++++++
|
|
16
16
|
|
|
17
17
|
::
|
|
18
18
|
|
|
19
19
|
LEVEL=GFN-FF
|
|
20
|
-
refine> rsearch> opt>
|
|
20
|
+
refine> rsearch> opt> tris_ala.xyz
|
|
21
21
|
|
|
22
22
|
# This is a comment line!
|
|
23
23
|
|
|
@@ -25,11 +25,9 @@ Work is in progress to expand this section with more examples.
|
|
|
25
25
|
# If XTB is not set as the default calculator, you can specify it
|
|
26
26
|
# here adding CALC=XTB in the keyword line.
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
# (H2N-Ala-Ala-Ala-OH), then operators are applied starting
|
|
30
|
-
# from the inside out:
|
|
28
|
+
# The operators are applied starting from the inside out:
|
|
31
29
|
|
|
32
|
-
# opt> - the
|
|
30
|
+
# opt> - the structure will be optimized
|
|
33
31
|
|
|
34
32
|
# rsearch> - a knowledge-based, torsion-based conformational search
|
|
35
33
|
# is carried out. The number of conformers generated can be adjusted
|
|
@@ -75,7 +73,7 @@ Work is in progress to expand this section with more examples.
|
|
|
75
73
|
|
|
76
74
|
::
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
KCAL=10
|
|
79
77
|
scan> atropisomer.xyz 1 2 9 10
|
|
80
78
|
|
|
81
79
|
# scan> : (four indices specified) performs two dihedral
|
|
@@ -84,12 +82,7 @@ Work is in progress to expand this section with more examples.
|
|
|
84
82
|
# 10 kcal/mol (KCAL keyword) form the lowest energy
|
|
85
83
|
# structure are re-scanned at increased accuracy (1°
|
|
86
84
|
# increments).
|
|
87
|
-
|
|
88
|
-
# SADDLE: Each maxima is then optimized to a saddle point.
|
|
89
|
-
|
|
90
|
-
# It is also possible to replace SADDLE with NEB to use scan
|
|
91
|
-
# points to run a NEB in an automated way.
|
|
92
|
-
|
|
85
|
+
|
|
93
86
|
.. figure:: /images/atropo.png
|
|
94
87
|
:alt: Example output structure
|
|
95
88
|
:width: 75%
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
.. _installation:
|
|
2
|
+
|
|
3
|
+
Installation
|
|
4
|
+
============
|
|
5
|
+
|
|
6
|
+
This program is written in Python (currently >=3.12). The recommended way to install it is through conda/mamba and uv.
|
|
7
|
+
|
|
8
|
+
::
|
|
9
|
+
|
|
10
|
+
# create a new conda environment and install firecode with uv
|
|
11
|
+
conda create --name firecode python=3.12 uv
|
|
12
|
+
conda activate firecode
|
|
13
|
+
uv pip install firecode
|
|
14
|
+
|
|
15
|
+
After installation, run the guided utility to finalize the setup:
|
|
16
|
+
|
|
17
|
+
::
|
|
18
|
+
|
|
19
|
+
firecode --setup
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Optional dependencies (WIP)
|
|
23
|
+
===========================
|
|
24
|
+
|
|
25
|
+
CREST
|
|
26
|
+
-----
|
|
27
|
+
|
|
28
|
+
This is free software. See the `GitHub repository <https://github.com/grimme-lab/crest>`__.
|
|
29
|
+
Currently only CREST 2.12 is supported, working on supporting the latest version is in progress.
|
|
30
|
+
|
|
31
|
+
::
|
|
32
|
+
|
|
33
|
+
# install mamba if you don't have it already
|
|
34
|
+
conda install -c conda-forge mamba
|
|
35
|
+
|
|
36
|
+
mamba install -c conda-forge crest==2.12
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
AIMNET2 / UMA models
|
|
40
|
+
--------------------
|
|
41
|
+
|
|
42
|
+
The software can be interfaced with AIMNET2 and UMA models. Work is in progress to port AIMNET2 models to the new codebase.
|
|
43
|
+
An interface to the UMA models is available provided that the models are present on the system at the location specified in
|
|
44
|
+
the settings.py file (change with ``firecode --settings``). The UMA models can be obtained from HuggingFace at https://huggingface.co/facebook/UMA.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
XTB (recommended for Force Field and semiempirical calculations)
|
|
49
|
+
----------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
This is free software. See the `GitHub
|
|
52
|
+
repository <https://github.com/grimme-lab/xtb>`__ and the
|
|
53
|
+
`documentation <https://xtb-docs.readthedocs.io/en/latest/contents.html>`__
|
|
54
|
+
for how to install it on your machine. The package and its python bindings are available through conda as well.
|
|
55
|
+
|
|
56
|
+
::
|
|
57
|
+
|
|
58
|
+
# install mamba if you don't have it already
|
|
59
|
+
conda install -c conda-forge mamba
|
|
60
|
+
|
|
61
|
+
mamba install -c conda-forge xtb xtb-python
|
|
62
|
+
|
|
63
|
+
TBLITE
|
|
64
|
+
------
|
|
65
|
+
|
|
66
|
+
Light-weight version of the xTB, free for academic use. See the `GitHub repository <https://github.com/tblite/tblite>`__.
|
|
67
|
+
|
|
68
|
+
::
|
|
69
|
+
|
|
70
|
+
# install mamba if you don't have it already
|
|
71
|
+
conda install -c conda-forge mamba
|
|
72
|
+
|
|
73
|
+
mamba install -c conda-forge tblite tblite-python
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
ORCA
|
|
77
|
+
----
|
|
78
|
+
|
|
79
|
+
This software is only free for academic use at an academic institution.
|
|
80
|
+
Detailed instructions on how to install and set up ORCA can be found in
|
|
81
|
+
`the official
|
|
82
|
+
website <https://sites.google.com/site/orcainputlibrary/setting-up-orca>`__.
|
|
83
|
+
Make sure to install and set up OpenMPI along with ORCA if you wish to
|
|
84
|
+
exploit multiple cores on your machine **(Note: semiempirical methods
|
|
85
|
+
cannot yet be parallelized in ORCA!)**
|
|
@@ -7,7 +7,7 @@ The program can be run from terminal, with the command:
|
|
|
7
7
|
|
|
8
8
|
::
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
firecode myinput.txt -n [custom_title]
|
|
11
11
|
|
|
12
12
|
A custom name for the run can be optionally provided with the -n flag, otherwise a time
|
|
13
13
|
stamp will be used to name the output files.
|
|
@@ -17,16 +17,14 @@ instruction in a string after the ``-cl``/``--command_line`` argument:
|
|
|
17
17
|
|
|
18
18
|
::
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
python -m firecode --command_line "csearch> molecule.xyz"
|
|
20
|
+
firecode -cl "csearch> molecule.xyz"
|
|
22
21
|
|
|
23
22
|
In this case, an input file will be written for you by the program.
|
|
24
23
|
|
|
25
24
|
Input formatting
|
|
26
25
|
----------------
|
|
27
26
|
|
|
28
|
-
The input can be any text file
|
|
29
|
-
sticking with ``.txt``.
|
|
27
|
+
The input can be any text file, but sticking with ``.txt`` or ``.inp`` is recommended.
|
|
30
28
|
|
|
31
29
|
- Any blank line will be ignored
|
|
32
30
|
- Any line starting with ``#`` will be ignored
|
|
@@ -34,17 +32,15 @@ sticking with ``.txt``.
|
|
|
34
32
|
|
|
35
33
|
Then, molecule files are specified. A molecule line is made up of these elements, in this order:
|
|
36
34
|
|
|
37
|
-
-
|
|
35
|
+
- Zero or more operators (*i.e.* ``csearch>``, ``opt>``, etc.) separated by spaces
|
|
38
36
|
- The molecule file name (required)
|
|
39
|
-
-
|
|
37
|
+
- Optional indices (numbers) and pairings (letters) for the molecule
|
|
38
|
+
- Optional properties of the molecule (*i.e.* ``charge=1``, ``property=value``)
|
|
40
39
|
|
|
41
|
-
An example with all
|
|
40
|
+
An example with all four is ``refine> rsearch> butadiene.xyz 6a 8b charge=1``.
|
|
42
41
|
|
|
43
|
-
FIRECODE
|
|
44
|
-
|
|
45
|
-
only the ``.xyz`` file format, particularly for multimolecular files
|
|
46
|
-
containing different conformers of the same molecule. **Molecule indices
|
|
47
|
-
are counted starting from zero!**
|
|
42
|
+
FIRECODE works with ``.xyz`` files. **Molecule indices
|
|
43
|
+
are zero-based! (counted starting from zero!)**
|
|
48
44
|
|
|
49
45
|
Operators
|
|
50
46
|
+++++++++
|
|
@@ -27,6 +27,7 @@ import time
|
|
|
27
27
|
import warnings
|
|
28
28
|
from copy import deepcopy
|
|
29
29
|
from shutil import rmtree
|
|
30
|
+
from subprocess import getoutput
|
|
30
31
|
|
|
31
32
|
import matplotlib.pyplot as plt
|
|
32
33
|
import numpy as np
|
|
@@ -46,7 +47,7 @@ from prism_pruner.utils import (align_structures, get_double_bonds_indices,
|
|
|
46
47
|
|
|
47
48
|
from firecode.algebra import norm_of, point_angle
|
|
48
49
|
from firecode.calculators.__init__ import NewFolderContext
|
|
49
|
-
from firecode.calculators.
|
|
50
|
+
from firecode.calculators._xtb import xtb_gsolv
|
|
50
51
|
from firecode.units import EH_TO_EV, EH_TO_KCAL, EV_TO_KCAL
|
|
51
52
|
from firecode.utils import (HiddenPrints, cartesian_product, clean_directory,
|
|
52
53
|
molecule_check, read_xyz, suppress_stdout_stderr,
|
|
@@ -701,107 +702,16 @@ def set_charge_and_mult_on_ase_atoms(ase_atoms, charge, mult):
|
|
|
701
702
|
mult_list[0] = mult - 1
|
|
702
703
|
ase_atoms.set_initial_magnetic_moments(mult_list)
|
|
703
704
|
|
|
704
|
-
|
|
705
|
-
embedder,
|
|
706
|
-
atoms,
|
|
707
|
-
coords,
|
|
708
|
-
charge: int,
|
|
709
|
-
mult: int,
|
|
710
|
-
|
|
711
|
-
constrained_indices=None,
|
|
712
|
-
constrained_distances=None,
|
|
713
|
-
|
|
714
|
-
constrained_angles_indices=None,
|
|
715
|
-
constrained_angles_values=None,
|
|
716
|
-
|
|
717
|
-
constrained_dihedrals_indices=None,
|
|
718
|
-
constrained_dihedrals_values=None,
|
|
719
|
-
|
|
720
|
-
ase_constraints=None,
|
|
721
|
-
|
|
722
|
-
steps=500,
|
|
723
|
-
safe=False,
|
|
724
|
-
safe_mask=None,
|
|
725
|
-
traj=None,
|
|
726
|
-
logfunction=None,
|
|
727
|
-
title='temp',
|
|
728
|
-
|
|
729
|
-
**kwargs,
|
|
730
|
-
):
|
|
731
|
-
'''
|
|
732
|
-
embedder: firecode embedder object
|
|
733
|
-
coords:
|
|
734
|
-
atoms:
|
|
735
|
-
constrained_indices:
|
|
736
|
-
safe: if True, adds a potential that prevents atoms from scrambling
|
|
737
|
-
safe_mask: bool array, with False for atoms to be excluded when calculating bonds to preserve
|
|
738
|
-
traj: if set to a string, traj is used as a filename for the bending trajectory.
|
|
739
|
-
not only the atoms will be printed, but also all the orbitals and the active pivot.
|
|
740
|
-
'''
|
|
741
|
-
ase_atoms = Atoms(atoms, positions=coords)
|
|
742
|
-
set_charge_and_mult_on_ase_atoms(ase_atoms, charge, mult)
|
|
743
|
-
|
|
744
|
-
# set calculator
|
|
745
|
-
ase_atoms.calc = embedder.dispatcher.get_ase_calc(embedder.options.theory_level, embedder.options.solvent)
|
|
746
|
-
constraints = []
|
|
747
|
-
|
|
748
|
-
if constrained_indices is not None:
|
|
749
|
-
constrained_distances = constrained_distances or [None for _ in constrained_indices]
|
|
750
|
-
for i, c in enumerate(constrained_indices):
|
|
751
|
-
i1, i2 = c
|
|
752
|
-
tgt_dist = constrained_distances[i] or norm_of(coords[i1]-coords[i2])
|
|
753
|
-
constraints.append(Spring(i1, i2, tgt_dist))
|
|
754
|
-
|
|
755
|
-
if constrained_angles_indices is not None:
|
|
756
|
-
constrained_angles_values = constrained_angles_values or [None for _ in constrained_angles_indices]
|
|
757
|
-
for i, c in enumerate(constrained_angles_indices):
|
|
758
|
-
i1, i2, i3 = c
|
|
759
|
-
tgt_angle = constrained_angles_values[i] or point_angle(coords[i1], coords[i2], coords[i3])
|
|
760
|
-
constraints.append(PlanarAngleSpring(i1, i2, i3, tgt_angle))
|
|
761
|
-
|
|
762
|
-
if constrained_dihedrals_indices is not None:
|
|
763
|
-
constrained_dihedrals_values = constrained_dihedrals_values or [None for _ in constrained_dihedrals_indices]
|
|
764
|
-
for i, c in enumerate(constrained_dihedrals_indices):
|
|
765
|
-
i1, i2, i3, i4 = c
|
|
766
|
-
tgt_angle = constrained_dihedrals_values[i] or dihedral((coords[i1], coords[i2], coords[i3], coords[i4]))
|
|
767
|
-
constraints.append(DihedralSpring(i1, i2, i3, i4, tgt_angle))
|
|
768
|
-
|
|
769
|
-
if ase_constraints is not None:
|
|
770
|
-
constraints.extend(ase_constraints)
|
|
771
|
-
|
|
772
|
-
if safe:
|
|
773
|
-
constraints.append(PreventScramblingConstraint(graphize(atoms, coords, safe_mask),
|
|
774
|
-
atoms,
|
|
775
|
-
double_bond_protection=embedder.options.double_bond_protection,
|
|
776
|
-
fix_angles=embedder.options.fix_angles_in_deformation))
|
|
777
|
-
|
|
778
|
-
ase_atoms.set_constraint(constraints)
|
|
779
|
-
|
|
780
|
-
t_start_opt = time.perf_counter()
|
|
781
|
-
with LBFGS(ase_atoms, maxstep=0.1, logfile=None, trajectory=traj) as opt:
|
|
782
|
-
opt.run(fmax=0.05, steps=steps)
|
|
783
|
-
iterations = opt.nsteps
|
|
705
|
+
return ase_atoms
|
|
784
706
|
|
|
785
|
-
|
|
786
|
-
success = (iterations < 499)
|
|
787
|
-
|
|
788
|
-
if logfunction is not None:
|
|
789
|
-
exit_str = 'REFINED' if success else 'MAX ITER'
|
|
790
|
-
logfunction(f' - {title} {exit_str} ({iterations} iterations, {time_to_string(time.perf_counter()-t_start_opt)})')
|
|
791
|
-
|
|
792
|
-
if embedder.options.final_sp_level is None:
|
|
793
|
-
energy = ase_atoms.get_total_energy() * EV_TO_KCAL
|
|
794
|
-
|
|
795
|
-
else:
|
|
796
|
-
ase_atoms.calc = embedder.dispatcher.get_ase_calc(embedder.options.final_sp_level, embedder.options.solvent)
|
|
797
|
-
energy = ase_atoms.get_total_energy() * EV_TO_KCAL
|
|
798
|
-
|
|
799
|
-
return new_structure, energy, success
|
|
800
|
-
|
|
801
|
-
def ase_popt_lite(
|
|
707
|
+
def ase_popt(
|
|
802
708
|
atoms,
|
|
803
709
|
coords,
|
|
804
710
|
ase_calc,
|
|
711
|
+
charge,
|
|
712
|
+
mult,
|
|
713
|
+
solvent=None,
|
|
714
|
+
add_alpb_solvation=False,
|
|
805
715
|
|
|
806
716
|
constrained_indices=None,
|
|
807
717
|
constrained_distances=None,
|
|
@@ -813,33 +723,23 @@ def ase_popt_lite(
|
|
|
813
723
|
constrained_dihedrals_values=None,
|
|
814
724
|
|
|
815
725
|
ase_constraints=None,
|
|
816
|
-
new_bond_preventer=None,
|
|
817
726
|
|
|
818
|
-
|
|
727
|
+
maxiter=None,
|
|
819
728
|
traj=None,
|
|
820
729
|
logfunction=None,
|
|
821
730
|
title='temp',
|
|
822
|
-
|
|
823
|
-
dummy_first=False,
|
|
731
|
+
debug=False,
|
|
824
732
|
|
|
825
733
|
**kwargs,
|
|
826
734
|
):
|
|
827
735
|
'''
|
|
828
|
-
embedder: firecode embedder object
|
|
829
|
-
coords:
|
|
830
|
-
atoms:
|
|
831
|
-
constrained_indices:
|
|
832
|
-
|
|
833
|
-
dummy_first: run a cycle with a fast, empty optimizer first, still enforcing constraints
|
|
834
736
|
|
|
835
737
|
'''
|
|
836
|
-
atoms = Atoms(atoms, positions=coords)
|
|
837
738
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
atoms.calc = ase_calc
|
|
739
|
+
ase_atoms = Atoms(atoms, positions=coords)
|
|
740
|
+
ase_atoms.calc = ase_calc
|
|
741
|
+
ase_atoms = set_charge_and_mult_on_ase_atoms(ase_atoms, charge, mult)
|
|
742
|
+
maxiter = maxiter or 750
|
|
843
743
|
|
|
844
744
|
constraints = []
|
|
845
745
|
|
|
@@ -867,41 +767,49 @@ def ase_popt_lite(
|
|
|
867
767
|
if ase_constraints is not None:
|
|
868
768
|
constraints.extend(ase_constraints)
|
|
869
769
|
|
|
870
|
-
|
|
770
|
+
ase_atoms.set_constraint(constraints)
|
|
871
771
|
|
|
872
|
-
|
|
873
|
-
with
|
|
772
|
+
# create working folder and cd into it
|
|
773
|
+
with NewFolderContext(title, delete_after=(not debug)):
|
|
874
774
|
|
|
875
|
-
|
|
775
|
+
t_start_opt = time.perf_counter()
|
|
876
776
|
|
|
877
|
-
|
|
878
|
-
with LBFGS(
|
|
879
|
-
opt.run(fmax=0.
|
|
777
|
+
with suppress_stdout_stderr():
|
|
778
|
+
with LBFGS(ase_atoms, maxstep=0.2, logfile=None, trajectory=traj) as opt:
|
|
779
|
+
opt.run(fmax=0.05, steps=maxiter)
|
|
780
|
+
iterations = opt.nsteps
|
|
880
781
|
|
|
881
|
-
|
|
882
|
-
|
|
782
|
+
new_structure = ase_atoms.get_positions()
|
|
783
|
+
success = (iterations < maxiter-1)
|
|
883
784
|
|
|
884
|
-
|
|
885
|
-
|
|
785
|
+
if logfunction is not None:
|
|
786
|
+
exit_str = 'REFINED' if success else 'MAX ITER'
|
|
787
|
+
logfunction(f' - {title} {exit_str} ({iterations} iterations, {time_to_string(time.perf_counter()-t_start_opt)})')
|
|
886
788
|
|
|
887
|
-
|
|
888
|
-
atoms.set_constraint(constraints)
|
|
889
|
-
atoms.calc = ase_calc
|
|
789
|
+
energy = ase_atoms.get_total_energy() * EV_TO_KCAL
|
|
890
790
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
791
|
+
if traj is not None:
|
|
792
|
+
getoutput(f"ase convert {traj} {traj}.xyz")
|
|
793
|
+
|
|
794
|
+
if solvent is not None and add_alpb_solvation:
|
|
795
|
+
gsolv = xtb_gsolv(
|
|
796
|
+
atoms,
|
|
797
|
+
new_structure,
|
|
798
|
+
model='alpb',
|
|
799
|
+
charge=charge,
|
|
800
|
+
mult=mult,
|
|
801
|
+
solvent=solvent,
|
|
802
|
+
title=title,
|
|
803
|
+
assert_convergence=True,
|
|
804
|
+
)
|
|
805
|
+
energy += gsolv
|
|
894
806
|
|
|
895
|
-
new_structure = atoms.get_positions()
|
|
896
|
-
success = (iterations < 499)
|
|
897
807
|
|
|
898
|
-
|
|
899
|
-
exit_str = 'REFINED' if success else 'MAX ITER'
|
|
900
|
-
logfunction(f' - {title} {exit_str} ({iterations} iterations, {time_to_string(time.perf_counter()-t_start_opt)})')
|
|
808
|
+
return new_structure, energy, success
|
|
901
809
|
|
|
902
|
-
energy = atoms.get_total_energy() * EV_TO_KCAL
|
|
903
810
|
|
|
904
|
-
|
|
811
|
+
def ase_popt_with_alpb(*args, **kwargs):
|
|
812
|
+
return ase_popt(*args, add_alpb_solvation=True, **kwargs)
|
|
905
813
|
|
|
906
814
|
|
|
907
815
|
def ase_bend(embedder, original_mol, conf, pivot, threshold, title='temp', traj=None, check=True):
|
|
@@ -1371,7 +1279,6 @@ def fsm_operator(embedder, optimize_endpoints=True):
|
|
|
1371
1279
|
from mlfsm.cos import FreezingString
|
|
1372
1280
|
from mlfsm.opt import CartesianOptimizer, InternalsOptimizer, Optimizer
|
|
1373
1281
|
|
|
1374
|
-
|
|
1375
1282
|
# interp = 'ric'
|
|
1376
1283
|
interp = 'cart'
|
|
1377
1284
|
maxiter = 100 # default = 3
|
|
@@ -1393,7 +1300,7 @@ def fsm_operator(embedder, optimize_endpoints=True):
|
|
|
1393
1300
|
|
|
1394
1301
|
reactant, _, _ = ase_popt(
|
|
1395
1302
|
embedder=embedder,
|
|
1396
|
-
|
|
1303
|
+
ase_atoms=mol.atoms,
|
|
1397
1304
|
coords=reactant,
|
|
1398
1305
|
charge=mol.charge,
|
|
1399
1306
|
mult=mol.mult,
|
|
@@ -1401,7 +1308,7 @@ def fsm_operator(embedder, optimize_endpoints=True):
|
|
|
1401
1308
|
|
|
1402
1309
|
product, _, _ = ase_popt(
|
|
1403
1310
|
embedder=embedder,
|
|
1404
|
-
|
|
1311
|
+
ase_atoms=mol.atoms,
|
|
1405
1312
|
coords=product,
|
|
1406
1313
|
charge=mol.charge,
|
|
1407
1314
|
mult=mol.mult,
|
|
@@ -1410,10 +1317,10 @@ def fsm_operator(embedder, optimize_endpoints=True):
|
|
|
1410
1317
|
reactant, product = align_structures(np.stack((reactant, product)))
|
|
1411
1318
|
|
|
1412
1319
|
reactant = Atoms(mol.atoms, reactant)
|
|
1413
|
-
set_charge_and_mult_on_ase_atoms(reactant, charge, mult)
|
|
1320
|
+
reactant = set_charge_and_mult_on_ase_atoms(reactant, charge, mult)
|
|
1414
1321
|
|
|
1415
1322
|
product = Atoms(mol.atoms, product)
|
|
1416
|
-
set_charge_and_mult_on_ase_atoms(product, charge, mult)
|
|
1323
|
+
product = set_charge_and_mult_on_ase_atoms(product, charge, mult)
|
|
1417
1324
|
|
|
1418
1325
|
|
|
1419
1326
|
workdir = f'{mol.rootname}_freezing_string'
|
|
@@ -37,6 +37,7 @@ from prism_pruner.utils import align_structures, time_to_string
|
|
|
37
37
|
from firecode.ase_manipulations import ase_neb
|
|
38
38
|
from firecode.errors import ZeroCandidatesError
|
|
39
39
|
from firecode.optimization_methods import optimize
|
|
40
|
+
from firecode.units import EV_TO_KCAL
|
|
40
41
|
from firecode.utils import clean_directory, loadbar, molecule_check, write_xyz
|
|
41
42
|
|
|
42
43
|
|
|
@@ -357,7 +358,7 @@ def ase_dih_scan(embedder,
|
|
|
357
358
|
|
|
358
359
|
iterations = opt.nsteps
|
|
359
360
|
|
|
360
|
-
energies.append(atoms.get_total_energy() *
|
|
361
|
+
energies.append(atoms.get_total_energy() * EV_TO_KCAL)
|
|
361
362
|
|
|
362
363
|
if logfile is not None:
|
|
363
364
|
elapsed = time() - t_start_step
|
|
@@ -13,6 +13,7 @@ from firecode.ase_manipulations import (DihedralSpring, PlanarAngleSpring,
|
|
|
13
13
|
from firecode.calculators.__init__ import NewFolderContext
|
|
14
14
|
from firecode.calculators._xtb import xtb_gsolv
|
|
15
15
|
from firecode.settings import UMA_MODEL_PATH
|
|
16
|
+
from firecode.units import EV_TO_KCAL
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def uma_opt(
|
|
@@ -120,7 +121,7 @@ def uma_opt(
|
|
|
120
121
|
exit_str = 'REFINED' if success else 'MAX ITER'
|
|
121
122
|
logfunction(f' - {title} {exit_str} ({iterations} iterations, {time_to_string(time.perf_counter()-t_start_opt)})')
|
|
122
123
|
|
|
123
|
-
energy = ase_atoms.get_total_energy() *
|
|
124
|
+
energy = ase_atoms.get_total_energy() * EV_TO_KCAL
|
|
124
125
|
|
|
125
126
|
if traj is not None:
|
|
126
127
|
os.system(f"ase convert {traj} {title}_trj.xyz")
|
|
@@ -158,7 +159,10 @@ def get_uma_calc(method="omol", logfunction=None):
|
|
|
158
159
|
|
|
159
160
|
except ImportError as err:
|
|
160
161
|
print(err)
|
|
161
|
-
raise ImportError('To run the UMA models, please install fairchem:\n
|
|
162
|
+
raise ImportError('To run the UMA models, please install fairchem:\n'
|
|
163
|
+
' >>> uv pip install fairchem-core\n' \
|
|
164
|
+
'or alternatively, install the "uma" version of firecode:\n'
|
|
165
|
+
' >>> uv pip install firecode[uma]\n')
|
|
162
166
|
|
|
163
167
|
gpu_bool = cuda.is_available()
|
|
164
168
|
|
|
@@ -30,6 +30,7 @@ import numpy as np
|
|
|
30
30
|
from firecode.algebra import norm_of, normalize
|
|
31
31
|
from firecode.calculators.__init__ import NewFolderContext
|
|
32
32
|
from firecode.graph_manipulations import get_sum_graph
|
|
33
|
+
from firecode.units import EH_TO_KCAL
|
|
33
34
|
from firecode.utils import clean_directory, read_xyz, write_xyz
|
|
34
35
|
|
|
35
36
|
|
|
@@ -377,7 +378,7 @@ def read_from_xtbtraj(filename):
|
|
|
377
378
|
xyzblock = lines[first_coord_line:]
|
|
378
379
|
|
|
379
380
|
coords = np.array([line.split()[1:] for line in xyzblock], dtype=float)
|
|
380
|
-
energy = float(lines[first_coord_line-1].split()[1]) *
|
|
381
|
+
energy = float(lines[first_coord_line-1].split()[1]) * EH_TO_KCAL
|
|
381
382
|
|
|
382
383
|
return coords, energy
|
|
383
384
|
|
|
@@ -390,7 +391,7 @@ def energy_grepper(filename, signal_string, position):
|
|
|
390
391
|
while True:
|
|
391
392
|
line = f.readline()
|
|
392
393
|
if signal_string in line:
|
|
393
|
-
return float(line.split()[position]) *
|
|
394
|
+
return float(line.split()[position]) * EH_TO_KCAL
|
|
394
395
|
if not line:
|
|
395
396
|
raise Exception(f'Could not find \'{signal_string}\' in file ({filename}).')
|
|
396
397
|
|
|
@@ -552,7 +553,7 @@ def crest_mtd_search(
|
|
|
552
553
|
|
|
553
554
|
'''
|
|
554
555
|
|
|
555
|
-
with NewFolderContext(title):
|
|
556
|
+
with NewFolderContext(title, delete_after=False):
|
|
556
557
|
|
|
557
558
|
if constrained_indices is not None:
|
|
558
559
|
if len(constrained_indices) == 0:
|
|
@@ -57,11 +57,10 @@ from firecode.numba_functions import (compenetration_check, count_clashes,
|
|
|
57
57
|
from firecode.operators import operate
|
|
58
58
|
from firecode.optimization_methods import Opt_func_dispatcher, fitness_check
|
|
59
59
|
from firecode.parameters import orb_dim_dict
|
|
60
|
-
from firecode.pt import pt
|
|
61
60
|
from firecode.references import references
|
|
62
61
|
from firecode.settings import DEFAULT_LEVELS, PROCS
|
|
63
62
|
from firecode.torsion_module import get_quadruplets
|
|
64
|
-
from firecode.utils import (Constraint,
|
|
63
|
+
from firecode.utils import (Constraint, saturation_check, ase_view,
|
|
65
64
|
auto_newline, cartesian_product, clean_directory,
|
|
66
65
|
loadbar, scramble_check, timing_wrapper, write_xyz)
|
|
67
66
|
|
|
@@ -399,7 +398,7 @@ class Embedder:
|
|
|
399
398
|
for mol in self.objects:
|
|
400
399
|
charge = int(mol.charge) if hasattr(mol, "charge") else self.options.charge
|
|
401
400
|
|
|
402
|
-
if
|
|
401
|
+
if saturation_check(mol.atoms, charge):
|
|
403
402
|
self.log(f"--> {mol.filename}: saturation check passed (even saturation index with CHG={charge}, MULT={self.options.mult})")
|
|
404
403
|
|
|
405
404
|
# this may be a radical (and we would expect an even multiplicity) or something is wrong
|
|
@@ -2223,6 +2222,7 @@ class RunEmbedding(Embedder):
|
|
|
2223
2222
|
ase_calc=self.dispatcher.ase_calc,
|
|
2224
2223
|
solvent=self.options.solvent,
|
|
2225
2224
|
charge=self.options.charge,
|
|
2225
|
+
mult=self.options.mult,
|
|
2226
2226
|
maxiter=maxiter,
|
|
2227
2227
|
conv_thr=conv_thr,
|
|
2228
2228
|
|
|
@@ -2291,8 +2291,8 @@ class RunEmbedding(Embedder):
|
|
|
2291
2291
|
else:
|
|
2292
2292
|
self.energies[i] = 1E10
|
|
2293
2293
|
|
|
2294
|
-
### Update checkpoint every
|
|
2295
|
-
chk_freq =
|
|
2294
|
+
### Update checkpoint every 50 optimized structures, and give an estimate of the remaining time
|
|
2295
|
+
chk_freq = self.options.checkpoint_frequency
|
|
2296
2296
|
if i % chk_freq == chk_freq-1:
|
|
2297
2297
|
|
|
2298
2298
|
with open(self.outname, 'w') as f:
|
|
@@ -2553,7 +2553,7 @@ class RunEmbedding(Embedder):
|
|
|
2553
2553
|
self.write_mol_info()
|
|
2554
2554
|
|
|
2555
2555
|
if self.embed is None:
|
|
2556
|
-
self.log('--> No embed requested, exiting.\n')
|
|
2556
|
+
self.log('--> No embed or refinement requested, exiting.\n')
|
|
2557
2557
|
self.normal_termination()
|
|
2558
2558
|
|
|
2559
2559
|
if self.embed == 'error':
|
|
@@ -32,7 +32,7 @@ from firecode.errors import CCReadError, NoOrbitalError
|
|
|
32
32
|
from firecode.graph_manipulations import is_sigmatropic, is_vicinal
|
|
33
33
|
from firecode.pt import pt
|
|
34
34
|
from firecode.reactive_atoms_classes import get_atom_type
|
|
35
|
-
from firecode.utils import read_xyz
|
|
35
|
+
from firecode.utils import read_xyz
|
|
36
36
|
|
|
37
37
|
warnings.simplefilter("ignore", UserWarning)
|
|
38
38
|
|
|
@@ -107,14 +107,6 @@ class Hypermolecule:
|
|
|
107
107
|
if '.' in filename:
|
|
108
108
|
raise SyntaxError((f'Molecule {filename} cannot be read. Please check your syntax.'))
|
|
109
109
|
|
|
110
|
-
try:
|
|
111
|
-
filename = smi_to_3d(filename, "generated_3D_coords")
|
|
112
|
-
print(f"--> Embedded SMILES string to 3D structure, saved as {filename}")
|
|
113
|
-
|
|
114
|
-
except Exception:
|
|
115
|
-
raise SyntaxError((f'The program is trying to read something that is not a valid molecule input ({filename}). ' +
|
|
116
|
-
'If this looks like a keyword, it is probably faulted by a syntax error.'))
|
|
117
|
-
|
|
118
110
|
self.rootname = filename.split('.')[0]
|
|
119
111
|
self.filename = filename
|
|
120
112
|
self.debug_logfunction = debug_logfunction
|