Verification

Verification

The model is verified: tests check that its components reproduce hand calculations and adapted IMO test cases. It is also compared with the results published in the EvacuatioNZ verification report; no EvacuatioNZ runs were made. A published network of a real building is compared with its EvacuatioNZ results in The Station nightclub. It is not validated: it has not been compared with evacuation drills, experiments or JuPedSim’s microscopic models.

Tests

The tests are in tests/. Run them from a clone of the repository:

uv run --extra cli --extra tui --group tui-test pytest -q

This runs the tests that every pull request runs on Python 3.13: the hand calculations and IMO cases, the EvacuatioNZ cases, the property tests on random networks (hypothesis profile pr, derandomized), the documented-number tests, the tests of the command line and those of the terminal UI. It ends with no failures and lists the long tests as deselected. In a fresh environment, a plain uv run pytest -q skips the tests of the coloured help and the pilot flows and snapshots of the terminal UI (tests/test_tui.py); uv run --extra cli pytest -q, the Python 3.10 leg of CI, skips only the latter.

The terminal UI is tested by pilot flows, by a byte-for-byte comparison of its result files with those of jupedsim-network run, and by SVG snapshots, which are also the figures of the Terminal UI page.

Two further commands run the long tests:

uv run --extra cli pytest -m slow
uv run pytest -m fuzz --hypothesis-profile=fuzz

The first runs the documented numbers of long runs: the 300-run case study, the max_density and hydraulic-coefficient sweeps, the time-step example in Limitations and the snippets that call run_many(500). CI runs it as its own job, docs-numbers, and the site deploys only when it passes. The second runs the long property runs and fixed-seed sweeps of .github/workflows/fuzz.yml, weekly and on demand.

The property tests check on random networks that

  • no agent is lost;
  • no link, and no shared two-way connection under "bounding" and "estimate", passes more than $1 + C\,t$ agents in any interval $t$;
  • no node exceeds max_density;
  • a seed reproduces its run;
  • networks with no two-way pair in use give the same result under all three counterflow values;
  • route tables take only tied shortest links.

The weekly job also reports how the evacuation time changes when $\Delta t$ is halved. It does not assert that a smaller $\Delta t$ never gives a later time, because that does not hold (Limitations).

The documented-number tests (tests/test_docs_numbers.py) rebuild every number on these pages that a run produces from the code and compare it with the page text exactly.

The table lists the tests with a hand-calculated expectation. “Result” is what the test measures with the current code. In the counterflow rows, values separated by “/” are for counterflow="independent" / "estimate" / "bounding"; the derivation is under Counterflow at a shared door.

CaseExpectedResultToleranceTest
IMO test 1: 40 m at 1.0 m/s40 s40.0 s0.5 stest_free_walking_speed_imo_test_1
IMO test 3 geometry, stair speed from 18/28 cm steps, as in EvacuatioNZ [2, §2.1.3]$10/(k(1-0.266\cdot0.54)) = 10.84$ s11.0 s ($\Delta t = 0.1$ s)0.25 stest_stair_speed_imo_test_3
IMO test 4 geometry, 100 agents, 1 m door, $F_s = 1.33$, hydraulic door flow as in EvacuatioNZ [2, §2.2]$(N-1)/C = 99/0.931 = 106.3$ s106.5 s1 stest_door_flow_imo_test_4
50 agents, 0.6 m opening$(N-1)/C = 49/0.78 = 62.8$ s63.0 s0.5 stest_opening_has_no_boundary_layer
200 agents at 2 m⁻² walk 20 m [3, p. 15]$20/(1.4\,(1-0.266\cdot2)) = 30.5$ s31.0 s0.6 stest_congested_walking_speed
Merge weights 1 : 3 over 150 sflow ratio 33.015 %test_merge_weights_split_flow
Stair 7/11 in: $k$ and $F_s = k/(4a)$1.08 m/s (SFPE Table 67.2 [1, p. 2174]), 1.01 persons/s/m (SFPE Table 67.5 [1, p. 2176])1.081, 1.0160.01test_stair_specific_flow_follows_geometry
One start node, 30 m of 18/28 cm stair against 35 m of level path to the exit, routing_policy="shortest_free_flow_time" (Routes)$k_\text{stair} = 51.8\sqrt{28/18}/60 = 1.0768$ m/s; costs $30/(0.85636 \cdot 1.0768) = 32.53$ s (stair) and $35/(0.85636 \cdot 1.4) = 29.19$ s (level), with $0.85636 = 1 - 0.266 \cdot 0.54$ the density floor factor; shortest distance takes the stair, shortest time the level path32.53 s, 29.19 s; routes as expected$10^{-6}$ relativetest_analytical_level_and_stair_costs
Supply ramp between passages, 45 agents per roompassages at $t_q + \Delta t\,\lceil k/(\varphi\,C\,\Delta t)\rceil$, $k = 1 \ldots 45$; first exit 94.5 s, $T = 150.0$ sequalexacttest_supply_ramp_holds_between_passages
Steady density on the ramp, exit door 0.7 m and 0.9 m$40\,D^*$ = 90.11 and 80.16 agentsmean 90.11 and 80.16, maximum 91 and 810.5 agent; maximum ≤ $\lceil 40\,D^* \rceil$test_supply_ramp_sets_steady_density
Chain of five 100 m² rooms A–B–C–D–E with exits at A and E (safe nodes s0 and s1); all six connections are 1 m doors of length 0; $N = 50$ agents in E, 1.2 m/s, no pre-movement, $\Delta t = 0.5\,\mathrm{s}$; both split_ties settings (Routes)$C = 1.3\,(1-2\cdot0.15) = 0.91$ /s; $\Delta t\,\lceil (N-1)/(C\,\Delta t)\rceil = 0.5\cdot\lceil 49/0.455\rceil = 54.0$ s54.0 s, E->s1 = 50, all other links 0exacttest_zero_length_chain_uses_adjacent_exit
Two 200 m² rooms A and B swap 20 + 20 agents through one two-way 1 m doorindependent: 21.5 s; estimate ($g \le 1$): $T \ge 43.5\,\mathrm{s}$, recursion 44.0 s; bounding ($g \le 0.94$): $T \ge 46.5\,\mathrm{s}$, recursion 46.5 s21.5 / 44.0 / 46.5 s; pair passes $\le 1 + C\,t$exacttest_counterflow_door_swap_balanced
Same door, 36 agents in A against 4 in Brecursion: $T$ = 39.0 / 45.5 / 47.0 s; B’s passages at 0.5, 1.5, 2.5, 3.5 / 4.0, 8.5, 14.5, 20.5 / 4.0, 9.0, 15.5, 22.0 sequalexacttest_counterflow_door_minor_ten_percent
1.2 m stair entry: 20 evacuees leave the flight, 4 responders enter itrecursion: evacuees’ $T$ = 21.5 / 29.0 / 30.0 s; responders out at 1.5–4.5 / 4.0, 9.0, 12.5, 19.5 / 4.0, 9.5, 13.5, 20.5 sequalexacttest_counterflow_stair_responders
Chain A–E of the row above, 10 agents per room, no target, both split_ties$\Delta t\,\lceil (N_A - 1)/(C\,\Delta t)\rceil$ = 26.5 s ($N_A = 25$) and 32.0 s ($N_A = 30$), the same under all three values; no link used both waysequalexacttest_default_routing_has_no_counterflow
1 agent in A against 50 in B, B of 20 m² ($D_B = 2.5\,\mathrm{m^{-2}}$)A’s agent exits at 13.0 s (estimate) and 14.0 s (bounding); $T$ = 57.0 s and 58.0 sequalexacttest_counterflow_supply_uses_door_share

The two supply-ramp tests check that the code delivers the share $\varphi_n$ of the update scheme, with $D_\text{max} = 2.75\,\text{m}^{-2}$ (the default max_density) and $D_\text{peak} = 1.88\,\text{m}^{-2}$. In the first, two 20 m² rooms of 45 agents each swap occupants through two one-way doors, 1 m wide and 2 m long, with $C\,\Delta t = 0.455$. The swap keeps $D = 2.25\,\text{m}^{-2}$ in both rooms, so one share $\varphi = 0.5745$ holds for all 45 passages. Walking 2 m at $0.5621\,\text{m/s}$ takes 8 steps, so the first step with a queue starts at $t_q = 3.5$ s. Each group then leaves through a 50 m one-way link to the far exit. Walking 50 m at the same speed takes 178 steps, so the first agent to pass, at 5.5 s, exits at 94.5 s. $T = 150.0$ s follows from a step-by-step recursion of these exits. In the second, a 40 m² room is fed through a 1 m one-way door ($C_\text{in} = 0.91\,\text{s}^{-1}$) and left through a door of width $w$, with $C_\text{out} = 1.3\,(w - 0.3) = 0.52$ and $0.78\,\text{s}^{-1}$. Setting $\varphi\,C_\text{in} = C_\text{out}$ gives $D^* = D_\text{max} - (D_\text{max} - D_\text{peak})\,C_\text{out}/C_\text{in}$. The test averages the occupancy over $t \ge 500\,\text{s}$ for $w = 0.7\,\text{m}$ and over $t \ge 800\,\text{s}$ for $w = 0.9\,\text{m}$.

Further tests check pre-movement delays, route choice, conservation of agents, that max_density is never exceeded, that no link passes more than $1 + C\,t$ agents in any interval $t$, reproducibility with a fixed seed, the stair-range warning, nan for incomplete runs, quantiles with incomplete runs, the error messages, that counterflow rejects unknown values (test_counterflow_rejects_unknown_value), and the means and truncation of the distributions. The two room swaps of test_supply_carry_admits_large_agent_swap are pinned to counterflow="independent".

Counterflow at a shared door

The rule is described in Counterflow. All five rows use $\Delta t = 0.5\,\mathrm{s}$, seed 1 and no pre-movement. Every agent queues at its first link in step 0; it reaches its next link, the exit or, for a responder, flight→floor, one step after its previous passage.

Door geometry (door_swap in tests/test_network.py). Rooms A and B are joined by connect("A", "B", width=1.0), a two-way door of length 0: $C = 1.3\,(1 - 0.3) = 0.91\,\mathrm{s^{-1}}$ and $C\,\Delta t = 0.455$. A’s agents head for B’s exit and B’s for A’s; both exits are 20 m openings of length 0. An agent that passes the door in step $k = 0, 1, \ldots$ is recorded in link_flow at $(k + 1)\,\Delta t$ and exits at $(k + 2)\,\Delta t$.

independent. A fresh link passes its first agent in step 0 and its $k$-th agent ($k \ge 2$) in step $\lceil (k - 1)/(C\,\Delta t) - 1\rceil$. With 20 agents: $\lceil 19/0.455 - 1\rceil = 41$, so $T = 43 \cdot 0.5\,\mathrm{s} = 21.5\,\mathrm{s}$. With 36: $\lceil 35/0.455 - 1\rceil = 76$, $T = 39.0\,\mathrm{s}$; the 4 agents in B pass in steps 0, 2, 4 and 6.

Bound for the shared door. In steps $0 \ldots m$ a pair passes at most $1 + g\,C\,\Delta t\,(m + 1)$ agents. Forty passages with $g \le 1$ need $m \ge 39/0.455 - 1$, so $m \ge 85$ and $T \ge 87 \cdot 0.5\,\mathrm{s} = 43.5\,\mathrm{s}$. With $g \le 0.94$: $m \ge \lceil 39/(0.94 \cdot 0.455) - 1\rceil = 91$, so $T \ge 46.5\,\mathrm{s}$, which bounding attains.

Recursion. The estimate and bounding values apply the rule step by step. With $n_A$, $n_B$ the queues, $s$ the minor share, $g = g_0 + (g_{1/2} - g_0)\,2s$, $y_A = 0.17 + 0.66\,n_A/(n_A + n_B)$, budget $B_P = c_P + g\,C\,\Delta t$ and key $\lambda = \sigma + (j + 1)/y$, the first steps of the balanced swap under estimate ($g_0 = 0.90$, $g_{1/2} = 1.00$, $c_P = 1$ at the start) are:

Step$n_A$, $n_B$$s$$g$$B_P$$\lambda_A$, $\lambda_B$Passes
020, 200.511.4552.000, 2.000A (tie: A→B was created first)
119, 200.48720.997440.909–none
219, 200.48720.997441.3634.034, 1.967B

The first steps of 36 against 4 under bounding ($g_0 = 0.84$, $g_{1/2} = 0.94$) are:

Step$n_A$, $n_B$$s$$g$$B_P$$\lambda_A$, $\lambda_B$Passes
036, 40.10000.86001.3911.309, 4.237A
135, 40.10260.86050.783–none
235, 40.10260.86051.1742.621, 4.207A
534, 40.10530.86111.3503.936, 4.176A
733, 40.10810.86161.1345.254, 4.143B

In step 7, B’s key is still $1/y_B = 1/0.2414 = 4.143$ ($\sigma_B = 0$), so B’s first agent passes and is recorded at 4.0 s.

Stair (test_counterflow_stair_responders). Node “flight” of 30 m² with 18/28 cm steps; rooms “lobby” and “floor” of 100 m²; safe node “street” off the lobby and “roof” off the floor, through 20 m one-way openings of length 0. connect("flight", "lobby", width=1.2, kind="stair") and the same to “floor”: $k = 51.8\sqrt{28/18}\ \mathrm{m/min} = 1.0768\,\mathrm{m/s}$, $F_s = k/(4a) = 1.0120\,\mathrm{s^{-1}m^{-1}}$, $C = 1.0120 \cdot 0.9 = 0.9108\,\mathrm{s^{-1}}$ and $C\,\Delta t = 0.4554$. The stair values $g_0$, $g_{1/2}$ apply. The 20 evacuees leave the flight to the lobby and exit at $(k + 2)\,\Delta t$; the 4 responders start in the lobby, target the roof, pass lobby→flight in step $k$, flight→floor in step $k + 1$ and exit at $(k + 3)\,\Delta t$. independent: evacuees $\lceil 19/0.4554 - 1\rceil = 41$, so 21.5 s; responders in steps 0, 2, 4, 6, so out at 1.5, 2.5, 3.5 and 4.5 s.

Chain. Rooms A–E as in the chain row above, with 10 agents per room. A’s queue never empties, so $T = \Delta t\,\lceil (N_A - 1)/(C\,\Delta t)\rceil$, where $N_A$ is the number of agents leaving through A->s0. With ties split, C’s 10 agents split 5/5, so $N_A = 25$ and $T = 26.5\,\mathrm{s}$. split_ties=False sends C’s 10 via B (and warns), so $N_A = 30$ and $T = 32.0\,\mathrm{s}$. The link totals for A->s0, B->A, C->B, C->D, D->E, E->s1 are 25, 15, 5, 5, 15, 25 and 30, 20, 10, 0, 10, 20.

Supply uses the door share. The door geometry, with B of 20 m² holding 50 agents ($D_B = 2.5\,\mathrm{m^{-2}}$) and 1 agent in A. B is above $D_\text{peak} = 1.88\,\mathrm{m^{-2}}$, so it admits A’s agent only when $\alpha_B = \gamma_B + \varphi_B\,\tilde C_A\,\Delta t \ge 1$, with $\varphi_B = (2.75 - D_B)/(2.75 - 1.88)$ and $\tilde C_A = y_A\,g\,C$, A’s share of the door. Under bounding, $y_A = 0.17 + 0.66/51 = 0.183$, $g = 0.844$ and $\tilde C_A\,\Delta t \approx 0.070$. $D_B$ falls by $0.05\,\mathrm{m^{-2}}$ with each agent that leaves B.

Step$D_B$ (m⁻²)$\alpha_B$$\gamma_B$ after the step$B_P$Passes
02.500.0200.0201.384B
52.400.1540.1541.304B
102.300.3280.3281.225B
152.200.5400.5401.146B
202.100.7930.7931.067B
242.001.0271.000 (cap)0.605none
252.001.0621.000 (cap)0.989none
262.001.0620.0621.374A

$\alpha_B$ first exceeds 1 in step 24, but the pair budget allows a passage only in step 26, where A’s key wins: A’s agent exits at $28 \cdot 0.5\,\mathrm{s} = 14.0\,\mathrm{s}$. With $C\,\Delta t$ in place of $\tilde C_A\,\Delta t$ it would exit at 6.0 s (5.5 s under estimate); with $\tilde C_A = 0$, only after $D_B$ falls below $1.88\,\mathrm{m^{-2}}$, at 17.5 s (16.5 s).

IMO tests as written and as tested

The IMO test cases are in MSC.1/Circ.1533, Appendix 2, paragraphs 3–6 [4].

  • Test 1 (one person, 2 m × 40 m corridor, 1 m/s, 40 s) is tested as written.
  • Test 3 as written asks that one person with a walking speed of 1 m/s covers a 2 m wide stair of 10 m, measured along the incline, in 10 s [4]. With 18/28 cm steps this model does not meet it, by design. On a stair the input speed only caps the walking speed, which comes from the stair geometry: $k = 51.8\sqrt{T/R}$ gives 1.077 m/s for 18/28 cm steps, and $k(1 - 0.266 \cdot 0.54) = 0.922$ m/s. A lone walker takes 10.84 s by hand calculation (11.0 s in the run at $\Delta t = 0.1$ s) instead of 10 s. Shallower steps with $T/R \ge 1.83$ cap the stair speed at or above 1 m/s. The test checks this adaptation, the same one EvacuatioNZ uses for its stair verification [2, §2.1.3].
  • Test 4 asks for 100 persons in an 8 m × 5 m room with a 1 m exit, and that the flow over the whole period does not exceed 1.33 persons/s [4]. The link capacity of 0.931 persons/s and the mean flow of 100/106.5 s = 0.94 persons/s both meet this criterion. Specific flow, boundary layers and a target time are not part of the test; the construction $1.33 \times 0.7$ m is EvacuatioNZ’s [2, §2.2].

Passage time: (N−1)/C and N/C

The door rows check the model’s own convention, in which the first agent passes at once and the last after $(N-1)/C$ (update scheme). The SFPE hand calculation is $N/C$ [1, Eq. 67.9, p. 2177]:

CaseModel$(N-1)/C$SFPE $N/C$EvacuatioNZ [2, §2.2]
IMO 4 geometry106.5 s106.3 s107.4 s107.5 s by hand, 108 s simulated
0.6 m opening63.0 s62.8 s64.1 s

The SFPE value for IMO 4 lies 1.07 s from the test’s expectation, more than its tolerance of 1 s. The model result lies 0.9 s below it.

EvacuatioNZ verification cases

The cases of the EvacuatioNZ verification report version 2.11 [2] are rebuilt with this model and compared three ways: the hand value, the result published in the report, and this model at $\Delta t = 0.5$ s. No EvacuatioNZ runs were made. Page numbers are the printed page numbers of the report; the PDF page is one higher. The tests are in tests/test_evacuationz_verification.py. Every expected value in them is a hand calculation; values read from figures of the report are never asserted.

The report’s inputs are mapped the same way in every case. These rules are accepted for the EvacuatioNZ cases only:

  • A door (enz_door) is a door with $b = 0.15$ m and $F_s = 1.33$ persons/s/m, EvacuatioNZ’s value, passed explicitly in each case; the model’s default stays $F_s = 1.3$. An untyped connection is an opening with $b = 0$ and $F_s = 1.33$, and stairs (enz_stairs) are a stair node with $F_s = k/(4a)$ from the step geometry.
  • A connection that is both stair and door is one link with the lower of the two capacities.
  • This model walks a link’s length inside the source node, so stair travel is put on the link leaving the stair node. The total distance is unchanged.
  • A stair given by its height $H$ has the length $L = H\sqrt{1 + (T/R)^2}$.
  • A random start distance is $U(0, L_{\max})$ with $L_{\max}$ stated per case; the report does not give the range.
CaseReportHand valueEvacuatioNZThis modelExplanation
Travel speed, 40 m along a link or from a start distance at 1.0 m/s§2.1.1–2.1.2, pp. 6–740 s40.5 s40.0 stest_travel_speed_from_start_distance
Stair speed, 10 m of 180/280 mm steps§2.1.3, p. 810.9 s (Eq. 2.1), 10.5 s (SFPE table)12 s11.0 s ($\Delta t = 0.1$ s), 11.5 s ($\Delta t = 0.5$ s)At $\Delta t = 0.5$ s: 10.84 s, plus one step for the transfer into the stair, rounded up to the step. test_stair_speed_imo_test_3, test_stair_flow_uncongested
Door flow, IMO 4 room, 100 agents, 1 m door§2.2, p. 9107.5 s ($N/C$ with $C = 0.93$)108 s106.5 sThis model’s convention is $(N-1)/C = 106.3$ s, see above
Door flow, 1–3 m doors and 1 m opening, 1–100 agents§2.2, p. 10$(N-1)/C$Fig. 2.2, graph onlytable belowtest_door_flow_widths
Stair flow, 1–1000 agents, stairs 10 × 1, 200 × 1 and 200 × 5 m§2.3, pp. 12–13$L/S_0 + (N-1)/C$Fig. 2.6, graph onlytable belowtest_stair_flow_*
Fire Engineering Design Guide, 90 agents, room over one stair§2.4, pp. 13–15186 s (report, p. 14), the sum of the FEDG’s 0.20 + 2.9 min [18, p. 231]; no room walk179 s (p. 14); 168 s with random start (p. 15)first exit 30.5 s; last exit 129.0 sCapacity bound $30.5 + 89/0.911 = 128.2$ s; exit C is merged into the stair link (lower capacity), see below. test_fedg_first_exit, test_fedg_last_exit_bound
SFPE Handbook nine-storey building§2.5, pp. 15–171524 s (SFPE Solution A, 25.4 min; Solution B 1518 s); ≥ 1538.9 s in this model’s conventions ($t_{\text{first}} + 1199/0.811$)1871 s (v2.11); 1471 ± 3 s in [7, manuscript p. 20; Fig. 10] (2009, different network)1548.5 s300 per floor on floors 2–9 [1, p. 2181] [7, Fig. 11] and a 36 in exit door per stair from the SFPE example [1, p. 2181]; the report gives neither, and neither EvacuatioNZ document gives the ground-floor exit. The exit door (0.811/s) controls: $70.0 + 1199/0.811$. Stair length 6.76 m from $H = 12$ ft. Landings are nodes: each link’s length is walked in the node it leaves, so the 4.8 m of landing travel is level travel and corridor→landing is 4.8 m shorter below the top floor. With the landing travel walked on the stair link instead, 1915.5 s. Agents start at the room door; the report draws a random start distance. With a start $U(0, 91.44)$ m, 1542.5 s (seed 1; first exit 64.0 s instead of 70.0 s; the exit door still controls). test_sfpe_nine_storey
SFPE Guide on Human Behavior, example 1, 300 agents, start at the door§2.6, pp. 18–20246 s (Guide); 234.95 s in this model’s conventions221.5 s235.5 s$149/0.682 + 15.27/S_0$. test_sfpe_guide_example_1
The same, start 200 ft from the door§2.6, pp. 18–20300 s (Guide); 285.8 s in this model’s conventions283 s286.0 sPlus 60.96 m at 1.199 m/s
Distributions: fixed 45 and 120 s, $U(10, 100)$, $N(120, 30)$, log-normal mean 5, sd 2§3.1, pp. 21–25means 55, 120, 5; sd 25.98, 30, 2Figs. 3.1–3.3, graph onlymeans 54.88, 119.66, 4.97; sd 26.07, 29.82, 1.99 (20 000 samples)test_fixed_distribution_is_exact, test_distribution_moments
Room clearance, IMO 4 room, fixed delay 0, 30, 120 s§3.2, p. 25$d + (N-1)/C$Fig. 3.4, graph only (≈ 114, 144, 234 s)106.5, 136.5, 226.5 s (start 0)A fixed delay shifts the result by exactly $d$, also with a dispersed start $U(0, 8)$ m and the same seed. EvacuatioNZ’s dispersed run without delay lies about 6 s above its own 108 s with the start at the door; this model gives 106.5 s at the door and 106.5–107.0 s with a dispersed start. test_room_clearance_*
Room clearance, triangular delay (0, $m$, $2m$), $m$ = 15, 30, 60 s, start at the door, seed 0§3.2, p. 25$\max_i(\tau_{(i)} + (N-1-i)/C)$: 107.84, 110.41, 128.01 sFig. 3.4, graph only108.5, 111.0, 128.5 sEach lies 0.49–0.66 s above its bound. test_room_clearance_triangular_bound
Room clearance, fixed delay 0, dispersed start $U(0, 8)$ m, 20 seeds§3.2, p. 25$(N-1)/C = 106.3$ sFig. 3.4, graph only (≈ 114 s)106.5–107.0 s, mean 106.6 sNo seed lies below the hand value. test_room_clearance_dispersed_without_delay
Exit choice, minimum distance§5.1.1, p. 31Exit 5Exit 5Exit 5test_exit_choice
Exit choice, specified exit§5.1.5, p. 33Exit 6Exit 6Exit 6test_exit_choice
Required connection§5.2, pp. 34–35direct doordirect doorthrough Room 2 and Room 3Not modelled. test_required_connection_is_not_modelled

Door and opening flow with the IMO 4 room, $F_s = 1.33$, start at the door. Every result lies within one step above $(N-1)/C$:

Width$N = 1$$N = 10$$N = 100$
1 m door0.5 s10.0 s106.5 s
2 m door0.5 s4.0 s44.0 s
3 m door0.5 s3.0 s28.0 s
1 m opening0.5 s7.0 s74.5 s

Stair flow with 180/280 mm steps: $k = 1.0768$ m/s, free stair speed $S_0 = k(1 - 0.266 \cdot 0.54) = 0.9221$ m/s and $C = 1.012\,(w - 0.3)$. The text of §2.3 names two stairs; the caption of Fig. 2.7 names 200 m stairs of 1.0 m and 5.0 m. All three are run.

Stair$N$This model$L/S_0 + (N-1)/C$Peak on the stair
10 × 1 m111.5 s10.84 s1
10 × 1 m1026.0 s23.55 s10
10 × 1 m100169.0 s150.60 s27 (limit)
10 × 1 m10001439.5 s1421.07 s27 (limit)
200 × 1 m1217.5 s216.90 s1
200 × 1 m10230.0 s229.60 s10
200 × 1 m100357.0 s356.65 s100
200 × 1 m10001984.5 s1627.12 s550 (limit)
200 × 5 m1217.5 s216.90 s1
200 × 5 m10219.0 s218.79 s10
200 × 5 m100238.0 s237.71 s100
200 × 5 m1000444.5 s426.93 s1000

While fewer than $0.54\,L\,w$ agents are on the stair, everyone walks at $S_0$ and the result lies within two steps of the hand value. With more agents the stair fills and everyone on it walks at $k(1 - 0.266\,D)$, so the hand value is only a lower bound. On the 10 m stair the node stays at its limit of 27 agents (2.7 m⁻²), and the slower walk adds about 18 s. On the 200 × 1 m stair the node holds 550 agents, its limit, and all walk at about 0.29 m/s. The flow from the first to the last exit is 1.012 persons/s per metre of effective width for both 1000-agent runs on the 200 m stairs, equal to the stair’s $F_s = k/(4a) = 1.012$. Fig. 2.7 of the report shows 1.0 persons/s/m.

Fire Engineering Design Guide. The example is the FEDG’s room over one stair [18, pp. 229–231]. The 10 × 10 m room holds $N_o = A_f D_o = 100 \times 0.9 = 90$ people, with $D_o = 0.9$ m⁻² from Table 11.1 [18, p. 229]. The report starts all agents 20 m from door B, a 1.0 m door into a 10 × 1.2 m stair [2, §2.4, p. 13], and this model’s test does the same. The stair link, $1.012 \times 0.9 = 0.911$ persons/s, limits the exit, not exit C with $1.33 \times 0.7 = 0.931$ persons/s (door B has the same capacity). The first agent reaches door B at 19.0 s and leaves the stair at 30.5 s: 30.0 s at the free stair speed, slowed by the agents that follow onto the stair. The capacity bound for the last exit is $30.5 + 89/0.911 = 128.2$ s; this model gives 129.0 s.

How the FEDG gets 186 s

The report’s hand value is 186 s [2, §2.4, p. 14]. The FEDG does not print it. It prints the stair walk $t_{ts} = 10/48.8 = 0.20$ min and the passage through exit C, a 1.0 m door at the foot of the stair, $t_{qc} = 90/31.4 = 2.9$ min [18, pp. 229, 231]. Their sum, 3.1 min or 186 s, is the evacuation time of 8.0 min less the response time of 4.9 min [18, pp. 230–231]. Unrounded, the same chain gives 184.8 s, 12.3 s on the stair and 172.5 s at exit C, with $D_s = 0.915$ m⁻² against the printed 0.92 (our arithmetic). Spearpoint (2009) gives a movement time of 185 s [7, manuscript p. 16].

The hand value contains no room walk. The FEDG assumes that the first person enters exit B at the start of the evacuation [18, p. 230], and Spearpoint (2009) writes that “the people immediately reach the top of the stairs” [7, manuscript p. 16]. The FEDG’s 20 m is $L_t$, the distance from the furthest point to exit B. It gives the last person’s walk, 0.30 min [18, p. 229], which is shorter than the 2.2 min queue at door B [18, p. 230] and does not enter the result. Starting every agent 20 m from the door is the report’s choice [2, §2.4, p. 13].

The FEDG computes the flow at door B as speed times density at the design density and carries it downstream: the stair density follows from that flow, and exit C passes the stair’s specific flow [18, pp. 230–231]:

  • door B: $F_s = 63.9 \times 0.9 = 57.5$ persons/min/m and $F_a = 57.5 \times 0.7 = 40.3$ persons/min (0.67 persons/s);
  • stair: $F_s = 40.3/0.9 = 44.8$ persons/min/m gives $D_s = 0.92$ m⁻² (the other root is 2.84) and $S = 48.8$ m/min;
  • exit C, effective width 0.7 m: $F_a = 44.8 \times 0.7 = 31.4$ persons/min (0.52 persons/s). This flow controls.

The FEDG gives the stair length as $L_s = 10.0$ m and uses it as a walked distance, $t_{ts} = L_s/S$ [18, pp. 229, 231]. The test uses 10.0 m for the stair node and the stair link, as Listing 2.10 does (lines 17 and 40) [2, §2.4, pp. 13–14]. The FEDG does not say whether 10 m is the walked length, the horizontal run or a height. Its plan, Fig. 11.6, draws the stair along the 10 m wall [18, p. 229], which suggests a horizontal run. The walked length would then be $10\sqrt{1 + (180/280)^2} = 11.9$ m, about 2 s more. For the convention of this model, see Limitations.

This model uses capacities instead: 0.931 persons/s at door B and 0.911 persons/s on the stair link. EvacuatioNZ puts exit C, the 1.0 m door, on the stair connection (enz_door in Listing 2.10, lines 46–48) [2, §2.4, pp. 13–14]. By the rule above, this model maps that connection to one link with the lower of the two capacities. The stair’s 0.911 persons/s is below the door’s 0.931 persons/s, so fedg() uses the stair link and exit C does not bind. The FEDG’s lower flow at exit C (0.522 persons/s) accounts for most of the 57 s between 186 s and 129 s: $89/0.522 - 89/0.911 \approx 73$ s more, 19 s less for the room walk and about 1 s more on the stair (our arithmetic).

EvacuatioNZ’s 179 s is about 50 s longer than this model’s result. In Fig. 2.8 its stair holds about 33 agents from about 80 s to 133 s, and its exits run at about 0.6 agents/s, below both capacities. In this model the stair holds at most 14 agents. The report does not say what limits the flow out of a full node in EvacuatioNZ, so the difference is unexplained. The two documents use different EvacuatioNZ versions and inputs: Spearpoint (2009) uses a zero-length room–stair connection and minimum, maximum or random start positions and reports 257 s, 275 s and 260 ± 4 s [7, manuscript pp. 16–17]; the report uses a 0.1 m connection and a 20 m start and gives 179 s and 168 s [2, §2.4, pp. 14–15].

Tied stairs. EvacuatioNZ splits the agents of §2.6 between the two stairs with a least-populated-connection rule. This model has no such rule; the two stairs are tied, and agents alternate between them (Networks). This gives the same 150/150 split by a different, fixed rule. With split_ties=False all 300 agents take one stair and leave after 455.5 s (start at the door) and 506.0 s (start 200 ft away). The report’s EvacuatioNZ result of 221.5 s lies within 1.6 s of $150/0.682 = 219.9$ s, although the last agent still has about 16 s of stair to descend; the Guide’s 246 s does not match $N/C$ at the door or the stair with these constants. In §2.5 the two stairs are tied at each corridor, so 150 agents per floor go to each, the same 150/150 split as the SFPE Solution B, which says “Divide each floor in half to produce two exit calculation zones” [1, p. 2182]. With split_ties=False all 2400 agents take one stair and leave after 3027.5 s.

In §5.1 the report gives no node sizes or widths; the test assumes 25 m² nodes, 1 m doors and a start $U(0, 5)$ m and checks only the exit used. The report’s distances of 5 m to Exit 5 and 15 m to Exit 3 leave out the 1 m link from Room 1 to Room 2; the full paths are 6 m and 16 m.

Rules of the report that this model does not have: door leaves and door closers (§2.2), the maximum-distance, minimum-nodes and random single exit choices (§5.1.2–5.1.4), required connections (§5.2) and the least-populated connection (§2.6).

Door flow and merging

Cumulative door flow against the model convention and the SFPE hand calculation, and the cumulative merge flows

(a) IMO test 4 geometry. The model follows $1 + C\,t$, the $(N-1)/C$ convention, to within one time step. The SFPE hand calculation $C\,t$ lies one agent lower and ends at $N/C = 107.4$ s; the inset shows the last 13 s. (b) Two rooms feeding a full corridor with merge weights 1 : 3. Over 150 s the flows reach 3 : 1. At the start, room a passes no one from 2.0 s to 17.0 s while room b catches up on the share it lost before the corridor filled (Limitations).

Sensitivity to max_density

In EvacuatioNZ version 1.2, raising the maximum node density from 2.5 to 3.5 m⁻² more than doubled the evacuation time of a 21-storey hotel without pre-movement delay, from 539 s to 1232 s [5, Table 5.5, p. 55]. With pre-movement delay it rose from 796 s to 1156 s. These are means of 100 runs with the local door queue density fixed at 2.2 m⁻²; the runs ranged from 529 to 553 s at 2.5 m⁻² and from 1107 to 1502 s at 3.5 m⁻², both without delay. Tsai judged the 3.5 m⁻² result improbable, since it was longer without delay than with delay [5, p. 56], and recommended 2.5 m⁻² [5, pp. 62, 69]. Tsai attributes the wider spread to queuing at higher allowed densities [5, p. 56]. We attribute the increase to the speed–density relation: close to the jam density $1/a = 3.76$ m⁻², a full node lets almost no one move, and a hard capacity limit lets nodes fill up to that density until the stream locks up.

The figure repeats the experiment with this model on a ten-storey building with one stair, comparing the two settings of supply_reduction. With a hard limit only, the evacuation time grows sharply above 3 m⁻². With supply reduction it stays almost constant. This shows only that supply reduction removes the effect in this building. The building is not the one Tsai used, so it says nothing about EvacuatioNZ’s numbers.

Evacuation time against max_density with and without supply reduction

Ten floors of 60 agents each (400 m² per floor, pre-movement U(30, 120) s) and one stair of 1.2 m with 0.9 m doors, all connected one way. The line is the median of 30 runs and the band covers 5–95 %. No run was incomplete.

Sensitivity to the hydraulic coefficients

HydraulicParameters lets a study change the SFPE coefficients (Networks). The figure changes one coefficient at a time in the one-stair building of the max_density sweep, with the default max_density. The stair is the bottleneck, so the evacuation time should follow its capacity: 600 agents pass its effective width of 0.9 m at the maximum specific flow $k_\text{stair}/(4a)$, after the earliest pre-movement time of 30 s. This bound is the dashed line.

Evacuation time against the stair coefficient, the slope a and the door specific flow

  • The stair coefficient sets $k_\text{stair}$, so the time falls as $1/k$: from 924 s at 40 m/min to 590 s at 65 m/min.
  • The slope $a$ scales the maximum flow as $1/a$, so the time grows in proportion to $a$: from 540 s at 0.19 to 726 s at 0.266. With the default door_specific_flow of 1.3, $a$ is at most 0.269 (Networks), so the sweep ends at the default. Below 0.182 the peak-flow density $1/(2a)$ exceeds the default max_density and supply reduction switches off, so the sweep starts at 0.19.
  • door_specific_flow changes nothing here: the ten doors together pass far more than the stair even at 0.7 persons/s/m. The median moves by 2 s between 0.7 and 1.3.

In every case the median lies 35 to 41 s above the bound: the start-up of the stream and the last agent’s walk down the stair. The line is the median of 30 runs and the band covers 5–95 %. No run of the sweep was incomplete. The sweep shows which coefficient this building responds to; it says nothing about which values are right. Changed coefficients are study assumptions, not validated ranges.

Reproducing the figures

The figures and animations on this site are produced by scripts/figures/make_figures.py and scripts/figures/make_gifs.py:

uv run --group docs python scripts/figures/make_figures.py OUTDIR
uv run --group docs python scripts/figures/make_gifs.py OUTDIR

Without OUTDIR they write to site/static/images/network/. The figures of the Terminal UI page are the snapshots of the terminal UI tests; scripts/figures/copy_tui_snapshots.py copies them, by default to site/static/images/tui/:

uv run --group docs python scripts/figures/copy_tui_snapshots.py OUTDIR
Last updated on