PathGennie is a lightweight Python toolkit for generating reactive molecular
dynamics paths with short adaptive MD bursts. It supports AMBER, GROMACS, and
OpenMM backends through small, case-local input.yaml files plus user-defined
collective variables and convergence checks.
The workflow is designed for fast path discovery: launch multiple short
tau1 trials from the current anchor state, bias the next anchor toward
progress in a projection space, continue with tau2, and repeat until the
case-specific convergence criterion is met.
The repository includes compact examples for conformational change, peptide folding/unfolding, host-guest unbinding, and QM/MM steering.
| Example | Backend(s) | What it demonstrates |
|---|---|---|
examples/alanine_dipeptide |
AMBER, GROMACS, OpenMM | Targeted phi/psi transition between Ramachandran basins |
examples/CLN025 |
AMBER, GROMACS | Chignolin path generation with end-to-end distance projections |
examples/OAMe-G2 |
GROMACS, OpenMM | Host-guest unbinding with COM-COM distance projections |
examples/qmmm_alanine_conformation |
AMBER | QM/MM alanine-dipeptide conformational steering |
examples/qmmm_reactive_sn2 |
AMBER | Reactive QM/MM: bond breaking/forming, refinement, free energy |
examples/path_refinement_engines |
all four | Engine-agnostic path refinement on any backend |
These animations are tracked in the repo and can be used as visual references for the kinds of paths PathGennie produces.
|
|
|
pathgennie/
core/ Backend-independent driver, selection, progress, device pool,
Engine + ExplorerPolicy protocols, strategy profiles, toy engine
cv/ Data-driven CVs: NumPy featurization + on-the-fly SPIB
(learned CV + emergent metastable states; needs PyTorch)
search/ Non-linear search: RRT / RRT-Connect + conformational roadmap
graph (Dijkstra + Yen k-shortest all-pairs pathways)
agent/ Rule-based agentic controller (adaptive N / tau1 / tau2)
sampling/ Enhanced-sampling stages on one contract (PathEnsemble +
SamplingStage): path-informed Weighted Ensemble and OPES (PLUMED)
utils/ Config validation, node-local scratch, ligand conformation /
PCA distance-CV generation (LigPCGen, `pcagen` CLI)
backends/
amber/ Device-aware AMBER engine + runner
gromacs/ Device-aware GROMACS engine + runner
openmm/ OpenMM in-process engine + runner
pathrefinement/ Path CVs (Branduardi s/z) + ensemble principal-curve path
refiner, with Muller-Brown / AlaD / CLN025 examples
we/ Standalone Huber-Kim Weighted Ensemble framework (wepath)
docs/ Manual + tutorials (start at docs/index.md)
tests/ pytest suite (selection, CV, I/O, device dispatch,
SPIB, RRT, roadmap, controller, WE, config, HPC parallel safety)
hpc/ PBS + Slurm submission scripts + self-check for cluster testing
benchmarks/
scaling.py Device-pool scaling benchmark
we_fes.py WE free-energy validation vs the analytic Wolfe-Quapp marginal
examples/
alanine_dipeptide/
CLN025/
OAMe-G2/
qmmm_alanine_conformation/
qmmm_reactive_sn2/
path_refinement_engines/
assets/
unbind.gif
unbind.webp
reaction.webp
movie.webp
CHANGELOG.md
environment.yml
Full manual and tutorials live in docs/; release notes in
CHANGELOG.md; the forward-looking strategic plan in
ROADMAP.md. Highlights: multi-GPU,
strategy profiles, SPIB CV,
RRT search, roadmap graph,
agentic controller, Weighted Ensemble,
OPES, path CVs,
path refinement, PCA CV space,
and the HPC guide.
Create the supplied Conda environment:
conda env create -f environment.yml
conda activate pathgennieInstall the package from this checkout:
pip install .
pip install ".[openmm]" # OpenMM backend (no longer a core dependency)
pip install ".[analysis]" # pcagen + path clusteringFor development, install it in editable mode:
pip install -e ".[examples]"Backend executables are configured per example. Update paths such as
amber.executable or gromacs.executable in the relevant input.yaml before
running on your machine.
cd examples/alanine_dipeptide/amber
python run_pg_amber.pyOutputs are written to pathgennie_amber_run/output/ by default:
reactive_path.pdbmetrics.csv
cd examples/alanine_dipeptide/gromacs
python run_pg_gromacs.pyOutputs are written to pathgennie_gmx_run/output/ by default:
reactive_path.xtcmetrics.csv
cd examples/alanine_dipeptide/openmm
python run_pg_openmm.pyOutputs are written to pathgennie_openmm_run/output/ by default:
reactive_path.dcdmetrics.csv
cd examples/qmmm_alanine_conformation/amber
python run_pg_amber.py --config input_c7ax.yamlSee
examples/qmmm_alanine_conformation/amber/README.md
for the QM/MM region, targets, and regeneration notes.
Bond breaking and forming, not just a conformational change. The four stages — discover, refine into a PathCV, free energy along it, plot — all at one level of theory (DFTB3):
cd examples/qmmm_reactive_sn2/amber
python 1_generate_paths.py --seeds 10 # multi-seed reactive path ensemble
python 2_refine_pathcv.py # -> a smooth PathCV
python 3_free_energy.py # -> F(s) by Weighted Ensemble
python 4_plot_2d_cv.py --ts 2.3565 # -> the 2-D mechanism plotSee examples/qmmm_reactive_sn2/amber/README.md
and the QM/MM workflow guide, which covers method
choice, why reactive barriers need shorter swarm segments than conformational
ones, and how a convergence criterion can report success on a reaction that never
happened.
PathRefiner accepts an injected sampler, so refinement is no longer OpenMM-only:
cd examples/path_refinement_engines
python refine_with_engine.py --engine toy # or openmm / amber / gromacsEach case is driven by a case-local YAML configuration file (typically input.yaml) containing configuration options for the simulation backend, PathGennie adaptive sampling parameters, MD engine controls, and the projection/convergence functions.
The file has four main parts:
- Backend block:
amber,gromacs, oropenmminput files and executable settings. pathgennie: adaptive sampling settings such asmode,tau1_steps,tau2_steps,max_trial,max_cycle,sigma, andtemperature. Multi-GPU / reproducibility keys:devices(list of GPU indices to spread the swarm across),workers_per_device(concurrent segments per GPU; replaces the legacytau1_workers), andseed(master RNG seed for the selection and velocity draws). Goal key:profile(discoveryfor fast candidate paths with ultrashort, greedy, geometric-CV trajectories — the original regime;samplingfor longer trajectories, a learned CV, and a downstream enhanced-sampling stage). Profile values are defaults; any explicitpathgenniekey overrides them.projection: Python module and function that map coordinates to a collective-variable vector.convergence: Python module and function that decide when the generated path has reached the desired state.
workdir(str): Output and scratch directory path. Defaults topathgennie_run(AMBER),pathgennie_gmx_run(GROMACS), orpathgennie_openmm_run(OpenMM).output(dict, OpenMM only): Override output files:trajectory(str): Filename for output reactive path. Defaults toreactive_path.dcd.metrics(str): Filename for output metrics CSV. Defaults tometrics.csv.wrap_pbc(bool): Iftrue, wrap coordinates within periodic box boundaries. Defaults tofalse.
system(dict, OpenMM only):system_file(str): Python script file (e.g.,system.py) containing a custommake_systembuilder.
topology(str): Path to.prmtoptopology file.initial_restart(str): Path to.rst7or.inpcrdcoordinate file.executable(str): Path to simulator executable (e.g.,sander,pmemd,pmemd.cuda).system(str): System type, either"explicit"or"implicit". Defaults to"explicit".mpi_launcher(str, optional): MPI launcher executable (e.g.,mpirun,mpiexec).mpi_ranks(int, optional): Number of parallel MPI processes (default: 1).mpi_launcher_args(list, optional): Additional arguments for the MPI launcher.
topology(str): Path to.toptopology file.initial_structure(str): Path to.grocoordinate structure file.executable(str): Path to GROMACS executable (e.g.,gmx,gmx_mpi).mdp(str): Path to a base GROMACS.mdpcontrol template file. Defaults tomd.mdp.reference_template(str, optional): Reference structure/topology file for mapping atom indices. (aliases:reference_structure,metadata). Defaults toinitial_structure.grompp_args(list, optional): List of command line flags to pass to GROMACSgrompp.mdrun_args(list, optional): List of command line flags to pass to GROMACSmdrun.
topology(str): Path to AMBER.prmtopor GROMACS.toptopology file.initial_restart(str): Path to AMBER.rst7/.inpcrdor GROMACS.grocoordinate structure file.platform(str): OpenMM platform name (Reference,CPU,CUDA, orOpenCL). Defaults toCPU.
mode(str): Sampling mode, either"escape"(drive progress away from start) or"target"(drive progress toward a target state).tau1_steps(int): Number of MD simulation steps per short-burst sampling trial.tau2_steps(int): Number of MD simulation steps per segment extension.max_trial(int): Number of parallel sampling trials run in each cycle.max_cycle(int): Maximum number of adaptive sampling cycles to run.save_freq(int): Number of cycles between saving coordinate frames (default: 10).sigma(float): Boltzmann weighting parameter controlling selection bias (lower = higher bias).temperature(float): Simulation temperature in Kelvin (default: 300.0).verbosity(int): Logging detail level:0(silent),1(minimal),2(verbose).target_projection(list of float, Target Mode only): Target CV coordinates.escape_metric(str, Escape Mode only):"distance_from_start"(maximise the Euclidean distance from the start CV — the default, and the objective the method is published with) or"cv0"(legacy: maximise only the first CV component). All three backends honour this key and share the same default. Before v1.4 the backends disagreed — OpenMM always useddistance_from_startwhile AMBER and GROMACS defaulted tocv0— so an identicalinput.yamloptimised a different quantity depending on the engine. Setescape_metric: cv0explicitly to restore the old AMBER/GROMACS behaviour.seed(int, optional): Master RNG seed for the selection draw and per-segment velocity randomisation. Set it for reproducible runs — the seed → trial mapping is deterministic even across the multi-GPU thread pool.
Parallel / device placement (AMBER, GROMACS & OpenMM):
devices(list of int, optional): Logical GPU indices to spread the swarm across. Interpreted relative to the scheduler'sCUDA_VISIBLE_DEVICESallocation — with--gres=gpu:2(Slurm) orngpus=2(PBS),devices: [0, 1]targets the two GPUs you were granted, never GPUs owned by another job. AMBER/GROMACS run each segment as a subprocess on its device; OpenMM builds one pool of in-process Contexts per listed device and runs each segment on a Context of the device it was assigned (trial i →devices[i % n]).workers_per_device(int, optional): Concurrent MD segments per device (replaces the legacytau1_workers). Use1for large systems that already fill a GPU;>1only for small systems. For OpenMM this is the number of Contexts per device ("auto": CPU cores, capped by free GPU memory).cpu_threads_per_worker(int, optional): Pin per-worker OpenMP/MKL threads (and inject GROMACS-ntomp) so concurrent CPU segments do not each grab every core. Set roughlycores / (devices × workers_per_device).
Streaming, rejection & downstream:
checkpoint_path(str, optional): Stream frames/metrics to this HDF5 file as the run proceeds (bounded memory for long runs).reject_worse_tau2/reject_worse_anchor(bool, optional): Reject a tau2 runner worse than its sampler / a candidate worse than the current anchor.profile(str, optional):discovery(fast candidate paths — the original ultrashort/greedy/geometric-CV regime) orsampling(longer segments, learned CV, downstream stage). Supplies defaults; explicit keys always win.downstream(str, optional): Name of a downstream enhanced-sampling stage (e.g.weighted_ensemble); its settings go in a top-level block of that name.
HPC note. For scaling on Slurm/PBS clusters — device placement, CPU thread pinning, node-local scratch, and known limitations — see the dedicated guide in
docs/hpc.mdand the review indocs/HPC_REVIEW.md.
controls(dict, AMBER/GROMACS): Key-value dictionary of.mdinor.mdpconfig parameters to override.extra_text(str, AMBER only): Arbitrary block of text to append to the end of the generated.mdinfiles.timestep_ps(float, OpenMM only): Integrator step size in picoseconds. Defaults to0.002.friction_per_ps(float, OpenMM only): Langevin integrator friction coefficient. Defaults to1.0.equilibration_steps(int, OpenMM only): Equilibration steps to run before path generation. Defaults to0.pressure(float, OpenMM only): System pressure in bar for Barostat when custom builders are loaded. Defaults to1.0.plumed_file(str, OpenMM only): Path to PLUMED file to attach PLUMED-based forces.
-
module(str): Case-local Python filename (without.py) containing the CV calculation function. -
function(str): Name of the Python function within that module. -
periodic(list, optional): Per-component CV period, used when scoring progress. Give360.0for an angle in degrees,6.283185for radians, andnullfor a non-periodic component such as a distance or PCA projection — e.g.periodic: [360.0, 360.0]for a (phi, psi) CV, or[360.0, null]for an angle plus a distance. Omit it entirely and every component is treated as non-periodic (the previous behaviour). Set this for dihedral CVs: without it, two angles either side of the ±180° branch cut are scored as ~360° apart when they are adjacent, which inflates the progress metric ~10× and rewards the sampler for crossing the cut instead of making real progress. -
Additional options: Any extra keys defined in this block are passed dynamically as keyword arguments (
**kwargs) to the projection function. -
Periodic box of each frame: declare a parameter named
boxand the function receives the box of the frame being scored, as a(3, 3)array of box-vector rows in Å (box.diagonal()gives the edge lengths of an orthorhombic box), or nothing for a non-periodic system. Under a barostat each trial has its own box, so minimum-image distances, periodic cluster analysis and densities should use it rather than a fixed value. All three backends supply it (OpenMM State box vectors, the.grobox line, therst7box line). Functions without aboxparameter are called exactly as before (**kwargsalone does not opt in). Aboxkey in this block acts as a fallback for frames without one. The same applies to the convergence function. Each saved frame's box is stored in the HDF5 output (box, aligned withtrajectory), and checkpoints keep the anchor's box, so a constant-pressure run resumes in its own box rather than the starting one.def ice_cluster_cv(coords, box=None, cutoff=3.5): L = box.diagonal() # this frame's box, Å ...
module(str): Case-local Python filename (without.py) containing the convergence check function.function(str): Name of the Python function.- Additional options: Any extra keys defined in this block are passed dynamically as keyword arguments (
**kwargs) to the convergence function.
pathgennie:
mode: target
target_projection: [60.0, 40.0]
tau1_steps: 2
tau2_steps: 4
max_trial: 10
max_cycle: 1000
save_freq: 10
sigma: 0.1
temperature: 300
projection:
module: phi_psi
function: phi_psi_cv
convergence:
module: phi_psi
function: reached_phi_psi
target: [60.0, 40.0]
tolerance: 15.0pathgennie:
mode: escape
tau1_steps: 5
tau2_steps: 10
devices: [0, 1, 2, 3] # spread the 10 samplers across 4 GPUs
workers_per_device: 1
seed: 12345 # reproducible selection / velocity draws
max_cycle: 5000
save_freq: 2
sigma: 0.25
temperature: 300
projection:
module: projection
function: com_com_distance_cv
group_a_resname: OCB
group_b_resname: MOL
convergence:
module: projection
function: dissociated
group_a_resname: OCB
group_b_resname: MOL
threshold: 10.0Instead of a hand-crafted progress variable, PathGennie can learn one on the fly
with SPIB (State Predictive Information Bottleneck, pathgennie.cv.spib),
which jointly learns a low-dimensional CV and an emergent set of metastable
states from the frames the run visits. SPIBProgress bootstraps from a coarse
geometric CV, buffers the path, retrains periodically (the iterative
path-learning cycle), and then steers using the learned latent. It is an adaptive
ProgressVariable, so it plugs into the same driver as the built-in metrics.
Requires the ml extra (pip install -e .[ml], i.e. PyTorch).
Once a path is discovered, the sampling package turns it into quantitative
results. WeightedEnsembleStage (pathgennie.sampling.weighted_ensemble) runs
path-informed Weighted Ensemble: it seeds weighted walkers from the discovered
PathEnsemble, propagates them with unbiased MD (reusing the same Engine and
multi-GPU executor — no bias forces), and resamples (split/merge, weight-conserving)
to keep walkers spread across CV bins along the path. It returns a free-energy
profile along the CV and, with recycling enabled, a steady-state rate constant.
WE and the OPES stage implement one SamplingStage contract and are selected by
name via make_stage("weighted_ensemble" | "opes", ...) or the
pathgennie.downstream config key, which the backends honour: set
downstream: weighted_ensemble (plus a weighted_ensemble: block) and the run
discovers a path then runs WE automatically, writing free_energy.csv (and
rate_constants.json if recycling). To do it from Python, run the driver with
collect_seeds=True and build the ensemble with build_path_ensemble(...).
benchmarks/we_fes.py validates the recovered free energy against the analytic
Wolfe–Quapp marginal (Pearson r ≈ 0.99).
OPES (free-energy surfaces) via PLUMED. OPESStage
(pathgennie.sampling.opes) generates an OPES_METAD PLUMED input and drives a
PLUMED-capable engine; a dependency-free OPES core (verified on the toy
Wolfe–Quapp marginal) is also provided. See docs/opes.md.
Path sampling (TPS/TIS) via OpenPathSampling. As an alternative to WE for
kinetics, PathSamplingStage (pathgennie.sampling.path_sampling) bridges a
discovered PathEnsemble to OpenPathSampling:
PathGennie's reactive path seeds TPS/TIS. The seed preparation (state ranges,
reactive sub-path extraction, TIS interfaces) is dependency-free and tested;
running TPS/TIS needs the pathsampling extra and an OPS engine. See
docs/path-sampling.md.
Beyond the greedy path, pathgennie.search.rrt provides RRT / RRT-Connect
tree search for pathways the monotone metric cannot follow (backtracking,
direction changes, orthogonal CVs), pathgennie.search.roadmap builds a
conformational graph and extracts the minimum-free-energy and competing pathways
between metastable states (Dijkstra + Yen), and pathgennie.agent provides a
rule-based controller that adapts the swarm size and segment lengths on the fly.
See the docs for details and tutorials.
The pathrefinement/ package adds path collective variables and a
path-refinement workflow on top of the discovery loop:
- Path CVs (
s,z) —pathrefinement.PathCVimplements the Branduardi path collective variables (progress along a reference path,s, and distance off it,z). Use them as a progress CV to follow or stay on a known channel. Seedocs/path-cv.md. - Path refinement —
pathrefinement.PathRefinerturns a rough initial path (e.g. one PathGennie discovers) into a smooth, representative path by alternating short MD exploration with a machine-learned principal-curve consensus. Runnable numbered examples for the Müller-Brown potential, alanine dipeptide, and chignolin live inpathrefinement/examples/. Seedocs/path-refinement.mdandpathrefinement/README.md. *(Needs themlextra- OpenMM.)*
- Artificial PCA distance-CV space —
pathgennie pcagenbuilds a robust PCA distance-CV space for host–guest / protein–ligand systems and reports the dimension of maximum separation. Seedocs/pca-cv.md.
- Copy the closest example directory for your backend.
- Replace topology, coordinate, restart, and MD-control files.
- Update the backend executable path in
input.yaml. - Implement a projection function that accepts coordinates and returns a NumPy array-like CV.
- Implement a convergence function that returns
Truewhen the path is done. - Tune
tau1_steps,tau2_steps,max_trial,sigma, andmax_cyclefor the system size and available compute.
PathGennie writes two primary artifacts:
- Reactive path trajectory: backend-dependent format such as
.pdb,.dcd,.xtc, or.nc. - Metrics CSV: one metric sample per adaptive cycle.
For AMBER and GROMACS runs, scratch files are created under the configured
workdir and removed after a successful run. Generated tau1 and tau2 MD
control files are kept in the work directory for inspection.
This project is distributed under the terms of the
LICENSE file.


