Skip to content

Production & publication readiness: hardening, reproducibility, packaging, examples, docs, tests - #2

Merged
dmighty007 merged 14 commits into
mainfrom
claude/autosampler-analysis-plan-jj0n1q
Jun 30, 2026
Merged

Production & publication readiness: hardening, reproducibility, packaging, examples, docs, tests#2
dmighty007 merged 14 commits into
mainfrom
claude/autosampler-analysis-plan-jj0n1q

Conversation

@namus

@namus namus commented Jun 30, 2026

Copy link
Copy Markdown
Member

Summary

A production- and publication-readiness pass over AutoSampler, acting on an independent code review. Fixes the release-gating blockers and works through the major correctness, reproducibility, packaging, CI, example, docs, and test gaps.

Suite: 95 → 118 tests passing · whole-tree ruff clean · all example configs validate · docs build verified.

Release-gating fixes

  • Green suite restoredexamples/template.yaml had drifted from the module template.
  • Documented install repairedenv.yml pinned pydantic 1.x (code is Pydantic v2) and omitted shapely (a core dep).
  • Delta-checkpoint resumeautosampler-path's load_history read a truncated (delta-only) history; now reconstructs the full history, writes atomically, and tolerates a corrupt delta. +tests.
  • Self-contained CPU hello-world — the AlaD Quick Start needed an external GROMACS force field; added a vacuum alanine-dipeptide example that runs end-to-end on CPU with no GPU and no external files.
  • phi_psi documented as AIB9-specific; CITATION.cff added.

Correctness & robustness

  • Local backend tolerates a single walker's failure instead of aborting the iteration; added an opt-in execution.walker_timeout hang guard.
  • Fixed a target-mode spawn crash (replace=False with mostly-zero weights) and a deep-TICA device mismatch.

Reproducibility

  • Threaded the configured seed into all learned-CV training (SPIB no longer hardcodes seed=42; torch RNG reseeded before every fit); SeedManager enables deterministic torch algorithms.

Packaging (PyPI + conda)

  • OpenMM is now optional and lazily importedimport autosampler no longer requires it, so the base pip install resolves; the engine imports on first use.
  • Full PyPI metadata, single-sourced version, tag→PyPI release workflow (trusted publishing), MANIFEST.in.

CI / quality

  • CI now lints the whole tree (was a hand-picked subset; ~250 findings cleaned), tests Python 3.10–3.12, and builds the docs.

Examples, docs, tests

  • Example configs for SPIB / deep-TICA / WE / target-mode / PBS + an examples/README.md index.
  • API reference (mkdocstrings), references/citations page, full CLI reference (incl. autosampler-init/-analyze), and the previously-missing config keys.
  • +23 tests: delta checkpoint, reproducibility, walker timeout, voronoi/lof/fps spawners, paths lineage.

Notes / follow-ups

  • All changes are opt-in or behaviour-preserving; existing configs keep working.
  • Deferred (tracked separately): subprocess-engine trajectory verification, triclinic PBC warning, scheduler-poll robustness, NaN guard in CV training; CLI/core orchestration tests; optional extra="forbid" config strictness.
  • Before publishing: confirm the author list / ORCIDs / affiliations and mint a Zenodo DOI in CITATION.cff.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT


Generated by Claude Code

claude added 14 commits June 30, 2026 04:04
Two release gates:
- examples/template.yaml drifted from autosampler/templates.py:DEFAULT_TEMPLATE
  (the template comment was edited without regenerating the committed example),
  making tests/test_input_template.py fail. Regenerated from the single source.
- env.yml pinned pydantic>=1.10 but the code requires Pydantic v2 (import would
  fail), and omitted shapely, a core dependency used by the Voronoi spawner/binner.
  Bumped pydantic>=2.0, added shapely>=2.0, and added the lightning/mlcolvar
  deep-CV backends so the documented `conda env create -f env.yml` can run the
  learned-CV tutorials.

Suite: 96 passed.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
…backend)

Checkpoint/resume (regressions from the delta-writing change):
- paths.load_history() read only a single iter_*/history.pkl, which after delta
  writing holds just the entries since the previous checkpoint — so the
  autosampler-path lineage/path tool silently saw a truncated history. It now
  reconstructs the full history by merging all deltas up to the target checkpoint.
- Checkpoint writes are now atomic (write .tmp, os.replace), mirroring run_task.py.
  A crash mid-write (e.g. an HPC walltime kill) can no longer truncate a delta and
  break the whole delta chain. The format_version marker is written last.
- Resume tolerates a corrupt/truncated delta (skip + warn) instead of crashing all
  future resumes. Shared reconstruct_history() helper used by load() and paths.
- Added tests/test_checkpoint_delta.py (round-trip, checkpoint-frequency gaps,
  corruption tolerance, atomicity, paths.load_history reconstruction).

Execution (local backend):
- A single walker raising (CUDA error, NaN blow-up, missing file) propagated
  through future.result() and crashed the entire iteration, discarding the other
  walkers and violating the list[bool] contract. The local backend now catches a
  walker's failure (in the worker and when collecting the result), logs it, and
  marks that walker unsuccessful — matching the scheduler path.

Note: reviewed the MSM "least-counts = 1/count^2" report and confirmed it is NOT
a bug — the per-frame value distributes the microstate-level 1/count weight across
its frames, exactly like the MSM-guided path's base/size_per_frame. Left unchanged.

Suite: 101 passed.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
…doc fixes

Packaging / release readiness:
- pyproject: add readme, license, [project.urls], keywords, real authors; bump
  Development Status to Beta (was Alpha while versioned 2.0.0); single-source the
  version from autosampler/__init__.py via [tool.setuptools.dynamic].
- Add CITATION.cff (GitHub "Cite this repository") with flagged TODOs for the
  final author list, ORCIDs, affiliations, and DOI; add a "How to cite" section
  to the README.

Examples / docs (zero-behavior, first-run experience):
- examples/AlaD/{config,config_voronoi}.yaml: replace the hardcoded developer path
  /home/dm/Soft/GMX26/... with an instructional placeholder, and fix the silently
  ignored `platform:` typo -> `platform_name:`. (OpenMM parses the GROMACS topology
  and needs the force-field include dir to resolve amber99sb.ff.)
- docs/notebook_tutorial.md: fix stale blob/devel link -> blob/main.
- docs/configuration.md + template.yaml: note that adaptive_feature_type: phi_psi
  is currently AIB9-specific and raises on other systems.

Suite: 101 passed.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
…tor)

tools/generate_review_pdf.py renders AutoSampler_Review.pdf — the consolidated
code-review / publication-readiness assessment (verdict, strengths, items fixed
during review, blockers, major correctness/reproducibility/packaging/docs gaps,
minor nits, and a prioritised path to release).

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
Learned-CV training was not reproducible from random_seed:
- AdaptiveSpaceModel had no seed; SPIB hardcoded seed=42 and ignored the config
  seed entirely. Added a `seed` to AdaptiveSpaceModel (plumbed from
  config.random_seed via core._adaptive_model_kwargs), threaded it into
  train_spib, and reseed the torch RNG at the start of every fit() so a CV
  retrained at iteration N is reproducible regardless of intervening RNG draws
  (network init, DataLoader shuffling).
- SeedManager now requests deterministic torch algorithm implementations
  (torch.use_deterministic_algorithms(warn_only=True)) and sets
  CUBLAS_WORKSPACE_CONFIG, in addition to the existing Python/NumPy/torch/cuDNN/
  Lightning seeding.
- Added tests/test_reproducibility.py (deterministic SeedManager; seed carried on
  the model; identical vampnet projection across two same-seed fits).

Suite: 104 passed.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
The default OpenMM engine runs in-process, so a hung GPU/driver could stall the
whole campaign forever (Batch 2 already handles walker *crashes*; this covers
*hangs*). Added execution.walker_timeout (seconds, opt-in): the local backend now
polls at the timeout cadence and, if any walker exceeds it, terminates the
batch's worker processes and marks the remaining walkers unsuccessful instead of
blocking indefinitely. Plumbed via make_backend; documented in the template.

Added tests/test_execution.py::test_local_backend_walker_timeout (hanging-executor
simulation; asserts the batch is reported failed and does not hang).

Suite: 105 passed.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
- spawners/density.py: _weighted_choice used replace=False even when fewer than
  top_n entries had nonzero probability, raising "fewer non-zero entries in p than
  size" in target mode (target_closeness zeroes distant bins). Now switches to
  replace=True in that case, matching the MSM spawner. Added a regression test.
- spaces/model.py: the deep-tica projection built its input tensor with no device
  while the model's params may be on CUDA, causing a device-mismatch RuntimeError.
  Now reads the device from the model parameters and moves the output to CPU,
  mirroring the spib branch.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
`import autosampler` previously required OpenMM because engines/__init__ eagerly
imported the OpenMM/GROMACS/Amber modules (openmm.py does `from openmm import *`
at top). Since OpenMM is most reliably installed from conda, a plain
`pip install autosampler` from PyPI would often fail to resolve.

- EngineFactory.register_lazy + lazy get(): engine backends are imported only
  when first requested, with an actionable error if the optional dependency is
  missing. engines/__init__ now registers lazily (no eager backend import); the
  engine classes remain accessible via module __getattr__ for compatibility.
- pyproject: move openmm out of core dependencies into an `[openmm]` extra (added
  to `all`); torch/MDAnalysis/deeptime remain pip-installable core deps.
- Verified: `import autosampler.core` no longer imports openmm; EngineFactory.get
  ("openmm") imports it on demand.

Suite: 107 passed.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
- Cleaned the ~250 ruff findings across the previously-unlinted modules
  (core.py, config.py, engines/*, checkpoints/manager.py, paths.py, spaces/*,
  spawners/*): autofixed the cosmetic bulk (typing modernization, import order,
  whitespace), added `from e` to four bare re-raises in spaces/features.py, and
  added strict= to zip() calls. Per-file ruff ignores for the two intentional
  patterns (core.py's pre-import warnings.filterwarnings -> E402; the OpenMM
  engine's `from openmm import *` -> F403/F405).
- CI now lints the WHOLE tree (`ruff check autosampler tests`) instead of a
  hand-picked subset, tests on Python 3.10/3.11/3.12 (was 3.10/3.11), installs
  shapely, and adds a docs-build job.
- Added .github/workflows/release.yml: tag (v*) -> build sdist/wheel, twine check,
  publish to PyPI via Trusted Publishing (OIDC, no token). Added MANIFEST.in.

Behaviour unchanged (cosmetic + lint only). Suite: 107 passed; whole-tree ruff clean.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
… index

A new user's first run previously broke (the AlaD Quick Start needs an external
GROMACS force field). This adds a genuinely self-contained, GPU-free hello-world
under examples/alanine_dipeptide/:
- structure.pdb: canonical 22-atom Ac-Ala-NMe (OpenMM test structure, MIT).
- build_system.py: builds a vacuum Amber14 System from it (OpenMM only, no
  external force-field files) and serialises system.xml (regenerable).
- system.py / project_phi_psi.py / config.yaml: fixed phi/psi CVs, density
  spawning, CPU platform, tiny walker/step counts.
Verified end-to-end: `--check` passes and a 2-iteration run completes on CPU in
~2 s/iteration, producing trajectories, CVs, and checkpoints.

Also adds examples/README.md indexing every example with what it demonstrates and
what it requires (CPU vs GPU, external force fields), pointing new users to the
alanine-dipeptide example first.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
… target, pbs)

Adds worked AIB9 example configs (reusing the bundled aib9_system.xml — no new MD
assets) for features that previously had no example:
- config_spib.yaml      — SPIB learned CV
- config_deep_tica.yaml — deep-TICA learned CV
- config_we.yaml        — weighted-ensemble spawner
- config_target.yaml    — target-mode search toward a CV point
- config_pbs.yaml       — PBS/Torque HPC execution backend
All eleven AIB9 configs validate against the schema; indexed in examples/README.md.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
…e helpers

- Voronoi/LOF/FPS spawners: explore + target modes return top_n valid in-range
  indices (importorskip shapely/sklearn so they skip cleanly when absent).
- autosampler.paths: frame_key, FrameRef round-trip, build_frame_records lineage
  links, map_global_frame bounds, history_records, nearest_record (incl. dim
  mismatch + empty-history errors).

Adds 11 tests; full suite green.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
- mkdocs.yml: wire the mkdocstrings (python) plugin and add nav entries.
- docs/api.md: mkdocstrings API reference for the public modules a user/referee
  calls (config, msm.estimator, msm.convergence, spaces.feature_selection,
  binning.adaptive, analysis.data/plots). Griffe analyses statically, so no heavy
  runtime deps are needed at build.
- docs/references.md: primary literature for the methods (MSM/PCCA+, TICA, VAMP/
  VAMPNets, SPIB, deep-TICA, TAE, weighted ensemble, MAB, deeptime/OpenMM/
  MDAnalysis); cross-linked from cv_methods.md.
- docs/cli.md: complete reference for all six console commands (incl. the
  previously-undocumented autosampler-init and autosampler-analyze), with real
  flags read from the *_cli modules.
- configuration.md: document the previously-missing spawner-tuning keys
  (recent_density_window, lof_neighbors, voronoi_*, resolution_*, target) and the
  new execution.walker_timeout.
- CI docs job installs the package (--no-deps) so mkdocstrings can resolve it.

https://claude.ai/code/session_01MjnMX5xKm184y4sLXhq4pT
@dmighty007
dmighty007 merged commit 249919a into main Jun 30, 2026
4 checks passed
@namus
namus deleted the claude/autosampler-analysis-plan-jj0n1q branch July 13, 2026 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants