Snapshots & Resume
Sim keeps a live SessionState that encapsulates time, states, parameters, the stepper workspace, and runtime metadata. Snapshots capture that state at a point in time so you can rewind, branch, or serialize a simulation, while run(resume=True) lets you grow recorded segments without rebuilding the model from scratch.
Snapshot fundamentals
- Initial snapshot: The
"initial"snapshot is created automatically before the firstrun()so you always have a known starting point to fall back to. create_snapshot(name, description="…"): Clones the currentSessionState, records the currenttime_shift/dt, stamps the snapshot withname/description, and saves the full workspace + stepper config. Duplicate names raise an error, so pick descriptive identifiers.list_snapshots()returnsname, simulation timet, step count, creation timestamp, and any description you provided.compat_check(snapshot)comparesSessionPins(spec hash, stepper, workspace signature, dtype, dynlib version) to guarantee a snapshot comes from a compatible build.reset()uses the same guard and will fail fast when the model, stepper, or dtype has changed.
Snapshots are lightweight to create and cheap to keep around, so take one whenever you hit a milestone (e.g., after applying a stimulus, finishing a parameter sweep, etc.).
Resetting and restarting
reset(name="initial")rolls the session back to a named snapshot and wipes recorded history, segments, pending run tags, and resume state. It restores_time_shiftand_nominal_dtfrom the snapshot so that futurerun()calls start from that exact moment.- After
reset, the recorder is cleared, which also resets the storedrecord_varsselection, so you can choose a different subset of variables before the next run. session_state_summary()reportscan_resume/reason, letting you query whetherresume=Trueis allowed without triggering the run logic.
Running and resuming
Sim.run(resume=True) continues from the most recent SessionState instead of restarting integration from t0. Key behaviors:
- Session continuity: The workspace, stepper configuration, and
time_shiftfrom the previous run are preserved, so the next segment feels like an uninterrupted extension in both deterministic and adaptive steppers. - Recording constraints: You cannot override
ic,params,t0, ordt, soresumealways starts where the session left off. Warm-uptransient > 0is disallowed because resume segments must continue immediately.record_varscannot be re-specified either; the first recorded run after aresetfixes the variable list and every subsequentresumerun reuses that list automatically. - Segment tracking: Each recorded run appends a
Segmententry describingt_start,t_end,step_start,step_end, and whether the chunk was produced via resume. Passtag="label"to therun()call to assign a friendly name—run#0,run#1, etc. are generated otherwise. Rename withname_segment()orname_last_segment()when you need human-readable labels forResultsView. - Results stitching: Resume reuses the same
_ResultAccumulator, soraw_results()/results()see a seamless time-series spanning every segment.run(resume=True)throws if the requested horizon does not extend beyond the current time, avoiding overlaps. - Compatibility guard: Before resuming,
can_resume()compares the current pins to those captured in theSessionState. If it returns(False, reason), rewrite the simulation by callingreset()or rebuild with a compatibleFullModel. - No parameter overrides inside resume: For a resumed segment you cannot pass new
ic,params,t0, ordt. The run keeps the parameters, stepper workspace, and timing from the previous segment, so changing values requires a reset, snapshot, or a separaterun()call that does not setresume=True.
Typical pattern:
sim.run(T=2.0, record=True, tag="phase-1")
sim.create_snapshot("phase-1", "after the first stimulus")
# Continue without rebuilding; the second run is appended
sim.run(T=5.0, resume=True, tag="phase-2")
# Start a different branch by resetting to the saved snapshot
sim.reset("phase-1")
sim.run(T=3.0, record=True, tag="phase-1-replay")
If you need to change parameters between segments, do so before the resumed run: reset to an earlier snapshot, assign() the new parameter/state values (or import a snapshot that already encodes them), then run without resume or call run(resume=True) once the new values are in place. Resume never accepts ic, params, t0, or dt overrides, so any new configuration must be done via snapshots/assignments that happen before the resumed segment starts.
Examples of changing parameters between segments
Example 1: Branching with parameter changes (no resume)
# Run initial segment
sim.run(T=2.0, record=True, tag="baseline")
# Create snapshot at end of first segment
sim.create_snapshot("after-baseline", "End of baseline run")
# Reset to snapshot and change a parameter
sim.reset("after-baseline")
sim.assign(I=15.0) # Change input current parameter
# Run new segment with modified parameter (starts fresh recording)
sim.run(T=3.0, record=True, tag="modified-current")
Example 2: Continuing with parameter changes (using resume)
# Run first segment
sim.run(T=2.0, record=True, tag="phase-1")
# Create snapshot
sim.create_snapshot("phase-1-end", "End of phase 1")
# Reset and modify parameters
sim.reset("phase-1-end")
sim.assign(a=0.02, b=0.25) # Change Izhikevich parameters
# Continue from the reset point with new parameters
sim.run(T=5.0, resume=True, tag="phase-2-modified")
Example 3: Using assign() with clear_history=True to start fresh
The assign() method has an optional clear_history parameter. When clear_history=True, it clears all previous results and segments while preserving the current session state (time, workspace, etc.) with the new assigned values. This effectively allows you to create a new segment without resetting to a snapshot:
# Run initial segment
sim.run(T=2.0, record=True, tag="initial")
# Assign new parameter values and clear history to start fresh recording
sim.assign(I=20.0, clear_history=True)
# This run creates a new segment (since history was cleared)
sim.run(T=3.0, record=True, tag="new-segment")
Note that clear_history=True does not change the simulation time or workspace state—it only clears the recorded results, allowing the next run() to start a new segment from the current session state.
Persistence and portability
export_snapshot(path, source="current" | "snapshot", name=...)writes a.npzfile containing:meta.json(schema version, pins, names, time/step counters,time_shift,nominal_dt, stepper config names/values)yandparamsvectors- Workspace buckets (
workspace/runtime/<name>,workspace/stepper/<name>) andstepper_configif present - The write happens atomically via a temporary file so partial writes never corrupt existing snapshots.
inspect_snapshot(path)readsmeta.jsonwithout changing the session, letting you verify compatibility before importing.import_snapshot(path)replaces the current session state with the contents of a snapshot file, clears results/segments, resets_time_shift/_nominal_dt, and rejects files whose pins do not match the active model.
Use export/import when you need to checkpoint a long computation, share a resume point with a colleague, or persist workflow state between CI runs.
Segment naming and resume metadata
- Each
Segmentcarries acfg_hash(stepper configuration digest) plusresumeflag so downstream tools can tell whether a chunk was created during a fresh run or viaresume. - Use
tagonrun()orname_segment()afterward to keep yoursegmentslisting readable;ResultsViewexposes these names so you can quickly extract the portion you care about. - When you reset, the segment list empties, but snapshots remain. Continue appending segments only with
resume=True—otherwiserun()clears the accumulator and starts a new recording pass.
Snapshot and resume controls keep your experiments reproducible: take snapshots at branch points, reset to them when you need to test variations, and resume to build long trajectories without losing history.