stjames 0.0.44__py3-none-any.whl → 0.0.46__py3-none-any.whl
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.
Potentially problematic release.
This version of stjames might be problematic. Click here for more details.
- stjames/constraint.py +42 -4
- stjames/correction.py +3 -0
- stjames/diis_settings.py +1 -1
- stjames/method.py +20 -31
- stjames/molecule.py +5 -7
- stjames/scf_settings.py +1 -1
- stjames/types.py +2 -0
- stjames/workflows/__init__.py +42 -0
- stjames/workflows/bde.py +6 -3
- stjames/workflows/conformer_search.py +352 -0
- stjames/workflows/descriptors.py +1 -1
- stjames/workflows/electronic_properties.py +96 -0
- stjames/workflows/fukui.py +1 -1
- stjames/workflows/molecular_dynamics.py +13 -6
- stjames/workflows/multistage_opt.py +87 -21
- stjames/workflows/redox_potential.py +69 -5
- stjames/workflows/scan.py +1 -1
- stjames/workflows/spin_states.py +2 -2
- stjames/workflows/tautomer.py +1 -1
- {stjames-0.0.44.dist-info → stjames-0.0.46.dist-info}/METADATA +2 -2
- {stjames-0.0.44.dist-info → stjames-0.0.46.dist-info}/RECORD +24 -22
- {stjames-0.0.44.dist-info → stjames-0.0.46.dist-info}/WHEEL +1 -1
- {stjames-0.0.44.dist-info → stjames-0.0.46.dist-info}/LICENSE +0 -0
- {stjames-0.0.44.dist-info → stjames-0.0.46.dist-info}/top_level.txt +0 -0
stjames/constraint.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Optional, Self
|
|
2
|
+
|
|
3
|
+
from pydantic import PositiveFloat, PositiveInt, model_validator
|
|
2
4
|
|
|
3
5
|
from .base import Base, LowercaseStrEnum
|
|
4
6
|
|
|
@@ -9,28 +11,64 @@ class ConstraintType(LowercaseStrEnum):
|
|
|
9
11
|
BOND = "bond"
|
|
10
12
|
ANGLE = "angle"
|
|
11
13
|
DIHEDRAL = "dihedral"
|
|
14
|
+
FREEZE_ATOMS = "freeze_atoms"
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class Constraint(Base):
|
|
15
|
-
"""
|
|
18
|
+
"""
|
|
19
|
+
Represents a single (absolute) constraint.
|
|
20
|
+
|
|
21
|
+
:param constraint_type: which type
|
|
22
|
+
:param atoms: the atoms in question. n.b. - these are 1-indexed!
|
|
23
|
+
:param value: the value to constrain this to, leaving this blank sets the current value
|
|
24
|
+
"""
|
|
16
25
|
|
|
17
26
|
constraint_type: ConstraintType
|
|
18
27
|
atoms: list[PositiveInt] # 1-indexed
|
|
28
|
+
value: Optional[float] = None
|
|
29
|
+
|
|
30
|
+
@model_validator(mode="after")
|
|
31
|
+
def check_atom_list_length(self) -> Self:
|
|
32
|
+
match self.constraint_type:
|
|
33
|
+
case ConstraintType.BOND:
|
|
34
|
+
if len(self.atoms) != 2:
|
|
35
|
+
raise ValueError("Bond constraint needs two atom indices!")
|
|
36
|
+
case ConstraintType.ANGLE:
|
|
37
|
+
if len(self.atoms) != 3:
|
|
38
|
+
raise ValueError("Angle constraint needs three atom indices!")
|
|
39
|
+
case ConstraintType.DIHEDRAL:
|
|
40
|
+
if len(self.atoms) != 4:
|
|
41
|
+
raise ValueError("Dihedral constraint needs four atom indices!")
|
|
42
|
+
case ConstraintType.FREEZE_ATOMS:
|
|
43
|
+
if len(self.atoms) == 0:
|
|
44
|
+
raise ValueError("Can't freeze atoms without any atoms to freeze!")
|
|
45
|
+
case _:
|
|
46
|
+
raise ValueError("Unknown constraint_type!")
|
|
47
|
+
|
|
48
|
+
return self
|
|
19
49
|
|
|
20
50
|
|
|
21
51
|
class PairwiseHarmonicConstraint(Base):
|
|
22
52
|
"""
|
|
23
53
|
Represents a harmonic constraint, with a characteristic spring constant.
|
|
54
|
+
|
|
55
|
+
:param atoms: which atoms to apply to
|
|
56
|
+
:param force_constant: the strength of the attraction, in kcal/mol/Å
|
|
57
|
+
:param equilibrium: the distance at which force is zero
|
|
24
58
|
"""
|
|
25
59
|
|
|
26
60
|
atoms: tuple[PositiveInt, PositiveInt] # 1-indexed
|
|
27
|
-
|
|
61
|
+
force_constant: PositiveFloat # kcal/mol / Å**2
|
|
62
|
+
equilibrium: PositiveFloat # Å
|
|
28
63
|
|
|
29
64
|
|
|
30
65
|
class SphericalHarmonicConstraint(Base):
|
|
31
66
|
"""
|
|
32
67
|
Represents a spherical harmonic constraint to keep a system near the origin.
|
|
68
|
+
|
|
69
|
+
:param confining radius: the confining radius, in Å
|
|
70
|
+
:param force_constant: the strength of the confinement, in kcal/mol/Å
|
|
33
71
|
"""
|
|
34
72
|
|
|
35
73
|
confining_radius: PositiveFloat
|
|
36
|
-
|
|
74
|
+
force_constant: PositiveFloat = 10 # kcal/mol / Å**2
|
stjames/correction.py
CHANGED
stjames/diis_settings.py
CHANGED
stjames/method.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
1
3
|
from .base import LowercaseStrEnum
|
|
2
4
|
|
|
3
5
|
|
|
@@ -7,6 +9,7 @@ class Method(LowercaseStrEnum):
|
|
|
7
9
|
|
|
8
10
|
PBE = "pbe"
|
|
9
11
|
B973C = "b97_3c"
|
|
12
|
+
B97D3BJ = "b97_d3bj"
|
|
10
13
|
R2SCAN = "r2scan"
|
|
11
14
|
R2SCAN3C = "r2scan_3c"
|
|
12
15
|
TPSS = "tpss"
|
|
@@ -28,6 +31,9 @@ class Method(LowercaseStrEnum):
|
|
|
28
31
|
DSDBLYPD3BJ = "dsd_blyp_d3bj"
|
|
29
32
|
|
|
30
33
|
AIMNET2_WB97MD3 = "aimnet2_wb97md3"
|
|
34
|
+
MACE_MP_0 = "mace_mp_0"
|
|
35
|
+
OCP24_S = "ocp24_s"
|
|
36
|
+
OCP24_L = "ocp24_l"
|
|
31
37
|
|
|
32
38
|
GFN_FF = "gfn_ff"
|
|
33
39
|
GFN0_XTB = "gfn0_xtb"
|
|
@@ -38,34 +44,17 @@ class Method(LowercaseStrEnum):
|
|
|
38
44
|
BP86 = "bp86"
|
|
39
45
|
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
XTB_METHODS = [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Method.R2SCAN3C,
|
|
56
|
-
Method.WB97X3C,
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
PREPACKAGED_METHODS = [
|
|
60
|
-
*MLFF,
|
|
61
|
-
*XTB_METHODS,
|
|
62
|
-
*COMPOSITE_METHODS,
|
|
63
|
-
]
|
|
64
|
-
|
|
65
|
-
METHODS_WITH_CORRECTION = [
|
|
66
|
-
Method.WB97XD3,
|
|
67
|
-
Method.WB97XV,
|
|
68
|
-
Method.WB97MV,
|
|
69
|
-
Method.WB97MD3BJ,
|
|
70
|
-
Method.DSDBLYPD3BJ,
|
|
71
|
-
]
|
|
47
|
+
NNPMethod = Literal[Method.AIMNET2_WB97MD3]
|
|
48
|
+
NNP_METHODS = [Method.AIMNET2_WB97MD3]
|
|
49
|
+
|
|
50
|
+
XTBMethod = Literal[Method.GFN_FF, Method.GFN0_XTB, Method.GFN1_XTB, Method.GFN2_XTB]
|
|
51
|
+
XTB_METHODS = [Method.GFN_FF, Method.GFN0_XTB, Method.GFN1_XTB, Method.GFN2_XTB]
|
|
52
|
+
|
|
53
|
+
CompositeMethod = Literal[Method.HF3C, Method.B973C, Method.R2SCAN3C, Method.WB97X3C]
|
|
54
|
+
COMPOSITE_METHODS = [Method.HF3C, Method.B973C, Method.R2SCAN3C, Method.WB97X3C]
|
|
55
|
+
|
|
56
|
+
PrepackagedMethod = XTBMethod | CompositeMethod | NNPMethod
|
|
57
|
+
PREPACKAGED_METHODS = [*XTB_METHODS, *COMPOSITE_METHODS]
|
|
58
|
+
|
|
59
|
+
MethodWithCorrection = Literal[Method.WB97XD3, Method.WB97XV, Method.WB97MV, Method.WB97MD3BJ, Method.DSDBLYPD3BJ]
|
|
60
|
+
METHODS_WITH_CORRECTION = [Method.WB97XD3, Method.WB97XV, Method.WB97MV, Method.WB97MD3BJ, Method.DSDBLYPD3BJ, Method.B97D3BJ]
|
stjames/molecule.py
CHANGED
|
@@ -8,7 +8,7 @@ from pydantic import NonNegativeInt, PositiveInt, ValidationError
|
|
|
8
8
|
from .atom import Atom
|
|
9
9
|
from .base import Base
|
|
10
10
|
from .periodic_cell import PeriodicCell
|
|
11
|
-
from .types import Matrix3x3, Vector3D, Vector3DPerAtom
|
|
11
|
+
from .types import FloatPerAtom, Matrix3x3, Vector3D, Vector3DPerAtom
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class MoleculeReadError(RuntimeError):
|
|
@@ -18,10 +18,8 @@ class MoleculeReadError(RuntimeError):
|
|
|
18
18
|
class VibrationalMode(Base):
|
|
19
19
|
frequency: float # in cm-1
|
|
20
20
|
reduced_mass: float # amu
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
force_constant: float
|
|
24
|
-
displacements: Vector3DPerAtom
|
|
21
|
+
force_constant: float # mDyne/Å
|
|
22
|
+
displacements: Vector3DPerAtom # Å
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
class Molecule(Base):
|
|
@@ -44,8 +42,8 @@ class Molecule(Base):
|
|
|
44
42
|
|
|
45
43
|
velocities: Optional[Vector3DPerAtom] = None # Å/fs
|
|
46
44
|
|
|
47
|
-
mulliken_charges:
|
|
48
|
-
mulliken_spin_densities:
|
|
45
|
+
mulliken_charges: FloatPerAtom | None = None
|
|
46
|
+
mulliken_spin_densities: FloatPerAtom | None = None
|
|
49
47
|
dipole: Optional[Vector3D] = None # in Debye
|
|
50
48
|
|
|
51
49
|
vibrational_modes: Optional[list[VibrationalMode]] = None
|
stjames/scf_settings.py
CHANGED
stjames/types.py
CHANGED
stjames/workflows/__init__.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
# ruff: noqa: F405
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
1
4
|
from .admet import *
|
|
2
5
|
from .basic_calculation import *
|
|
3
6
|
from .bde import *
|
|
4
7
|
from .conformer import *
|
|
8
|
+
from .conformer_search import *
|
|
5
9
|
from .descriptors import *
|
|
10
|
+
from .electronic_properties import *
|
|
6
11
|
from .fukui import *
|
|
7
12
|
from .molecular_dynamics import *
|
|
8
13
|
from .multistage_opt import *
|
|
@@ -11,3 +16,40 @@ from .redox_potential import *
|
|
|
11
16
|
from .scan import *
|
|
12
17
|
from .spin_states import *
|
|
13
18
|
from .tautomer import *
|
|
19
|
+
from .workflow import Workflow
|
|
20
|
+
|
|
21
|
+
WORKFLOW_NAME = Literal[
|
|
22
|
+
"admet",
|
|
23
|
+
"basic_calculation",
|
|
24
|
+
"bde",
|
|
25
|
+
"conformers",
|
|
26
|
+
"conformer_search",
|
|
27
|
+
"descriptors",
|
|
28
|
+
"electronic_properties",
|
|
29
|
+
"fukui",
|
|
30
|
+
"molecular_dynamics",
|
|
31
|
+
"multistage_opt",
|
|
32
|
+
"pka",
|
|
33
|
+
"redox_potential",
|
|
34
|
+
"scan",
|
|
35
|
+
"spin_states",
|
|
36
|
+
"tautomers",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
WORKFLOW_MAPPING: dict[str, Workflow] = {
|
|
40
|
+
"admet": ADMETWorkflow, # type: ignore [dict-item]
|
|
41
|
+
"basic_calculation": BasicCalculationWorkflow, # type: ignore [dict-item]
|
|
42
|
+
"bde": BDEWorkflow, # type: ignore [dict-item]
|
|
43
|
+
"conformers": ConformerWorkflow, # type: ignore [dict-item]
|
|
44
|
+
"conformer_search": ConformerSearchWorkflow, # type: ignore [dict-item]
|
|
45
|
+
"descriptors": DescriptorsWorkflow, # type: ignore [dict-item]
|
|
46
|
+
"electronic_properties": ElectronicPropertiesWorkflow, # type: ignore [dict-item]
|
|
47
|
+
"fukui": FukuiIndexWorkflow, # type: ignore [dict-item]
|
|
48
|
+
"molecular_dynamics": MolecularDynamicsWorkflow, # type: ignore [dict-item]
|
|
49
|
+
"multistage_opt": MultiStageOptWorkflow, # type: ignore [dict-item]
|
|
50
|
+
"pka": pKaWorkflow, # type: ignore [dict-item]
|
|
51
|
+
"redox_potential": RedoxPotentialWorkflow, # type: ignore [dict-item]
|
|
52
|
+
"scan": ScanWorkflow, # type: ignore [dict-item]
|
|
53
|
+
"spin_states": SpinStatesWorkflow, # type: ignore [dict-item]
|
|
54
|
+
"tautomers": TautomerWorkflow, # type: ignore [dict-item]
|
|
55
|
+
}
|
stjames/workflows/bde.py
CHANGED
|
@@ -58,12 +58,12 @@ class BDEWorkflow(Workflow, MultiStageOptMixin):
|
|
|
58
58
|
:param initial_molecule: Molecule of interest
|
|
59
59
|
:param mode: Mode for workflow
|
|
60
60
|
:param multistage_opt_settings: set by mode unless mode=MANUAL (ignores additional settings if set)
|
|
61
|
-
:param solvent: solvent to use
|
|
61
|
+
:param solvent: solvent to use for singlepoint
|
|
62
62
|
:param xtb_preopt: pre-optimize with xtb (sets based on mode when None)
|
|
63
|
+
:param frequencies: whether to calculate frequencies
|
|
63
64
|
|
|
64
65
|
Overridden:
|
|
65
66
|
:param mso_mode: Mode for MultiStageOptSettings
|
|
66
|
-
:param frequencies: whether to calculate frequencies
|
|
67
67
|
|
|
68
68
|
Turned off:
|
|
69
69
|
:param constraints: constraints to add (not supported)
|
|
@@ -81,7 +81,6 @@ class BDEWorkflow(Workflow, MultiStageOptMixin):
|
|
|
81
81
|
"""
|
|
82
82
|
|
|
83
83
|
mso_mode: Mode = _sentinel_mso_mode # type: ignore [assignment]
|
|
84
|
-
frequencies: bool = False
|
|
85
84
|
optimize_fragments: bool = None # type: ignore [assignment]
|
|
86
85
|
|
|
87
86
|
atoms: tuple[PositiveInt, ...] = Field(default_factory=tuple)
|
|
@@ -106,6 +105,10 @@ class BDEWorkflow(Workflow, MultiStageOptMixin):
|
|
|
106
105
|
"""
|
|
107
106
|
return f"{type(self).__name__} {self.mode.name}\n" + "\n".join(map(str, self.fragment_indices))
|
|
108
107
|
|
|
108
|
+
@property
|
|
109
|
+
def level_of_theory(self) -> str:
|
|
110
|
+
return self.multistage_opt_settings.level_of_theory
|
|
111
|
+
|
|
109
112
|
@property
|
|
110
113
|
def energies(self) -> tuple[float | None, ...]:
|
|
111
114
|
return tuple(bde.energy for bde in self.bdes)
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"""Conformer Search Workflow."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC
|
|
4
|
+
from typing import Self, Sequence, TypeVar
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field, field_validator, model_validator
|
|
7
|
+
|
|
8
|
+
from ..base import LowercaseStrEnum
|
|
9
|
+
from ..constraint import Constraint
|
|
10
|
+
from ..method import Method, XTBMethod
|
|
11
|
+
from ..mode import Mode
|
|
12
|
+
from ..types import UUID
|
|
13
|
+
from .multistage_opt import MultiStageOptMixin
|
|
14
|
+
from .workflow import Workflow
|
|
15
|
+
|
|
16
|
+
_sentinel = object()
|
|
17
|
+
|
|
18
|
+
_T = TypeVar("_T")
|
|
19
|
+
_U = TypeVar("_U")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def check_sentinel(value: _T, default: _U) -> _T | _U:
|
|
23
|
+
"""Return value unless _sentinel, then return default."""
|
|
24
|
+
return default if value is _sentinel else value
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ScreeningSettings(BaseModel):
|
|
28
|
+
"""
|
|
29
|
+
Settings for determining unique and useful conformers.
|
|
30
|
+
|
|
31
|
+
:param energy_threshold: maximum relative energy for screening
|
|
32
|
+
:param rotational_constants_threshold: maximum difference in rotational constants for screening
|
|
33
|
+
:param rmsd: Cartesian RMSD for screening
|
|
34
|
+
:param max_confs: maximum number of conformers to keep
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
energy_threshold: float | None = None # kcal/mol
|
|
38
|
+
rotational_constants_threshold: float | None = 0.02
|
|
39
|
+
rmsd: float | None = 0.25
|
|
40
|
+
max_confs: int | None = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ConformerGenSettings(BaseModel):
|
|
44
|
+
"""
|
|
45
|
+
Conformer generation settings.
|
|
46
|
+
|
|
47
|
+
Conformers are generated and an initial screening is performed to remove duplicates and high-energy conformers.
|
|
48
|
+
|
|
49
|
+
:param mode: Mode for calculations
|
|
50
|
+
:param conf_opt_method: method for the optimization
|
|
51
|
+
:param screening: post-generation screening settings
|
|
52
|
+
:param constraints: constraints for conformer generation
|
|
53
|
+
:param nci: add a constraining potential for non-covalent interactions
|
|
54
|
+
:param max_confs: maximum number of conformers to keep
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
mode: Mode = Mode.RAPID
|
|
58
|
+
conf_opt_method: XTBMethod = Method.GFN_FF
|
|
59
|
+
screening: ScreeningSettings | None = None
|
|
60
|
+
constraints: Sequence[Constraint] = tuple()
|
|
61
|
+
nci: bool = False
|
|
62
|
+
max_confs: int | None = None
|
|
63
|
+
|
|
64
|
+
def __str__(self) -> str:
|
|
65
|
+
"""Return a string representation of the ConformerGenSettings."""
|
|
66
|
+
return repr(self)
|
|
67
|
+
|
|
68
|
+
def __repr__(self) -> str:
|
|
69
|
+
"""Return a string representation of the ConformerGenSettings."""
|
|
70
|
+
return f"<{type(self).__name__} {self.mode.name}>"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ETKDGSettings(ConformerGenSettings):
|
|
74
|
+
"""
|
|
75
|
+
Settings for ETKDG conformer generation.
|
|
76
|
+
|
|
77
|
+
Inherited:
|
|
78
|
+
:param mode: Mode for calculations
|
|
79
|
+
:param conf_opt_method: method for the optimization
|
|
80
|
+
:param screening: post-generation screening settings
|
|
81
|
+
:param constraints: constraints for conformer generation
|
|
82
|
+
:param nci: add a constraining potential for non-covalent interactions (not supported in ETKDG)
|
|
83
|
+
:param max_confs: maximum number of conformers to keep
|
|
84
|
+
|
|
85
|
+
New:
|
|
86
|
+
:param num_initial_confs: number of initial conformers to generate
|
|
87
|
+
:param num_confs_considered: number of conformers to consider for optimization
|
|
88
|
+
:param num_confs_taken: number of final conformers to take
|
|
89
|
+
:param max_mmff_energy: MMFF energy cutoff
|
|
90
|
+
:param max_mmff_iterations: MMFF optimization iterations
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
num_initial_confs: int = 300
|
|
94
|
+
num_confs_considered: int = 100
|
|
95
|
+
max_mmff_iterations: int = 500
|
|
96
|
+
max_mmff_energy: float | None = 30
|
|
97
|
+
|
|
98
|
+
@field_validator("constraints")
|
|
99
|
+
def check_constraints(cls, constraints: Sequence[Constraint]) -> Sequence[Constraint]:
|
|
100
|
+
if constraints:
|
|
101
|
+
raise ValueError("ETKDG does not support constraints")
|
|
102
|
+
|
|
103
|
+
return tuple(constraints)
|
|
104
|
+
|
|
105
|
+
@field_validator("nci")
|
|
106
|
+
def check_nci(cls, nci: bool) -> bool:
|
|
107
|
+
if nci:
|
|
108
|
+
raise ValueError("ETKDG does not support NCI")
|
|
109
|
+
|
|
110
|
+
return nci
|
|
111
|
+
|
|
112
|
+
@model_validator(mode="after")
|
|
113
|
+
def validate_and_build(self) -> Self:
|
|
114
|
+
match self.mode:
|
|
115
|
+
case Mode.MANUAL:
|
|
116
|
+
pass
|
|
117
|
+
case Mode.RECKLESS:
|
|
118
|
+
self.num_initial_confs = 200
|
|
119
|
+
self.num_confs_considered = 50
|
|
120
|
+
self.max_confs = 20 if self.max_confs is None else self.max_confs
|
|
121
|
+
self.max_mmff_energy = 20
|
|
122
|
+
case Mode.RAPID:
|
|
123
|
+
self.max_confs = 50 if self.max_confs is None else self.max_confs
|
|
124
|
+
self.conf_opt_method = Method.GFN0_XTB
|
|
125
|
+
case _:
|
|
126
|
+
raise NotImplementedError(f"Unsupported mode: {self.mode}")
|
|
127
|
+
|
|
128
|
+
return self
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class iMTDSpeeds(LowercaseStrEnum):
|
|
132
|
+
MEGAQUICK = "megaquick"
|
|
133
|
+
SUPERQUICK = "superquick"
|
|
134
|
+
QUICK = "quick"
|
|
135
|
+
NORMAL = "normal"
|
|
136
|
+
EXTENSIVE = "extensive"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class iMTDSettings(ConformerGenSettings, ABC):
|
|
140
|
+
"""
|
|
141
|
+
Settings for iMTD style conformer generation.
|
|
142
|
+
|
|
143
|
+
RECKLESS:
|
|
144
|
+
- GFN-FF//MTD(GFN-FF)
|
|
145
|
+
- Megaquick
|
|
146
|
+
- No GC
|
|
147
|
+
- No rotamer metadynamics
|
|
148
|
+
- Energy window = 5.0
|
|
149
|
+
- Run scaling factor = 0.5
|
|
150
|
+
- 6 MTD runs
|
|
151
|
+
RAPID:
|
|
152
|
+
- GFN0//MTD(GFN-FF)
|
|
153
|
+
- Superquick
|
|
154
|
+
- No GC
|
|
155
|
+
- No rotamer metadynamics
|
|
156
|
+
- Energy window = 5.0
|
|
157
|
+
- Run scaling factor = 0.5
|
|
158
|
+
- 6 MTD runs
|
|
159
|
+
CAREFUL:
|
|
160
|
+
- GFN2//MTD(GFN-FF)
|
|
161
|
+
- Quick
|
|
162
|
+
- GC (for iMTD-GC)
|
|
163
|
+
- Rotamer metadynamics (for iMTD-GC)
|
|
164
|
+
- Energy window = 5.0
|
|
165
|
+
- Run scaling factor = 0.5
|
|
166
|
+
- 6 MTD runs
|
|
167
|
+
METICULOUS:
|
|
168
|
+
- GFN2//MTD(GFN2)
|
|
169
|
+
- "Normal"
|
|
170
|
+
- GC (for iMTD-GC)
|
|
171
|
+
- Rotamer metadynamics (for iMTD-GC)
|
|
172
|
+
- Energy window = 6.0
|
|
173
|
+
- Run scaling factor = 1
|
|
174
|
+
- 14 MTD runs (2 with extreme values)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
See https://github.com/crest-lab/crest/blob/5ca82feb2ec4df30a0129db957163c934f085952/src/choose_settings.f90#L202
|
|
178
|
+
and https://github.com/crest-lab/crest/blob/5ca82feb2ec4df30a0129db957163c934f085952/src/confparse.f90#L825
|
|
179
|
+
for how quick, superquick, and megaquick are defined.
|
|
180
|
+
|
|
181
|
+
Additional notes:
|
|
182
|
+
Extensive mode
|
|
183
|
+
- GC
|
|
184
|
+
- Rotamer metadynamics
|
|
185
|
+
- Energy window = 8.0
|
|
186
|
+
- Run scaling factor = 2
|
|
187
|
+
- 14 MTD runs (2 with extreme values)
|
|
188
|
+
|
|
189
|
+
--NCI may switch things to QUICK?
|
|
190
|
+
|
|
191
|
+
Inherited:
|
|
192
|
+
:param mode: Mode for calculations
|
|
193
|
+
:param conf_opt_method: method for the optimization
|
|
194
|
+
:param screening: post-generation screening settings (not used)
|
|
195
|
+
:param constraints: constraints to add
|
|
196
|
+
:param nci: add an ellipsoide potential around the input structure
|
|
197
|
+
:param max_confs: maximum number of conformers to keep
|
|
198
|
+
|
|
199
|
+
New:
|
|
200
|
+
:param mtd_method: method for the metadynamics
|
|
201
|
+
:param speed: speed of the calculations (CREST specific setting)
|
|
202
|
+
:param reopt: re-optimize conformers (corrects for the lack of rotamer metadynamics and GC)
|
|
203
|
+
:param free_energy_weights: calculate frequencies and re-weight based on free energies
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
mtd_method: XTBMethod = Method.GFN_FF
|
|
207
|
+
mtd_runtype: str = "imtd-gc"
|
|
208
|
+
|
|
209
|
+
speed: iMTDSpeeds = iMTDSpeeds.QUICK
|
|
210
|
+
reopt: bool = _sentinel # type: ignore [assignment]
|
|
211
|
+
free_energy_weights: bool = False
|
|
212
|
+
|
|
213
|
+
@model_validator(mode="after")
|
|
214
|
+
def validate_and_build_imtdgc_settings(self) -> Self:
|
|
215
|
+
match self.mode:
|
|
216
|
+
case Mode.MANUAL:
|
|
217
|
+
if self.reopt is _sentinel:
|
|
218
|
+
raise ValueError("Must specify reopt with MANUAL mode")
|
|
219
|
+
case Mode.RECKLESS: # GFN-FF//MTD(GFN-FF)
|
|
220
|
+
self.max_confs = 20 if self.max_confs is None else self.max_confs
|
|
221
|
+
self.speed = iMTDSpeeds.MEGAQUICK
|
|
222
|
+
self.reopt = check_sentinel(self.reopt, True)
|
|
223
|
+
case Mode.RAPID: # GFN0//MTD(GFN-FF)
|
|
224
|
+
self.max_confs = 50 if self.max_confs is None else self.max_confs
|
|
225
|
+
self.speed = iMTDSpeeds.SUPERQUICK
|
|
226
|
+
self.conf_opt_method = Method.GFN0_XTB
|
|
227
|
+
self.reopt = check_sentinel(self.reopt, True)
|
|
228
|
+
case Mode.CAREFUL: # GFN2//MTD(GFN-FF)
|
|
229
|
+
self.speed = iMTDSpeeds.QUICK
|
|
230
|
+
self.conf_opt_method = Method.GFN2_XTB
|
|
231
|
+
self.reopt = check_sentinel(self.reopt, False)
|
|
232
|
+
case Mode.METICULOUS: # GFN2//MTD(GFN2)
|
|
233
|
+
self.speed = iMTDSpeeds.NORMAL
|
|
234
|
+
self.mtd_method = Method.GFN2_XTB
|
|
235
|
+
self.conf_opt_method = Method.GFN2_XTB
|
|
236
|
+
self.reopt = check_sentinel(self.reopt, False)
|
|
237
|
+
# case Mode.EXTREME: # GFN2//MTD(GFN2)
|
|
238
|
+
# self.mtd_method = Method.GFN2_XTB
|
|
239
|
+
# self.conf_opt_method = Method.GFN2_XTB
|
|
240
|
+
# self.speed = iMTDSpeeds.EXTENSIVE
|
|
241
|
+
# self.reopt = check_sentinel(self.reopt, False)
|
|
242
|
+
case _:
|
|
243
|
+
raise NotImplementedError(f"Unsupported mode: {self.mode}")
|
|
244
|
+
|
|
245
|
+
return self
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class iMTDGCSettings(iMTDSettings):
|
|
249
|
+
run_type: str = "imtdgc"
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class iMTDsMTDSettings(iMTDSettings):
|
|
253
|
+
run_type: str = "imtd-smtd"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class ConformerGenMixin(BaseModel):
|
|
257
|
+
"""
|
|
258
|
+
Mixin for workflows that need conformer generation.
|
|
259
|
+
|
|
260
|
+
:param conf_gen_mode: Mode for calculations
|
|
261
|
+
:param conf_gen_settings: settings for conformer generation
|
|
262
|
+
:param constraints: constraints to add
|
|
263
|
+
:param nci: add a constraining potential for non-covalent interactions
|
|
264
|
+
:param max_confs: maximum number of conformers to keep
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
conf_gen_mode: Mode = Mode.RAPID
|
|
268
|
+
conf_gen_settings: ConformerGenSettings = _sentinel # type: ignore [assignment]
|
|
269
|
+
constraints: Sequence[Constraint] = tuple()
|
|
270
|
+
nci: bool = False
|
|
271
|
+
max_confs: int | None = None
|
|
272
|
+
|
|
273
|
+
@model_validator(mode="after")
|
|
274
|
+
def validate_and_build_conf_gen_settings(self) -> Self:
|
|
275
|
+
"""Validate and build the ConformerGenSettings."""
|
|
276
|
+
if self.conf_gen_settings is not _sentinel and self.conf_gen_mode != Mode.MANUAL:
|
|
277
|
+
raise ValueError("Cannot specify conf_gen_settings with non-MANUAL mode")
|
|
278
|
+
|
|
279
|
+
match self.conf_gen_mode:
|
|
280
|
+
case Mode.MANUAL:
|
|
281
|
+
if self.conf_gen_settings is _sentinel:
|
|
282
|
+
raise ValueError("Must specify conf_gen_settings with MANUAL mode")
|
|
283
|
+
|
|
284
|
+
case Mode.RECKLESS | Mode.RAPID:
|
|
285
|
+
# ETKDGSettings will error if constraints or nci are set
|
|
286
|
+
self.conf_gen_settings = ETKDGSettings(mode=self.conf_gen_mode, constraints=self.constraints, nci=self.nci, max_confs=self.max_confs)
|
|
287
|
+
case Mode.CAREFUL | Mode.METICULOUS:
|
|
288
|
+
self.conf_gen_settings = iMTDSettings(mode=self.conf_gen_mode, constraints=self.constraints, nci=self.nci, max_confs=self.max_confs)
|
|
289
|
+
|
|
290
|
+
case _:
|
|
291
|
+
raise NotImplementedError(f"Unsupported mode: {self.conf_gen_mode}")
|
|
292
|
+
|
|
293
|
+
return self
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class ConformerSearchMixin(ConformerGenMixin, MultiStageOptMixin):
|
|
297
|
+
"""
|
|
298
|
+
Mixin for workflows that need conformer search—a combination of conformer generation and optimization.
|
|
299
|
+
|
|
300
|
+
Inherited (ConformerGenMixin):
|
|
301
|
+
:param conf_gen_mode: Mode for conformer generation
|
|
302
|
+
:param mso_mode: Mode for MultiStageOptSettings
|
|
303
|
+
:param conf_gen_settings: settings for conformer generation
|
|
304
|
+
:param nci: add a constraining potential for non-covalent interactions
|
|
305
|
+
|
|
306
|
+
Inherited (MultiStageOptMixin):
|
|
307
|
+
:param multistage_opt_settings: set by mso_mode unless mode=MANUAL (ignores additional settings if set)
|
|
308
|
+
:param solvent: solvent to use
|
|
309
|
+
:param xtb_preopt: pre-optimize with xtb (sets based on mode when None)
|
|
310
|
+
:param transition_state: whether this is a transition state
|
|
311
|
+
:param frequencies: whether to calculate frequencies
|
|
312
|
+
|
|
313
|
+
Inherited (Both):
|
|
314
|
+
:param constraints: constraints to add (diamond inheritance, works as expected)
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
def __str__(self) -> str:
|
|
318
|
+
"""Return a string representation of the ConformerSearch workflow."""
|
|
319
|
+
return repr(self)
|
|
320
|
+
|
|
321
|
+
def __repr__(self) -> str:
|
|
322
|
+
"""Return a string representation of the ConformerSearch workflow."""
|
|
323
|
+
return f"<{type(self).__name__} {self.conf_gen_mode.name} {self.mso_mode.name}>"
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class ConformerSearchWorkflow(ConformerSearchMixin, Workflow):
|
|
327
|
+
"""
|
|
328
|
+
ConformerSearch Workflow.
|
|
329
|
+
|
|
330
|
+
Inherited:
|
|
331
|
+
:param initial_molecule: Molecule of interest
|
|
332
|
+
:param conf_gen_mode: Mode for calculations
|
|
333
|
+
:param conf_gen_settings: settings for conformer generation
|
|
334
|
+
:param mso_mode: Mode for MultiStageOptSettings
|
|
335
|
+
:param multistage_opt_settings: set by mode unless mode=MANUAL (ignores additional settings if set)
|
|
336
|
+
:param solvent: solvent to use
|
|
337
|
+
:param xtb_preopt: pre-optimize with xtb (sets based on mode when None)
|
|
338
|
+
:param constraints: constraints to add
|
|
339
|
+
:param transition_state: whether this is a transition state
|
|
340
|
+
:param frequencies: whether to calculate frequencies
|
|
341
|
+
|
|
342
|
+
Ignored:
|
|
343
|
+
:param mode: Mode to use (not used)
|
|
344
|
+
|
|
345
|
+
New:
|
|
346
|
+
:param conformer_uuids: list of UUIDs of the Molecules generated
|
|
347
|
+
:param energies: energies of the molecules
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
# Results
|
|
351
|
+
conformer_uuids: list[list[UUID | None]] = Field(default_factory=list)
|
|
352
|
+
energies: list[float] = Field(default_factory=list)
|
stjames/workflows/descriptors.py
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from pydantic import NonNegativeFloat, NonNegativeInt
|
|
2
|
+
|
|
3
|
+
from ..base import Base
|
|
4
|
+
from ..settings import Settings
|
|
5
|
+
from ..types import UUID, FloatPerAtom, Matrix3x3, Vector3D
|
|
6
|
+
from .workflow import Workflow
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PropertyCubePoint(Base):
|
|
10
|
+
x: float
|
|
11
|
+
y: float
|
|
12
|
+
z: float
|
|
13
|
+
val: float
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PropertyCube(Base):
|
|
17
|
+
"""Represents a "cubefile" of some property."""
|
|
18
|
+
|
|
19
|
+
cube_points: list[PropertyCubePoint]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MolecularOrbitalCube(PropertyCube):
|
|
23
|
+
"""
|
|
24
|
+
Cube of a molecular orbital.
|
|
25
|
+
|
|
26
|
+
Inherits `cube_data`.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
occupation: NonNegativeInt
|
|
30
|
+
energy: float
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ElectronicPropertiesWorkflow(Workflow):
|
|
34
|
+
"""
|
|
35
|
+
Workflow for computing electronic properties.
|
|
36
|
+
|
|
37
|
+
Inherited
|
|
38
|
+
:param initial_molecule: Molecule of interest
|
|
39
|
+
|
|
40
|
+
Config settings:
|
|
41
|
+
:param settings: settings for the calculation
|
|
42
|
+
:param compute_density_cube: whether to compute the density cube
|
|
43
|
+
:param compute_electrostatic_potential_cube: whether to compute the electrostatic potential cube
|
|
44
|
+
:param compute_num_occupied_orbitals: number of occupied orbitals to save
|
|
45
|
+
:param compute_num_virtual_orbitals: number of virtual orbitals to save
|
|
46
|
+
|
|
47
|
+
Populated while running:
|
|
48
|
+
:param calc_uuid: UUID of the calculation
|
|
49
|
+
:param dipole: dipole moment
|
|
50
|
+
:param quadrupole: quadrupole moment
|
|
51
|
+
:param lowdin_charges: Löwdin charges
|
|
52
|
+
:param mulliken_charges: Mulliken charges
|
|
53
|
+
:param wiberg_bond_orders: Wiberg bond orders (`atom1`, `atom2`, `order`)
|
|
54
|
+
:param mayer_bond_orders: Mayer bond orders (`atom1`, `atom2`, `order`)
|
|
55
|
+
|
|
56
|
+
:param density_cube: electron density, as a cube
|
|
57
|
+
:param density_cube_alpha: α electron density, as a cube
|
|
58
|
+
:param density_cube_beta: β electron density, as a cube
|
|
59
|
+
:param density_cube_difference: difference spin densities, as a cube
|
|
60
|
+
|
|
61
|
+
:param electrostatic_potential_cube: electrostatic potential, as a cube
|
|
62
|
+
|
|
63
|
+
:param molecular_orbitals: MOs, key is absolute orbital index (for closed-shell species (RHF))
|
|
64
|
+
:param molecular_orbitals_alpha: α MOs, key is absolute orbital index (for open-shell species (UHF/ROHF))
|
|
65
|
+
:param molecular_orbitals_beta: β MOs, key is absolute orbital index (for open-shell species (UHF/ROHF))
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# Config settings
|
|
69
|
+
settings: Settings
|
|
70
|
+
compute_density_cube: bool = True
|
|
71
|
+
compute_electrostatic_potential_cube: bool = True
|
|
72
|
+
compute_num_occupied_orbitals: NonNegativeInt = 1
|
|
73
|
+
compute_num_virtual_orbitals: NonNegativeInt = 1
|
|
74
|
+
|
|
75
|
+
# Results
|
|
76
|
+
calc_uuid: UUID | None = None
|
|
77
|
+
|
|
78
|
+
dipole: Vector3D | None = None
|
|
79
|
+
quadrupole: Matrix3x3 | None = None
|
|
80
|
+
|
|
81
|
+
mulliken_charges: FloatPerAtom | None = None
|
|
82
|
+
lowdin_charges: FloatPerAtom | None = None
|
|
83
|
+
|
|
84
|
+
wiberg_bond_orders: list[tuple[NonNegativeInt, NonNegativeInt, NonNegativeFloat]] = []
|
|
85
|
+
mayer_bond_orders: list[tuple[NonNegativeInt, NonNegativeInt, NonNegativeFloat]] = []
|
|
86
|
+
|
|
87
|
+
density_cube: PropertyCube | None = None
|
|
88
|
+
density_cube_alpha: PropertyCube | None = None
|
|
89
|
+
density_cube_beta: PropertyCube | None = None
|
|
90
|
+
density_cube_difference: PropertyCube | None = None
|
|
91
|
+
|
|
92
|
+
electrostatic_potential_cube: PropertyCube | None = None
|
|
93
|
+
|
|
94
|
+
molecular_orbitals: dict[NonNegativeInt, MolecularOrbitalCube] = {}
|
|
95
|
+
molecular_orbitals_alpha: dict[NonNegativeInt, MolecularOrbitalCube] = {}
|
|
96
|
+
molecular_orbitals_beta: dict[NonNegativeInt, MolecularOrbitalCube] = {}
|
stjames/workflows/fukui.py
CHANGED
|
@@ -9,6 +9,12 @@ from ..types import UUID
|
|
|
9
9
|
from .workflow import Workflow
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
class MolecularDynamicsInitialization(LowercaseStrEnum):
|
|
13
|
+
RANDOM = "random"
|
|
14
|
+
QUASICLASSICAL = "quasiclassical"
|
|
15
|
+
READ = "read"
|
|
16
|
+
|
|
17
|
+
|
|
12
18
|
class ThermodynamicEnsemble(LowercaseStrEnum):
|
|
13
19
|
NPT = "npt"
|
|
14
20
|
NVT = "nvt"
|
|
@@ -18,22 +24,25 @@ class ThermodynamicEnsemble(LowercaseStrEnum):
|
|
|
18
24
|
class Frame(Base):
|
|
19
25
|
index: int # what number frame this is within the MD simulation
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
calculation_uuid: UUID | None = None # UUID of calculation
|
|
22
28
|
|
|
23
29
|
pressure: float
|
|
24
30
|
temperature: float
|
|
31
|
+
volume: float
|
|
25
32
|
energy: float
|
|
26
33
|
|
|
27
34
|
|
|
28
35
|
class MolecularDynamicsSettings(Base):
|
|
29
36
|
ensemble: ThermodynamicEnsemble = ThermodynamicEnsemble.NVT
|
|
37
|
+
initialization: MolecularDynamicsInitialization = MolecularDynamicsInitialization.RANDOM
|
|
30
38
|
|
|
31
39
|
timestep: PositiveFloat = 1.0 # fs
|
|
32
40
|
num_steps: PositiveInt = 500
|
|
41
|
+
save_interval: PositiveInt = 10
|
|
33
42
|
|
|
34
43
|
confining_constraint: SphericalHarmonicConstraint | None = None
|
|
35
44
|
|
|
36
|
-
temperature: PositiveFloat
|
|
45
|
+
temperature: PositiveFloat = 300 # K
|
|
37
46
|
pressure: PositiveFloat | None = None # atm
|
|
38
47
|
|
|
39
48
|
langevin_thermostat_timescale: PositiveFloat = 100 # fs
|
|
@@ -46,7 +55,7 @@ class MolecularDynamicsSettings(Base):
|
|
|
46
55
|
"""Check that NVT ensemble always has temperature defined, and that NPT has temp and pressure defined."""
|
|
47
56
|
if self.ensemble == ThermodynamicEnsemble.NVT and self.temperature is None:
|
|
48
57
|
raise ValueError("NVT ensemble must have a temperature defined")
|
|
49
|
-
|
|
58
|
+
elif self.ensemble == ThermodynamicEnsemble.NPT and (self.temperature is None or self.pressure is None):
|
|
50
59
|
raise ValueError("NPT ensemble must have both temperature and pressure defined")
|
|
51
60
|
return self
|
|
52
61
|
|
|
@@ -56,7 +65,5 @@ class MolecularDynamicsWorkflow(Workflow):
|
|
|
56
65
|
calc_settings: Settings
|
|
57
66
|
calc_engine: str | None = None
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# uuids of scan points
|
|
68
|
+
# UUIDs of scan points
|
|
62
69
|
frames: list[Frame] = []
|
|
@@ -27,14 +27,14 @@ class MultiStageOptSettings(BaseModel):
|
|
|
27
27
|
wB97M-D3BJ/def2-TZVPPD//wB97X-3c//r²SCAN-3c with GFN2-xTB pre-opt
|
|
28
28
|
|
|
29
29
|
Notes:
|
|
30
|
-
- No solvent in
|
|
30
|
+
- No solvent in any optimizations when using Modes
|
|
31
31
|
- If solvent: xTB singlepoints use CPCMX, xTB optimizations use ALBP, all else use CPCM
|
|
32
32
|
- Allows a single point to be called with no optimization
|
|
33
33
|
|
|
34
34
|
:param mode: Mode for settings
|
|
35
35
|
:param optimization_settings: list of opt settings to apply successively
|
|
36
36
|
:param singlepoint_settings: final single point settings
|
|
37
|
-
:param solvent: solvent to use
|
|
37
|
+
:param solvent: solvent to use for singlepoint
|
|
38
38
|
:param xtb_preopt: pre-optimize with xtb (sets based on mode when None)
|
|
39
39
|
:param constraints: constraints for optimization
|
|
40
40
|
:param transition_state: whether this is a transition state
|
|
@@ -44,17 +44,17 @@ class MultiStageOptSettings(BaseModel):
|
|
|
44
44
|
>>> msos
|
|
45
45
|
<MultiStageOptSettings RAPID>
|
|
46
46
|
>>> msos.level_of_theory
|
|
47
|
-
'r2scan_3c/cpcm(water)//gfn2_xtb
|
|
47
|
+
'r2scan_3c/cpcm(water)//gfn2_xtb'
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
50
|
mode: Mode
|
|
51
51
|
optimization_settings: Sequence[Settings] = tuple()
|
|
52
52
|
singlepoint_settings: Settings | None = None
|
|
53
53
|
solvent: Solvent | None = None
|
|
54
|
-
xtb_preopt: bool
|
|
54
|
+
xtb_preopt: bool = False
|
|
55
55
|
constraints: Sequence[Constraint] = tuple()
|
|
56
56
|
transition_state: bool = False
|
|
57
|
-
frequencies: bool =
|
|
57
|
+
frequencies: bool = False
|
|
58
58
|
|
|
59
59
|
def __str__(self) -> str:
|
|
60
60
|
return repr(self)
|
|
@@ -78,7 +78,7 @@ class MultiStageOptSettings(BaseModel):
|
|
|
78
78
|
|
|
79
79
|
>>> msos = MultiStageOptSettings(mode=Mode.RAPID, solvent="hexane")
|
|
80
80
|
>>> msos.level_of_theory
|
|
81
|
-
'r2scan_3c/cpcm(hexane)//gfn2_xtb
|
|
81
|
+
'r2scan_3c/cpcm(hexane)//gfn2_xtb'
|
|
82
82
|
"""
|
|
83
83
|
methods = [self.singlepoint_settings] if self.singlepoint_settings else []
|
|
84
84
|
methods += reversed(self.optimization_settings)
|
|
@@ -148,39 +148,34 @@ class MultiStageOptSettings(BaseModel):
|
|
|
148
148
|
match mode:
|
|
149
149
|
case Mode.RECKLESS:
|
|
150
150
|
self.xtb_preopt = False
|
|
151
|
-
self.optimization_settings = [opt(Method.GFN_FF,
|
|
151
|
+
self.optimization_settings = [opt(Method.GFN_FF, freq=self.frequencies)]
|
|
152
152
|
self.singlepoint_settings = sp(Method.GFN2_XTB, solvent=self.solvent)
|
|
153
153
|
|
|
154
154
|
case Mode.RAPID:
|
|
155
|
-
self.xtb_preopt = bool(self.xtb_preopt)
|
|
156
155
|
self.optimization_settings = [
|
|
157
156
|
*gfn0_pre_opt * self.xtb_preopt,
|
|
158
|
-
opt(Method.GFN2_XTB,
|
|
157
|
+
opt(Method.GFN2_XTB, freq=self.frequencies),
|
|
159
158
|
]
|
|
160
159
|
self.singlepoint_settings = sp(Method.R2SCAN3C, solvent=self.solvent)
|
|
161
160
|
|
|
162
161
|
case Mode.CAREFUL:
|
|
163
|
-
self.xtb_preopt = (self.xtb_preopt is None) or self.xtb_preopt
|
|
164
162
|
self.optimization_settings = [
|
|
165
163
|
*gfn2_pre_opt * self.xtb_preopt,
|
|
166
|
-
opt(Method.R2SCAN3C,
|
|
164
|
+
opt(Method.R2SCAN3C, freq=self.frequencies),
|
|
167
165
|
]
|
|
168
166
|
self.singlepoint_settings = sp(Method.WB97X3C, solvent=self.solvent)
|
|
169
167
|
|
|
170
168
|
case Mode.METICULOUS:
|
|
171
|
-
self.xtb_preopt = (self.xtb_preopt is None) or self.xtb_preopt
|
|
172
169
|
self.optimization_settings = [
|
|
173
170
|
*gfn2_pre_opt * self.xtb_preopt,
|
|
174
|
-
opt(Method.R2SCAN3C
|
|
175
|
-
opt(Method.WB97X3C,
|
|
171
|
+
opt(Method.R2SCAN3C),
|
|
172
|
+
opt(Method.WB97X3C, freq=self.frequencies),
|
|
176
173
|
]
|
|
177
174
|
self.singlepoint_settings = sp(Method.WB97MD3BJ, "def2-TZVPPD", solvent=self.solvent)
|
|
178
175
|
|
|
179
176
|
case mode:
|
|
180
177
|
raise NotImplementedError(f"Cannot assign settings for {mode=}")
|
|
181
178
|
|
|
182
|
-
assert self.xtb_preopt is not None
|
|
183
|
-
|
|
184
179
|
|
|
185
180
|
class MultiStageOptWorkflow(Workflow, MultiStageOptSettings):
|
|
186
181
|
"""
|
|
@@ -191,7 +186,7 @@ class MultiStageOptWorkflow(Workflow, MultiStageOptSettings):
|
|
|
191
186
|
:param mode: Mode for workflow
|
|
192
187
|
:param optimization_settings: list of opt settings to apply successively
|
|
193
188
|
:param singlepoint_settings: final single point settings
|
|
194
|
-
:param solvent: solvent to use
|
|
189
|
+
:param solvent: solvent to use for singlepoint
|
|
195
190
|
:param xtb_preopt: pre-optimize with xtb (sets based on mode when None)
|
|
196
191
|
:param constraints: constraints for optimization
|
|
197
192
|
:param transition_state: whether this is a transition state
|
|
@@ -206,7 +201,7 @@ class MultiStageOptWorkflow(Workflow, MultiStageOptSettings):
|
|
|
206
201
|
>>> msow
|
|
207
202
|
<MultiStageOptWorkflow RAPID>
|
|
208
203
|
>>> msow.level_of_theory
|
|
209
|
-
'r2scan_3c/cpcm(water)//gfn2_xtb
|
|
204
|
+
'r2scan_3c/cpcm(water)//gfn2_xtb'
|
|
210
205
|
"""
|
|
211
206
|
|
|
212
207
|
# Populated while running the workflow
|
|
@@ -228,14 +223,14 @@ class MultiStageOptMixin(BaseModel):
|
|
|
228
223
|
Mixin for workflows that use MultiStageOptSettings.
|
|
229
224
|
"""
|
|
230
225
|
|
|
231
|
-
mso_mode: Mode
|
|
226
|
+
mso_mode: Mode = Mode.AUTO
|
|
232
227
|
# Need to use a sentinel object to make both mypy and pydantic happy
|
|
233
228
|
multistage_opt_settings: MultiStageOptSettings = _sentinel_msos # type: ignore [assignment]
|
|
234
229
|
solvent: Solvent | None = None
|
|
235
|
-
xtb_preopt: bool
|
|
230
|
+
xtb_preopt: bool = False
|
|
236
231
|
constraints: Sequence[Constraint] = tuple()
|
|
237
232
|
transition_state: bool = False
|
|
238
|
-
frequencies: bool =
|
|
233
|
+
frequencies: bool = False
|
|
239
234
|
|
|
240
235
|
@model_validator(mode="after")
|
|
241
236
|
def set_mso_settings(self) -> Self:
|
|
@@ -265,3 +260,74 @@ class MultiStageOptMixin(BaseModel):
|
|
|
265
260
|
)
|
|
266
261
|
|
|
267
262
|
return self
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def build_mso_settings(
|
|
266
|
+
sp_method: Method,
|
|
267
|
+
sp_basis_set: str | None,
|
|
268
|
+
opt_methods: list[Method],
|
|
269
|
+
opt_basis_sets: list[str | None],
|
|
270
|
+
mode: Mode = Mode.MANUAL,
|
|
271
|
+
solvent: Solvent | None = None,
|
|
272
|
+
use_solvent_for_opt: bool = False,
|
|
273
|
+
constraints: list[Constraint] | None = None,
|
|
274
|
+
transition_state: bool = False,
|
|
275
|
+
frequencies: bool = False,
|
|
276
|
+
) -> MultiStageOptSettings:
|
|
277
|
+
"""
|
|
278
|
+
Helper function to construct multi-stage opt settings objects manually.
|
|
279
|
+
|
|
280
|
+
There's no xTB pre-optimization here - add that yourself!
|
|
281
|
+
|
|
282
|
+
:param optimization_settings: optimization settings to apply successively
|
|
283
|
+
:param singlepoint_settings: final single point settings
|
|
284
|
+
:param mode: Mode for settings, defaults to `MANUAL`
|
|
285
|
+
:param solvent: solvent to use
|
|
286
|
+
:param use_solvent_for_opt: whether to conduct opts with solvent
|
|
287
|
+
:param constraints: constraints for optimization
|
|
288
|
+
:param transition_state: whether this is a transition state
|
|
289
|
+
:param frequencies: whether to calculate frequencies
|
|
290
|
+
:returns: MultiStageOptSettings
|
|
291
|
+
"""
|
|
292
|
+
if constraints is None:
|
|
293
|
+
constraints = []
|
|
294
|
+
|
|
295
|
+
opt_settings = OptimizationSettings(constraints=constraints, transition_state=transition_state)
|
|
296
|
+
|
|
297
|
+
OPT = [Task.OPTIMIZE if not transition_state else Task.OPTIMIZE_TS]
|
|
298
|
+
|
|
299
|
+
def opt(method: Method, basis_set: str | None = None, solvent: Solvent | None = None, freq: bool = False) -> Settings:
|
|
300
|
+
"""Generates optimization settings."""
|
|
301
|
+
model = "alpb" if method in XTB_METHODS else "cpcm"
|
|
302
|
+
|
|
303
|
+
return Settings(
|
|
304
|
+
method=method,
|
|
305
|
+
basis_set=basis_set,
|
|
306
|
+
tasks=OPT + [Task.FREQUENCIES] * freq,
|
|
307
|
+
solvent_settings=SolventSettings(solvent=solvent, model=model) if (solvent and use_solvent_for_opt) else None,
|
|
308
|
+
opt_settings=opt_settings,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
def sp(method: Method, basis_set: str | None = None, solvent: Solvent | None = None) -> Settings:
|
|
312
|
+
"""Generate singlepoint settings."""
|
|
313
|
+
model = "cpcmx" if method in XTB_METHODS else "cpcm"
|
|
314
|
+
|
|
315
|
+
return Settings(
|
|
316
|
+
method=method,
|
|
317
|
+
basis_set=basis_set,
|
|
318
|
+
tasks=[Task.ENERGY],
|
|
319
|
+
solvent_settings=SolventSettings(solvent=solvent, model=model) if solvent else None,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
return MultiStageOptSettings(
|
|
323
|
+
mode=mode,
|
|
324
|
+
optimization_settings=[
|
|
325
|
+
opt(method=method, basis_set=basis_set, solvent=solvent, freq=frequencies) for method, basis_set in zip(opt_methods, opt_basis_sets, strict=True)
|
|
326
|
+
],
|
|
327
|
+
singlepoint_settings=sp(method=sp_method, basis_set=sp_basis_set, solvent=solvent),
|
|
328
|
+
solvent=solvent,
|
|
329
|
+
xtb_preopt=False,
|
|
330
|
+
constraints=constraints,
|
|
331
|
+
transition_state=transition_state,
|
|
332
|
+
frequencies=frequencies,
|
|
333
|
+
)
|
|
@@ -1,22 +1,59 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any, TypeVar
|
|
2
|
+
|
|
3
|
+
from pydantic import ValidationInfo, field_validator, model_validator
|
|
2
4
|
|
|
3
5
|
from ..mode import Mode
|
|
4
6
|
from ..solvent import Solvent
|
|
5
7
|
from ..types import UUID
|
|
8
|
+
from .multistage_opt import MultiStageOptMixin
|
|
6
9
|
from .workflow import Workflow
|
|
7
10
|
|
|
11
|
+
_T = TypeVar("_T")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RedoxPotentialWorkflow(Workflow, MultiStageOptMixin):
|
|
15
|
+
"""
|
|
16
|
+
Workflow for computing spin states of molecules.
|
|
17
|
+
|
|
18
|
+
Uses the modes from MultiStageOptSettings.
|
|
19
|
+
|
|
20
|
+
Inherited
|
|
21
|
+
:param initial_molecule: Molecule of interest
|
|
22
|
+
:param mode: Mode for workflow
|
|
23
|
+
:param multistage_opt_settings: set by mode unless mode=MANUAL (ignores additional settings if set)
|
|
24
|
+
:param xtb_preopt: pre-optimize with xtb (sets based on mode when None)
|
|
25
|
+
:param constraints: constraints to add
|
|
26
|
+
:param transition_state: whether this is a transition state
|
|
27
|
+
:param frequencies: whether to calculate frequencies
|
|
28
|
+
|
|
29
|
+
Overridden:
|
|
30
|
+
:param mso_mode: Mode for MultiStageOptSettings
|
|
31
|
+
:param solvent: solvent to use for optimization
|
|
32
|
+
|
|
33
|
+
New:
|
|
34
|
+
:param reduction: whether or not to calculate the reduction half-reaction
|
|
35
|
+
:param oxidation: whether or not to calculate the oxidation half-reaction
|
|
36
|
+
:param neutral_molecule: UUID of the calculation for the neutral molecule
|
|
37
|
+
:param anion_molecule: UUID of the calculation for the anion molecule
|
|
38
|
+
:param cation_molecule: UUID of the calculation for the cation molecule
|
|
39
|
+
:param reduction_potential: the final potential, in V
|
|
40
|
+
:param oxidation_potential: the final potential, in V
|
|
41
|
+
|
|
42
|
+
Legacy:
|
|
43
|
+
:param redox_type: one of "reduction" or "oxidation"
|
|
44
|
+
:param redox_potential: the corresponding potential, in V
|
|
45
|
+
"""
|
|
8
46
|
|
|
9
|
-
class RedoxPotentialWorkflow(Workflow):
|
|
10
|
-
mode: Mode = Mode.RAPID
|
|
11
47
|
solvent: Solvent = Solvent.ACETONITRILE
|
|
48
|
+
|
|
12
49
|
reduction: bool = True
|
|
13
50
|
oxidation: bool = True
|
|
14
51
|
|
|
15
52
|
# legacy values - remove in future release!
|
|
16
|
-
redox_type:
|
|
53
|
+
redox_type: str | None = None
|
|
17
54
|
redox_potential: float | None = None
|
|
18
55
|
|
|
19
|
-
#
|
|
56
|
+
# UUIDs
|
|
20
57
|
neutral_molecule: UUID | None = None
|
|
21
58
|
anion_molecule: UUID | None = None
|
|
22
59
|
cation_molecule: UUID | None = None
|
|
@@ -24,6 +61,33 @@ class RedoxPotentialWorkflow(Workflow):
|
|
|
24
61
|
reduction_potential: float | None = None
|
|
25
62
|
oxidation_potential: float | None = None
|
|
26
63
|
|
|
64
|
+
@field_validator("solvent", mode="before")
|
|
65
|
+
@classmethod
|
|
66
|
+
def only_mecn_please(cls, val: Solvent | None) -> Solvent:
|
|
67
|
+
"""Only MeCN please!"""
|
|
68
|
+
if val != Solvent.ACETONITRILE:
|
|
69
|
+
raise ValueError("Only acetonitrile permitted!")
|
|
70
|
+
|
|
71
|
+
return val
|
|
72
|
+
|
|
73
|
+
@field_validator("constraints", "transition_state")
|
|
74
|
+
@classmethod
|
|
75
|
+
def turned_off(cls, value: _T, info: ValidationInfo) -> _T:
|
|
76
|
+
if value:
|
|
77
|
+
raise ValueError(f"{info.field_name} not supported in redox potential workflows.")
|
|
78
|
+
|
|
79
|
+
return value
|
|
80
|
+
|
|
81
|
+
@model_validator(mode="before")
|
|
82
|
+
@classmethod
|
|
83
|
+
def set_mode_and_mso_mode(cls, values: dict[str, Any]) -> dict[str, Any]:
|
|
84
|
+
"""Set the MultiStageOptSettings mode to match current redox potential mode, and select mode if `Auto`."""
|
|
85
|
+
if ("mode" not in values) or (values["mode"] == Mode.AUTO):
|
|
86
|
+
values["mode"] = Mode.RAPID
|
|
87
|
+
|
|
88
|
+
values["mso_mode"] = values["mode"]
|
|
89
|
+
return values
|
|
90
|
+
|
|
27
91
|
def model_post_init(self, __context: Any) -> None:
|
|
28
92
|
"""Keep back-compatible with old schema."""
|
|
29
93
|
if self.redox_type == "oxidation":
|
stjames/workflows/scan.py
CHANGED
stjames/workflows/spin_states.py
CHANGED
|
@@ -51,8 +51,8 @@ class SpinStatesWorkflow(Workflow, MultiStageOptMixin):
|
|
|
51
51
|
:param initial_molecule: Molecule of interest
|
|
52
52
|
:param mode: Mode for workflow
|
|
53
53
|
:param multistage_opt_settings: set by mode unless mode=MANUAL (ignores additional settings if set)
|
|
54
|
-
:param solvent: solvent to use
|
|
55
|
-
:param xtb_preopt: pre-optimize with xtb
|
|
54
|
+
:param solvent: solvent to use for optimization
|
|
55
|
+
:param xtb_preopt: pre-optimize with xtb
|
|
56
56
|
:param constraints: constraints to add
|
|
57
57
|
:param transition_state: whether this is a transition state
|
|
58
58
|
:param frequencies: whether to calculate frequencies
|
stjames/workflows/tautomer.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: stjames
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.46
|
|
4
4
|
Summary: standardized JSON atom/molecule encoding scheme
|
|
5
5
|
Author-email: Corin Wagen <corin@rowansci.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/rowansci/stjames
|
|
@@ -8,7 +8,7 @@ Project-URL: Bug Tracker, https://github.com/rowansci/stjames/issues
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
-
Requires-Dist: pydantic
|
|
11
|
+
Requires-Dist: pydantic>=2.4
|
|
12
12
|
Requires-Dist: numpy
|
|
13
13
|
|
|
14
14
|
# stjames
|
|
@@ -4,25 +4,25 @@ stjames/atom.py,sha256=w7q-x9xpBw4sJ1WGrWt65WAaStxhz-m7dugXCYEOpq4,2064
|
|
|
4
4
|
stjames/base.py,sha256=9PvUjBeVSkmA3TaruaB0uvjFMbWYTGKXECISNGAj_AU,1201
|
|
5
5
|
stjames/basis_set.py,sha256=wI3M2q9uPf9jhKpAi4E2DrsyKzloDGLRjAlk7krdYgc,949
|
|
6
6
|
stjames/calculation.py,sha256=O2LwwQ_cOLmDOGXTHA9J71YbUZXigUSbvbLA-fSVm3w,915
|
|
7
|
-
stjames/constraint.py,sha256=
|
|
8
|
-
stjames/correction.py,sha256=
|
|
9
|
-
stjames/diis_settings.py,sha256=
|
|
7
|
+
stjames/constraint.py,sha256=B6oV0rYjmAWr8gpi5f03gRy_uuqjUURVDVwoez5Cfbg,2442
|
|
8
|
+
stjames/correction.py,sha256=ZVErCcj4TPyZeKrdvXVjHa0tFynsCaoy96QZUVxWFM8,413
|
|
9
|
+
stjames/diis_settings.py,sha256=4m1EQQWBlpHhMnWopix8qOqJv7QCluvdnV9jSKJDFtE,552
|
|
10
10
|
stjames/grid_settings.py,sha256=WrSNGc-8_f87YBZYt9Hh7RbhM4MweADoVzwBMcSqcsE,640
|
|
11
11
|
stjames/int_settings.py,sha256=5HXp8opt5ZyY1UpmfaK7NVloWVLM5jkG0elEEqpVLUo,896
|
|
12
12
|
stjames/message.py,sha256=Rq6QqmHZKecWxYH8fVyXmuoCCPZv8YinvgykSeorXSU,216
|
|
13
|
-
stjames/method.py,sha256=
|
|
13
|
+
stjames/method.py,sha256=a6QQff-0YsutkOTuOcGrdDW76x9ZexiNLdKzzoE1Vcw,1698
|
|
14
14
|
stjames/mode.py,sha256=xw46Cc7f3eTS8i35qECi-8DocAlANhayK3w4akD4HBU,496
|
|
15
|
-
stjames/molecule.py,sha256=
|
|
15
|
+
stjames/molecule.py,sha256=v8NikFHfwOahXSo4VKGSqeHKI2HIoRdNjGE0GkZgNS4,10554
|
|
16
16
|
stjames/opt_settings.py,sha256=gxXGtjy9l-Q5Wen9eO6T6HHRCuS8rfOofdVQIJj0JcI,550
|
|
17
17
|
stjames/periodic_cell.py,sha256=JDCyynpamggTNi_HnTnnotRbeSMBfYc-srhD-IwUnrg,996
|
|
18
18
|
stjames/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
stjames/scf_settings.py,sha256=
|
|
19
|
+
stjames/scf_settings.py,sha256=WotVgVrayQ_8PUHP39zVtG7iLT9PV41lpzruttFACP8,2356
|
|
20
20
|
stjames/settings.py,sha256=tfgEYns6WdsheQ6wpR6uyI8O4s2iTqyH7YWtNQ36k74,8666
|
|
21
21
|
stjames/solvent.py,sha256=u037tmu-9oa21s-WEDZ7VC7nuNVjkqR2ML4JWjWSME4,1158
|
|
22
22
|
stjames/status.py,sha256=wTKNcNxStoEHrxxgr_zTyN90NITa3rxMQZzOgrCifEw,332
|
|
23
23
|
stjames/task.py,sha256=OLINRqe66o7t8arffilwmggrF_7TH0L79u6DhGruxV8,329
|
|
24
24
|
stjames/thermochem_settings.py,sha256=ZTLz31v8Ltutde5Nfm0vH5YahWjcfFWfr_R856KffxE,517
|
|
25
|
-
stjames/types.py,sha256=
|
|
25
|
+
stjames/types.py,sha256=CPKR0g_kdFejMjGdKBjtuJRQqfmAZ-uIaSuGR1vBzCQ,245
|
|
26
26
|
stjames/data/__init__.py,sha256=O59Ksp7AIqwOELCWymfCx7YeBzwNOGCMlGQi7tNLqiE,24
|
|
27
27
|
stjames/data/bragg_radii.json,sha256=hhbn-xyZNSdmnULIjN2Cvq-_BGIZIqG243Ls_mey61w,1350
|
|
28
28
|
stjames/data/elements.py,sha256=9BW01LZlyJ0H5s7Q26vUmjZIST41fwOYYrGvmPd7q0w,858
|
|
@@ -30,23 +30,25 @@ stjames/data/isotopes.json,sha256=5ba8QnLrHD_Ypv2xekv2cIRwYrX3MQ19-1FOFtt0RuU,83
|
|
|
30
30
|
stjames/data/nist_isotopes.json,sha256=d5DNk1dX0iB1waEYIRR6JMHuA7AuYwSBEgBvb4EKyhM,14300
|
|
31
31
|
stjames/data/read_nist_isotopes.py,sha256=y10FNjW43QpC45qib7VHsIghEwT7GG5rsNwHdc9osRI,3309
|
|
32
32
|
stjames/data/symbol_element.json,sha256=vl_buFusTqBd-muYQtMLtTDLy2OtBI6KkBeqkaWRQrg,1186
|
|
33
|
-
stjames/workflows/__init__.py,sha256=
|
|
33
|
+
stjames/workflows/__init__.py,sha256=IRcfBNaFWVMmixQHjPKcBJkcUYWRnXNwrx2MUFNiQKM,1843
|
|
34
34
|
stjames/workflows/admet.py,sha256=V8noO0Eb7h2bDFSnj6Pxv4ILm0lGxyVRCi13hE0zmEQ,149
|
|
35
35
|
stjames/workflows/basic_calculation.py,sha256=q48bpab7ZqmRTR4PsGC6bWkuxqkVdJRM8gysevTYXP0,212
|
|
36
|
-
stjames/workflows/bde.py,sha256=
|
|
36
|
+
stjames/workflows/bde.py,sha256=iNrBiAUJA-VaAB-eFddApUO2xIc5PyPYXNtC2stQ_OU,9667
|
|
37
37
|
stjames/workflows/conformer.py,sha256=YYwL3l7OaVeea4N9-ihghwa_ieKY6hia9LNbiTraMb0,2732
|
|
38
|
-
stjames/workflows/
|
|
39
|
-
stjames/workflows/
|
|
40
|
-
stjames/workflows/
|
|
41
|
-
stjames/workflows/
|
|
38
|
+
stjames/workflows/conformer_search.py,sha256=zmGaSuka0VClmX36AkKvJAN565-hyp2ZJQIjhkAMQRM,12924
|
|
39
|
+
stjames/workflows/descriptors.py,sha256=lRRCsGzad3nIg0wI1090ffaXB0FVh0nRRb2lNxCY0kI,281
|
|
40
|
+
stjames/workflows/electronic_properties.py,sha256=DFrzU49rux13Fy5q7pgvuYNjiyC2KwMtqU6FTAxg9jo,3339
|
|
41
|
+
stjames/workflows/fukui.py,sha256=CsJ3_gvzqEqcxwYN7bnNIa37F3KlLm7obsU77TGmDgo,348
|
|
42
|
+
stjames/workflows/molecular_dynamics.py,sha256=wx633IhPjRwEYvfyuRnSb0c84lN2WtZJET2q-SJv5DY,2211
|
|
43
|
+
stjames/workflows/multistage_opt.py,sha256=FXSm-adv9TIiE6ftWPO50Yq9ypoJ7GSPkJKpnC0r4kQ,12686
|
|
42
44
|
stjames/workflows/pka.py,sha256=zpR90Yv2L-D56o2mGArM8027DWpnFFnay31UR9Xh5Nc,774
|
|
43
|
-
stjames/workflows/redox_potential.py,sha256=
|
|
44
|
-
stjames/workflows/scan.py,sha256=
|
|
45
|
-
stjames/workflows/spin_states.py,sha256=
|
|
46
|
-
stjames/workflows/tautomer.py,sha256=
|
|
45
|
+
stjames/workflows/redox_potential.py,sha256=e7WOyTIC_1NPfh7amvW7YzqQezcswX9YaXT-qPiePAo,3651
|
|
46
|
+
stjames/workflows/scan.py,sha256=Wqimw1nMErKOYHcC7U1hNC8LZb5XPtS-nE1a-c_6_88,814
|
|
47
|
+
stjames/workflows/spin_states.py,sha256=TXHqB7ClTkkCy1Yfcsv99v2woAhT8oG1-uaF20-oMbQ,4592
|
|
48
|
+
stjames/workflows/tautomer.py,sha256=owZOOfGlohxlaOG1pGpx7dVPvas8ZEnl_9Ms5F0Kpms,421
|
|
47
49
|
stjames/workflows/workflow.py,sha256=tIu5naADYgYS7kdW8quvGEWHWosBcrIdcD7L86v-uMQ,976
|
|
48
|
-
stjames-0.0.
|
|
49
|
-
stjames-0.0.
|
|
50
|
-
stjames-0.0.
|
|
51
|
-
stjames-0.0.
|
|
52
|
-
stjames-0.0.
|
|
50
|
+
stjames-0.0.46.dist-info/LICENSE,sha256=i7ehYBS-6gGmbTcgU4mgk28pyOx2kScJ0kcx8n7bWLM,1084
|
|
51
|
+
stjames-0.0.46.dist-info/METADATA,sha256=sagkuDdeazTP1wvoGMsletsSSFzY_8Qjv0shhmcj17w,1627
|
|
52
|
+
stjames-0.0.46.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
53
|
+
stjames-0.0.46.dist-info/top_level.txt,sha256=FYCwxl6quhYOAgG-mnPQcCK8vsVM7B8rIUrO-WrQ_PI,8
|
|
54
|
+
stjames-0.0.46.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|