Speed in practice
Note
This page shows the smoke-speed model at work: its API and runs on the assets. For its definition, parameters and defaults, see Models › Smoke-speed model.
Part of pyFDS-Evac.
The pyFDS-Evac smoke-speed model reduces agent walking speed based on
local smoke conditions. It takes the extinction coefficient K [1/m] as
its primary input and applies one of two speed-reduction laws, selected
via SmokeSpeedConfig.speed_law.
Speed-reduction laws
The agent walks at v0 * speed_factor(K), where v0 is its clear-air speed
and the factor follows speed_law="lund" (default) or "fridolf". The
fridolf law (Fridolf et al. 2019, Eq. 7) reduces speed additively, so its factor
also depends on v0. The coded
equations, the SmokeSpeedConfig defaults and the departures from the
literature are on the smoke-speed model page;
the published laws are on
Walking speed in smoke.
Extinction sources
The model accepts any object that implements the ExtinctionSampler
protocol (a sample_extinction(time_s, x, y) -> float method). Two
built-in implementations are available:
ExtinctionField– reads theSOOT EXTINCTION COEFFICIENTquantity from FDS slice data viafdsreader. Use this for real FDS output.ConstantExtinctionField– returns a fixed K value everywhere. Use this for deterministic verification cases such as ISO 20414 Table 21.
Loading from FDS data
To load extinction data from an FDS case directory:
from pyfds_evac.core.smoke_speed import ExtinctionField
field = ExtinctionField.from_fds(
"path/to/fds_case",
slice_height_m=1.6, # default 1.6 m, FDS+Evac HUMAN_SMOKE_HEIGHT
)If a queried point falls outside the FDS domain, sample_extinction
returns 0.0 (clear air) and logs a warning on the first occurrence.
Using a constant field
To use a uniform extinction value for verification:
from pyfds_evac.core.smoke_speed import ConstantExtinctionField
field = ConstantExtinctionField(extinction_per_m=1.0)Configuration
SmokeSpeedConfig bundles the model coefficients with runtime
settings:
from pyfds_evac.core.smoke_speed import SmokeSpeedConfig
config = SmokeSpeedConfig(
fds_dir="path/to/fds_case",
update_interval_s=1.0, # how often agents resample extinction
slice_height_m=1.6, # default 1.6 m, FDS+Evac HUMAN_SMOKE_HEIGHT
speed_law="lund", # or "fridolf"
)The law coefficients (alpha, beta, min_speed_factor,
visibility_factor_c) are further fields; their defaults are listed on the
smoke-speed model page.
The update_interval_s field controls how frequently each agent
queries the extinction field during the simulation loop. A value of
1.0 means one sample per agent per second of simulated time.
Putting it together
To create a full smoke-speed model and query it:
from pyfds_evac.core.smoke_speed import (
ExtinctionField,
SmokeSpeedConfig,
SmokeSpeedModel,
)
field = ExtinctionField.from_fds(config.fds_dir)
model = SmokeSpeedModel(field, config)
# Query at a specific point and time
extinction_K, speed_factor = model.sample(time_s=30.0, x=5.0, y=3.0)
# Or get just the factor
factor = model.speed_factor(time_s=30.0, x=5.0, y=3.0)Runs on the assets
Run the ISO 20414 Test 18 (Table 21) corridor with a constant extinction coefficient:
uv run run.py \
--scenario assets/ISO-table21 \
--constant-extinction 1.0 \
--smoke-update-interval 0.1 \
--output-smoke-history /tmp/iso-table21-smoke-history.csv \
--cleanupRun the smoke-speed model against FDS results read through fdsreader. The
repository ships the deck, not its output — the slices are 4.2 MB and the full
run 54 MB — so run FDS once first:
mkdir -p /tmp/iso21 && cd /tmp/iso21 \
&& fds /path/to/assets/ISO-table21/ISO-table21.fds && cd - # ~8 min
uv run run.py \
--scenario assets/ISO-table21 \
--fds-dir /tmp/iso21 \
--smoke-update-interval 0.1 \
--output-smoke-history /tmp/iso-table21-fds-smoke-history.csv \
--cleanupInspect the FDS quantities available through fdsreader:
uv run run.py --inspect-fds --fds-dir /tmp/iso21 --scenario assets/ISO-table21For a case where the coupling is exercised without running FDS yourself, see
assets/iso_table22_coupled: its output
is committed (136 kB) and a test reads it on every CI run.
Plot smoke-speed history for a single agent:
uv run python scripts/plot_smoke_history.py \
--input /tmp/iso-table21-smoke-history.csv \
--output /tmp/iso-table21-smoke-history.png \
--agent-id 1Plot aggregate smoke-speed history:
uv run python scripts/plot_smoke_history.py \
--input /tmp/iso-table21-smoke-history.csv \
--output /tmp/iso-table21-smoke-history-aggregate.pngGenerate a stable ISO 20414 Test 18 (Table 21) sweep artifact under artifacts/:
uv run python scripts/generate_iso_table21_sweep.pyFigure: 
Generate the FDS+Evac smoke-density vs speed verification plot:
uv run python scripts/generate_smoke_density_speed_plot.pyFigure: 
Conversion utilities
Two helper functions support the soot-density-based workflow from the original FDS+Evac guide:
extinction_from_soot_density(soot_density_mg_per_m3)– converts soot density to extinction usingK = K_m * rho_s * 1e-6, whereK_m(mass_extinction_coefficient_m2_per_kg, default 8700 m²/kg) is the FDS default mass-specific extinction coefficient (see Extinction coefficient).speed_from_soot_density(base_speed, soot_density_mg_per_m3)– computes the reduced walking speed directly from soot density.
References
- Smoke-speed model: coded form, defaults and deviations from the literature.
- ISO 20414 Test 18 and the S2 corridor test
(
tests/verification/test_s2_corridor_speed.py): how the speed reduction is verified. - Walking speed in smoke and Extinction coefficient: the published laws and their sources.
- evac.f90 – Original FDS+Evac Fortran source (FDS commit c9da70d7a) for cross-referencing implementation details.