Absorbing infinite swapping into PyRETIS

This page is the entry point for developers contributing to the ongoing work of absorbing the infinite-swapping (∞RETIS) code path into PyRETIS. It summarises the goal, the current state, the conventions in force, and where the detailed working documents live.

Goal

PyRETIS currently hosts two co-existing path-sampling implementations that are being unified into one:

  • pyretis-native – the classical PyRETIS engine (pyretis/core/, pyretis/engines/, pyretis/setup/).
  • infinite swapping – an absorbed sampler (asynchronous replica-exchange with infinite-swap moves and wire fencing), currently promoted into the public pyretis.simulation namespace (e.g. pyretis/simulation/scheduler.py).

The end state is a single code path. Two rules govern the work:

  1. No brand. The container name “infretis”/”∞RETIS” is being retired from PyRETIS. Absorbed methods are named for what they are: the analysis is WHAM, the sampler is infinite swapping (stem infswap). Pre-existing literal artifacts (infretis_data.txt, the _inf modules, the [runner] TOML schema) are renamed in a separate, planned pass.
  2. Reproducibility first. Results must be deterministic and correct. A reference comparison is only useful if it fails when the physics is wrong (see Test policy (green == correct)).

What works today

  • pyretisrun is the single entry point. It runs the infinite-swapping sampler when the input TOML selects it, via [simulation] task = "infinite_swapping" or the [runner] section. The old infretisrun command has been removed.
  • The WHAM crossing-probability / rate analysis lives in pyretis/analysis/wham_analysis.py (a faithful implementation of the standard weighted-histogram procedure for TIS; the previous infretis_analysis.py stub was scientifically wrong).
  • The two paths now share a single System type (A3.2c) and a single Path type (A3.1b – the inf-flavour Path was folded into pyretis.core.path.Path, its disk loaders moved to pyretis.core.path_load). The random-number generator is unified on PCG64 (A3.4), so a native run and the infinite-swapping sampler draw the same byte stream from the same seed.

How to pick the sampler from the input

# classical RETIS / TIS / MD-flux, single worker:
pyretisrun -i retis.toml -p

# infinite swapping (multi-worker, infinite-swap + wire fencing):
#   the TOML selects it via task = "infinite_swapping" or [runner]
pyretisrun -i infswap.toml

See examples/validation/ for runnable showcases of both.

Test policy (green == correct)

  • Run ./test-easy.sh (unit + integration + style) before every commit.
  • Run ./test-heavy.sh (engine reference suites + tutorials, 40-60 min) before a pushtest-easy does not run the example compare.py harnesses, so a reference/default change can pass test-easy and still break test-heavy.
  • A comparison must not pass on degenerate input. The shared primitives in pyretis/testing/simulation_comparison.py reject empty data, shape mismatches, NaNs at mismatched positions, and entirely-NaN columns; a quantity an engine does not report must be excluded explicitly (skip_cols=), never by letting NaN == NaN pass.

Working documents (in the repository)

  • MERGE_TODO.md – the running roadmap of alignment tasks with IDs/status. Grab a TODO and flip it to IN PROGRESS.
  • docs/inf_removal_validation.md – the evidence ledger: what is proven reproducible before any _inf module is deleted.
  • docs/debrand_plan.md – the phased plan and naming map for retiring the brand (102 identifiers, risk callouts).
  • docs/test_integrity_audit.md – whether the example comparisons are meaningful, and the known gaps.

Resolved issues

  • test-gromacs/test-load/test-initialise previously asserted that a loaded run bit-for-bit reproduces a fresh run – that is restart semantics, not load semantics. It has been reframed to load semantics (commit b619a767): it now runs the loaded scenario twice from the same loaded path and initial GROMACS RNG state and compares the two, which is what a load must guarantee (it works and reproduces previously loaded results). Rigorous load-determinism is covered by the internal engine (test-internal/retis-load-sparse), and exact continuation by the restart tests (test-internal/{retis,tis,md,mdflux}-restart, test-gromacs/test-restart).
  • The merge-readiness review’s findings (H1–H4, M) are fixed: the load-traj energy comparison is data-driven per ensemble (not a blanket skip); pyretisrun restores the completed-restart guard and the descriptive missing-input message; the WHAM lamres default uses the smallest interface gap with a commensurability check; and _wham_pq always returns one crossing probability per interface.

Known issues

  • External-engine potential energy coverage: OpenMM does not report a potential (its column is skipped explicitly); CP2K loaded frames have no computed energy (matching-NaN, finite values still compared).