mddem_scheduler
Dependency-injection scheduler for MDDEM, inspired by Bevy. All simulation state lives in typed resources. Systems declare the resources they need as function arguments and the scheduler injects them automatically.
Schedule Sets
The per-step schedule runs in this order:
Setup systems run before the run loop, in order: PreSetup, Setup, PostSetup. In multi-stage simulations ([[run]] config), setup systems re-run at each stage boundary as SchedulerManager.index advances.
Resources: Res<T> and ResMut<T>
Systems declare shared state via Res<T> (read) and ResMut<T> (read-write). The scheduler borrows them from a central HashMap<TypeId, RefCell<Box<dyn Any>>>.
Local<T> -- Per-System Persistent State
Local<T> gives a system its own private state that persists across timesteps, initialized with T::default() on first use. Unlike ResMut<T>, a Local is not shared with any other system.
DEM use cases
- Mindlin-Deresiewicz tangential spring history (contact-pair displacement accumulation)
- Per-system step counters or timers without global resources
- Cached neighbor list statistics between rebuilds
MD use cases
- FENE bond extension history
- Thermostat state (Nose-Hoover chain variables) local to the thermostat system
- Per-system RNG state for stochastic force methods (Langevin)
Run Conditions -- .run_if()
A run condition is any DI function that returns bool. Attach one to a system with .run_if(); the system is skipped when the condition returns false.
app.add_update_system;
Conditions compose naturally with ordering and states:
app.add_update_system;
DEM use cases
- Restart file writing every N steps
- VTK/VTP output at a coarser interval than thermo output
- Neighbor-list validity checks (rebuild only when displacement threshold exceeded)
- Contact statistics collection during production only, not during initial settling
MD use cases
- Radial distribution function accumulation every N steps
- Mean-square displacement logging during NVT production after an NVE equilibration
- Pressure tensor averaging on a coarser schedule than force evaluation
System Ordering -- .label(), .before(), .after()
Within a ScheduleSet, systems normally run in registration order. Explicit ordering constraints let you express dependencies without hard-coding plugin registration order. The scheduler performs a topological sort (Kahn's algorithm) at startup and panics on cycles.
app.add_update_system;
app.add_update_system;
app.add_update_system;
Labels are plain strings and scoped to their ScheduleSet -- "hertz" in Force and "hertz" in PostForce are independent.
DEM use cases
- Normal contact must be computed before tangential contact (tangential force depends on normal overlap)
- Cohesive/van-der-Waals corrections applied after the base Hertz kernel
- Heat conduction through contacts computed after contact geometry is known
MD use cases
- Short-range pair forces before long-range corrections (e.g., PPPM mesh forces after real-space forces)
- Bond forces before angle/dihedral forces that read the same atom force array
- Constraint projection (SHAKE/RATTLE) strictly after all unconstrained forces are accumulated
Simulation States
States let a simulation move through named phases (e.g., settling -> production) without if guards scattered across system bodies. Each state transition is deferred to PostFinalIntegration so the current step always completes with a consistent state.
app.add_update_system;
in_state(S) is itself a run condition and composes with .run_if():
app.add_update_system;
DEM use cases
- Settling -> Shear: pack particles under gravity until kinetic energy drops below a threshold, then enable Lees-Edwards boundary shear
- Fill -> Compress -> Release: multi-stage die-compaction workflow; each stage activates different boundary motion systems
- Initialization -> Production -> Quench: granular cooling study where force model or restitution coefficient changes between phases
MD use cases
- Equilibration -> NVT -> NPT: run NVE first to relax bad contacts, couple thermostat, then couple barostat
- Melting -> Quench: temperature ramp systems active only in the appropriate phase
- Steered MD -> Unbiased MD: bias potential applied only during the pulling phase
Schedule Visualization
Pass --schedule on the command line to print the compiled schedule to the terminal and write a Graphviz DOT file:
This produces schedule.dot in the working directory. Generate an image with:
The DOT output includes:
- Setup systems grouped by
ScheduleSetupSet(blue clusters) - Update systems grouped by
ScheduleSet(yellow clusters) - Red dashed edges for
.before()/.after()ordering constraints - Blue edges for implicit ScheduleSet ordering
- Green loop-back edge showing the per-step run loop
Example output: