Concurrent Scenario Runner
Executes a list of Scenario instances concurrently and writes all results to a shared KSLDatabase.
Execution model
simulate operates in two phases:
Phase 1 — concurrent simulation. Each scenario is dispatched as an independent coroutine on SimulationDispatcher.default, a CPU-bounded dispatcher limited to Runtime.availableProcessors() threads. Every coroutine builds a fresh Model via scenario.modelBuilder, attaches an InMemorySnapshotCollector to the model's lifecycle emitters, and runs the simulation. All database-bound data is captured in memory during this phase; no database writes occur.
Phase 2 — sequential database commit. After all coroutines complete (awaitAll), the collected snapshots are written to kslDb one scenario at a time via SnapshotBatchWriter. Serialising the writes avoids concurrent SQLite access while keeping simulation time fully parallel.
Model isolation requirement
Every scenario submitted to this runner must use a ModelBuilderIfc that constructs a fully independent Model instance on each ModelBuilderIfc.build call. Scenarios built with the backward-compatible model: Model constructors of Scenario wrap a single shared instance and must not be used here — concurrent coroutines operating on the same model produce incorrect results and data races.
Error handling
If a simulation throws a RuntimeException, the failing scenario's coroutine catches the exception, logs it, and continues without affecting other concurrent scenarios. The failing scenario's Scenario.simulationRun will contain the error message via SimulationRun.runErrorMsg; its partial snapshots are not committed to the database.
Parameters
Runner name; also used as the default database file stem and output directory name.
Initial list of scenarios to register.
Root directory under which per-scenario output sub-directories are created.
Shared database that receives all scenario results.
When true (the default, preserving the original behaviour), every scenario gets its own subdirectory under pathToOutputDirectory named <scenarioName>_OutputDir; each subdir contains that scenario's kslOutput.txt and any per- scenario CSV / plot artifacts the model writes. When false, every per-scenario model writes directly into pathToOutputDirectory and the diagnostic log uses a scenario- distinguished filename (kslOutput_<scenarioName>.txt) so concurrent writers don't clash and re-runs overwrite cleanly. Parallel to ParallelDesignedExperiment.useDesignPointOutputDirs — same substrate-level knob shape for the per-item-subdir question that the two runners share.
Constructors
Properties
Read-only ordered list of registered scenarios.
Read-only map of scenario name to Scenario.
Functions
Registers scenario with this runner. The scenario name must be unique.
Creates a Scenario from a ModelBuilderIfc and a full ExperimentRunParameters snapshot, registers it with this runner, and returns it.
Cancel a single scenario by name without stopping the rest of the sweep. Looks up the scenario's coroutine job and issues a cooperative cancellation against it. Returns true when a running scenario was found; false when the name is unknown, has already finished, or hasn't started yet.
Sets the number of replications to numReps for every registered scenario.
Returns a map of scenario name → per-replication observations for responseName across all executed scenarios. Scenarios not yet executed or producing no observations for the response are silently omitted.
Returns the scenario with the given name, or null if none is registered.
Runs the selected scenarios concurrently and writes results to kslDb.
Assigns non-overlapping pre-run sub-stream advances to selected scenarios.
Writes basic half-width summary reports for each scenario to out.