Summary
Compute-heavy tasks in MDFactory (building systems, running simulations) are currently handed off to Nextflow (workflows/simulate.nf, workflows/build.nf) and require manual orchestration via shell scripts (workflows/run_full_pipeline.sh). Nextflow will be removed completely. There is no smooth Python-native integration of compute workflow management. For analysis execution, we use submitit to wrap lightweight Python functions for trajectory analyses (mdfactory/analysis/submit.py), but this doesn't extend to the heavier build/simulate workloads.
This issue tracks a proof-of-concept investigation of Parsl as a Python-native workflow manager for MDFactory, particularly for handling GROMACS MD runs and system builds through its bash_app, SLURM provider, retry functionality, and checkpoint/restart support.
Current Behavior
- Simulation orchestration is done via Nextflow processes (
minimization → nvt → npt → production) defined in workflows/simulate.nf with SLURM config in workflows/simulate.config.
- Build orchestration uses
workflows/build.nf to run mdfactory prepare-build then mdfactory build per hash.
- Analysis dispatch uses submitit (
mdfactory/analysis/submit.py) — one SLURM job per simulation path.
- There is no Python-level MD run orchestration; the user must manually invoke Nextflow and adapt SLURM configuration.
- No unified status tracking, retry handling, or restart capability across build/simulate/analysis.
Proposed Behavior
A Parsl-based execution layer inside MDFactory that:
- Replaces Nextflow entirely for both build and simulation orchestration.
- Runs system builds (
mdfactory build) on GPU nodes via SLURM — builds are compute-heavy (OpenMM compression) and belong on HPC, not login nodes.
- Chains GROMACS simulation stages (EM → NVT → NPT → production) via
@bash_app + futures.
- Submits work to SLURM via
HighThroughputExecutor + SlurmProvider (pilot-job model).
- Supports custom workflow composition on the fly — e.g., packing multiple simulations onto a single node/job, or composing arbitrary build→simulate→analysis pipelines from Python.
- Closely integrates with and reuses existing MDFactory building blocks (
build.py, run_schedules/, Pydantic models) rather than reimplementing logic.
- Handles embarrassingly parallel campaigns (hundreds of independent builds/simulations).
- Provides retry, checkpoint/restart, and monitoring without external tooling.
Note: SLURM autodetection (detecting whether we're on a SLURM cluster) is out of scope — handled separately in another PR.
Requirements Matrix
| Capability |
Parsl Mechanism |
PoC Scope |
| Python-native orchestration |
@bash_app/@python_app decorators, futures-based DAG |
✅ Core |
| CLI integration |
Config objects generated from MDFactory models |
✅ Core |
| System-building workflow support |
@python_app or @bash_app invoking mdfactory build on GPU nodes |
✅ Core |
| Simulation workflow support |
@bash_app chaining EM→NVT→NPT→production |
✅ Core |
| SLURM submission |
SlurmProvider + HighThroughputExecutor |
✅ Core |
| Embarrassingly parallel execution |
Loop of app calls → auto-parallel futures |
✅ Core |
| External command execution |
@bash_app returns shell command string (with module loads, cd, etc.) |
✅ Core |
| Dynamic workflow generation |
Plain Python generating app calls from Pydantic models |
✅ Core |
| Pydantic-compatible planning |
MDFactory models → Parsl config/task generation |
✅ Core |
| Reusable command/task templates |
Parameterized @bash_app functions reusing MDFactory building blocks |
✅ Core |
| Custom workflow composition |
Composing tasks flexibly (multi-sim per node, arbitrary pipelines) |
✅ Core |
| Monitoring / job status tracking |
MonitoringHub → SQLite DB |
✅ Core |
| User-facing status command |
Query monitoring.db or MDFactory state |
🔲 Stretch |
| Retries |
Config(retries=N, retry_handler=...) |
✅ Core |
| Restart / resume support |
checkpoint_mode='task_exit' + get_all_checkpoints() |
✅ Core |
| GROMACS checkpoint restart |
@bash_app generating gmx mdrun -cpi ... -append |
🔲 Stretch |
| Output-aware completion checks |
Pre-check output files before submitting task |
🔲 Stretch |
| MDFactory-owned persistent state |
Sync Parsl monitoring.db to MDFactory registry |
🔲 Future |
| Dry-run / inspectable plan |
Generate tasks without parsl.load() |
✅ Core |
| Multi-stage workflow composition |
Future-chaining: step2(step1(x)) |
✅ Core |
| Many-simulation campaign execution |
Loop over hashes/replicas |
✅ Core |
| Minimal boilerplate |
Single Config object, no external files |
✅ Core |
| Low conceptual overhead |
Hidden behind MDFactory CLI/API |
✅ Core |
| Backend abstraction |
LocalProvider ↔ SlurmProvider swap |
✅ Core |
| Future extensibility |
Multiple executors, @join_app for dynamic sub-workflows |
🔲 Future |
Acceptance Criteria
Technical Notes
Relevant existing code to reuse/integrate with:
mdfactory/build.py — build pipeline (build_mixedbox, build_bilayer, build_lnp) — should be callable from Parsl tasks
mdfactory/workflows.py — run_build_from_file() / run_build_from_dict() dispatch
mdfactory/run_schedules/gromacs/ — MDP templates for EM/NVT/NPT/production
mdfactory/models/input.py — BuildInput Pydantic model with SHA-1 hash
mdfactory/analysis/submit.py — existing submitit pattern (SlurmConfig dataclass, path resolution)
mdfactory/cli.py — cyclopts CLI (integration point for workflow commands)
workflows/simulate.nf — current Nextflow workflow (reference for what to replace)
workflows/simulate.config — SLURM config (maps to SlurmProvider params)
Parsl architecture for this use case:
HighThroughputExecutor with SlurmProvider + SrunLauncher for GPU nodes
worker_init for environment setup: module load gromacs-gpu, conda/pixi activation, etc.
scheduler_options='#SBATCH --gres=gpu:1' for GPU allocation
- Pilot-job model: few SLURM jobs hosting many tasks (reduces scheduler pressure vs. submitit's 1-job-per-task)
MonitoringHub for SQLite-backed status tracking
HPC-aware bash_app patterns to validate:
@bash_app
def grompp(work_dir, mdp, gro, top, tpr_out, stdout=parsl.AUTO_LOGNAME):
# Real HPC apps need: module loads, cd to workdir, proper env
return f'''
module load gromacs-gpu/2024
cd {work_dir}
gmx grompp -f {mdp} -c {gro} -p {top} -o {tpr_out} -maxwarn 1
'''
@bash_app
def mdrun(work_dir, tpr, deffnm, ntomp=8, stdout=parsl.AUTO_LOGNAME):
return f'''
module load gromacs-gpu/2024
cd {work_dir}
gmx mdrun -s {tpr} -deffnm {deffnm} -ntomp {ntomp} -nb gpu -pme gpu
'''
@python_app
def build_system(build_input_dict):
"""Run mdfactory build on a GPU node — reuses existing building blocks."""
from mdfactory.workflows import run_build_from_dict
return run_build_from_dict(build_input_dict)
# Chain: grompp → mdrun, implicit dependency via futures
tpr = grompp('/scratch/sim001', 'em.mdp', 'system.gro', 'topology.top', 'em.tpr')
em_result = mdrun('/scratch/sim001', tpr, 'min')
# Custom workflow: multiple sims on one node
@bash_app
def multi_sim_node(work_dirs, deffnms, stdout=parsl.AUTO_LOGNAME):
"""Pack multiple short simulations onto a single GPU node."""
commands = []
for wd, name in zip(work_dirs, deffnms):
commands.append(f'cd {wd} && gmx mdrun -deffnm {name} -ntomp 4 &')
commands.append('wait')
return '\n'.join(['module load gromacs-gpu/2024'] + commands)
Risks to investigate:
- Working directory management: Parsl workers may not
cd to the expected simulation directory — must be explicit in bash_app commands
- Environment setup:
module load and pixi/conda activation must work inside worker processes
- GPU allocation: ensuring correct GPU assignment when multiple tasks share a node
- File staging: whether
parsl.File objects are needed or if absolute paths suffice on shared filesystems
- Custom node packing: whether
HighThroughputExecutor supports multiple tasks per node cleanly, or if WorkQueueExecutor / TaskVineExecutor is better
- Overhead of monitoring for large campaigns (1000+ tasks)
- Serialization of MDFactory objects (Pydantic models, OpenFF molecules) when using
@python_app
Summary
Compute-heavy tasks in MDFactory (building systems, running simulations) are currently handed off to Nextflow (
workflows/simulate.nf,workflows/build.nf) and require manual orchestration via shell scripts (workflows/run_full_pipeline.sh). Nextflow will be removed completely. There is no smooth Python-native integration of compute workflow management. For analysis execution, we use submitit to wrap lightweight Python functions for trajectory analyses (mdfactory/analysis/submit.py), but this doesn't extend to the heavier build/simulate workloads.This issue tracks a proof-of-concept investigation of Parsl as a Python-native workflow manager for MDFactory, particularly for handling GROMACS MD runs and system builds through its
bash_app, SLURM provider, retry functionality, and checkpoint/restart support.Current Behavior
minimization → nvt → npt → production) defined inworkflows/simulate.nfwith SLURM config inworkflows/simulate.config.workflows/build.nfto runmdfactory prepare-buildthenmdfactory buildper hash.mdfactory/analysis/submit.py) — one SLURM job per simulation path.Proposed Behavior
A Parsl-based execution layer inside MDFactory that:
mdfactory build) on GPU nodes via SLURM — builds are compute-heavy (OpenMM compression) and belong on HPC, not login nodes.@bash_app+ futures.HighThroughputExecutor+SlurmProvider(pilot-job model).build.py,run_schedules/, Pydantic models) rather than reimplementing logic.Note: SLURM autodetection (detecting whether we're on a SLURM cluster) is out of scope — handled separately in another PR.
Requirements Matrix
@bash_app/@python_appdecorators, futures-based DAG@python_appor@bash_appinvokingmdfactory buildon GPU nodes@bash_appchaining EM→NVT→NPT→productionSlurmProvider+HighThroughputExecutor@bash_appreturns shell command string (with module loads, cd, etc.)@bash_appfunctions reusing MDFactory building blocksMonitoringHub→ SQLite DBmonitoring.dbor MDFactory stateConfig(retries=N, retry_handler=...)checkpoint_mode='task_exit'+get_all_checkpoints()@bash_appgeneratinggmx mdrun -cpi ... -appendparsl.load()step2(step1(x))Configobject, no external filesLocalProvider↔SlurmProviderswap@join_appfor dynamic sub-workflowsAcceptance Criteria
@bash_appthat runsgmx grompp+gmx mdrunfor a single simulation stage, including proper HPC context (module loads, working directory, environment setup)mdfactory build) running on GPU nodes via SLURM through ParslSlurmProvideron the HPC clusterCustom workflow composition demonstrated (e.g., multiple simulations packed onto a single node/job)build.py, Pydantic models, run schedules — not reimplementing)Technical Notes
Relevant existing code to reuse/integrate with:
mdfactory/build.py— build pipeline (build_mixedbox,build_bilayer,build_lnp) — should be callable from Parsl tasksmdfactory/workflows.py—run_build_from_file()/run_build_from_dict()dispatchmdfactory/run_schedules/gromacs/— MDP templates for EM/NVT/NPT/productionmdfactory/models/input.py—BuildInputPydantic model with SHA-1 hashmdfactory/analysis/submit.py— existing submitit pattern (SlurmConfigdataclass, path resolution)mdfactory/cli.py— cyclopts CLI (integration point for workflow commands)workflows/simulate.nf— current Nextflow workflow (reference for what to replace)workflows/simulate.config— SLURM config (maps toSlurmProviderparams)Parsl architecture for this use case:
HighThroughputExecutorwithSlurmProvider+SrunLauncherfor GPU nodesworker_initfor environment setup:module load gromacs-gpu, conda/pixi activation, etc.scheduler_options='#SBATCH --gres=gpu:1'for GPU allocationMonitoringHubfor SQLite-backed status trackingHPC-aware bash_app patterns to validate:
Risks to investigate:
cdto the expected simulation directory — must be explicit in bash_app commandsmodule loadand pixi/conda activation must work inside worker processesparsl.Fileobjects are needed or if absolute paths suffice on shared filesystemsHighThroughputExecutorsupports multiple tasks per node cleanly, or ifWorkQueueExecutor/TaskVineExecutoris better@python_app