From 53ba5761c9fc856c04e707fc9443b18fac11c1f3 Mon Sep 17 00:00:00 2001 From: "Matthew W. Thompson" Date: Fri, 25 Sep 2026 12:33:14 -0500 Subject: [PATCH 1/4] Revamp examples --- examples/{run_density.py => density/run.py} | 93 +++-- examples/mvp/run.py | 79 ++++ examples/prep_compute_configs.ipynb | 221 ----------- .../prepare_compute/prepare_compute.ipynb | 342 ++++++++++++++++++ examples/run_hvap.py | 56 --- tyff/compute/workflow.py | 2 +- 6 files changed, 488 insertions(+), 305 deletions(-) rename examples/{run_density.py => density/run.py} (68%) create mode 100644 examples/mvp/run.py delete mode 100644 examples/prep_compute_configs.ipynb create mode 100644 examples/prepare_compute/prepare_compute.ipynb delete mode 100644 examples/run_hvap.py diff --git a/examples/run_density.py b/examples/density/run.py similarity index 68% rename from examples/run_density.py rename to examples/density/run.py index 1753d77..22e79be 100644 --- a/examples/run_density.py +++ b/examples/density/run.py @@ -8,11 +8,49 @@ from tyff.compute.configs import hpc3_config, local_config from tyff.compute.fetch import fetch_trajectory_paths_from_target from tyff.compute.workflow import SimulationWorkflow -from tyff.datasets.thermoml import ThermoMLDataSet +from tyff.targets.thermo import DataEntry -with open("tyff/_tests/data/thermoml/single_density.xml") as f: - dataset = ThermoMLDataSet.from_xml(f.read()) - density_target = dataset.properties[0] +density_targets = [ + DataEntry(**data) + for data in [ + { + "id": 74669191270958899039426367776551206167278900382279422138348522811937124722445, + "tag": "density", + "smiles": ["COCCO"], + "x": [1.0], + "temperature": 293.15, + "pressure": 101.3, + "value": 0.9648800000000002, + "std": 5.0000000000000016e-05, + "units": "gram / milliliter", + "source": "", + }, + { + "id": "", + "tag": "density", + "smiles": ["CCC(=O)OC"], + "x": [1.0], + "temperature": 293.15, + "pressure": 101.325, + "value": 0.9101800000000002, + "std": 0.00045, + "units": "gram / milliliter", + "source": "", + }, + { + "id": "", + "tag": "density", + "smiles": ["C=COCCC"], + "x": [1.0], + "temperature": 298.15, + "pressure": 101.325, + "value": 0.7629800000000002, + "std": 0.00061, + "units": "gram / milliliter", + "source": "", + }, + ] +] job_specs = list() @@ -28,39 +66,40 @@ account="dmobley_lab_gpu", ), ) as workflow: - for extra_molecules in range(2): - workflow.submit_target( - density_target, - force_field="openff-2.3.0.offxml", - n_molecules=200 + extra_molecules, - n_replicates=5, - ) + workflow.submit_target_batch( + density_targets, + force_field="openff-2.3.0.offxml", + n_molecules=200, + n_replicates=5, + ) - for extra_molecules in range(2): + for density_target in density_targets: workflow.estimate_target( density_target, force_field="openff-2.3.0.offxml", - n_molecules=200 + extra_molecules, + n_molecules=200, n_replicates=5, ) else: # local testing - with SimulationWorkflow(base_dir, local_config(max_workers=10)) as workflow: - for extra_molecules in range(2): - workflow.submit_target( - density_target, - force_field="openff-2.3.0.offxml", - n_molecules=200 + extra_molecules, - n_replicates=5, - ) + with SimulationWorkflow( + base_dir, + local_config(max_workers=10), + ) as workflow: + workflow.submit_target_batch( + density_targets, + force_field="openff-2.3.0.offxml", + n_molecules=200, + n_replicates=3, + ) - for extra_molecules in range(2): + for density_target in density_targets: workflow.estimate_target( density_target, force_field="openff-2.3.0.offxml", - n_molecules=200 + extra_molecules, - n_replicates=5, + n_molecules=200, + n_replicates=3, ) # TODO: Show how to check status while running @@ -71,10 +110,10 @@ base_dir=base_dir, target=density_target, force_field="openff-2.3.0.offxml", - n_molecules=200 + extra_molecules, - n_replicates=5, + n_molecules=200, + n_replicates=3, ) - for extra_molecules in range(2) + for density_target in density_targets ] print(trajectory_paths) """ diff --git a/examples/mvp/run.py b/examples/mvp/run.py new file mode 100644 index 0000000..034c369 --- /dev/null +++ b/examples/mvp/run.py @@ -0,0 +1,79 @@ +import socket + +import parsl + +from tyff.compute.configs import hpc3_config, local_config +from tyff.compute.workflow import SimulationWorkflow +from tyff.targets.thermo import DataEntry + +# 1. Establish target data +targets = [ + DataEntry(**data) + for data in [ + { + "id": 74669191270958899039426367776551206167278900382279422138348522811937124722445, + "tag": "density", + "smiles": ["COCCO"], + "x": [1.0], + "temperature": 293.15, + "pressure": 101.3, + "value": 0.9648800000000002, + "std": 5.0000000000000016e-05, + "units": "gram / milliliter", + "source": "", + }, + { + "id": 4455979010545387927019552539812888795231031600148607549210198983695932067156, + "tag": "enthalpy_of_vaporization", + "smiles": ["Fc1ccccc1Cl"], + "x": [1.0], + "temperature": 298.15, + "pressure": None, + "value": 10.51625239005736, + "std": 0.14340344168260036, + "units": "kcal/mol", + "source": "10.1016/j.fluid.2014.12.023", + }, + ] +] + +job_specs = list() + +base_dir = "mvp_jobs" + +# 2. Run (compute) jobs +if "hpc3" in socket.gethostname(): + # production runs on HPC3 (SLURM cluster with GPUs) + with SimulationWorkflow( + base_dir, + hpc3_config( + partition="gpu", + account="dmobley_lab_gpu", + ), + ) as workflow: + workflow.submit_target_batch( + targets, + force_field="openff-2.3.0.offxml", + n_molecules=200, + n_replicates=5, + ) + +else: + # local testing + with SimulationWorkflow( + base_dir, + local_config(max_workers=10), + ) as workflow: + workflow.submit_target_batch( + targets, + force_field="openff-2.3.0.offxml", + n_molecules=200, + n_replicates=3, + ) + + +try: + parsl.clear() + parsl.dfk().cleanup() +except Exception: + pass diff --git a/examples/prep_compute_configs.ipynb b/examples/prep_compute_configs.ipynb deleted file mode 100644 index 7de3db5..0000000 --- a/examples/prep_compute_configs.ipynb +++ /dev/null @@ -1,221 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d93f78b0", - "metadata": {}, - "source": [ - "## Load ThermoML data\n", - "\n", - "ThermoML data is loaded from XML into the `ThermoMLDataSet` class. Each has a `.properties` attribute which enumerates each of individual physical property targets, themselves stored as dict-like `DataEntry` objets.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "18703ce3", - "metadata": { - "execution": { - "iopub.execute_input": "2026-07-16T11:14:45.523550Z", - "iopub.status.busy": "2026-07-16T11:14:45.523314Z", - "iopub.status.idle": "2026-07-16T11:14:54.976643Z", - "shell.execute_reply": "2026-07-16T11:14:54.976196Z", - "shell.execute_reply.started": "2026-07-16T11:14:45.523529Z" - }, - "scrolled": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/mattthompson/software/tyff/.pixi/envs/dev/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - }, - { - "data": { - "text/plain": [ - "[{'id': 99595555472285796331286665565837685644847269654436554750580343052999515028260,\n", - " 'tag': 'density',\n", - " 'smiles': ['COCCO'],\n", - " 'x': [1.0],\n", - " 'temperature': 293.15,\n", - " 'pressure': 101.3,\n", - " 'value': 0.9648800000000002,\n", - " 'std': 5.0000000000000016e-05,\n", - " 'units': 'gram / milliliter',\n", - " 'source': '../tyff/_tests/data/thermoml/single_density.xml'},\n", - " {'id': 11047488098043560832107567886742111298523947631970831407582183320640598564429,\n", - " 'tag': 'enthalpy_of_mixing',\n", - " 'smiles': ['C1CCCCC1', 'CCCCCC'],\n", - " 'x': [0.219, 0.781],\n", - " 'temperature': 298.15,\n", - " 'pressure': 101.0,\n", - " 'value': 0.030210325047801148,\n", - " 'std': 0.00015105162523900573,\n", - " 'units': 'kcal/mol',\n", - " 'source': '../tyff/_tests/data/thermoml/single_dhmix.xml'},\n", - " {'id': 93331053100587520630295449730237975581244846769048933157057842574798938029340,\n", - " 'tag': 'enthalpy_of_vaporization',\n", - " 'smiles': ['Fc1ccccc1Cl'],\n", - " 'x': [1.0],\n", - " 'temperature': 298.15,\n", - " 'pressure': None,\n", - " 'value': 10.51625239005736,\n", - " 'std': 0.14340344168260036,\n", - " 'units': 'kcal/mol',\n", - " 'source': '../tyff/_tests/data/thermoml/single_dhvap.xml'},\n", - " {'id': 80076498838707442168614078629777862445594790468286042153533019576213966266416,\n", - " 'tag': 'dielectric_constant',\n", - " 'smiles': ['CCCOCCO'],\n", - " 'x': [1.0],\n", - " 'temperature': 293.15,\n", - " 'pressure': 101.0,\n", - " 'value': 11.76,\n", - " 'std': 0.02,\n", - " 'units': 'dimensionless',\n", - " 'source': '../tyff/_tests/data/thermoml/single_dielectric.xml'}]" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from tyff.datasets.thermoml import ThermoMLDataSet\n", - "\n", - "# These XML files are from testing data and may or may not have sensible values\n", - "properties = [\n", - " ThermoMLDataSet.from_file(f\"../tyff/_tests/data/thermoml/single_{tag}.xml\").properties[0]\n", - " for tag in [\n", - " \"density\",\n", - " \"dhmix\",\n", - " \"dhvap\",\n", - " \"dielectric\",\n", - " ]\n", - "]\n", - "\n", - "# These dicts store only the properties parsed from ThermoML data, nothing about how they ought to be simulated\n", - "properties" - ] - }, - { - "cell_type": "markdown", - "id": "566b9443", - "metadata": {}, - "source": [ - "## Prepare simulation configs\n", - "\n", - "These configs, also dict-based, store all information necessary to run simulations that will estimate the loaded properties. These intentionally lose information about the associated properties in order to avoid unnecessary duplication of simulations." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "9f846bba", - "metadata": { - "execution": { - "iopub.execute_input": "2026-07-16T11:14:54.977202Z", - "iopub.status.busy": "2026-07-16T11:14:54.976999Z", - "iopub.status.idle": "2026-07-16T11:14:54.998711Z", - "shell.execute_reply": "2026-07-16T11:14:54.997849Z", - "shell.execute_reply.started": "2026-07-16T11:14:54.977191Z" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'tag': 'liquid',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['COCCO'],\n", - " 'x': [1.0],\n", - " 'temperature': 293.15,\n", - " 'pressure': 101.3,\n", - " 'density': 0.9648800000000002},\n", - " {'tag': 'liquid',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['C1CCCCC1', 'CCCCCC'],\n", - " 'x': [0.219, 0.781],\n", - " 'temperature': 298.15,\n", - " 'pressure': 101.0,\n", - " 'density': None},\n", - " {'tag': 'liquid',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['C1CCCCC1'],\n", - " 'x': [1.0],\n", - " 'temperature': 298.15,\n", - " 'pressure': 101.0,\n", - " 'density': None},\n", - " {'tag': 'liquid',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['CCCCCC'],\n", - " 'x': [1.0],\n", - " 'temperature': 298.15,\n", - " 'pressure': 101.0,\n", - " 'density': None},\n", - " {'tag': 'liquid',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['Fc1ccccc1Cl'],\n", - " 'x': [1.0],\n", - " 'temperature': 298.15,\n", - " 'pressure': None,\n", - " 'density': None},\n", - " {'tag': 'gas',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['Fc1ccccc1Cl'],\n", - " 'x': [1.0],\n", - " 'temperature': 298.15},\n", - " {'tag': 'liquid',\n", - " 'force_field': 'openff-2.3.0.offxml',\n", - " 'n_molecules': 800,\n", - " 'smiles': ['CCCOCCO'],\n", - " 'x': [1.0],\n", - " 'temperature': 293.15,\n", - " 'pressure': 101.0,\n", - " 'density': None}]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from tyff.compute.prep import compute_configs_from_data_entries\n", - "\n", - "compute_configs = compute_configs_from_data_entries(properties, force_field=\"openff-2.3.0.offxml\", n_molecules=800)\n", - "compute_configs" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/prepare_compute/prepare_compute.ipynb b/examples/prepare_compute/prepare_compute.ipynb new file mode 100644 index 0000000..2296cc5 --- /dev/null +++ b/examples/prepare_compute/prepare_compute.ipynb @@ -0,0 +1,342 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d93f78b0", + "metadata": {}, + "source": [ + "## Load ThermoML data\n", + "\n", + "ThermoML data is loaded from XML into the `ThermoMLDataSet` class. Each has a `.properties` attribute which enumerates each of individual physical property targets, themselves stored as dict-like `DataEntry` objets.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "18703ce3", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T11:14:45.523550Z", + "iopub.status.busy": "2026-07-16T11:14:45.523314Z", + "iopub.status.idle": "2026-07-16T11:14:54.976643Z", + "shell.execute_reply": "2026-07-16T11:14:54.976196Z", + "shell.execute_reply.started": "2026-07-16T11:14:45.523529Z" + }, + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': 4259994470836813493764664715224159905758010119739293980634600054209439522772,\n", + " 'tag': 'density',\n", + " 'smiles': ['COCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.3,\n", + " 'value': 0.9648800000000002,\n", + " 'std': 5.0000000000000016e-05,\n", + " 'units': 'gram / milliliter',\n", + " 'source': '../tyff/_tests/data/thermoml/single_density.xml'},\n", + " {'id': 66323530876095036060664573044728364423328787940483679608729445680433942045769,\n", + " 'tag': 'enthalpy_of_mixing',\n", + " 'smiles': ['C1CCCCC1', 'CCCCCC'],\n", + " 'x': [0.219, 0.781],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'value': 0.030210325047801148,\n", + " 'std': 0.00015105162523900573,\n", + " 'units': 'kcal/mol',\n", + " 'source': '../tyff/_tests/data/thermoml/single_dhmix.xml'},\n", + " {'id': 18748660119058168652914886624917662935872726343855494928447440015723070863619,\n", + " 'tag': 'enthalpy_of_vaporization',\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': None,\n", + " 'value': 10.51625239005736,\n", + " 'std': 0.14340344168260036,\n", + " 'units': 'kcal/mol',\n", + " 'source': '../tyff/_tests/data/thermoml/single_dhvap.xml'},\n", + " {'id': 98598723396134232378866892872395413623580076462933441604540518928980937053144,\n", + " 'tag': 'dielectric_constant',\n", + " 'smiles': ['CCCOCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.0,\n", + " 'value': 11.76,\n", + " 'std': 0.02,\n", + " 'units': 'dimensionless',\n", + " 'source': '../tyff/_tests/data/thermoml/single_dielectric.xml'}]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from tyff.datasets.thermoml import ThermoMLDataSet\n", + "\n", + "# These XML files are from testing data and may or may not have sensible values\n", + "properties = [\n", + " ThermoMLDataSet.from_file(f\"../tyff/_tests/data/thermoml/single_{tag}.xml\").properties[0]\n", + " for tag in [\n", + " \"density\",\n", + " \"dhmix\",\n", + " \"dhvap\",\n", + " \"dielectric\",\n", + " ]\n", + "]\n", + "\n", + "# These dicts store only the properties parsed from ThermoML data, nothing about how they ought to be simulated\n", + "properties" + ] + }, + { + "cell_type": "markdown", + "id": "566b9443", + "metadata": {}, + "source": [ + "## Prepare simulation configs\n", + "\n", + "These configs, also dict-based, store all information necessary to run simulations that will estimate the loaded properties. These intentionally lose information about the associated properties in order to avoid unnecessary duplication of simulations." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9f846bba", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-16T11:14:54.977202Z", + "iopub.status.busy": "2026-07-16T11:14:54.976999Z", + "iopub.status.idle": "2026-07-16T11:14:54.998711Z", + "shell.execute_reply": "2026-07-16T11:14:54.997849Z", + "shell.execute_reply.started": "2026-07-16T11:14:54.977191Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['COCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.3,\n", + " 'density': 0.9648800000000002},),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['COCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.3,\n", + " 'density': 0.9648800000000002},),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['COCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.3,\n", + " 'density': 0.9648800000000002},),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['C1CCCCC1', 'CCCCCC'],\n", + " 'x': [0.219, 0.781],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},\n", + " {'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['C1CCCCC1'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},\n", + " {'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['CCCCCC'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None}),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['C1CCCCC1', 'CCCCCC'],\n", + " 'x': [0.219, 0.781],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},\n", + " {'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['C1CCCCC1'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},\n", + " {'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['CCCCCC'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None}),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['C1CCCCC1', 'CCCCCC'],\n", + " 'x': [0.219, 0.781],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},\n", + " {'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['C1CCCCC1'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},\n", + " {'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['CCCCCC'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': 101.0,\n", + " 'density': None}),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': None,\n", + " 'density': None},\n", + " {'tag': 'gas',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 1,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15}),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': None,\n", + " 'density': None},\n", + " {'tag': 'gas',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 1,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15}),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15,\n", + " 'pressure': None,\n", + " 'density': None},\n", + " {'tag': 'gas',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 1,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['Fc1ccccc1Cl'],\n", + " 'x': [1.0],\n", + " 'temperature': 298.15}),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 0,\n", + " 'smiles': ['CCCOCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 1,\n", + " 'smiles': ['CCCOCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},),\n", + " ({'tag': 'liquid',\n", + " 'force_field': 'openff-2.3.0.offxml',\n", + " 'n_molecules': 800,\n", + " 'replicate_index': 2,\n", + " 'smiles': ['CCCOCCO'],\n", + " 'x': [1.0],\n", + " 'temperature': 293.15,\n", + " 'pressure': 101.0,\n", + " 'density': None},)]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from tyff.compute.prep import compute_configs_from_data_entries\n", + "\n", + "compute_configs = compute_configs_from_data_entries(properties, force_field=\"openff-2.3.0.offxml\", n_molecules=800)\n", + "compute_configs" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/run_hvap.py b/examples/run_hvap.py deleted file mode 100644 index 8c8fdbb..0000000 --- a/examples/run_hvap.py +++ /dev/null @@ -1,56 +0,0 @@ -import parsl - -from tyff.compute.configs import local_config, slurm_config -from tyff.compute.workflow import SimulationWorkflow -from tyff.datasets.thermoml import ThermoMLDataSet - -with open("tyff/_tests/data/thermoml/single_dhvap.xml") as f: - dataset = ThermoMLDataSet.from_xml(f.read()) - dhvap_target = dataset.properties[0] - -job_specs = list() - -base_dir = "dhvap_example" - - -# production on GPU cluster -if False: - with SimulationWorkflow(base_dir, slurm_config("gpu")) as workflow: - pass - -# local testing -with SimulationWorkflow(base_dir, local_config(max_workers=10)) as workflow: - for extra_molecules in range(2): - workflow.submit_target( - dhvap_target, - force_field="openff-2.3.0.offxml", - n_molecules=500 + extra_molecules, - n_replicates=5, - ) - - for extra_molecules in range(2): - workflow.estimate_target( - dhvap_target, - force_field="openff-2.3.0.offxml", - n_molecules=500 + extra_molecules, - n_replicates=5, - ) - -""" -dHvap estimate for target with below ID, force field openff-2.3.0.offxml, 500 molecules, and -5 replicates: - (target ID: -4455979010545387927019552539812888795231031600148607549210198983695932067156) - 49.108 ± 1.366 kJ/mol -dHvap estimate for target with below ID, force field openff-2.3.0.offxml, 501 molecules, and -5 replicates: - (target ID: -4455979010545387927019552539812888795231031600148607549210198983695932067156) - 49.096 ± 1.310 kJ/mol -""" - -try: - parsl.clear() - parsl.dfk().cleanup() -except Exception: - pass diff --git a/tyff/compute/workflow.py b/tyff/compute/workflow.py index 179ecc8..88bef12 100644 --- a/tyff/compute/workflow.py +++ b/tyff/compute/workflow.py @@ -113,7 +113,7 @@ def submit_target( def submit_target_batch( self, - target_configs: list[DataEntry], + target_configs: Sequence[DataEntry], force_field: str, n_molecules: int, n_replicates: int = 3, From 42f5fc25a89ca12869417dee5c4f13e23597e02b Mon Sep 17 00:00:00 2001 From: "Matthew W. Thompson" Date: Fri, 25 Sep 2026 12:34:54 -0500 Subject: [PATCH 2/4] Update `.gitignore` to include VS Code config --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9971668..a848e6f 100644 --- a/.gitignore +++ b/.gitignore @@ -189,7 +189,7 @@ cython_debug/ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore # and can be added to the global gitignore or merged into this file. However, if you prefer, # you could uncomment the following to ignore the entire vscode folder -# .vscode/ +.vscode/ # Ruff stuff: .ruff_cache/ From e61c6ee384749438c54c5190cda41950d4c51f22 Mon Sep 17 00:00:00 2001 From: "Matthew W. Thompson" Date: Fri, 25 Sep 2026 15:04:14 -0500 Subject: [PATCH 3/4] Add back `TensorReporter` in MD simulations --- tyff/compute/_equilibrate.py | 20 +++++++++++++++----- tyff/compute/_produce.py | 28 +++++++++++++++++++--------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/tyff/compute/_equilibrate.py b/tyff/compute/_equilibrate.py index 36fac51..641916f 100644 --- a/tyff/compute/_equilibrate.py +++ b/tyff/compute/_equilibrate.py @@ -5,6 +5,7 @@ from parsl import File +import tyff.mm from tyff.compute._files import ( EquilibrationFiles, MinimizationFiles, @@ -122,18 +123,27 @@ def _run_equilibration( ) ) - dcd_reporter = openmm.app.DCDReporter( - file=files["dcd_trajectory"].filepath, - reportInterval=1000, + simulation.reporters.append( + openmm.app.DCDReporter( + file=files["dcd_trajectory"].filepath, + reportInterval=1000, + ) ) - simulation.reporters.append(dcd_reporter) - simulation.context.setVelocitiesToTemperature( compute_config["temperature"], # kelvin, but as float compute_config["replicate_index"] + 1, ) + simulation.reporters.append( + tyff.mm.TensorReporter( + output_file=open(files["msgpack_trajectory"].filepath, "ab"), + report_interval=1000, + beta=1.0 / openmm.unit.kilocalories_per_mole, + pressure=pressure * openmm.unit.kilopascal, + ) + ) + logger.info("Running 10,000 steps of MD") detected_platform = simulation.context.getPlatform().getName() diff --git a/tyff/compute/_produce.py b/tyff/compute/_produce.py index 78caec1..ede5c77 100644 --- a/tyff/compute/_produce.py +++ b/tyff/compute/_produce.py @@ -7,6 +7,7 @@ import openmm.app from parsl import File +import tyff.mm from tyff.compute._files import ( EquilibrationFiles, ProductionFiles, @@ -97,6 +98,11 @@ def _run_production( assert barostat.getDefaultPressure() is not None + pressure = compute_config.get("pressure", None) + + if pressure is None: + raise PressureNotDefinedError("Trying to set up NPT simulation but no pressure defined.") + simulation.context.setVelocitiesToTemperature( compute_config["temperature"], # kelvin, but as float compute_config["replicate_index"] + 1, @@ -117,17 +123,21 @@ def _run_production( ) ) - dcd_reporter = openmm.app.DCDReporter( - file=files["dcd_trajectory"].filepath, - reportInterval=1000, + simulation.reporters.append( + openmm.app.DCDReporter( + file=files["dcd_trajectory"].filepath, + reportInterval=1000, + ) ) - simulation.reporters.append(dcd_reporter) - - pressure = compute_config.get("pressure", None) - - if pressure is None: - raise PressureNotDefinedError("Trying to set up NPT simulation but no pressure defined.") + simulation.reporters.append( + tyff.mm.TensorReporter( + output_file=open(files["msgpack_trajectory"].filepath, "ab"), + report_interval=1000, + beta=1.0 / openmm.unit.kilocalories_per_mole, + pressure=pressure * openmm.unit.kilopascal, + ) + ) logger.info("Running 100,000 steps of MD") From 5dfff60901718c7b277896e298ac3840b1e5891b Mon Sep 17 00:00:00 2001 From: "Matthew W. Thompson" Date: Mon, 28 Sep 2026 12:01:44 -0500 Subject: [PATCH 4/4] Claude-suggested improvements --- tyff/compute/_equilibrate.py | 4 ++-- tyff/compute/_produce.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tyff/compute/_equilibrate.py b/tyff/compute/_equilibrate.py index 641916f..c61e273 100644 --- a/tyff/compute/_equilibrate.py +++ b/tyff/compute/_equilibrate.py @@ -137,9 +137,9 @@ def _run_equilibration( simulation.reporters.append( tyff.mm.TensorReporter( - output_file=open(files["msgpack_trajectory"].filepath, "ab"), + output_file=files["msgpack_trajectory"].filepath, report_interval=1000, - beta=1.0 / openmm.unit.kilocalories_per_mole, + beta=1.0 / (openmm.unit.MOLAR_GAS_CONSTANT_R * compute_config["temperature"] * openmm.unit.kelvin), pressure=pressure * openmm.unit.kilopascal, ) ) diff --git a/tyff/compute/_produce.py b/tyff/compute/_produce.py index ede5c77..12f5bd9 100644 --- a/tyff/compute/_produce.py +++ b/tyff/compute/_produce.py @@ -132,9 +132,9 @@ def _run_production( simulation.reporters.append( tyff.mm.TensorReporter( - output_file=open(files["msgpack_trajectory"].filepath, "ab"), + output_file=files["msgpack_trajectory"].filepath, report_interval=1000, - beta=1.0 / openmm.unit.kilocalories_per_mole, + beta=1.0 / (openmm.unit.MOLAR_GAS_CONSTANT_R * compute_config["temperature"] * openmm.unit.kelvin), pressure=pressure * openmm.unit.kilopascal, ) )