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.
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/.gitignore +2 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/.pre-commit-config.yaml +1 -5
- strain_relief-1.0.dev0/.vscode/launch.json +68 -0
- strain_relief-1.0.dev0/PKG-INFO +192 -0
- strain_relief-1.0.dev0/README.md +161 -0
- strain_relief-1.0.dev0/assets/strain_relief_plus_logo.png +0 -0
- strain_relief-1.0.dev0/examples/example_config.yaml +44 -0
- strain_relief-1.0.dev0/examples/example_scripts.sh +54 -0
- strain_relief-1.0.dev0/examples/tutorial.ipynb +1495 -0
- strain_relief-1.0.dev0/hydra_config/calculator/fairchem.yaml +4 -0
- strain_relief-1.0.dev0/hydra_config/calculator/mace.yaml +4 -0
- strain_relief-1.0.dev0/hydra_config/calculator/mmff94.yaml +1 -0
- {strain_relief-0.4.dev0/src/strain_relief → strain_relief-1.0.dev0}/hydra_config/conformers/default.yaml +1 -1
- strain_relief-1.0.dev0/hydra_config/default.yaml +22 -0
- strain_relief-1.0.dev0/hydra_config/experiment/fairchem.yaml +23 -0
- strain_relief-1.0.dev0/hydra_config/experiment/mace.yaml +23 -0
- strain_relief-1.0.dev0/hydra_config/experiment/mmff94.yaml +20 -0
- strain_relief-1.0.dev0/hydra_config/experiment/pytest.yaml +18 -0
- {strain_relief-0.4.dev0/src/strain_relief → strain_relief-1.0.dev0}/hydra_config/io/default.yaml +4 -1
- strain_relief-1.0.dev0/hydra_config/optimiser/bfgs.yaml +5 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/pyproject.toml +40 -20
- strain_relief-1.0.dev0/setup.sh +28 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/__init__.py +10 -0
- strain_relief-1.0.dev0/src/strain_relief/cmdline/_strain_relief.py +17 -0
- strain_relief-1.0.dev0/src/strain_relief/compute_strain.py +213 -0
- strain_relief-1.0.dev0/src/strain_relief/configs/__init__.py +3 -0
- strain_relief-1.0.dev0/src/strain_relief/configs/_configs.py +101 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/conformers/_rdkit_generation.py +23 -15
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/constants/__init__.py +8 -2
- strain_relief-1.0.dev0/src/strain_relief/constants/_str.py +9 -0
- strain_relief-1.0.dev0/src/strain_relief/constants/_units.py +19 -0
- strain_relief-1.0.dev0/src/strain_relief/data_types/__init__.py +9 -0
- strain_relief-1.0.dev0/src/strain_relief/data_types/_types.py +21 -0
- strain_relief-1.0.dev0/src/strain_relief/io/__init__.py +8 -0
- strain_relief-1.0.dev0/src/strain_relief/io/_input.py +210 -0
- strain_relief-1.0.dev0/src/strain_relief/io/_output.py +222 -0
- strain_relief-1.0.dev0/src/strain_relief/optimisation/__init__.py +3 -0
- strain_relief-1.0.dev0/src/strain_relief/optimisation/_optimisation.py +102 -0
- strain_relief-1.0.dev0/src/strain_relief.egg-info/SOURCES.txt +71 -0
- strain_relief-1.0.dev0/tests/cmdline/test_strain_relief.py +41 -0
- strain_relief-1.0.dev0/tests/configs/test_configs.py +256 -0
- strain_relief-1.0.dev0/tests/conformers/test_rdkit_generation.py +34 -0
- strain_relief-1.0.dev0/tests/conftest.py +135 -0
- strain_relief-1.0.dev0/tests/constants/test_str.py +20 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/constants/test_units.py +1 -0
- strain_relief-1.0.dev0/tests/data/all_charged.parquet +0 -0
- strain_relief-1.0.dev0/tests/data/ligboundconf.parquet +0 -0
- strain_relief-1.0.dev0/tests/io/test_input.py +103 -0
- strain_relief-1.0.dev0/tests/io/test_output.py +52 -0
- strain_relief-1.0.dev0/tests/optimisation/test_optimisation.py +27 -0
- strain_relief-1.0.dev0/tests/test_compute_strain.py +80 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/test_init.py +1 -0
- strain_relief-1.0.dev0/uv.lock +2019 -0
- strain_relief-0.4.dev0/Dockerfile-strain-relief +0 -140
- strain_relief-0.4.dev0/PKG-INFO +0 -188
- strain_relief-0.4.dev0/README.md +0 -159
- strain_relief-0.4.dev0/assets/strain_relief_logo.png +0 -0
- strain_relief-0.4.dev0/ci.yml +0 -85
- strain_relief-0.4.dev0/env.yml +0 -9
- strain_relief-0.4.dev0/examples/example_script.sh +0 -17
- strain_relief-0.4.dev0/examples/examples.sh +0 -37
- strain_relief-0.4.dev0/examples/tutorial.ipynb +0 -250
- strain_relief-0.4.dev0/requirements-dev.in +0 -5
- strain_relief-0.4.dev0/requirements.in +0 -11
- strain_relief-0.4.dev0/src/strain_relief/calculators/__init__.py +0 -11
- strain_relief-0.4.dev0/src/strain_relief/calculators/_mmff94.py +0 -77
- strain_relief-0.4.dev0/src/strain_relief/calculators/_nnp.py +0 -44
- strain_relief-0.4.dev0/src/strain_relief/cmdline/_strain_relief.py +0 -94
- strain_relief-0.4.dev0/src/strain_relief/constants/_str.py +0 -4
- strain_relief-0.4.dev0/src/strain_relief/constants/_units.py +0 -19
- strain_relief-0.4.dev0/src/strain_relief/energy_eval/__init__.py +0 -10
- strain_relief-0.4.dev0/src/strain_relief/energy_eval/_energy_eval.py +0 -61
- strain_relief-0.4.dev0/src/strain_relief/energy_eval/_mmff94.py +0 -81
- strain_relief-0.4.dev0/src/strain_relief/energy_eval/_nnp.py +0 -115
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/default.yaml +0 -13
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/default.yaml +0 -1
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/fairchem.yaml +0 -5
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/mace.yaml +0 -5
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/mmff94.yaml +0 -4
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/energy_eval/mmff94s.yaml +0 -4
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/experiment/fairchem.yaml +0 -19
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/experiment/mace.yaml +0 -19
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/experiment/mmff94s.yaml +0 -11
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/fairchem.yaml +0 -8
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/mace.yaml +0 -8
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/mmff94.yaml +0 -7
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/minimisation/mmff94s.yaml +0 -7
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/model/fairchem.yaml +0 -6
- strain_relief-0.4.dev0/src/strain_relief/hydra_config/model/mace.yaml +0 -6
- strain_relief-0.4.dev0/src/strain_relief/io/__init__.py +0 -10
- strain_relief-0.4.dev0/src/strain_relief/io/_io.py +0 -272
- strain_relief-0.4.dev0/src/strain_relief/io/utils_mol_format.py +0 -52
- strain_relief-0.4.dev0/src/strain_relief/minimisation/__init__.py +0 -12
- strain_relief-0.4.dev0/src/strain_relief/minimisation/_minimisation.py +0 -59
- strain_relief-0.4.dev0/src/strain_relief/minimisation/_mmff94.py +0 -51
- strain_relief-0.4.dev0/src/strain_relief/minimisation/_nnp.py +0 -79
- strain_relief-0.4.dev0/src/strain_relief/minimisation/utils_bfgs.py +0 -145
- strain_relief-0.4.dev0/src/strain_relief/minimisation/utils_minimisation.py +0 -177
- strain_relief-0.4.dev0/src/strain_relief.egg-info/SOURCES.txt +0 -94
- strain_relief-0.4.dev0/tests/calculators/test_mmff94.py +0 -36
- strain_relief-0.4.dev0/tests/cmdline/test_strain_relief.py +0 -111
- strain_relief-0.4.dev0/tests/conformers/test_rdkit_generation.py +0 -31
- strain_relief-0.4.dev0/tests/conftest.py +0 -130
- strain_relief-0.4.dev0/tests/constants/test_str.py +0 -11
- strain_relief-0.4.dev0/tests/data/all_charged.parquet +0 -0
- strain_relief-0.4.dev0/tests/data/ligboundconf.parquet +0 -0
- strain_relief-0.4.dev0/tests/data/water.xyz +0 -5
- strain_relief-0.4.dev0/tests/energy_eval/test_energy_eval.py +0 -72
- strain_relief-0.4.dev0/tests/energy_eval/test_mmff94.py +0 -34
- strain_relief-0.4.dev0/tests/energy_eval/test_nnp.py +0 -89
- strain_relief-0.4.dev0/tests/io/test_io.py +0 -47
- strain_relief-0.4.dev0/tests/io/test_utils_mol_format.py +0 -60
- strain_relief-0.4.dev0/tests/minimisation/_init__.py +0 -0
- strain_relief-0.4.dev0/tests/minimisation/test_minimisation.py +0 -50
- strain_relief-0.4.dev0/tests/minimisation/test_mmff94.py +0 -22
- strain_relief-0.4.dev0/tests/minimisation/test_nnp.py +0 -30
- strain_relief-0.4.dev0/tests/minimisation/test_utils_bfgs.py +0 -6
- strain_relief-0.4.dev0/tests/minimisation/test_utils_minimisation.py +0 -119
- strain_relief-0.4.dev0/uv.lock +0 -1468
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/LICENSE +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/MANIFEST.in +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/assets/strain_relief_protocol.png +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/data/example_ligboundconf.sdf +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/data/example_ligboundconf_input.parquet +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/examples/mace_training_script.sh +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/models/MACE_SPICE2_NEUTRAL.model +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/setup.cfg +0 -0
- /strain_relief-0.4.dev0/src/strain_relief/hydra_config/__init__.py → /strain_relief-1.0.dev0/src/strain_relief/calculators/.gitkeep +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/cmdline/__init__.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/conformers/__init__.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/src/strain_relief/io/utils_s3.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/__init__.py +0 -0
- {strain_relief-0.4.dev0/tests/calculators → strain_relief-1.0.dev0/tests/cmdline}/__init__.py +0 -0
- {strain_relief-0.4.dev0/tests/cmdline → strain_relief-1.0.dev0/tests/configs}/__init__.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/conformers/__init__.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/constants/__init__.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/data/target.parquet +0 -0
- {strain_relief-0.4.dev0/tests/energy_eval → strain_relief-1.0.dev0/tests/io}/__init__.py +0 -0
- {strain_relief-0.4.dev0 → strain_relief-1.0.dev0}/tests/models/MACE.model +0 -0
- {strain_relief-0.4.dev0/tests/io → strain_relief-1.0.dev0/tests/optimisation}/__init__.py +0 -0
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
repos:
|
|
2
2
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
-
rev:
|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
+

|
|
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
|
|
Binary file
|
|
@@ -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
|