jupedsim_scenarios.sweep#

Monte Carlo sweep over scenario parameters and seeds.

run_sweep walks the cartesian product of one or more named axes and runs the scenario once per (axis-combination, seed) trial. Per-axis mutations are applied via user-supplied callables so the sweep doesn’t need to know about the scenario’s internal mutator surface — anything that mutates the scenario in place works:

sweep = run_sweep(

base, axes={“v0”: [0.8, 1.2], “model”: [“CollisionFreeSpeedModel”]}, apply={

“v0”: lambda s, v: s.set_agent_params(0, desired_speed=v), “model”: lambda s, v: s.set_model_type(v),

}, seeds=range(40, 50),

) df = sweep.to_dataframe() # one row per trial; axis values + metrics

The library owns: cartesian product, seed iteration, per-trial scenario isolation (.copy() per trial), per-trial sqlite output naming, and result tabulation.

Set workers=N (or workers=0 for one process per CPU) to run trials in parallel via joblib.Parallel (loky backend). Mutations are applied in the parent process so user-supplied apply callables don’t need any special pickling treatment — only the resulting mutated Scenario crosses the process boundary.

Attributes#

Classes#

SweepResult

Collection of trials produced by run_sweep.

Trial

One realised cell of the sweep: axis values + seed + result.

Functions#

run_sweep(, output_dir, workers, progress, int, dict], ...)

Run the scenario once per (axis combination, seed) pair.

run_sweep_from_factory(, output_dir, workers, ...)

Run one simulation per (trial-params, seed) pair, building each

Module Contents#

class SweepResult[source]#

Collection of trials produced by run_sweep.

Holds the per-trial ScenarioResult objects (each pointing at its own on-disk sqlite). Call .cleanup() when done to delete the sqlites, or .save(path) first if you want to keep the metadata.

cleanup() None[source]#

Remove every trial’s sqlite trajectory file.

save(path: str | pathlib.Path) None[source]#

Persist sweep metadata (axes, seeds, per-trial paths + metrics) as JSON.

The trajectory sqlites themselves are NOT moved — they stay where run_sweep’s output_dir put them. load() reattaches metadata to the sqlite files; if the sqlites are gone, the loaded result is metadata-only.

to_dataframe()[source]#

Return a pandas DataFrame with one row per trial.

Columns: every axis name, seed, success, evacuation_time, total_agents, agents_evacuated, agents_remaining, sqlite_path.

axes: dict[str, list[Any]][source]#
seeds: list[int | None] = [][source]#
trials: list[Trial][source]#
class Trial[source]#

One realised cell of the sweep: axis values + seed + result.

extras is an opaque per-trial payload. run_sweep always leaves it None; run_sweep_from_factory lets the factory attach anything it likes (geometry, label, computed metadata) so downstream code can pick it up via for t in sweep.trials: t.extras.

axis_values: dict[str, Any][source]#
extras: Any = None[source]#
index: int[source]#
result: jupedsim_scenarios.runner.ScenarioResult[source]#
seed: int[source]#
property success: bool[source]#
run_sweep(scenario: jupedsim_scenarios.runner.Scenario, *, axes: collections.abc.Mapping[str, collections.abc.Sequence[Any]] | None = None, apply: collections.abc.Mapping[str, AxisApplyFn] | None = None, seeds: collections.abc.Iterable[int | None] = (None,), output_dir: str | pathlib.Path | None = None, workers: int = 1, progress: collections.abc.Callable[[int, int, dict], None] | None = None) SweepResult[source]#

Run the scenario once per (axis combination, seed) pair.

Parameters:
  • scenario – The base scenario. .copy() is taken per trial; the caller’s scenario is never mutated.

  • axes – Mapping of axis name → list of values. Trials cover the full cartesian product. Empty / None ⇒ no parameter sweep (seed-only).

  • apply – Mapping of axis name → callable (Scenario, value) -> None. Mutates the trial’s scenario copy in place. Required for each axis in axes.

  • seeds – Seeds to replicate every axis combination over. Default (None,) ⇒ one trial per combination with whatever seed the scenario carries.

  • output_dir – If given, every trial’s sqlite trajectory is placed inside it with a deterministic name (trial_<index>.sqlite). If omitted, each trial gets its own tempfile (cleaned by SweepResult.cleanup).

  • workers – Number of parallel worker processes. 1 runs sequentially in the calling process; >1 dispatches trials via joblib.Parallel (loky backend); 0 selects os.cpu_count(). Trial-level mutations are applied in the parent process, so user apply callables don’t need any special pickling treatment.

  • progress – Optional callback invoked after each trial with (trial_index, total_trials, axis_values_with_seed).

Return type:

SweepResult

run_sweep_from_factory(factory: ScenarioFactoryFn, *, trials: collections.abc.Iterable[collections.abc.Mapping[str, Any]], seeds: collections.abc.Iterable[int | None] = (None,), output_dir: str | pathlib.Path | None = None, workers: int = 1, progress: collections.abc.Callable[[int, int, dict], None] | None = None) SweepResult[source]#

Run one simulation per (trial-params, seed) pair, building each scenario fresh via a user-supplied factory.

Use this when the scenario can’t be expressed as a single base mutated by axis values — typically because the geometry itself depends on trial parameters (e.g. a loop track whose radius scales with agent count). Each call to factory(trial_params) is expected to construct a fresh Scenario.

Parameters:
  • factory – Callable (trial_params) -> Scenario or (trial_params) -> (Scenario, extras). Called once per trial-parameters dict in the parent process; the resulting Scenario is then pickled to a worker for the actual simulation. extras (if returned) is attached to Trial.extras for the caller to read after the sweep completes.

  • trials – Iterable of trial-parameters mappings. The mapping’s keys become the DataFrame columns when you call SweepResult.to_dataframe(), so name them meaningfully.

  • seeds – Seeds to replicate every trial-params combination over. Default (None,) ⇒ one run per trial-params dict using the seed embedded in the factory’s Scenario.

  • output_dir – Same semantics as run_sweep.

  • workers – Same semantics as run_sweep.

  • progress – Same semantics as run_sweep.

Return type:

SweepResult

AxisApplyFn[source]#
ScenarioFactoryFn[source]#