Cross-backend MD handoff (PyCHARMM ↔ JAX-MD ↔ ASE)¶
Campaign jobs chain via depends_on. Each completed stage writes
output_dir/handoff/state.npz (and optionally handoff/final.res) containing:
| Field | Description |
|---|---|
positions |
Cartesian coordinates (Å) |
velocities |
Atomic velocities (Å/ps) when available |
cell |
3×3 periodic cell from PBC equilibration |
metadata |
Prior backend, stages, source path |
See MdHandoffState.
Default policy on handoff¶
When continuing from a handoff (depends_on or --continue-from):
- Pre-minimization is skipped unless
handoff_pre_minimize: true. - Overlap rescue at placement is skipped (geometry is assumed equilibrated).
- Cutoffs must match the predecessor job (
defaults:in campaign YAML). - Box: handoff
cellwins over campaignbox_size; a warning is printed if both differ. - Velocities: used when present and
continue_velocities: true(default), unless pre-min ran.
When to enable pre-minimization¶
| YAML flag | Use when |
|---|---|
handoff_pre_minimize: true |
Always relax on the MMML surface after PyCHARMM equil |
handoff_quality_gate: true |
Only pre-min if initial MMML |F| > handoff_quality_fmax_eVA (default 1.0 eV/Å) |
defaults:
mm_switch_on: 9.0
mm_switch_width: 1.5
ml_switch_width: 1.0
runs:
pycharmm_equil:
backend: pycharmm
setup: pbc_npt
md_stages: "mini,heat,equi"
jaxmd_prod:
backend: jaxmd
setup: pbc_nvt
depends_on: pycharmm_equil
handoff_quality_gate: true
handoff_quality_fmax_eVA: 1.0
jaxmd_minimize_steps: 500
Diagnostics¶
JAX-MD / ASE write handoff_policy.json in the job output directory with box source,
velocity policy, cutoffs, and initial MMML energy/forces.
PyCHARMM runtime guards¶
Topology, parameter, PSF, and coordinate reads use a relaxed BOMLEV/WRNLEV
context only while the read is active, then restore the prior levels before the
next CHARMM command. This avoids leaving bomlev 0 pinned after benign read
warnings, which can later abort MLpot registration or dynamics setup.
Before production dynamics, MMML clears CHARMM COMP coordinates and scalar
components so stale comparison data is never interpreted as velocities when
iasvel=0 or restart paths are reused. clear_comp_for_production() preserves
its quiet argument: normal calls are visible by default, and staged workflows
can opt into quiet CHARMM housekeeping when running with reduced log noise.
Interpreting initial MMML energy¶
Positive total MMML energy (eV) is normal — the hybrid calculator is not zero-referenced like CHARMM. High |F| (≫ 1 eV/Å) after handoff usually means cutoff mismatch or missing pre-min on the MMML surface.
Box and velocities on write (PyCHARMM)¶
At the end of pycharmm_equil, handoff_from_charmm resolves the cubic cell as:
- Live CHARMM
pbound_get_size(during/after CPT) !CRYSTAL PARAMETERSin the last stage restart (equi_*.res)- Campaign
--box-sizefallback
Velocities are taken from the live CHARMM coordinate set, then from the last restart !VELOCITIES block if needed.
If an older handoff/state.npz lacks cell or velocities, load_dependency_handoff enriches from staged .res files in the predecessor job directory.
PyCHARMM continuation (JAX-MD → prod)¶
When a later campaign job runs PyCHARMM with a handoff, prepare_pycharmm_handoff_continuation patches coordinates (and velocities when continue_velocities is true) into a restart file using, in order:
--handoff-template-resrestart_pathmetadata on the handoffhandoff/final.resnext tocontinue_from/state.npz- Local staged
heat/equi/prodrestarts
The patched handoff/continue_seed.res is READ restart into CHARMM so the first dynamics stage uses restart=True (not new + Boltzmann assign).
Velocity carry-over (JAX-MD)¶
Handoff velocities are applied to the JAX-MD integrator momentum (mass × v) when:
continue_velocities: true(default)- Pre-minimization did not run (positions unchanged)
After pre-min, velocities are re-thermalized at --temperature.
Drift removal (handoff_velocity_remove_drift: true, default) zeros net momentum
and angular momentum before dynamics.
Continue a JAX-MD NVE from a partial trajectory¶
Aborted or partial NVE runs write output_dir/pbc_nve_jaxmd_nve.h5 (and
.traj) with positions and velocities each recording interval. You can restart
without Packmol rebuild:
# Single job (mmml md-system --config …) — do NOT pass --rebuild-packmol
setup: pbc_nve
backend: jaxmd
composition: DCM:80
checkpoint: /path/to/ckpt
output_dir: artifacts/md_run_nve_cont
box_size: 30.0
temperature: 250.0
ps: 100
dt_fs: 0.5
md_stages: nve
continue_from: artifacts/md_run/pbc_nve_jaxmd_nve.h5
continue_from_frame: 140 # 0-based; NOT -1 if the last frame exploded
continue_velocities: true # keep momenta for true NVE continuation
jax_md_update_interval: 1
min_intermonomer_atom_distance: 1.5
dynamics_overlap_action: error
CLI equivalent:
mmml md-system --config md_system.yaml \
--continue-from artifacts/md_run/pbc_nve_jaxmd_nve.h5 \
--continue-from-frame 140
Frame choice: with steps_per_recording: 500 and dt_fs: 0.5, frame k
is at step (k+1)*500 and time (k+1)*0.25 ps. After a PE→KE spike, pick a
frame before the bad record (e.g. the last quiet row in the log). Last
frame (continue_from_frame: -1) is wrong if that frame is the explosion.
Also accepts handoff/state.npz, ASE .traj, or CHARMM .res via the same
continue_from key.
Replicate NVE from one restart (repeat, not repeats)¶
Single-job YAML has no repeats: key. Use a campaign with job key
repeat: (singular) and --run-all:
# campaign_nve_reps.yaml
defaults:
backend: jaxmd
setup: pbc_nve
composition: DCM:80
checkpoint: /path/to/ckpt
box_size: 30.0
temperature: 250.0
dt_fs: 0.5
ps: 100
md_stages: nve
jax_md_update_interval: 1
min_intermonomer_atom_distance: 1.5
dynamics_overlap_action: error
runs:
nve_from_partial:
description: 10 NVE replicas from one pre-crash HDF5 frame
repeat: 10
output_dir: artifacts/nve_reps
continue_from: artifacts/md_run/pbc_nve_jaxmd_nve.h5
continue_from_frame: 140
# Independent trajectories: redraw Maxwell–Boltzmann per seed offset
continue_velocities: false
seed: 22
mmml md-system --config campaign_nve_reps.yaml --run-all
# resume later: add --resume
| Behavior | Detail |
|---|---|
| Outputs | artifacts/nve_reps/rep00 … rep09 |
| Seeds | seed, seed+1, … (replicate index offset) |
Same continue_from |
All reps start from that geometry/frame |
continue_velocities: true |
Same momenta → near-identical NVE paths (seed unused for velocities) |
continue_velocities: false |
Re-thermalize at temperature with per-rep seed → independent runs |
depends_on: some_equil_job is the usual campaign pattern when the predecessor
wrote handoff/state.npz; continue_from + continue_from_frame is for an
existing .h5 / .traj / .npz path (including a crashed NVE).