Source code for pyretis.simulation.scheduler
"""Main infinite-swapping scheduler loop."""
import copy
from pyretis.simulation.setup import setup_internal, setup_runner
[docs]
def scheduler(config):
"""Run the infinite-swapping scheduler loop."""
# setup repex, runner and futures
md_items, state = setup_internal(config)
# Write a COMPLETE output.toml before the first cycle runs: the
# resolved config (defaults already applied by setup_config) plus the
# running [current] state (cstep, RNG, frac, active paths). This makes
# a run resumable from t0 -- even one interrupted before its first
# cycle completes -- from the single output.toml file. A fresh start
# writes cstep=0 with NO restarted_from (seeded RNG); a resume carries
# restarted_from forward. The per-cycle write_toml then keeps it
# current as sampling proceeds.
state.write_toml()
runner, futures = setup_runner(state)
try:
# submit the first number of workers
while state.initiate():
# give each worker its own md_items
worker_md_items = copy.deepcopy(md_items)
# pick and prep ens and path for the next job
worker_md_items = state.prep_md_items(worker_md_items)
# submit job to scheduler
futures.add(runner.submit_work(worker_md_items))
# main step loop
while state.loop():
# Get futures as they are completed
future = futures.as_completed()
if future:
worker_md_items = state.treat_output(future.result())
# submit new job
if state.cstep + state.workers <= state.tsteps:
# chose ens and path for the next job
worker_md_items = state.prep_md_items(worker_md_items)
# submit job to scheduler
futures.add(runner.submit_work(worker_md_items))
# end client (normal, graceful shutdown)
runner.stop()
except BaseException:
# On any error or interrupt (including the KeyboardInterrupt
# raised from the SIGTERM handler), force-release the worker pool
# so it is never orphaned, then re-raise.
runner.close()
raise