forcefill 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- forcefill-1.0.0/CHANGELOG.md +85 -0
- forcefill-1.0.0/LICENSE +21 -0
- forcefill-1.0.0/MANIFEST.in +19 -0
- forcefill-1.0.0/PKG-INFO +208 -0
- forcefill-1.0.0/README.md +169 -0
- forcefill-1.0.0/forcefill/__init__.py +88 -0
- forcefill-1.0.0/forcefill/_pipeline.py +440 -0
- forcefill-1.0.0/forcefill/_residue_names.py +344 -0
- forcefill-1.0.0/forcefill/_spec.py +449 -0
- forcefill-1.0.0/forcefill/amber.py +280 -0
- forcefill-1.0.0/forcefill/charmm.py +371 -0
- forcefill-1.0.0/forcefill/checks.py +463 -0
- forcefill-1.0.0/forcefill/clean_structure.py +428 -0
- forcefill-1.0.0/forcefill/espaloma.py +178 -0
- forcefill-1.0.0/forcefill/ligand.py +315 -0
- forcefill-1.0.0/forcefill/ligand_files.py +632 -0
- forcefill-1.0.0/forcefill/merge.py +164 -0
- forcefill-1.0.0/forcefill/preflight.py +205 -0
- forcefill-1.0.0/forcefill/py.typed +0 -0
- forcefill-1.0.0/forcefill/smirnoff.py +480 -0
- forcefill-1.0.0/forcefill/structure.py +368 -0
- forcefill-1.0.0/forcefill/topology.py +223 -0
- forcefill-1.0.0/forcefill.egg-info/PKG-INFO +208 -0
- forcefill-1.0.0/forcefill.egg-info/SOURCES.txt +27 -0
- forcefill-1.0.0/forcefill.egg-info/dependency_links.txt +1 -0
- forcefill-1.0.0/forcefill.egg-info/requires.txt +13 -0
- forcefill-1.0.0/forcefill.egg-info/top_level.txt +1 -0
- forcefill-1.0.0/pyproject.toml +155 -0
- forcefill-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to forcefill are recorded here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the version numbers
|
|
5
|
+
follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html): the public API
|
|
6
|
+
is everything exported from `forcefill/__init__.py`, so a breaking change to any
|
|
7
|
+
of it requires a major bump.
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [1.0.0] - 2026-09-18
|
|
12
|
+
|
|
13
|
+
First release. The API below is now covered by the compatibility promise above.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **`build_forcefield_xml(pdb_file, output_xml, ...)`** — takes a PDB, finds
|
|
18
|
+
every residue the base force field has no template for
|
|
19
|
+
(`ForceField.getUnmatchedResidues`), parameterizes the ones a stand-alone
|
|
20
|
+
small-molecule treatment is valid for, and writes one OpenMM ffxml you load
|
|
21
|
+
alongside the standard force fields. Returns a `ParameterizationResult`
|
|
22
|
+
carrying the per-residue XMLs, the skipped residues with their reasons, and
|
|
23
|
+
the working directory.
|
|
24
|
+
- **`build_ligand_xml(ligands, output_xml, ...)`** — the same pipeline for
|
|
25
|
+
ligands with no structure at all, from SDF, MOL2, SMILES or a `LigandSpec`,
|
|
26
|
+
singly or as a batch.
|
|
27
|
+
- **Four backends**, selected with `backend=` globally or per ligand:
|
|
28
|
+
- `"gaff"` (default) — `antechamber` GAFF2 atom types with AM1-BCC charges,
|
|
29
|
+
plus `parmchk2` for the missing parameters.
|
|
30
|
+
- `"smirnoff"` — OpenFF, default `openff-2.2.1`, through
|
|
31
|
+
`openmmforcefields`. Accepts a released force field by name, a local
|
|
32
|
+
OFFXML, or a layered list of both.
|
|
33
|
+
- `"espaloma"` — the Espaloma graph network, default `espaloma-0.3.2`.
|
|
34
|
+
Optional dependency; it pulls in PyTorch.
|
|
35
|
+
- `"charmm"` — converts the CGenFF stream file ParamChem returns, against
|
|
36
|
+
`CHARMM_BASE_FORCEFIELD`. Handles the LJ conversion that ParmEd's own
|
|
37
|
+
CHARMM writer gets wrong.
|
|
38
|
+
Backends may be mixed across residues in one run; the resulting XMLs merge
|
|
39
|
+
into a single loadable file.
|
|
40
|
+
- **`LigandSpec`** — per-ligand settings (input file or SMILES, net charge,
|
|
41
|
+
multiplicity, backend, force field, CHARMM files, atom type, charge method,
|
|
42
|
+
extra `antechamber` arguments), overriding the run-wide defaults.
|
|
43
|
+
- **BespokeFit support** — a BespokeFit OFFXML is accepted wherever a SMIRNOFF
|
|
44
|
+
force field is, with checks that the fit actually belongs to the molecule it
|
|
45
|
+
is being applied to, so bought QC is not silently applied to the wrong ligand.
|
|
46
|
+
- **Preflight checks**, before anything expensive: the net charge is read from
|
|
47
|
+
the ligand file, a supplied file is confirmed to be the same molecule as the
|
|
48
|
+
residue it stands in for, and the geometry is screened for the faults that
|
|
49
|
+
produce NaN energies.
|
|
50
|
+
- **Post-parameterization validation** — an `openmm.System` is built from
|
|
51
|
+
`base force field + new XML` for every parameterized residue on its own, and
|
|
52
|
+
for the whole input when nothing was skipped, so a template that does not
|
|
53
|
+
match its residue fails at build time instead of at simulation time.
|
|
54
|
+
`minimize=True` additionally catches parameters that are unphysical rather
|
|
55
|
+
than merely absent. `validate_forcefield_xml`, `minimize_with_forcefield_xml`
|
|
56
|
+
and `add_extra_particles` are public for use on their own.
|
|
57
|
+
- **`clean_pdb` / `clean_topology`** — drop water, bulk buffer ions and
|
|
58
|
+
crystallization additives while keeping structural metals, either as a
|
|
59
|
+
pre-step (`clean_structure=True`) or on their own. The residue sets
|
|
60
|
+
(`WATER_RESIDUES`, `BULK_ION_RESIDUES`, `ADDITIVE_RESIDUES`,
|
|
61
|
+
`STRUCTURAL_METAL_RESIDUES`) are public and inspectable.
|
|
62
|
+
- **Refusal with a reason** — chemistry a stand-alone treatment is not valid
|
|
63
|
+
for (covalently bound residues, monatomic species, polymer fragments) is
|
|
64
|
+
skipped and reported in `result.skipped`, rather than silently given wrong
|
|
65
|
+
parameters.
|
|
66
|
+
- **Supporting public API** — `merge_ffxml`, `find_nonstandard_residues`,
|
|
67
|
+
`extract_residue_to_pdb`, `assemble_openmm_ffxml`, `run_antechamber`,
|
|
68
|
+
`run_parmchk2`, `locate_gaff_dat`, `residue_templates_with_virtual_sites`,
|
|
69
|
+
and the `DEFAULT_*` constants.
|
|
70
|
+
- **Typing** — the package is fully annotated and ships a PEP 561 `py.typed`
|
|
71
|
+
marker, so annotations are visible to type checkers in consuming projects.
|
|
72
|
+
- **Documentation** at [forcefill.readthedocs.io](https://forcefill.readthedocs.io),
|
|
73
|
+
covering installation, a quickstart, the four backends, CHARMM/CGenFF,
|
|
74
|
+
BespokeFit, cleaning, what gets skipped and why, and an API reference.
|
|
75
|
+
|
|
76
|
+
### Known limitations
|
|
77
|
+
|
|
78
|
+
- Covalently bound ligands are skipped deliberately: a stand-alone treatment of
|
|
79
|
+
a polymer-linked residue is wrong whichever backend produces it.
|
|
80
|
+
- There is no command-line interface yet.
|
|
81
|
+
- Re-running into an existing working directory repeats finished `antechamber`
|
|
82
|
+
jobs; nothing is cached between runs.
|
|
83
|
+
|
|
84
|
+
[Unreleased]: https://github.com/LouieSlocombe/forcefill/compare/v1.0.0...HEAD
|
|
85
|
+
[1.0.0]: https://github.com/LouieSlocombe/forcefill/releases/tag/v1.0.0
|
forcefill-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Louie Slocombe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# What goes into the sdist beyond the package itself. The wheel is unaffected —
|
|
2
|
+
# that is [tool.setuptools.package-data] in pyproject.toml.
|
|
3
|
+
#
|
|
4
|
+
# Without this file setuptools falls back to a distutils default that picks up
|
|
5
|
+
# `tests/test_*.py` and nothing else, which ships a suite that cannot even be
|
|
6
|
+
# collected: conftest.py, helpers.py, tests/data/ and the examples/data/ fixtures
|
|
7
|
+
# two of the tests read are all missing. Ship it whole or not at all — and not at
|
|
8
|
+
# all is right here, because the suite cannot run from an sdist install in any
|
|
9
|
+
# case: it needs AmberTools, which is not a Python package, and
|
|
10
|
+
# openmmforcefields >= 0.16, which does not exist on PyPI. Run it from a checkout
|
|
11
|
+
# (see docs/contributing.md).
|
|
12
|
+
prune tests
|
|
13
|
+
|
|
14
|
+
include CHANGELOG.md
|
|
15
|
+
|
|
16
|
+
# Never useful to a consumer.
|
|
17
|
+
global-exclude *.py[cod]
|
|
18
|
+
global-exclude .DS_Store
|
|
19
|
+
prune **/__pycache__
|
forcefill-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: forcefill
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Parameterize non-standard PDB residues (ligands, cofactors) into OpenMM force-field XML with AmberTools GAFF/AM1-BCC, OpenFF Sage or CHARMM CGenFF
|
|
5
|
+
Author-email: Louie Slocombe <louies@hotmail.co.uk>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/LouieSlocombe/forcefill
|
|
8
|
+
Project-URL: Repository, https://github.com/LouieSlocombe/forcefill
|
|
9
|
+
Project-URL: Documentation, https://forcefill.readthedocs.io
|
|
10
|
+
Project-URL: Changelog, https://github.com/LouieSlocombe/forcefill/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issues, https://github.com/LouieSlocombe/forcefill/issues
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Intended Audience :: Science/Research
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: openmm>=7.6
|
|
28
|
+
Requires-Dist: parmed>=3.4
|
|
29
|
+
Requires-Dist: rdkit
|
|
30
|
+
Requires-Dist: openff-toolkit>=0.16
|
|
31
|
+
Requires-Dist: openmmforcefields>=0.16
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest; extra == "test"
|
|
34
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: ruff==0.16.2; extra == "dev"
|
|
37
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# forcefill
|
|
41
|
+
|
|
42
|
+
[](https://github.com/LouieSlocombe/forcefill/actions/workflows/ci.yml)
|
|
43
|
+
[](https://forcefill.readthedocs.io/en/latest/)
|
|
44
|
+
[](https://pypi.org/project/forcefill/)
|
|
45
|
+
[](https://pypi.org/project/forcefill/)
|
|
46
|
+
|
|
47
|
+
Turn ligands into a ready-to-use [OpenMM](https://openmm.org) force-field XML —
|
|
48
|
+
either the non-standard residues (ligands, cofactors, hetero molecules) found in
|
|
49
|
+
a PDB, or ligand files on their own. Parameters come from AmberTools
|
|
50
|
+
(`antechamber` + `parmchk2`) via [ParmEd](https://github.com/ParmEd/ParmEd),
|
|
51
|
+
from [OpenFF](https://openforcefield.org) Sage or
|
|
52
|
+
[Espaloma](https://github.com/choderalab/espaloma) via
|
|
53
|
+
[openmmforcefields](https://github.com/openmm/openmmforcefields), or — for
|
|
54
|
+
CHARMM — by converting the CGenFF stream file
|
|
55
|
+
[ParamChem](https://cgenff.paramchem.org) gave you.
|
|
56
|
+
|
|
57
|
+
The output is a plain ffxml file you load alongside the standard force fields:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
ff = ForceField("amber14-all.xml", "amber14/tip3p.xml", "extras.xml")
|
|
61
|
+
system = ff.createSystem(pdb.topology)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Two ways in, depending on whether you have a structure:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from forcefill import build_forcefield_xml, build_ligand_xml
|
|
68
|
+
|
|
69
|
+
# A complex: find what amber14 cannot match and parameterize it
|
|
70
|
+
build_forcefield_xml("complex.pdb", "extras.xml")
|
|
71
|
+
|
|
72
|
+
# Just the ligand, no structure anywhere
|
|
73
|
+
build_ligand_xml("benzamidinium.sdf", "ben.xml")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## What it does
|
|
77
|
+
|
|
78
|
+
1. **Identify** — `ForceField.getUnmatchedResidues` finds every residue the
|
|
79
|
+
base force field (default: `amber14-all.xml` + `amber14/tip3p.xml`) has no
|
|
80
|
+
template for.
|
|
81
|
+
2. **Classify** — only chemistry a stand-alone GAFF treatment is actually
|
|
82
|
+
*valid* for gets parameterized; see
|
|
83
|
+
[What gets skipped, and why](https://forcefill.readthedocs.io/en/latest/guide/what-gets-parameterized.html).
|
|
84
|
+
3. **Check** — before anything expensive: the net charge is read from the ligand
|
|
85
|
+
file, a supplied file is confirmed to be the same molecule as the residue, and
|
|
86
|
+
the geometry is checked for the faults that produce NaN energies.
|
|
87
|
+
4. **Parameterize** — each unique residue through `antechamber` (GAFF2 atom
|
|
88
|
+
types, AM1-BCC charges → `.mol2`) and `parmchk2` (missing parameters →
|
|
89
|
+
`.frcmod`), through OpenFF with `backend="smirnoff"`, through the Espaloma
|
|
90
|
+
graph network with `backend="espaloma"`, or from a CGenFF stream file with
|
|
91
|
+
`backend="charmm"`.
|
|
92
|
+
5. **Assemble** — one XML per residue, plus one combined XML.
|
|
93
|
+
6. **Validate** — an `openmm.System` is built from `base force field + new XML`
|
|
94
|
+
for every parameterized residue on its own (and for the whole input when
|
|
95
|
+
nothing was skipped), so a template that does not match its residue fails
|
|
96
|
+
loudly here instead of at simulation time. `minimize=True` additionally
|
|
97
|
+
catches parameters that are unphysical rather than merely absent (see
|
|
98
|
+
[Checks](https://forcefill.readthedocs.io/en/latest/guide/checks.html)).
|
|
99
|
+
|
|
100
|
+
## Documentation
|
|
101
|
+
|
|
102
|
+
Full documentation is at **[forcefill.readthedocs.io](https://forcefill.readthedocs.io/en/latest/)**:
|
|
103
|
+
|
|
104
|
+
| | |
|
|
105
|
+
|---|---|
|
|
106
|
+
| [Installation](https://forcefill.readthedocs.io/en/latest/installation.html) | conda-forge, and the two dependencies that are not ordinary ones |
|
|
107
|
+
| [Quickstart](https://forcefill.readthedocs.io/en/latest/quickstart.html) | a complex in, an ffxml out, and simulating with it |
|
|
108
|
+
| [What gets skipped, and why](https://forcefill.readthedocs.io/en/latest/guide/what-gets-parameterized.html) | the residues forcefill refuses, and what to do instead |
|
|
109
|
+
| [Cleaning the structure](https://forcefill.readthedocs.io/en/latest/guide/cleaning.html) | water, buffer ions and crystallization additives — and the metals it keeps |
|
|
110
|
+
| [Ligand input](https://forcefill.readthedocs.io/en/latest/guide/ligands.html) | SDF, MOL2 or SMILES; `LigandSpec`; ligands with no structure at all |
|
|
111
|
+
| [Four backends](https://forcefill.readthedocs.io/en/latest/guide/backends.html) | GAFF, OpenFF Sage, Espaloma, CGenFF — and which mix |
|
|
112
|
+
| [CHARMM and CGenFF](https://forcefill.readthedocs.io/en/latest/guide/charmm.html) | converting a ParamChem stream file, and the three ways doing it by hand goes wrong |
|
|
113
|
+
| [Bespoke torsions](https://forcefill.readthedocs.io/en/latest/guide/bespokefit.html) | a BespokeFit OFFXML, and the checks that protect the QC you paid for |
|
|
114
|
+
| [Checks](https://forcefill.readthedocs.io/en/latest/guide/checks.html) | what runs before the expensive step, and what runs after |
|
|
115
|
+
| [Things to get right](https://forcefill.readthedocs.io/en/latest/guide/gotchas.html) | explicit hydrogens, net charge, virtual sites, the periodic box |
|
|
116
|
+
| [Relation to `openmmforcefields`](https://forcefill.readthedocs.io/en/latest/guide/openmmforcefields.html) | which template generators forcefill uses, and why not `GAFFTemplateGenerator` |
|
|
117
|
+
| [API reference](https://forcefill.readthedocs.io/en/latest/api/index.html) | every public function, class and constant |
|
|
118
|
+
|
|
119
|
+
## Installation
|
|
120
|
+
|
|
121
|
+
AmberTools is conda-only, so conda-forge is the recommended route:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
conda env create -f environment.yml
|
|
125
|
+
conda activate forcefill
|
|
126
|
+
pip install -e . --no-deps
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Or into an existing environment:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
conda install -c conda-forge openmm parmed ambertools
|
|
133
|
+
pip install forcefill
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Requires Python ≥ 3.10. Two things are not ordinary dependencies: AmberTools is
|
|
137
|
+
not a Python package (the `antechamber` and `parmchk2` executables must be on
|
|
138
|
+
`PATH` for the `gaff` backend), and `espaloma` is optional because it pulls in
|
|
139
|
+
PyTorch. The full list, and the reason the `openmmforcefields` floor is 0.16, is
|
|
140
|
+
in [the installation guide](https://forcefill.readthedocs.io/en/latest/installation.html).
|
|
141
|
+
|
|
142
|
+
## Quickstart
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from forcefill import build_forcefield_xml
|
|
146
|
+
|
|
147
|
+
result = build_forcefield_xml(
|
|
148
|
+
"complex.pdb",
|
|
149
|
+
"extras.xml",
|
|
150
|
+
net_charges={"LIG": -1}, # essential for sensible AM1-BCC charges
|
|
151
|
+
clean_structure=True, # drop water, buffer ions and crystallization additives
|
|
152
|
+
)
|
|
153
|
+
print(result.parameterized) # ['LIG']
|
|
154
|
+
print(result.skipped) # {'ZN': 'monatomic species - ...'}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
then simulate with:
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
from openmm import app
|
|
161
|
+
|
|
162
|
+
pdb = app.PDBFile("complex.pdb")
|
|
163
|
+
ff = app.ForceField("amber14-all.xml", "amber14/tip3p.xml", "extras.xml")
|
|
164
|
+
system = ff.createSystem(pdb.topology)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`result` also reports the per-residue XML files (`result.residue_xmls`), the
|
|
168
|
+
skip reasons (`result.skipped`), and the directory holding every intermediate
|
|
169
|
+
file (`result.workdir`) for inspection — pass `cleanup=True` to remove it on
|
|
170
|
+
success.
|
|
171
|
+
|
|
172
|
+
More, including per-ligand settings and the other three backends, in
|
|
173
|
+
[the guide](https://forcefill.readthedocs.io/en/latest/guide/index.html).
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
conda env create -f environment.yml && conda activate forcefill
|
|
179
|
+
pip install -e . --no-deps
|
|
180
|
+
pytest -m "not integration and not smirnoff" # fast hermetic tests only
|
|
181
|
+
pytest # everything, including real antechamber and OpenFF
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Style is enforced by ruff (`pip install -e '.[dev]' && pre-commit install`).
|
|
185
|
+
|
|
186
|
+
The docs build is pip-only and separate from the conda environment — see
|
|
187
|
+
[Contributing](https://forcefill.readthedocs.io/en/latest/contributing.html),
|
|
188
|
+
which also has the release process.
|
|
189
|
+
|
|
190
|
+
## Changelog
|
|
191
|
+
|
|
192
|
+
Every release is described in [CHANGELOG.md](CHANGELOG.md). The public API is
|
|
193
|
+
everything exported from `forcefill/__init__.py`, and it follows semantic
|
|
194
|
+
versioning from 1.0.0 on.
|
|
195
|
+
|
|
196
|
+
## Roadmap
|
|
197
|
+
|
|
198
|
+
- A `forcefill` command-line interface — `build_ligand_xml` is the shape one
|
|
199
|
+
wants.
|
|
200
|
+
- Caching, so re-runs into the same workdir skip finished antechamber jobs —
|
|
201
|
+
and finished SMIRNOFF/Espaloma templates, which openmmforcefields' own
|
|
202
|
+
`cache=` cannot help with on the code path forcefill uses.
|
|
203
|
+
- Covalently bound ligands. Still skipped, and deliberately: a stand-alone
|
|
204
|
+
treatment of a polymer-linked residue is wrong whichever backend produces it.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# forcefill
|
|
2
|
+
|
|
3
|
+
[](https://github.com/LouieSlocombe/forcefill/actions/workflows/ci.yml)
|
|
4
|
+
[](https://forcefill.readthedocs.io/en/latest/)
|
|
5
|
+
[](https://pypi.org/project/forcefill/)
|
|
6
|
+
[](https://pypi.org/project/forcefill/)
|
|
7
|
+
|
|
8
|
+
Turn ligands into a ready-to-use [OpenMM](https://openmm.org) force-field XML —
|
|
9
|
+
either the non-standard residues (ligands, cofactors, hetero molecules) found in
|
|
10
|
+
a PDB, or ligand files on their own. Parameters come from AmberTools
|
|
11
|
+
(`antechamber` + `parmchk2`) via [ParmEd](https://github.com/ParmEd/ParmEd),
|
|
12
|
+
from [OpenFF](https://openforcefield.org) Sage or
|
|
13
|
+
[Espaloma](https://github.com/choderalab/espaloma) via
|
|
14
|
+
[openmmforcefields](https://github.com/openmm/openmmforcefields), or — for
|
|
15
|
+
CHARMM — by converting the CGenFF stream file
|
|
16
|
+
[ParamChem](https://cgenff.paramchem.org) gave you.
|
|
17
|
+
|
|
18
|
+
The output is a plain ffxml file you load alongside the standard force fields:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
ff = ForceField("amber14-all.xml", "amber14/tip3p.xml", "extras.xml")
|
|
22
|
+
system = ff.createSystem(pdb.topology)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Two ways in, depending on whether you have a structure:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from forcefill import build_forcefield_xml, build_ligand_xml
|
|
29
|
+
|
|
30
|
+
# A complex: find what amber14 cannot match and parameterize it
|
|
31
|
+
build_forcefield_xml("complex.pdb", "extras.xml")
|
|
32
|
+
|
|
33
|
+
# Just the ligand, no structure anywhere
|
|
34
|
+
build_ligand_xml("benzamidinium.sdf", "ben.xml")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What it does
|
|
38
|
+
|
|
39
|
+
1. **Identify** — `ForceField.getUnmatchedResidues` finds every residue the
|
|
40
|
+
base force field (default: `amber14-all.xml` + `amber14/tip3p.xml`) has no
|
|
41
|
+
template for.
|
|
42
|
+
2. **Classify** — only chemistry a stand-alone GAFF treatment is actually
|
|
43
|
+
*valid* for gets parameterized; see
|
|
44
|
+
[What gets skipped, and why](https://forcefill.readthedocs.io/en/latest/guide/what-gets-parameterized.html).
|
|
45
|
+
3. **Check** — before anything expensive: the net charge is read from the ligand
|
|
46
|
+
file, a supplied file is confirmed to be the same molecule as the residue, and
|
|
47
|
+
the geometry is checked for the faults that produce NaN energies.
|
|
48
|
+
4. **Parameterize** — each unique residue through `antechamber` (GAFF2 atom
|
|
49
|
+
types, AM1-BCC charges → `.mol2`) and `parmchk2` (missing parameters →
|
|
50
|
+
`.frcmod`), through OpenFF with `backend="smirnoff"`, through the Espaloma
|
|
51
|
+
graph network with `backend="espaloma"`, or from a CGenFF stream file with
|
|
52
|
+
`backend="charmm"`.
|
|
53
|
+
5. **Assemble** — one XML per residue, plus one combined XML.
|
|
54
|
+
6. **Validate** — an `openmm.System` is built from `base force field + new XML`
|
|
55
|
+
for every parameterized residue on its own (and for the whole input when
|
|
56
|
+
nothing was skipped), so a template that does not match its residue fails
|
|
57
|
+
loudly here instead of at simulation time. `minimize=True` additionally
|
|
58
|
+
catches parameters that are unphysical rather than merely absent (see
|
|
59
|
+
[Checks](https://forcefill.readthedocs.io/en/latest/guide/checks.html)).
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
Full documentation is at **[forcefill.readthedocs.io](https://forcefill.readthedocs.io/en/latest/)**:
|
|
64
|
+
|
|
65
|
+
| | |
|
|
66
|
+
|---|---|
|
|
67
|
+
| [Installation](https://forcefill.readthedocs.io/en/latest/installation.html) | conda-forge, and the two dependencies that are not ordinary ones |
|
|
68
|
+
| [Quickstart](https://forcefill.readthedocs.io/en/latest/quickstart.html) | a complex in, an ffxml out, and simulating with it |
|
|
69
|
+
| [What gets skipped, and why](https://forcefill.readthedocs.io/en/latest/guide/what-gets-parameterized.html) | the residues forcefill refuses, and what to do instead |
|
|
70
|
+
| [Cleaning the structure](https://forcefill.readthedocs.io/en/latest/guide/cleaning.html) | water, buffer ions and crystallization additives — and the metals it keeps |
|
|
71
|
+
| [Ligand input](https://forcefill.readthedocs.io/en/latest/guide/ligands.html) | SDF, MOL2 or SMILES; `LigandSpec`; ligands with no structure at all |
|
|
72
|
+
| [Four backends](https://forcefill.readthedocs.io/en/latest/guide/backends.html) | GAFF, OpenFF Sage, Espaloma, CGenFF — and which mix |
|
|
73
|
+
| [CHARMM and CGenFF](https://forcefill.readthedocs.io/en/latest/guide/charmm.html) | converting a ParamChem stream file, and the three ways doing it by hand goes wrong |
|
|
74
|
+
| [Bespoke torsions](https://forcefill.readthedocs.io/en/latest/guide/bespokefit.html) | a BespokeFit OFFXML, and the checks that protect the QC you paid for |
|
|
75
|
+
| [Checks](https://forcefill.readthedocs.io/en/latest/guide/checks.html) | what runs before the expensive step, and what runs after |
|
|
76
|
+
| [Things to get right](https://forcefill.readthedocs.io/en/latest/guide/gotchas.html) | explicit hydrogens, net charge, virtual sites, the periodic box |
|
|
77
|
+
| [Relation to `openmmforcefields`](https://forcefill.readthedocs.io/en/latest/guide/openmmforcefields.html) | which template generators forcefill uses, and why not `GAFFTemplateGenerator` |
|
|
78
|
+
| [API reference](https://forcefill.readthedocs.io/en/latest/api/index.html) | every public function, class and constant |
|
|
79
|
+
|
|
80
|
+
## Installation
|
|
81
|
+
|
|
82
|
+
AmberTools is conda-only, so conda-forge is the recommended route:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
conda env create -f environment.yml
|
|
86
|
+
conda activate forcefill
|
|
87
|
+
pip install -e . --no-deps
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Or into an existing environment:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
conda install -c conda-forge openmm parmed ambertools
|
|
94
|
+
pip install forcefill
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Requires Python ≥ 3.10. Two things are not ordinary dependencies: AmberTools is
|
|
98
|
+
not a Python package (the `antechamber` and `parmchk2` executables must be on
|
|
99
|
+
`PATH` for the `gaff` backend), and `espaloma` is optional because it pulls in
|
|
100
|
+
PyTorch. The full list, and the reason the `openmmforcefields` floor is 0.16, is
|
|
101
|
+
in [the installation guide](https://forcefill.readthedocs.io/en/latest/installation.html).
|
|
102
|
+
|
|
103
|
+
## Quickstart
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from forcefill import build_forcefield_xml
|
|
107
|
+
|
|
108
|
+
result = build_forcefield_xml(
|
|
109
|
+
"complex.pdb",
|
|
110
|
+
"extras.xml",
|
|
111
|
+
net_charges={"LIG": -1}, # essential for sensible AM1-BCC charges
|
|
112
|
+
clean_structure=True, # drop water, buffer ions and crystallization additives
|
|
113
|
+
)
|
|
114
|
+
print(result.parameterized) # ['LIG']
|
|
115
|
+
print(result.skipped) # {'ZN': 'monatomic species - ...'}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
then simulate with:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from openmm import app
|
|
122
|
+
|
|
123
|
+
pdb = app.PDBFile("complex.pdb")
|
|
124
|
+
ff = app.ForceField("amber14-all.xml", "amber14/tip3p.xml", "extras.xml")
|
|
125
|
+
system = ff.createSystem(pdb.topology)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`result` also reports the per-residue XML files (`result.residue_xmls`), the
|
|
129
|
+
skip reasons (`result.skipped`), and the directory holding every intermediate
|
|
130
|
+
file (`result.workdir`) for inspection — pass `cleanup=True` to remove it on
|
|
131
|
+
success.
|
|
132
|
+
|
|
133
|
+
More, including per-ligand settings and the other three backends, in
|
|
134
|
+
[the guide](https://forcefill.readthedocs.io/en/latest/guide/index.html).
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
conda env create -f environment.yml && conda activate forcefill
|
|
140
|
+
pip install -e . --no-deps
|
|
141
|
+
pytest -m "not integration and not smirnoff" # fast hermetic tests only
|
|
142
|
+
pytest # everything, including real antechamber and OpenFF
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Style is enforced by ruff (`pip install -e '.[dev]' && pre-commit install`).
|
|
146
|
+
|
|
147
|
+
The docs build is pip-only and separate from the conda environment — see
|
|
148
|
+
[Contributing](https://forcefill.readthedocs.io/en/latest/contributing.html),
|
|
149
|
+
which also has the release process.
|
|
150
|
+
|
|
151
|
+
## Changelog
|
|
152
|
+
|
|
153
|
+
Every release is described in [CHANGELOG.md](CHANGELOG.md). The public API is
|
|
154
|
+
everything exported from `forcefill/__init__.py`, and it follows semantic
|
|
155
|
+
versioning from 1.0.0 on.
|
|
156
|
+
|
|
157
|
+
## Roadmap
|
|
158
|
+
|
|
159
|
+
- A `forcefill` command-line interface — `build_ligand_xml` is the shape one
|
|
160
|
+
wants.
|
|
161
|
+
- Caching, so re-runs into the same workdir skip finished antechamber jobs —
|
|
162
|
+
and finished SMIRNOFF/Espaloma templates, which openmmforcefields' own
|
|
163
|
+
`cache=` cannot help with on the code path forcefill uses.
|
|
164
|
+
- Covalently bound ligands. Still skipped, and deliberately: a stand-alone
|
|
165
|
+
treatment of a polymer-linked residue is wrong whichever backend produces it.
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
from importlib import metadata as _metadata
|
|
2
|
+
|
|
3
|
+
from ._pipeline import ParameterizationResult
|
|
4
|
+
from ._spec import (
|
|
5
|
+
BACKENDS,
|
|
6
|
+
CHARMM_BASE_FORCEFIELD,
|
|
7
|
+
DEFAULT_BASE_FORCEFIELD,
|
|
8
|
+
DEFAULT_ESPALOMA_FORCEFIELD,
|
|
9
|
+
DEFAULT_SMIRNOFF_FORCEFIELD,
|
|
10
|
+
LigandSpec,
|
|
11
|
+
)
|
|
12
|
+
from .amber import (
|
|
13
|
+
DEFAULT_AMBERTOOLS_TIMEOUT,
|
|
14
|
+
assemble_openmm_ffxml,
|
|
15
|
+
locate_gaff_dat,
|
|
16
|
+
run_antechamber,
|
|
17
|
+
run_parmchk2,
|
|
18
|
+
)
|
|
19
|
+
from .checks import (
|
|
20
|
+
DEFAULT_MINIMIZATION_PLATFORM,
|
|
21
|
+
DEFAULT_MINIMIZATION_TOLERANCE,
|
|
22
|
+
MinimizationResult,
|
|
23
|
+
add_extra_particles,
|
|
24
|
+
minimize_with_forcefield_xml,
|
|
25
|
+
residue_templates_with_virtual_sites,
|
|
26
|
+
validate_forcefield_xml,
|
|
27
|
+
)
|
|
28
|
+
from .clean_structure import (
|
|
29
|
+
ADDITIVE_RESIDUES,
|
|
30
|
+
BULK_ION_RESIDUES,
|
|
31
|
+
STRUCTURAL_METAL_RESIDUES,
|
|
32
|
+
WATER_RESIDUES,
|
|
33
|
+
CleaningResult,
|
|
34
|
+
clean_pdb,
|
|
35
|
+
clean_topology,
|
|
36
|
+
)
|
|
37
|
+
from .ligand import build_ligand_xml
|
|
38
|
+
from .merge import merge_ffxml
|
|
39
|
+
from .structure import build_forcefield_xml
|
|
40
|
+
from .topology import extract_residue_to_pdb, find_nonstandard_residues
|
|
41
|
+
|
|
42
|
+
# The version lives in pyproject.toml and reaches here through the installed
|
|
43
|
+
# metadata; the fallback covers an uninstalled checkout.
|
|
44
|
+
try:
|
|
45
|
+
__version__ = _metadata.version("forcefill")
|
|
46
|
+
except _metadata.PackageNotFoundError: # uninstalled checkout
|
|
47
|
+
__version__ = "0.0.0+unknown"
|
|
48
|
+
|
|
49
|
+
# The reading and conversion helpers are not re-exported: they say where they
|
|
50
|
+
# belong (`forcefill.ligand_files.inspect_ligand_file(...)`,
|
|
51
|
+
# `forcefill.charmm.read_charmm_files(...)`), and the top level stays about the
|
|
52
|
+
# pipeline.
|
|
53
|
+
# `clean_structure` is also the name of a *module* here; it stays out of
|
|
54
|
+
# __all__ because at the top level that name reads as build_forcefield_xml's
|
|
55
|
+
# `clean_structure=` switch. Its public names are re-exported above.
|
|
56
|
+
__all__ = [
|
|
57
|
+
"ADDITIVE_RESIDUES",
|
|
58
|
+
"BACKENDS",
|
|
59
|
+
"BULK_ION_RESIDUES",
|
|
60
|
+
"CHARMM_BASE_FORCEFIELD",
|
|
61
|
+
"DEFAULT_AMBERTOOLS_TIMEOUT",
|
|
62
|
+
"DEFAULT_BASE_FORCEFIELD",
|
|
63
|
+
"DEFAULT_ESPALOMA_FORCEFIELD",
|
|
64
|
+
"DEFAULT_MINIMIZATION_PLATFORM",
|
|
65
|
+
"DEFAULT_MINIMIZATION_TOLERANCE",
|
|
66
|
+
"DEFAULT_SMIRNOFF_FORCEFIELD",
|
|
67
|
+
"STRUCTURAL_METAL_RESIDUES",
|
|
68
|
+
"WATER_RESIDUES",
|
|
69
|
+
"CleaningResult",
|
|
70
|
+
"LigandSpec",
|
|
71
|
+
"MinimizationResult",
|
|
72
|
+
"ParameterizationResult",
|
|
73
|
+
"add_extra_particles",
|
|
74
|
+
"assemble_openmm_ffxml",
|
|
75
|
+
"build_forcefield_xml",
|
|
76
|
+
"build_ligand_xml",
|
|
77
|
+
"clean_pdb",
|
|
78
|
+
"clean_topology",
|
|
79
|
+
"extract_residue_to_pdb",
|
|
80
|
+
"find_nonstandard_residues",
|
|
81
|
+
"locate_gaff_dat",
|
|
82
|
+
"merge_ffxml",
|
|
83
|
+
"minimize_with_forcefield_xml",
|
|
84
|
+
"residue_templates_with_virtual_sites",
|
|
85
|
+
"run_antechamber",
|
|
86
|
+
"run_parmchk2",
|
|
87
|
+
"validate_forcefield_xml",
|
|
88
|
+
]
|