Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9fdc7d3
Stage Jacobian app
mattwthompson Sep 25, 2026
2fa4339
Merge remote-tracking branch 'upstream/main' into jacobian-app
mattwthompson Sep 25, 2026
5f07be2
Remove temporary analysis app
mattwthompson Sep 25, 2026
738e637
Refactor app call, load some values from disk
mattwthompson Sep 25, 2026
4b5fa20
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 25, 2026
7972934
More input management
mattwthompson Sep 25, 2026
2d73bd0
Merge remote-tracking branch 'upstream/jacobian-app' into jacobian-app
mattwthompson Sep 25, 2026
de28e60
Fix import, add temporary check
mattwthompson Sep 25, 2026
57b27ac
Merge remote-tracking branch 'upstream/main' into jacobian-app
mattwthompson Sep 28, 2026
fd311f1
Revert "Remove temporary analysis app"
mattwthompson Sep 28, 2026
d8dbf21
Dependency/tooling updates
mattwthompson Sep 28, 2026
4b5c233
Also serialize ensemble averages and Jacobian matrices
mattwthompson Sep 28, 2026
009044c
Update example, clean up apps/workflow manager
mattwthompson Sep 28, 2026
8fe27a3
Do not sort
mattwthompson Sep 28, 2026
e105111
Serialize and de-serialize `TensorForceField`
mattwthompson Sep 29, 2026
c52e67f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 29, 2026
9fe39f1
Debug/fixes
mattwthompson Sep 30, 2026
911ae6d
Merge remote-tracking branch 'upstream/jacobian-app' into jacobian-app
mattwthompson Sep 30, 2026
6f9aa31
Stage new design
mattwthompson Sep 30, 2026
95f8afa
Create "reference" tensor force field representing all systems
mattwthompson Sep 30, 2026
863c770
Update comments
mattwthompson Oct 1, 2026
3eaf061
Merge remote-tracking branch 'upstream/main' into jacobian-app
mattwthompson Oct 1, 2026
538c6fd
Improve handling "reference" force fields
mattwthompson Oct 1, 2026
fc8066f
Fixes
mattwthompson Oct 1, 2026
e34f43a
Add basic test
mattwthompson Oct 1, 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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repos:
exclude: '\.(json)$'
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.7
rev: v0.16.9
hooks:
- id: ruff-check
args: ["--fix"]
Expand Down
28 changes: 28 additions & 0 deletions examples/density/run.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import pathlib
import socket

Expand All @@ -7,6 +8,8 @@

from tyff.compute.configs import hpc3_config, local_config
from tyff.compute.fetch import fetch_trajectory_paths_from_target
from tyff.compute.jobs import make_job_id
from tyff.compute.prep import _compute_configs_from_data_entry
from tyff.compute.workflow import SimulationWorkflow
from tyff.targets.thermo import DataEntry

Expand Down Expand Up @@ -73,6 +76,7 @@
n_replicates=5,
)

# naive property estimate, no tensor math
for density_target in density_targets:
workflow.estimate_target(
density_target,
Expand All @@ -94,6 +98,7 @@
n_replicates=3,
)

# naive property estimate, no tensor math
for density_target in density_targets:
workflow.estimate_target(
density_target,
Expand All @@ -104,6 +109,29 @@

# TODO: Show how to check status while running

# this generally happens under the hood
compute_configs = [
_compute_configs_from_data_entry(
target,
force_field="openff-2.3.0.offxml",
n_molecules=200,
)
for target in density_targets
]

print(f"Number of targets for which compute configs were generated: {len(compute_configs)}")
print(f"Number of replicates for each target: {[len(replicates) for replicates in compute_configs]}")

# this is a list of job directories of each individual job (total of 9, 3x replicates of 3 targets)
job_ids = [make_job_id(liquid_job) for replicate in compute_configs for row in replicate for liquid_job in row]

for job_id in job_ids:
print(job_id)
print(json.loads(open(f"density_example/{job_id}/compute_config.json").read()))
print(json.loads(open(f"density_example/{job_id}/ensemble_averages.json").read()))

# now for the old-school statistics, etc.

# get trajectory paths from root job directory and per-target info (without knowing internal compute configs)
trajectory_paths = [
fetch_trajectory_paths_from_target(
Expand Down
6,161 changes: 2,774 additions & 3,387 deletions pixi.lock

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ rdkit-stubs = "*"
parsl = "*"
rich = "*"
tyff = { path = ".", editable = true }
# probably optional-ish below here
jupyter = "*"
nbconvert = "*"
tensorboard = "*"
tensorboardx = "*"
uncertainties = "*"

[dependencies]
openmm = "8.4.*" # need to help Pixi, since conda solve constraints PyPI solve
Expand All @@ -42,15 +48,12 @@ openff-nagl-base = "*"
openff-nagl-models = "*"
openmmtools = "*"
pydantic-units = "*"
sqlalchemy = ">=2.0.14,<2.1.0"
pytorch = "*"
NNPOps = "*"
datasets = "*"
bokeh = "3.9.*"
# probably optional-ish below here
jupyter = "*"
nbconvert = "*"
tensorboard = "*"
tensorboardx = "*"
uncertainties = "*"
openff-packmol = "0.1.*"
openff-evaluator-base = "*"
# shims
Expand Down
47 changes: 47 additions & 0 deletions tyff/_tests/compute/test_jacobians.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import shutil
from importlib.resources import files

import pytest
from parsl import File

from tyff.compute._files import ProductionFiles
from tyff.compute._jacobian import _get_ensemble_average_and_jacobian


@pytest.fixture
def production_future() -> dict[str, ProductionFiles]:
return {
"simulation_files": ProductionFiles(
topology=File(files("tyff") / "_tests/data/app_files/sample_density/production_topology.pdb"),
dcd_trajectory=File(files("tyff") / "_tests/data/app_files/sample_density/production_trajectory.dcd"),
msgpack_trajectory=File(
files("tyff") / "_tests/data/app_files/sample_density/production_trajectory.msgpack"
),
log=File(files("tyff") / "_tests/data/app_files/sample_density/produce.log"),
state_data=File(files("tyff") / "_tests/data/app_files/sample_density/production.csv"),
system=File(files("tyff") / "_tests/data/app_files/sample_density/production_system.xml"),
integrator=File(files("tyff") / "_tests/data/app_files/sample_density/production_integrator.xml"),
checkpoint=File(files("tyff") / "_tests/data/app_files/sample_density/production_checkpoint.chk"),
)
}


def test_jacobian(production_future, tmp_path):
for file in [
"compute_config.json",
"production_trajectory.msgpack",
"single_molecule_interchange_0.json",
"single_molecule_interchange_1.json",
]:
shutil.copy(
str(files("tyff") / f"_tests/data/app_files/sample_density/{file}"),
str(tmp_path / file),
)

averages, jacobians = _get_ensemble_average_and_jacobian(
production_future,
tmp_path,
reference_force_field_path=File(files("tyff") / "_tests/data/app_files/sample_density/ref.ff.json"),
)

assert len(averages) == jacobians.shape[0]
29 changes: 25 additions & 4 deletions tyff/_tests/data/app_files/make_sample_density_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
import pathlib
import random

import openff.toolkit
from rich.pretty import pprint as print

import tyff.converters
from tyff._serialization import dump_tensor_force_field
from tyff.compute._analyze import _run_density_analysis
from tyff.compute._equilibrate import _run_equilibration
from tyff.compute._minimize import _minimize_energy
Expand All @@ -15,9 +18,11 @@

pathlib.Path("sample_density/").mkdir(exist_ok=True)

FORCE_FIELD = "openff-2.3.0.offxml"

target = DataEntry(
**{
"id": random.randint(10**15, 10**16 - 1),
"id": random.randint(10**15, 10**16 - 1), # TODO: Make this the real ID
"tag": "density",
"x": [0.5, 0.5],
"smiles": [
Expand All @@ -33,12 +38,28 @@
}
)

with open("sample_density/target_config.json", "w") as target_config:
json.dump(target, target_config, indent=4)
with open("sample_density/target_config.json", "w") as target_config_file:
json.dump(target, target_config_file, indent=4)

smirnoff_force_field = openff.toolkit.ForceField(FORCE_FIELD)

interchanges = [
smirnoff_force_field.create_interchange(openff.toolkit.Molecule.from_smiles(smiles_).to_topology())
for smiles_ in target["smiles"]
]

for index, interchange in enumerate(interchanges):
with open(f"sample_density/single_molecule_interchange_{index}.json", "w") as f:
f.write(interchange.model_dump_json())

reference_force_field, _ = tyff.converters.convert_interchange(interchanges)

with open("sample_density/ref.ff.json", "w") as reference_force_field_file:
json.dump(dump_tensor_force_field(reference_force_field), reference_force_field_file, indent=4)

compute = _make_liquid_density_compute_configs(
data_entry=target,
force_field="openff-2.3.0.offxml",
force_field=FORCE_FIELD,
n_molecules=200,
)[0][0]

Expand Down
Loading
Loading