Scenario JSON

A scenario is a config.json plus a geometry.wkt walkable area, in a directory or a ZIP. This page lists the JSON keys that change a result, with their defaults. The meaning of the model parameters is on the Models pages; this page links there rather than repeating the equations.

The keys are read by load_scenario and the JuPedSim set-up in simulation_init.py. A key that is not listed here is either layout data for JuPedSim Web (config.ui_state) or not read by the run.

Where scenario files come from

Scenario files are drawn in JuPedSim Web and exported as a ZIP, or copied from an example and edited. The app does not write the pyFDS-Evac keys (routing, exit schedules, familiarity, the sign’s max_distance); add them by hand after the last export. Create a scenario shows the three routes and how to check the result.

Top-level structure

{
  "config": { "simulation_settings": { "simulationParams": {…}, "baseSeed": … } },
  "exits":         { "<id>": {…} },
  "distributions": { "<id>": { "coordinates": […], "parameters": {…} } },
  "checkpoints":   { "<id>": {…} },
  "waypoints":     { "<id>": {…} },
  "zones":         { "<id>": {…} },
  "journeys":      [ { "id": …, "stages": […] } ],
  "transitions":   [ { "from": …, "to": …, "journey_id": … } ],
  "journeys_v2":   [ { "id": …, "sequence": […] } ],
  "waypoint_routing": {…},
  "routing":       {…}
}

journeys and transitions are the stage graph that set-up builds on; a journey needs its transitions (#504). journeys_v2, as JuPedSim Web writes it, is converted into them only when journeys is empty; see Create a scenario. waypoints carry signs only.

Simulation settings

Under config.simulation_settings.

KeyDefaultEffect
simulationParams.max_simulation_time300 sThe run stops here. The run also ends earlier, with end_reason all_mobile_left, when only incapacitated agents remain; see Reading the results. With --fds-dir it must not exceed the last FDS slice time by more than one output interval, unless --allow-fds-horizon-hold is given (#340).
simulationParams.model_type"CollisionFreeSpeedModel"The JuPedSim movement model; see Movement models › Choosing a model.
simulationParams.number, .radius, .v010, 0.2 m, 1.25 m/sDeck-wide defaults for a spawn area that does not set its own number, radius or v0, with and without journeys; see Spawn areas. A deck without spawn areas places number agents in the whole walkable area. number is read with Python’s int() (3.9 and "3" give 3), radius and v0 with float(), so numeric strings are accepted; null means unset. number must be 0 or more, radius and v0 finite and greater than 0, and true or false is not a number. A value that does not convert, such as "3.9" for number or "fast" for v0, a number below 0, a radius or v0 of 0, below 0, infinite or NaN ("1e400", "nan"), or a boolean, stops the run with a ValueError that names the key.
simulationParams.smoke_slice_heightnone (--smoke-slice-height, 1.6 m)Absolute FDS slice height [m] for smoke, gases and sign legibility. pyfds-evac --smoke-slice-height overrides it; the run prints the value when it comes from here. pyfds-evac init writes the floor level plus HUMAN_SMOKE_HEIGHT. The GUI and TUI do not read it yet.
baseSeed42Random seed; run.py --seed overrides it.

simulationParams.dt is not read: the JuPedSim step is 0.01 s, and the trajectory is written every tenth step (10 frames/s).

Social force model

Read when model_type is "SocialForceModel". The symbols are those of Helbing, Farkas & Vicsek (2000), Eqs. (1)–(3) (doi:10.1038/35035023); a missing key takes JuPedSim 1.4.2’s default.

Key (simulationParams.)JuPedSim parameterSymbolUnitDefault
sfm_body_forceSocialForceModel(body_force=)kkg s⁻²120000
sfm_frictionSocialForceModel(friction=)κkg m⁻¹ s⁻¹always 0, see below
agent_strengthagent_scale, per agentA, agent termN2000
sfm_obstacle_scaleobstacle_scale, per agentA, wall termN2000
agent_rangeforce_distance, per agentBm0.08
relaxation_timereaction_time, per agentτs0.5

Negative, non-finite or non-numeric sfm_body_force, sfm_friction or sfm_obstacle_scale stop the run with ValueError. JuPedSim 1.4.2 has one friction for the agent and wall terms and applies the wall term with the wrong sign (jupedsim#1677), so friction is always passed as 0, also when sfm_friction is missing (#635). A deck that declares sfm_friction above 0 gets a warning. The run manifest records what JuPedSim received under sfm.

Spawn areas: distributions.<id>.parameters

parameters is an object, or the same object as a JSON-encoded string; both read the same everywhere: the run, --show-config, the TUI, the GUI and the Scenario views (#644):

"parameters": {"number": 20, "v0": 1.2}
"parameters": "{\"number\": 20, \"v0\": 1.2}"

A missing or null parameters, a string that is not valid JSON, and a string or value that is not an object ("null", "[]", "42", []) read as no parameters, so every key takes its default. The Scenario.set_agent_params(), set_agent_count() and set_flow_schedule() setters store an object: a string is replaced by the object it encodes, with all its keys, and an unreadable value by an empty object, before the setter’s keys are written.

KeyDefaultRangeEffect
numbersimulationParams.number, else 10≥ 0Agents placed at the start by number, or added over the window with use_flow_spawning. Not read, and not checked, in the percentage modes. No value is taken from another spawn area.
distribution_mode"by_number"by_number, by_percentage, fill_area, until_fullby_percentage fills the polygon to percentage (default 50) of its capacity estimate: ⌊estimate × percentage / 100⌋ agents, at least 1. The estimate is ⌊A / (π r²) / 2⌋ for the spawn area A clipped to the walkable area and the largest agent radius r (radius, or mean + 3 × radius_std up to 1 m for a Gaussian radius; at least 0.1 m). number is not read. The same count applies at the start and with use_flow_spawning; --print-summary shows it. percentage is clamped to 1–100; a value that is not a number takes the default. The by_percentage count is exact: when JuPedSim cannot seat it, the run stops with a SpawnCapacityError, which near 100 % can happen. fill_area and until_full take the same count, with percentage defaulting to 100, as an upper bound: at the start they place as many agents as fit up to it, the run prints Distribution '<id>': fill_area placed N of at most M agents, and the result (ScenarioResult.fill_placement, the closing summary line) records it; --print-summary shows up to M agents, and --export-only does not report it as over-full. With or without journeys, every exact count is placed before any fill mode, whatever the deck order, and the fill modes share what is left.
v0simulationParams.v0, else 1.25 m/sfinite, ≥ 0Clear-air walking speed, for every movement model (FDS+Evac VEL_MEAN; 1.2 before). Every smoke, irritant and zone factor multiplies this value.
v0_distribution"constant"constant, gaussiangaussian draws per agent with v0_std; draws are clipped to [0.1, 5.0] m/s.
v0_stdnone—Spread of the Gaussian draw.
radiussimulationParams.radius, else 0.2 mfinite, > 0Body radius: packing, spawn spacing, and the radius + 0.5 m arrival distance at a checkpoint (an agent also arrives when its centre is inside the checkpoint polygon). An agent leaves at an exit when its centre enters the exit polygon or comes within 0.03 m of it.
radius_distribution"constant"constant, gaussiangaussian draws per agent with radius_std, clipped to [0.1 m, b], where b = min(max(radius + 3 × radius_std, 0.1), 1.0) m is the radius placement spaces agents for. Only agents placed at the start are drawn; flow-spawned agents take radius.
radius_stdnone—Spread of the Gaussian draw.
use_premovementconstant 10 s when no pre-movement key is set, with a warningtrue, falseDelay before the agent starts moving. Setting any pre-movement key, including use_premovement: false, turns the default off.
premovement_distribution"gamma"gamma, lognormal, weibull, uniform, constantDistribution of the delay.
premovement_param_a, premovement_param_bthe preset of the distribution—Override the preset; the presets and their sources are in Coming from FDS+Evac.
premovement_seednone—Separate seed for the pre-movement draw. When set, the pre-movement times are the same for every run seed.
premovement_offset_snone≥ 0 sA fixed delay added to every agent’s drawn pre-movement time, so nobody starts earlier. It stands for FDS+Evac’s detection time, and it is also the way to let the fire develop before the alarm (Pathfinder’s time offset for FDS results): the FDS clock is not shifted, agents are in the building from ignition, and while they wait the smoke update skips them, so they accrue no dose (see Spawn areas). pyfds-evac init writes it. It needs use_premovement: true, and without it the run stops with a ValueError. Applies with and without journeys; ignored with flow spawning.
use_flow_spawningfalse—Add agents over time instead of at the start (no pre-movement then).
flow_start_time, flow_end_time0 s, 10 s—Window of flow spawning. A flow agent keeps twice the larger radius from every agent already in the run; while no position in the area is that free, it waits, and one still waiting when the window closes does not enter (agents_not_spawned); a run whose building then empties ends there (end_reason flows_closed). Besides that spacing, only a position JuPedSim refuses (too close to an agent or a wall, or outside the walkable area) makes the agent wait; any other error while building a flow agent, such as no valid entry stage, no exit or exit journey, or an invalid agent parameter, stops the run with an error naming the distribution, its source and the position, and is not counted in agents_not_spawned.
flow_schedulenonea list of windowsFlow windows that replace flow_start_time, flow_end_time and number: each {"flow_start_time", "flow_end_time", "number"} (aliases start_time_s, end_time_s, sim_count) adds number agents at evenly spaced times within its window, as written, at most one per 0.01 s time step; a window shorter than number × 0.01 s, or one whose agents per second exceed the area’s capacity estimate, stops the run. Agents of a window that the time limit cuts off count as not spawned; a run whose building empties after the last flow window with agents still to enter closed ends then (end_reason flows_closed). An entry that is not an object, a time that is not a finite number, a start below 0, an end not after the start or a number that is not a whole number ≥ 1 stops the run. Each of these errors is a SpawnConfigError (a ValueError) that names the distribution, printed by the CLI in one line; --export-only reports the same. Scenario.set_flow_schedule() writes it.
initial_number0≥ 0With flow_schedule: agents placed at the start beside the scheduled ones, checked against the area’s capacity as number is. Ignored, and not checked, without flow_schedule.
familiarity"full"full, discovery, or a probability in [0, 1]What the agents know of the exits at the start; see Models › Wayfinding.
entrancenonean exit idOne exit, reachable from the spawn area, that the agents know from the start.
no_known_exit"default_route"default_route, explore, return, stayWhat an agent does while no exit is reachable in its map. default_route (the FDS+Evac counterpart) follows the journey, or without one the nearest exit on foot, and flags leaving by an exit not in the map. explore, return and stay need rerouting and are refused with --smoke-blind; see Models › Wayfinding §2.4.

A spawn area’s own number, radius and v0 are read as the simulationParams values are: number with int(), radius and v0 with float(), so numeric strings are accepted, and true or false is not a number. The bounds are the same with one exception: a spawn area’s v0 may be 0, which places agents that stand still (the stationary FED verification cases use it), while simulationParams.v0 must be greater than 0, since it is the speed of every spawn area that sets none. A value that does not convert or is out of range, such as "-1" for number or "nan" for v0, stops the run at the start with a ValueError that names the distribution and the key (desired_speed when the deck set that alias). null means unset, as for the simulationParams values: the spawn area takes the deck-wide default (#649).

desired_speed, desired_speed_distribution and desired_speed_std are aliases of v0, v0_distribution and v0_std. An alias set alone is used as its v0* key. An alias and its v0* key with the same value are accepted; with different values the run stops at the start with a ValueError that names the distribution and both keys (Troubleshooting). --show-config, the TUI and the GUI report the same error before a run. This check applies to the scenario JSON; Scenario.set_agent_params() in Python lets desired_speed win instead (#586).

While an agent waits out its pre-movement time, the smoke update skips it, so it starts at its full clear-air speed.

Exits: exits.<id>

KeyDefaultEffect
coordinatesrequiredExit polygon.
enable_throughput_throttling, max_throughputfalse, 0Cap the removal rate at the exit: an agent whose centre is inside the exit polygon, or within 0.03 m of it, is removed only if at least 1/max_throughput s have passed since the last removal there; otherwise it waits. A throttled exit is steered directly. This caps the rate; it does not model door flow. A max_throughput of 0 disables the cap.
capacity_agents_per_srouting.default_exit_capacity (1.3 agents/s)Exit capacity used to estimate queue time when routes are priced.
open_from_snone (open from the start)The exit opens at this time [s], a finite number ≥ 0.
closed_after_snone (never closes)The exit closes at this time [s], a finite number ≥ 0 and greater than open_from_s.
signan omni-directional sign at the exit’s centre, c = 3The sign agents read; keys below.

An exit with open_from_s or closed_after_s is open while open_from_s ≤ t < closed_after_s (#373). While it is closed:

  • it removes nobody: an agent standing in it waits there;
  • routes are ranked without it, both the opening choice and every re-evaluation, and it is no target for exploring or wandering. An exit is judged by whether it is open at the time of ranking, not at the time the agent would arrive;
  • an agent whose route ends at it re-evaluates at the next reroute check (every second), whatever --reroute-interval says, and takes the best open exit it knows. The switch is logged with the reason exit_closed when the exit has closed (closed_after_s passed). An exit that has not opened yet (open_from_s still ahead) was never the agent’s exit: the first open exit it is given is logged as initial. An agent that knows no open exit acts by its spawn area’s no_known_exit mode. Under the default, default_route, it walks to the nearest open exit on foot, which need not be in its map, and the switch is logged as default_route. Under explore it is not told of another exit: it heads for a known node it has not visited, or else wanders over the nodes it knows; an agent that knows only its spawn area and the closed exit has neither, so it keeps its route and waits at the closed exit. With every exit closed, an agent keeps its route and waits.

When an exit opens, nobody is made to re-decide: an agent takes it at its next regular re-evaluation, up to --reroute-interval later.

A run without rerouting (--no-enable-rerouting or --smoke-blind) honours the schedule too (#395). At the same one-second check, only the agents whose route ends at a closed exit choose again, once for each closure, scored as their opening choice is: on the map they hold, without the queue term, with the smoke at that time, or in clear air when the run is smoke-blind. An agent that knows no open exit takes the default route to the nearest open exit on foot; with no exit open it waits and is checked again every second. The route history logs the switches: exit_closed for an exit that has closed, initial for an agent whose exit has not opened yet and is sent to an open one it knows, and default_route for an agent sent to an exit it does not know. Without rerouting nobody re-decides when an exit opens.

A schedule cannot be combined with --replay-exits, and a run with a scheduled exit stops with an error when an agent walks a JuPedSim journey instead of a routed path (a spawn area with no journey in a scenario that has journeys). Without a schedule nothing changes.

Signs: sign

Exits, checkpoints and waypoints can carry a sign. A node without one gets an omni-directional sign at its position with c = 3, so every exit is subject to smoke-dependent legibility.

KeyDefaultEffect
x, yrequired in an authored signSign position [m].
alphanone (omni-directional)Bearing the sign faces [°], clockwise from north (+y); the sign is readable only from the side it faces.
c3The constant C of the legibility law V = C/K.
max_distance--max-sign-distance (30 m)Farthest reading distance for this sign, even in clear air.

The legibility rule is on Models › Wayfinding.

Checkpoints and zones

KeyObjectDefaultEffect
coordinatesbothrequiredPolygon.
speed_factorboth1.0Multiplies the speed of agents inside; clipped to [0, 3]. A negative or non-numeric value becomes 1.0.
waiting_timecheckpoint0 sTime agents wait at the checkpoint.
waiting_time_distribution, waiting_time_stdcheckpointconstant, 1.0 s"gaussian" draws the wait per agent.
enable_throughput_throttling, max_throughputcheckpointfalse, 1.0Cap the flow through the checkpoint.

Where to draw checkpoints, how large, and how they join the route graph: How do I place checkpoints?.

Journey splits: waypoint_routing

A journey in which a checkpoint has more than one outgoing transition needs the shares of agents that take each branch:

"waypoint_routing": {
  "<checkpoint id>": {
    "<journey id>": {
      "destinations": [ { "target": "<stage id>", "percentage": 60 }, … ]
    }
  }
}
KeyDefaultEffect
destinations[].targetrequiredA stage the journey’s transitions lead to from this checkpoint. Every such stage must be listed.
destinations[].percentage0Share of the agents sent to target. The sum must be greater than 0.

Without it, or with a target missing, the set-up stops with Explicit routing required for <checkpoint> in <journey> or Explicit routing for <checkpoint> in <journey> is incomplete (_create_journeys_with_percentages in simulation_init.py). The shares set the authored journey only. With rerouting on, the default of run.py, the route-cost model picks each agent’s exit: in assets/t_junction with 40 agents, shares of 99/1 and 1/99 both sent all 40 to the nearer east exit, while with --no-enable-rerouting 99/1 sent all 40 west. JuPedSim Web does not write this key.

Route choice: routing

The routing block sets the route-cost model. Its keys, defaults and the constants that no key can set are listed in one place, Models › Routing › Parameters. cost_model must be exactly "gate" or "additive" (lower case); without the key it is "gate". Any other value stops the run with a ValueError that lists the two names, also with --no-enable-rerouting, since the first exit choice uses the cost model too.

fallback_return_lockout_s, the 10 s return lockout between two refused routes (#458), was removed in #187. A scenario that still sets it stops with a ValueError naming the removal, also with --no-enable-rerouting; delete the key. path_switch_anchor, the fraction of the walked path’s rank_cost a new path to the same exit had to come in under, was removed in the same issue and is refused the same way: the path is now taken whenever it is strictly cheaper. tau_return_margin, the factor (0.8) on tau_max that a rival exit’s optical depth had to come in under, was removed in the same issue and is refused the same way: every exit is now refused above tau_max. fed_return_margin, the fraction of fed_rejection_threshold above which a rival exit was refused for dose, was removed in the same issue and is refused the same way: a rival is now held to fed_rejection_threshold, as the current exit is.

Each switching margin must be a number in its range, or the run stops with a ValueError naming the key, also with --no-enable-rerouting: exit_switch_anchor, current_exit_discount and clean_exit_margin in (0, 1]; tau_deadband and fallback_switch_margin in [0, 1]. The value that switches a margin off is in range: 1, or 0 for tau_deadband and fallback_switch_margin. fallback_switch_margin = 1 keeps the current exit between two refused routes unless it must be fled, the scenario-file way to the hold rule.

The routing keys alpha, beta, min_speed_factor and base_speed_m_per_s only estimate travel time when a route is priced. They do not change how fast agents walk.

fed_rate_memo (default true) remembers the FED rate a route reads at a point for the run; false reads the model every time. It changes run time only; see Segment caching. A value that is not true or false stops the run with a ValueError naming the key.

Not in the JSON

Some parameters exist only in Python, as fields of a config object:

  • the smoke-speed law and its parameters (SmokeSpeedConfig: speed_law, alpha, beta, min_speed_factor, visibility_factor_c); a configured run always uses the Lund law with the defaults on Models › Smoke speed;
  • RerouteConfig.exit_switch_anchor, which, when set, overrides the routing key exit_switch_anchor for that run.

Tracking issue for this reference: #119.

Last updated on