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.
@@ -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
@@ -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__
@@ -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
+ [![ci](https://github.com/LouieSlocombe/forcefill/actions/workflows/ci.yml/badge.svg)](https://github.com/LouieSlocombe/forcefill/actions/workflows/ci.yml)
43
+ [![docs](https://readthedocs.org/projects/forcefill/badge/?version=latest)](https://forcefill.readthedocs.io/en/latest/)
44
+ [![pypi](https://img.shields.io/pypi/v/forcefill.svg)](https://pypi.org/project/forcefill/)
45
+ [![python](https://img.shields.io/pypi/pyversions/forcefill.svg)](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
+ [![ci](https://github.com/LouieSlocombe/forcefill/actions/workflows/ci.yml/badge.svg)](https://github.com/LouieSlocombe/forcefill/actions/workflows/ci.yml)
4
+ [![docs](https://readthedocs.org/projects/forcefill/badge/?version=latest)](https://forcefill.readthedocs.io/en/latest/)
5
+ [![pypi](https://img.shields.io/pypi/v/forcefill.svg)](https://pypi.org/project/forcefill/)
6
+ [![python](https://img.shields.io/pypi/pyversions/forcefill.svg)](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
+ ]