strain-relief 0.4.dev0__tar.gz → 1.0.dev0__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 (140) hide show
  1. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/.gitignore +2 -0
  2. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/.pre-commit-config.yaml +1 -5
  3. strain_relief-1.0.dev0/.vscode/launch.json +68 -0
  4. strain_relief-1.0.dev0/PKG-INFO +192 -0
  5. strain_relief-1.0.dev0/README.md +161 -0
  6. strain_relief-1.0.dev0/assets/strain_relief_plus_logo.png +0 -0
  7. strain_relief-1.0.dev0/examples/example_config.yaml +44 -0
  8. strain_relief-1.0.dev0/examples/example_scripts.sh +54 -0
  9. strain_relief-1.0.dev0/examples/tutorial.ipynb +1495 -0
  10. strain_relief-1.0.dev0/hydra_config/calculator/fairchem.yaml +4 -0
  11. strain_relief-1.0.dev0/hydra_config/calculator/mace.yaml +4 -0
  12. strain_relief-1.0.dev0/hydra_config/calculator/mmff94.yaml +1 -0
  13. {strain_relief-0.4.dev0/src/strain_relief → strain_relief-1.0.dev0}/hydra_config/conformers/default.yaml +1 -1
  14. strain_relief-1.0.dev0/hydra_config/default.yaml +22 -0
  15. strain_relief-1.0.dev0/hydra_config/experiment/fairchem.yaml +23 -0
  16. strain_relief-1.0.dev0/hydra_config/experiment/mace.yaml +23 -0
  17. strain_relief-1.0.dev0/hydra_config/experiment/mmff94.yaml +20 -0
  18. strain_relief-1.0.dev0/hydra_config/experiment/pytest.yaml +18 -0
  19. {strain_relief-0.4.dev0/src/strain_relief → strain_relief-1.0.dev0}/hydra_config/io/default.yaml +4 -1
  20. strain_relief-1.0.dev0/hydra_config/optimiser/bfgs.yaml +5 -0
  21. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/pyproject.toml +40 -20
  22. strain_relief-1.0.dev0/setup.sh +28 -0
  23. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/__init__.py +10 -0
  24. strain_relief-1.0.dev0/src/strain_relief/cmdline/_strain_relief.py +17 -0
  25. strain_relief-1.0.dev0/src/strain_relief/compute_strain.py +213 -0
  26. strain_relief-1.0.dev0/src/strain_relief/configs/__init__.py +3 -0
  27. strain_relief-1.0.dev0/src/strain_relief/configs/_configs.py +101 -0
  28. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/conformers/_rdkit_generation.py +23 -15
  29. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/constants/__init__.py +8 -2
  30. strain_relief-1.0.dev0/src/strain_relief/constants/_str.py +9 -0
  31. strain_relief-1.0.dev0/src/strain_relief/constants/_units.py +19 -0
  32. strain_relief-1.0.dev0/src/strain_relief/data_types/__init__.py +9 -0
  33. strain_relief-1.0.dev0/src/strain_relief/data_types/_types.py +21 -0
  34. strain_relief-1.0.dev0/src/strain_relief/io/__init__.py +8 -0
  35. strain_relief-1.0.dev0/src/strain_relief/io/_input.py +210 -0
  36. strain_relief-1.0.dev0/src/strain_relief/io/_output.py +222 -0
  37. strain_relief-1.0.dev0/src/strain_relief/optimisation/__init__.py +3 -0
  38. strain_relief-1.0.dev0/src/strain_relief/optimisation/_optimisation.py +102 -0
  39. strain_relief-1.0.dev0/src/strain_relief.egg-info/SOURCES.txt +71 -0
  40. strain_relief-1.0.dev0/tests/cmdline/test_strain_relief.py +41 -0
  41. strain_relief-1.0.dev0/tests/configs/test_configs.py +256 -0
  42. strain_relief-1.0.dev0/tests/conformers/test_rdkit_generation.py +34 -0
  43. strain_relief-1.0.dev0/tests/conftest.py +135 -0
  44. strain_relief-1.0.dev0/tests/constants/test_str.py +20 -0
  45. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/constants/test_units.py +1 -0
  46. strain_relief-1.0.dev0/tests/data/all_charged.parquet +0 -0
  47. strain_relief-1.0.dev0/tests/data/ligboundconf.parquet +0 -0
  48. strain_relief-1.0.dev0/tests/io/test_input.py +103 -0
  49. strain_relief-1.0.dev0/tests/io/test_output.py +52 -0
  50. strain_relief-1.0.dev0/tests/optimisation/test_optimisation.py +27 -0
  51. strain_relief-1.0.dev0/tests/test_compute_strain.py +80 -0
  52. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/test_init.py +1 -0
  53. strain_relief-1.0.dev0/uv.lock +2019 -0
  54. strain_relief-0.4.dev0/Dockerfile-strain-relief +0 -140
  55. strain_relief-0.4.dev0/PKG-INFO +0 -188
  56. strain_relief-0.4.dev0/README.md +0 -159
  57. strain_relief-0.4.dev0/assets/strain_relief_logo.png +0 -0
  58. strain_relief-0.4.dev0/ci.yml +0 -85
  59. strain_relief-0.4.dev0/env.yml +0 -9
  60. strain_relief-0.4.dev0/examples/example_script.sh +0 -17
  61. strain_relief-0.4.dev0/examples/examples.sh +0 -37
  62. strain_relief-0.4.dev0/examples/tutorial.ipynb +0 -250
  63. strain_relief-0.4.dev0/requirements-dev.in +0 -5
  64. strain_relief-0.4.dev0/requirements.in +0 -11
  65. strain_relief-0.4.dev0/src/strain_relief/calculators/__init__.py +0 -11
  66. strain_relief-0.4.dev0/src/strain_relief/calculators/_mmff94.py +0 -77
  67. strain_relief-0.4.dev0/src/strain_relief/calculators/_nnp.py +0 -44
  68. strain_relief-0.4.dev0/src/strain_relief/cmdline/_strain_relief.py +0 -94
  69. strain_relief-0.4.dev0/src/strain_relief/constants/_str.py +0 -4
  70. strain_relief-0.4.dev0/src/strain_relief/constants/_units.py +0 -19
  71. strain_relief-0.4.dev0/src/strain_relief/energy_eval/__init__.py +0 -10
  72. strain_relief-0.4.dev0/src/strain_relief/energy_eval/_energy_eval.py +0 -61
  73. strain_relief-0.4.dev0/src/strain_relief/energy_eval/_mmff94.py +0 -81
  74. strain_relief-0.4.dev0/src/strain_relief/energy_eval/_nnp.py +0 -115
  75. strain_relief-0.4.dev0/src/strain_relief/hydra_config/default.yaml +0 -13
  76. strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/default.yaml +0 -1
  77. strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/fairchem.yaml +0 -5
  78. strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/mace.yaml +0 -5
  79. strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/mmff94.yaml +0 -4
  80. strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/mmff94s.yaml +0 -4
  81. strain_relief-0.4.dev0/src/strain_relief/hydra_config/experiment/fairchem.yaml +0 -19
  82. strain_relief-0.4.dev0/src/strain_relief/hydra_config/experiment/mace.yaml +0 -19
  83. strain_relief-0.4.dev0/src/strain_relief/hydra_config/experiment/mmff94s.yaml +0 -11
  84. strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/fairchem.yaml +0 -8
  85. strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/mace.yaml +0 -8
  86. strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/mmff94.yaml +0 -7
  87. strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/mmff94s.yaml +0 -7
  88. strain_relief-0.4.dev0/src/strain_relief/hydra_config/model/fairchem.yaml +0 -6
  89. strain_relief-0.4.dev0/src/strain_relief/hydra_config/model/mace.yaml +0 -6
  90. strain_relief-0.4.dev0/src/strain_relief/io/__init__.py +0 -10
  91. strain_relief-0.4.dev0/src/strain_relief/io/_io.py +0 -272
  92. strain_relief-0.4.dev0/src/strain_relief/io/utils_mol_format.py +0 -52
  93. strain_relief-0.4.dev0/src/strain_relief/minimisation/__init__.py +0 -12
  94. strain_relief-0.4.dev0/src/strain_relief/minimisation/_minimisation.py +0 -59
  95. strain_relief-0.4.dev0/src/strain_relief/minimisation/_mmff94.py +0 -51
  96. strain_relief-0.4.dev0/src/strain_relief/minimisation/_nnp.py +0 -79
  97. strain_relief-0.4.dev0/src/strain_relief/minimisation/utils_bfgs.py +0 -145
  98. strain_relief-0.4.dev0/src/strain_relief/minimisation/utils_minimisation.py +0 -177
  99. strain_relief-0.4.dev0/src/strain_relief.egg-info/SOURCES.txt +0 -94
  100. strain_relief-0.4.dev0/tests/calculators/test_mmff94.py +0 -36
  101. strain_relief-0.4.dev0/tests/cmdline/test_strain_relief.py +0 -111
  102. strain_relief-0.4.dev0/tests/conformers/test_rdkit_generation.py +0 -31
  103. strain_relief-0.4.dev0/tests/conftest.py +0 -130
  104. strain_relief-0.4.dev0/tests/constants/test_str.py +0 -11
  105. strain_relief-0.4.dev0/tests/data/all_charged.parquet +0 -0
  106. strain_relief-0.4.dev0/tests/data/ligboundconf.parquet +0 -0
  107. strain_relief-0.4.dev0/tests/data/water.xyz +0 -5
  108. strain_relief-0.4.dev0/tests/energy_eval/test_energy_eval.py +0 -72
  109. strain_relief-0.4.dev0/tests/energy_eval/test_mmff94.py +0 -34
  110. strain_relief-0.4.dev0/tests/energy_eval/test_nnp.py +0 -89
  111. strain_relief-0.4.dev0/tests/io/test_io.py +0 -47
  112. strain_relief-0.4.dev0/tests/io/test_utils_mol_format.py +0 -60
  113. strain_relief-0.4.dev0/tests/minimisation/_init__.py +0 -0
  114. strain_relief-0.4.dev0/tests/minimisation/test_minimisation.py +0 -50
  115. strain_relief-0.4.dev0/tests/minimisation/test_mmff94.py +0 -22
  116. strain_relief-0.4.dev0/tests/minimisation/test_nnp.py +0 -30
  117. strain_relief-0.4.dev0/tests/minimisation/test_utils_bfgs.py +0 -6
  118. strain_relief-0.4.dev0/tests/minimisation/test_utils_minimisation.py +0 -119
  119. strain_relief-0.4.dev0/uv.lock +0 -1468
  120. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/LICENSE +0 -0
  121. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/MANIFEST.in +0 -0
  122. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/assets/strain_relief_protocol.png +0 -0
  123. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/data/example_ligboundconf.sdf +0 -0
  124. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/data/example_ligboundconf_input.parquet +0 -0
  125. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/examples/mace_training_script.sh +0 -0
  126. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/models/MACE_SPICE2_NEUTRAL.model +0 -0
  127. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/setup.cfg +0 -0
  128. /strain_relief-0.4.dev0/src/strain_relief/hydra_config/__init__.py → /strain_relief-1.0.dev0/src/strain_relief/calculators/.gitkeep +0 -0
  129. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/cmdline/__init__.py +0 -0
  130. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/conformers/__init__.py +0 -0
  131. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/io/utils_s3.py +0 -0
  132. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/__init__.py +0 -0
  133. {strain_relief-0.4.dev0/tests/calculators → strain_relief-1.0.dev0/tests/cmdline}/__init__.py +0 -0
  134. {strain_relief-0.4.dev0/tests/cmdline → strain_relief-1.0.dev0/tests/configs}/__init__.py +0 -0
  135. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/conformers/__init__.py +0 -0
  136. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/constants/__init__.py +0 -0
  137. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/data/target.parquet +0 -0
  138. {strain_relief-0.4.dev0/tests/energy_eval → strain_relief-1.0.dev0/tests/io}/__init__.py +0 -0
  139. {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/models/MACE.model +0 -0
  140. {strain_relief-0.4.dev0/tests/io → strain_relief-1.0.dev0/tests/optimisation}/__init__.py +0 -0
@@ -9,3 +9,5 @@ __pycache__/
9
9
  *.pyc
10
10
 
11
11
  tests/models/eSEN.pt
12
+
13
+ outputs/
@@ -1,15 +1,11 @@
1
1
  repos:
2
2
  - repo: https://github.com/pre-commit/pre-commit-hooks
3
- rev: v4.5.0
3
+ rev: v6.0.0
4
4
  hooks:
5
5
  - id: check-yaml
6
6
  - id: trailing-whitespace
7
7
  - id: end-of-file-fixer
8
8
  - id: debug-statements
9
- - repo: https://github.com/kynan/nbstripout
10
- rev: 0.6.0
11
- hooks:
12
- - id: nbstripout
13
9
  - repo: https://github.com/astral-sh/ruff-pre-commit
14
10
  rev: v0.2.2
15
11
  hooks:
@@ -0,0 +1,68 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "Python Debugger: Current File",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "program": "${file}",
12
+ "console": "integratedTerminal",
13
+ "justMyCode": false
14
+ },
15
+ {
16
+ "name": "train (mmff94)",
17
+ "type": "debugpy",
18
+ "program": "${workspaceFolder}/src/strain_relief/cmdline/_strain_relief.py",
19
+ "request": "launch",
20
+ "console": "integratedTerminal",
21
+ "justMyCode": true,
22
+ "args": [
23
+ "experiment=mmff94s",
24
+ "conformers.numConfs=1",
25
+ "io.input.parquet_path=${workspaceFolder}/data/example_ligboundconf_input.parquet",
26
+ ],
27
+ "env": {
28
+ "HYDRA_FULL_ERROR": "1",
29
+ }
30
+ },
31
+ {
32
+ "name": "train (mace - gpu)",
33
+ "type": "debugpy",
34
+ "program": "${workspaceFolder}/src/strain_relief/cmdline/_strain_relief.py",
35
+ "request": "launch",
36
+ "console": "integratedTerminal",
37
+ "justMyCode": false,
38
+ "args": [
39
+ "experiment=mace",
40
+ "conformers.numConfs=1",
41
+ "io.input.parquet_path=${workspaceFolder}/data/example_ligboundconf_input.parquet",
42
+ "device=cuda",
43
+ ],
44
+ "env": {
45
+ "HYDRA_FULL_ERROR": "1",
46
+ "CUDA_LAUNCH_BLOCKING": "1"
47
+ }
48
+ },
49
+ {
50
+ "name": "train (mace- cpu)",
51
+ "type": "debugpy",
52
+ "program": "${workspaceFolder}/src/strain_relief/cmdline/_strain_relief.py",
53
+ "request": "launch",
54
+ "console": "integratedTerminal",
55
+ "justMyCode": false,
56
+ "args": [
57
+ "experiment=mace",
58
+ "conformers.numConfs=1",
59
+ "io.input.parquet_path=${workspaceFolder}/data/example_ligboundconf_input.parquet",
60
+ "device=cpu",
61
+ ],
62
+ "env": {
63
+ "HYDRA_FULL_ERROR": "1",
64
+ "CUDA_LAUNCH_BLOCKING": "1"
65
+ }
66
+ },
67
+ ]
68
+ }
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: strain-relief
3
+ Version: 1.0.dev0
4
+ Summary: Calculates ligand strain of small molecules from their docked poses.
5
+ Author-email: Ewan Wallace <erw@wallace2.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/prescient-design/StrainRelief
8
+ Requires-Python: ==3.11.*
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: rdkit
12
+ Requires-Dist: ase
13
+ Requires-Dist: numpy
14
+ Requires-Dist: pandas
15
+ Requires-Dist: omegaconf
16
+ Requires-Dist: hydra-core
17
+ Requires-Dist: pyarrow
18
+ Requires-Dist: fastparquet
19
+ Requires-Dist: universal-pathlib
20
+ Requires-Dist: boto3
21
+ Requires-Dist: loguru
22
+ Requires-Dist: rich
23
+ Requires-Dist: neural-optimiser
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest; extra == "dev"
26
+ Requires-Dist: pytest-mock; extra == "dev"
27
+ Requires-Dist: pytest-cov; extra == "dev"
28
+ Requires-Dist: pre-commit; extra == "dev"
29
+ Requires-Dist: ipykernel; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ # StrainRelief 💊
33
+ StrainRelief calculates the ligand strain of docked poses and has a suite of different force fields with which to do this. This includes our own MACE neural network potential trained on SPICE2 and also Meta's FAIRChem models, such as e-SEN and UMA. Optimisations are run in parallel using the neural-optimiser package.
34
+
35
+ - 📄 The publication can be found [here](https://pubs.acs.org/doi/10.1021/acs.jcim.5c00586).
36
+ - 📊 All relevant datasets [here](https://huggingface.co/datasets/erwallace/LigBoundConf2.0).
37
+ - 💬 RAG [chatbot](https://strain-relief.streamlit.app/) for questions about the paper and references.
38
+ - 💻 Chatbot source [code](https://github.com/erwallace/paper_query).
39
+ - 📉 neural-optimiser [package](https://github.com/erwallace/neural-optimiser).
40
+
41
+ ![Strain Relief Logo](assets/strain_relief_plus_logo.png)
42
+
43
+ ## Update 1.0.0
44
+
45
+ This update focuses on accelerating the StrainRelief backend and increasig usability through simpler configurations and workflows:
46
+
47
+ - Molecular optimisation are now paralellised using the `neural-optimiser` [package](https://github.com/erwallace/neural-optimiser) providing a 3x speed-up.
48
+ - New simplified hyra configuration. An example of the full configuration is given [here](./examples/example_config.yaml).
49
+
50
+ **Note:** this introduces changes that are not backwards-compatible with previous versions.
51
+
52
+ ## Installation
53
+ Pre-requisities: Python 3.11, PyTorch and PyTorch Geometric compatible with your envirnment
54
+
55
+ ```bash
56
+ # For example
57
+ uv pip install torch==2.8.0 -f https://data.pyg.org/whl/torch-2.8.0+cu128.html
58
+ uv pip install torch-geometric==2.7.0 torch-cluster -f https://data.pyg.org/whl/torch-2.8.0+cu128.html
59
+ ```
60
+
61
+ ### Installation from PyPi
62
+
63
+ ```
64
+ pip install strain-relief
65
+ ```
66
+
67
+ ### Installation from source (uv)
68
+ ```bash
69
+ uv sync --extra dev --editable
70
+ ```
71
+ or create a virtual environment and install the package and its dependencies in editable mode:
72
+ ```bash
73
+ uv venv
74
+ source .venv/bin/activate
75
+ # [install torch and torch-geometric as above]
76
+ uv pip install -e ".[dev]"
77
+ uv pip install --force-reinstall e3nn==0.5 fairchem-core
78
+
79
+ uv run pre-commit install
80
+ ```
81
+ **Note:** `mace-torch==0.3.x` requires `e3nn==0.4.4` (only for training, not inference). `fairchem-core` requires `e3nn>=0.5`. So until `mace-torch==0.4` is released we will have to do this finicky way of installing ([GitHub issue](https://github.com/ACEsuit/mace/issues/555)).
82
+
83
+ ## The Protocol
84
+
85
+ The protocol used in StrainRelief is designed to be simple, fast and model agnostic - all that is needed to apply a new force field is to write a `neural-optimiser` `Calculator` class (such as an ASE calculator wrapper). Additionally, the package is already compatible with all MACE and Meta FAIRChem models.
86
+
87
+ ![Strain Relief Protocol](assets/strain_relief_protocol.png)
88
+
89
+ The protocol consists of 5 steps:
90
+
91
+ 1. Minimise the docked pose with a loose convergence criteria to give a local minimum.
92
+ 2. Generate 20 conformers from the docked ligand pose.
93
+ 3. Minimise the generated conformers (and the original docked pose) with a stricter convergence criteria.
94
+ 4. Evaluate the energy of all conformers and choose the lowest energy as an approximation of the global minimum.
95
+ 5. Calculate `E(ligand strain) = E(local minimum) - E(global minimum)` and apply threshold.
96
+
97
+ **N.B.** energies returned are in kcal/mol.
98
+
99
+ ## Usage
100
+
101
+ StrainRelief runs are configured using hydra configs.
102
+
103
+ ### Python Package
104
+
105
+ ```
106
+ from strain_relief import compute_strain
107
+
108
+ computed = compute_strain(poses: list[RDKit.Mol], config: DictConfig)
109
+
110
+ for i, r in computed.iterrows():
111
+ print(f"Pose {r['id']} has a strain of {r['ligand_strain']:.2f} kcal/mol")
112
+ ```
113
+ For a complete set of examples see the tutorial [notebook](./examples/tutorial.ipynb).
114
+
115
+ ### Command Line
116
+
117
+ ```bash
118
+ strain-relief \
119
+ experiment=mmff94 \
120
+ io.input.parquet_path=data/example_ligboundconf_input.parquet \
121
+ io.output.parquet_path=data/example_ligboundconf_output.parquet \
122
+ conformers.numConfs=1 \
123
+ ```
124
+
125
+ More examples are given [here](./examples/example_scripts.sh), including the command used for the calculations in the StrainRelief paper.
126
+
127
+ ### Adding Your Own Calculator
128
+
129
+ Add a new `Calculator` [class](https://github.com/erwallace/neural-optimiser/blob/main/src/neural_optimiser/calculators/base.py) from `neural-optimiser` to the `strain_relief/calculators/` directory. This can be as simple as implementing a wrapper around an existing ASE calculator:
130
+ ```python
131
+ from neural_optimiser.calculators.base import Calculator
132
+
133
+ class YourCalculator(Calculator):
134
+
135
+ def __init__(self, **kwargs):
136
+ self.calculator = YourASECalculator(**kwargs)
137
+
138
+ def _calculate(self, batch: Data | Batch) -> tuple[torch.Tensor, torch.Tensor]:
139
+ """Return (energies, forces) from the calculator."""
140
+ ase_atoms = batch.to_ase()
141
+ ase_atoms.calc = self.calculator
142
+ return ase_atoms.get_potential_energy(), ase_atoms.get_gradients()
143
+ ```
144
+ **Note:** `MACECalculator` and `FAIRChemCalculator` from `neural-optimiser` use a `from_atomic_data` helper method. This converts `ConformerBatch` objects to `AtomicData` model inputs in a batched process; a workflow bottleneck not handled by either the MACE or FAIRChem internal ASE calculators. I would recommend implementing something similar for high throughput workflows.
145
+
146
+ Add a new config to `hydra_config/calculator/your_calculator.yaml`:
147
+
148
+ ```
149
+ _target_: strain_relief.calculators.your_calculator.YourCalculator
150
+ model_paths: null
151
+ device: ${device}
152
+ any_other_kwargs: null
153
+ ```
154
+
155
+ ### Configurations
156
+
157
+ **Common kwargs**
158
+ - `threshold` (set by default to 16.1 kcal/mol - calibrated using [LigBoundConf 2.0](https://huggingface.co/datasets/erwallace/LigBoundConf2.0))
159
+ - `conformers.numConfs`
160
+ - `global_optimiser.steps`/`local_optimiser.steps`
161
+ - `global_optimiser.fmax`/`local_optimiser.fmax`
162
+ - `io.input.include_charged`
163
+ - `hydra.verbose`
164
+ - `seed`
165
+
166
+ ### Logging
167
+
168
+ Logging is set to the `INFO` level by default which logs only aggregate information. `hydra.verbose=true` can be used to activate `DEBUG` level logging which includes information for every molecule and conformer.
169
+
170
+ ## Unit Tests
171
+
172
+ - `uv run pytest tests/` - runs all tests (unit and integration)
173
+ - `uv run pytest tests/ -m "not integration"` - runs all unit tests
174
+
175
+ **Note:** Unit tests will run on a GPU if available.
176
+
177
+ ## Citations
178
+ If you use StrainRelief or adapt the StrainRelief code for any purpose, please cite:
179
+
180
+ ```bibtex
181
+ @article{wallace2025strain,
182
+ title={Strain Problems Got You in a Twist? Try StrainRelief: A Quantum-Accurate Tool for Ligand Strain Calculations},
183
+ author={Wallace, Ewan RS and Frey, Nathan C and Rackers, Joshua A},
184
+ journal={Journal of Chemical Information and Modeling},
185
+ year={2025},
186
+ publisher={ACS Publications},
187
+ url={https://pubs.acs.org/doi/10.1021/acs.jcim.5c00586}
188
+ }
189
+ ```
190
+
191
+ ## More information
192
+ For any questions, please reach out to [Ewan Wallace](https://www.linkedin.com/in/ewan-wallace-82297318a/): ewan.wallace@roche.com
@@ -0,0 +1,161 @@
1
+ # StrainRelief 💊
2
+ StrainRelief calculates the ligand strain of docked poses and has a suite of different force fields with which to do this. This includes our own MACE neural network potential trained on SPICE2 and also Meta's FAIRChem models, such as e-SEN and UMA. Optimisations are run in parallel using the neural-optimiser package.
3
+
4
+ - 📄 The publication can be found [here](https://pubs.acs.org/doi/10.1021/acs.jcim.5c00586).
5
+ - 📊 All relevant datasets [here](https://huggingface.co/datasets/erwallace/LigBoundConf2.0).
6
+ - 💬 RAG [chatbot](https://strain-relief.streamlit.app/) for questions about the paper and references.
7
+ - 💻 Chatbot source [code](https://github.com/erwallace/paper_query).
8
+ - 📉 neural-optimiser [package](https://github.com/erwallace/neural-optimiser).
9
+
10
+ ![Strain Relief Logo](assets/strain_relief_plus_logo.png)
11
+
12
+ ## Update 1.0.0
13
+
14
+ This update focuses on accelerating the StrainRelief backend and increasig usability through simpler configurations and workflows:
15
+
16
+ - Molecular optimisation are now paralellised using the `neural-optimiser` [package](https://github.com/erwallace/neural-optimiser) providing a 3x speed-up.
17
+ - New simplified hyra configuration. An example of the full configuration is given [here](./examples/example_config.yaml).
18
+
19
+ **Note:** this introduces changes that are not backwards-compatible with previous versions.
20
+
21
+ ## Installation
22
+ Pre-requisities: Python 3.11, PyTorch and PyTorch Geometric compatible with your envirnment
23
+
24
+ ```bash
25
+ # For example
26
+ uv pip install torch==2.8.0 -f https://data.pyg.org/whl/torch-2.8.0+cu128.html
27
+ uv pip install torch-geometric==2.7.0 torch-cluster -f https://data.pyg.org/whl/torch-2.8.0+cu128.html
28
+ ```
29
+
30
+ ### Installation from PyPi
31
+
32
+ ```
33
+ pip install strain-relief
34
+ ```
35
+
36
+ ### Installation from source (uv)
37
+ ```bash
38
+ uv sync --extra dev --editable
39
+ ```
40
+ or create a virtual environment and install the package and its dependencies in editable mode:
41
+ ```bash
42
+ uv venv
43
+ source .venv/bin/activate
44
+ # [install torch and torch-geometric as above]
45
+ uv pip install -e ".[dev]"
46
+ uv pip install --force-reinstall e3nn==0.5 fairchem-core
47
+
48
+ uv run pre-commit install
49
+ ```
50
+ **Note:** `mace-torch==0.3.x` requires `e3nn==0.4.4` (only for training, not inference). `fairchem-core` requires `e3nn>=0.5`. So until `mace-torch==0.4` is released we will have to do this finicky way of installing ([GitHub issue](https://github.com/ACEsuit/mace/issues/555)).
51
+
52
+ ## The Protocol
53
+
54
+ The protocol used in StrainRelief is designed to be simple, fast and model agnostic - all that is needed to apply a new force field is to write a `neural-optimiser` `Calculator` class (such as an ASE calculator wrapper). Additionally, the package is already compatible with all MACE and Meta FAIRChem models.
55
+
56
+ ![Strain Relief Protocol](assets/strain_relief_protocol.png)
57
+
58
+ The protocol consists of 5 steps:
59
+
60
+ 1. Minimise the docked pose with a loose convergence criteria to give a local minimum.
61
+ 2. Generate 20 conformers from the docked ligand pose.
62
+ 3. Minimise the generated conformers (and the original docked pose) with a stricter convergence criteria.
63
+ 4. Evaluate the energy of all conformers and choose the lowest energy as an approximation of the global minimum.
64
+ 5. Calculate `E(ligand strain) = E(local minimum) - E(global minimum)` and apply threshold.
65
+
66
+ **N.B.** energies returned are in kcal/mol.
67
+
68
+ ## Usage
69
+
70
+ StrainRelief runs are configured using hydra configs.
71
+
72
+ ### Python Package
73
+
74
+ ```
75
+ from strain_relief import compute_strain
76
+
77
+ computed = compute_strain(poses: list[RDKit.Mol], config: DictConfig)
78
+
79
+ for i, r in computed.iterrows():
80
+ print(f"Pose {r['id']} has a strain of {r['ligand_strain']:.2f} kcal/mol")
81
+ ```
82
+ For a complete set of examples see the tutorial [notebook](./examples/tutorial.ipynb).
83
+
84
+ ### Command Line
85
+
86
+ ```bash
87
+ strain-relief \
88
+ experiment=mmff94 \
89
+ io.input.parquet_path=data/example_ligboundconf_input.parquet \
90
+ io.output.parquet_path=data/example_ligboundconf_output.parquet \
91
+ conformers.numConfs=1 \
92
+ ```
93
+
94
+ More examples are given [here](./examples/example_scripts.sh), including the command used for the calculations in the StrainRelief paper.
95
+
96
+ ### Adding Your Own Calculator
97
+
98
+ Add a new `Calculator` [class](https://github.com/erwallace/neural-optimiser/blob/main/src/neural_optimiser/calculators/base.py) from `neural-optimiser` to the `strain_relief/calculators/` directory. This can be as simple as implementing a wrapper around an existing ASE calculator:
99
+ ```python
100
+ from neural_optimiser.calculators.base import Calculator
101
+
102
+ class YourCalculator(Calculator):
103
+
104
+ def __init__(self, **kwargs):
105
+ self.calculator = YourASECalculator(**kwargs)
106
+
107
+ def _calculate(self, batch: Data | Batch) -> tuple[torch.Tensor, torch.Tensor]:
108
+ """Return (energies, forces) from the calculator."""
109
+ ase_atoms = batch.to_ase()
110
+ ase_atoms.calc = self.calculator
111
+ return ase_atoms.get_potential_energy(), ase_atoms.get_gradients()
112
+ ```
113
+ **Note:** `MACECalculator` and `FAIRChemCalculator` from `neural-optimiser` use a `from_atomic_data` helper method. This converts `ConformerBatch` objects to `AtomicData` model inputs in a batched process; a workflow bottleneck not handled by either the MACE or FAIRChem internal ASE calculators. I would recommend implementing something similar for high throughput workflows.
114
+
115
+ Add a new config to `hydra_config/calculator/your_calculator.yaml`:
116
+
117
+ ```
118
+ _target_: strain_relief.calculators.your_calculator.YourCalculator
119
+ model_paths: null
120
+ device: ${device}
121
+ any_other_kwargs: null
122
+ ```
123
+
124
+ ### Configurations
125
+
126
+ **Common kwargs**
127
+ - `threshold` (set by default to 16.1 kcal/mol - calibrated using [LigBoundConf 2.0](https://huggingface.co/datasets/erwallace/LigBoundConf2.0))
128
+ - `conformers.numConfs`
129
+ - `global_optimiser.steps`/`local_optimiser.steps`
130
+ - `global_optimiser.fmax`/`local_optimiser.fmax`
131
+ - `io.input.include_charged`
132
+ - `hydra.verbose`
133
+ - `seed`
134
+
135
+ ### Logging
136
+
137
+ Logging is set to the `INFO` level by default which logs only aggregate information. `hydra.verbose=true` can be used to activate `DEBUG` level logging which includes information for every molecule and conformer.
138
+
139
+ ## Unit Tests
140
+
141
+ - `uv run pytest tests/` - runs all tests (unit and integration)
142
+ - `uv run pytest tests/ -m "not integration"` - runs all unit tests
143
+
144
+ **Note:** Unit tests will run on a GPU if available.
145
+
146
+ ## Citations
147
+ If you use StrainRelief or adapt the StrainRelief code for any purpose, please cite:
148
+
149
+ ```bibtex
150
+ @article{wallace2025strain,
151
+ title={Strain Problems Got You in a Twist? Try StrainRelief: A Quantum-Accurate Tool for Ligand Strain Calculations},
152
+ author={Wallace, Ewan RS and Frey, Nathan C and Rackers, Joshua A},
153
+ journal={Journal of Chemical Information and Modeling},
154
+ year={2025},
155
+ publisher={ACS Publications},
156
+ url={https://pubs.acs.org/doi/10.1021/acs.jcim.5c00586}
157
+ }
158
+ ```
159
+
160
+ ## More information
161
+ For any questions, please reach out to [Ewan Wallace](https://www.linkedin.com/in/ewan-wallace-82297318a/): ewan.wallace@roche.com
@@ -0,0 +1,44 @@
1
+ seed: -1
2
+ threshold: 16.1
3
+ num_workers: 0
4
+ device: cpu
5
+ batch_size: 1
6
+
7
+ io:
8
+ input:
9
+ parquet_path: data/example_ligboundconf_input.parquet
10
+ mol_col_name: null
11
+ id_col_name: null
12
+ include_charged: true
13
+ output:
14
+ parquet_path: null
15
+ mol_col_name: ${..input.mol_col_name}
16
+ id_col_name: ${..input.id_col_name}
17
+ molecule_attr: ${..input.id_col_name}
18
+
19
+ conformers:
20
+ randomSeed: ${seed}
21
+ numConfs: 1
22
+ maxAttempts: 10
23
+ pruneRmsThresh: 0.1
24
+ clearConfs: false
25
+ numThreads: ${num_workers}
26
+
27
+ calculator:
28
+ _target_: neural_optimiser.calculators.MACECalculator
29
+ model_paths: models/MACE_SPICE2_NEUTRAL.model
30
+ device: ${device}
31
+
32
+ local_optimiser:
33
+ _target_: neural_optimiser.optimisers.BFGS
34
+ max_step: 0.04
35
+ steps: 250
36
+ fmax: 0.5
37
+ fexit: 10
38
+
39
+ global_optimiser:
40
+ _target_: neural_optimiser.optimisers.BFGS
41
+ max_step: 0.04
42
+ steps: 250
43
+ fmax: 0.05
44
+ fexit: 50
@@ -0,0 +1,54 @@
1
+ #!/bin/bash
2
+
3
+ #SBATCH -J strain
4
+ #SBATCH -o example_script-%j.out
5
+ #SBATCH -p gpu2
6
+ #SBATCH --gpus-per-node 1
7
+ #SBATCH --mem 10GB
8
+
9
+ # scripts should be run from the StrainRelief root directory
10
+
11
+ source ~/StrainRelief/.venv/bin/activate # with uv
12
+ # mamba activate strain # with conda/mamba
13
+
14
+ # You must choose a minimisation and energy evaluation method from "mmff94",
15
+ # "mmff94s", "mace" or "fairchem". The calculator works best when the same
16
+ # force field is used for both methods. If this is the case, "energy_eval"
17
+ # does not need to be specified.
18
+
19
+ # This is the simplest and fastest implementation of StrainRelief using MMFF94s
20
+ # and a minimial example dataset.
21
+ strain-relief \
22
+ io.input.parquet_path=./data/example_ligboundconf_input.parquet \
23
+ io.output.parquet_path=./data/example_ligboundconf_output.parquet \
24
+ optimiser@local_optimiser=bfgs \
25
+ optimiser@global_optimiser=bfgs \
26
+ calculator=mmff94 \
27
+ batch_size=1 \
28
+ device=cpu
29
+
30
+ # This script demonstrates using different force fields for minimisation
31
+ # (MMFF94s) and energy evaluations (MACE).
32
+ strain-relief \
33
+ io.input.parquet_path=./data/example_ligboundconf_input.parquet \
34
+ io.output.parquet_path=./data/example_ligboundconf_output.parquet \
35
+ optimiser@local_optimiser=bfgs \
36
+ optimiser@global_optimiser=bfgs \
37
+ calculator=mmff94 \
38
+ +calculator@energy_evaluation.calculator=mace \
39
+ +energy_evaluation.calculator.model_paths=./tests/models/MACE.model \
40
+ batch_size=1 \
41
+ device=cpu
42
+
43
+ # This is the script as used for most calculations in the StrainRelief paper.
44
+ # MACE is used for minimisation (and energy evalutions implicitly). A looser
45
+ # convergence criteria is used for local minimisation.
46
+ strain-relief \
47
+ io.input.parquet_path=../data/example_ligboundconf_input.parquet \
48
+ io.output.parquet_path=../data/example_ligboundconf_output.parquet \
49
+ optimiser@local_optimiser=bfgs \
50
+ optimiser@global_optimiser=bfgs \
51
+ calculator=mace \
52
+ calculator.model_paths=./tests/models/MACE.model \
53
+ hydra.verbose=true \
54
+ device=cuda