Skip to content

MSM analysis & plotting

When msm.enabled is set, each iteration writes an iter_*/msm.npz with the MSM diagnostics (timescales, VAMP-2, stationary distribution, transition matrix, metastable populations, and the implied-timescale sweep). Trails-MD ships utilities to turn these into figures.

One-command report

trails-md-analyze --run-dir runs/adaptive_msm_vampnet
# -> runs/adaptive_msm_vampnet/analysis/convergence_report.png

The report is a 2x2 panel: VAMP-2 convergence, slowest-timescale convergence, the CV free-energy surface, and the latest implied-timescale sweep (or MSM network). Options: --outfile, --temperature (for free energies in kJ/mol).

Programmatic API

Data utilities (no matplotlib required):

from trails_md.analysis import data

series = data.load_msm_series("runs/my_run")     # iterations, vamp2, timescales
latest = data.load_latest_msm("runs/my_run")     # arrays of the last msm.npz
points = data.load_cv_points("runs/my_run")      # all CV projections stacked

# Free energies (kJ/mol, min shifted to 0):
F = data.free_energy_from_populations(latest["metastable_populations"])
Fxy, xe, ye = data.free_energy_surface(points, bins=60, temperature=300.0)

Plotting (needs pip install "trails-md[examples]"); each function takes an optional ax and returns it:

from trails_md.analysis import plots

plots.plot_vamp2_convergence(series)
plots.plot_timescale_convergence(series)
plots.plot_implied_timescales(latest["its_lagtimes"], latest["its_timescales"])
plots.plot_free_energy_surface(points)
plots.plot_metastable_free_energy(latest["metastable_populations"])
plots.plot_msm_network(latest["transition_matrix"], latest["stationary_distribution"])

# Or the full multi-panel report:
plots.plot_convergence_report("runs/my_run", outfile="report.png")

What to look for

  • Implied timescales should plateau (become flat in lag time) — the signal that the MSM is Markovian at the chosen lag.
  • VAMP-2 / timescale convergence flattening across iterations indicates the sampling (and the MSM) have converged — the same signals the ConvergenceMonitor uses to stop automatically.
  • The free-energy surface reveals basins and barriers in the CV space; the MSM network summarises metastable states and their connectivity.

Weighted-ensemble kinetics (rate / MFPT)

If you ran in kinetics mode (spawn_scheme: we with inherit_velocities: true and a recycle_target), the rate is read from the recycled-flux series, not from an MSM. trails-md-analyze reports it and writes a convergence plot:

trails-md-analyze --run-dir runs/my_kinetics_run
# -> MFPT estimate, tau, plateau ratio, converged/not, and
#    runs/my_kinetics_run/analysis/flux_convergence.png

τ (step * dt) is auto-detected from the run log; use --tau-ps / --config if needed and --discard-fraction to change the transient cut. The status / plateau ratio is the key check — a still-decaying or still-rising flux means the steady state has not been reached and the run needs more iterations. (If a run has both a recycled flux series and msm.npz, both reports are produced.)

Programmatic equivalents:

from trails_md.analysis.data import load_flux_history
from trails_md.spawners.we import steady_state_mfpt

flux = load_flux_history("runs/my_kinetics_run")
r = steady_state_mfpt(flux, tau_ps=step * dt)     # r.mfpt_ns, r.plateau_ratio, r.converged