Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4839dc7
Use thermo and energy errors in loss function
mattwthompson Oct 27, 2026
8f6befc
Start making weights for types of targets
mattwthompson Oct 27, 2026
8de767f
Refactor handling of "reference" force field
mattwthompson Nov 4, 2026
47fe3ae
Some fixes for pressure handling
mattwthompson Nov 6, 2026
bf0c3cb
Add integration test with water at different temperatures
mattwthompson Nov 6, 2026
027c51e
Add GPU-based test
mattwthompson Nov 7, 2026
619a32d
More safely recurse directories
mattwthompson Nov 8, 2026
6319867
Pin Pytest <9.2
mattwthompson Nov 8, 2026
5473dbf
Drop GPU action for now
mattwthompson Nov 8, 2026
7ff398d
Merge branch 'pressure-fixes' into merge-thermo-energy
mattwthompson Nov 8, 2026
2002af0
Merge remote-tracking branch 'upstream/main' into merge-thermo-energy
mattwthompson Nov 11, 2026
ada9cb8
Tidy comments in MVP script
mattwthompson Nov 11, 2026
52f91c0
Improve OpenMM platform handling, loss reporting, SMILES parsing
mattwthompson Nov 11, 2026
3be5802
Add OpenMM helper file
mattwthompson Nov 11, 2026
3e9e031
Update test to use mapped SMILES in target
mattwthompson Nov 11, 2026
dee2bd2
Debug
mattwthompson Nov 10, 2026
1ef798d
Force CPU platform in CI
mattwthompson Nov 12, 2026
fb1d52e
Minor cleanup
mattwthompson Nov 12, 2026
9df454b
Cleanup, drop GPU tests
mattwthompson Nov 12, 2026
5a6baff
Update hooks, lockfile
mattwthompson Nov 12, 2026
5f429cd
Improve logging
mattwthompson Nov 12, 2026
11539db
Use OpenCL in my local setup
mattwthompson Nov 12, 2026
9ccdf05
Make local config work on Linux as well
mattwthompson Nov 12, 2026
42451d8
Write ensemble averages with indent
mattwthompson Nov 12, 2026
6f8a42a
Improve short-circuit condition
mattwthompson Nov 12, 2026
ff54193
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 12, 2026
faa7b89
Lint
mattwthompson Nov 12, 2026
381db9a
Merge remote-tracking branch 'upstream/merge-thermo-energy' into merg…
mattwthompson Nov 12, 2026
ebc7da7
Shut down Parl's data flow kernel in each iteration
mattwthompson Nov 12, 2026
cd1858b
Cleanup from code review
mattwthompson Nov 13, 2026
d64c087
Update hooks, lockfile
mattwthompson Nov 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ repos:
exclude: '\.(json)$'
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.17.2
rev: v0.17.5
hooks:
- id: ruff-check
args: ["--fix"]
- id: ruff-format
- repo: https://github.com/tox-dev/pyproject-fmt
rev: v2.30.3
rev: v2.30.6
hooks:
- id: pyproject-fmt
- repo: https://github.com/tombi-toml/tombi-pre-commit
rev: v1.9.6
rev: v1.11.2
hooks:
- id: tombi-format
args: ["--offline"]
Expand Down
70 changes: 30 additions & 40 deletions examples/mvp/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@
N_MOLECULES = 200
INITIAL_FORCE_FIELD = "openff-2.3.0.offxml"

MERGE_DATA = False
# these weights should be exposed to the user in some sort of training config
# probably a good phase II task
COEFFICIENTS = {
"energy": 0.1,
"force": 0.01,
"thermo": 100_000.0,
}


def load_datasets(root: Path) -> tuple[Dataset, Dataset]:
Expand Down Expand Up @@ -58,9 +64,7 @@ def main(root: Path) -> None:
smiles_set={
*thermo.extract_smiles(thermo_data),
*energy.extract_smiles(energy_data),
}
if MERGE_DATA
else {*thermo.extract_smiles(thermo_data)},
},
smirnoff_force_field=ForceField(INITIAL_FORCE_FIELD),
)

Expand All @@ -75,36 +79,23 @@ def main(root: Path) -> None:
},
attributes={},
)

theta = trainable.to_values().requires_grad_(True)

# TODO: Possible drop in L-M optimizer
optimizer = Adam([theta], lr=0.01)

# TODO: inner/outer loop, or any way of stepping through QM optimization
# without running MD jobs each time
for epoch in range(N_EPOCHS):
# maybe do this outside of loop for iteration 0, then
# at end of loop for [1, ..., N_EPOCHS]?
# this is linked under the hood to theta - needed to gradients together
current_ff = trainable.to_force_field(theta) # 287

# import json
# from tyff._serialization import load_tensor_force_field

# sum(t.numel() for t in _pack_force_field(ref)[0] if t is not None)
# is probably 208

# current_ff = load_tensor_force_field(
# json.loads(
# open(
# 'examples/mvp/EPOCH_0/simulations/reference_force_fields/reference.json'
# ).read()
# )
# )

# no return value?
simulate(
force_field=current_ff,
epoch_dir=root / f"EPOCH_{epoch}",
thermo_data=thermo_data,
smirnoff_force_field=ForceField(INITIAL_FORCE_FIELD),
smirnoff_force_field=INITIAL_FORCE_FIELD,
n_replicates=N_REPLICATES,
n_molecules=N_MOLECULES,
)
Expand All @@ -115,27 +106,26 @@ def main(root: Path) -> None:
epoch_dir=root / f"EPOCH_{epoch}",
)

if MERGE_DATA:
energy_ref, energy_pred, forces_ref, forces_pred = energy.predict(
energy_data,
current_ff,
topologies,
normalize=False,
)
energy_ref, energy_pred, forces_ref, forces_pred = energy.predict(
energy_data,
current_ff,
topologies,
normalize=False,
)

# the weights in front of each category of loss (energy, forces, and thermo)
# should be exposed to the user in some sort of training config
# probably a good phase II task
loss = (
(energy_pred - energy_ref).square().mean()
+ 0.1 * (forces_pred - forces_ref).square().mean()
+ (y_pred - y_ref).square().mean()
)
else:
loss = (y_pred - y_ref).square().mean()
# can construct loss function in many different ways, including modifying coefficients
loss = (
COEFFICIENTS["energy"] * (energy_pred - energy_ref).square().mean()
+ COEFFICIENTS["force"] * (forces_pred - forces_ref).square().mean()
+ COEFFICIENTS["thermo"] * (y_pred - y_ref).square().mean()
)

logger.info(f"EPOCH {epoch}: loss={loss.item():.6f}")
print(f"EPOCH {epoch}: loss={loss.item():.6f}")
print(f"\tloss component energy (after applying {COEFFICIENTS=})")
print(f"\tenergy {COEFFICIENTS['energy'] * (energy_pred - energy_ref).square().mean()}")
print(f"\tforce {COEFFICIENTS['force'] * (forces_pred - forces_ref).square().mean()}")
print(f"\tthermo {COEFFICIENTS['thermo'] * (y_pred - y_ref).square().mean()}")

optimizer.zero_grad()

Expand All @@ -156,7 +146,7 @@ def main(root: Path) -> None:
indent=4,
)

# write out FF as SMIRNOFF force field
# update SMIRNOFF force field with new values from tensor FF
convert_tensor_force_field(
original_force_field=ForceField(INITIAL_FORCE_FIELD),
tensor_force_field=updated_tensor_force_field,
Expand Down
Loading
Loading