Fire Verification Cases
Exec/CanonicalTests/Fire/Verification collects fire cases whose answer is
known independently of the code: an exact solution of the equations the fire
module solves, or a published result. Each case directory holds its decks, the
script that writes any rasters or ignition files (their output is committed), a
run_<case>.sh that runs the decks and then the check, and a
check_<case>.py that compares the output with the reference and exits
non-zero on a failure. Every README records the agreement measured with the
committed decks; the numbers below are from those runs.
MPIRUN="mpirun -np 2" ./run_<case>.sh /path/to/erf_exec # runs, then checks
SKIP_RUN=1 ./run_<case>.sh x # checks only
Two options exist for these cases, both off by default.
erf.fire.ros_model = "prescribed" sets the rate of spread in the deck,
with \(R_b\) given by erf.fire.prescribed.ros or per fuel code by
erf.fire.prescribed.by_fuel. It has no wind, slope or moisture dependence
and no direction, so directional_ros is turned off and the level set solves
the eikonal equation \(|\nabla T| = 1/R\) as posed: the arrival time is the
shortest travel time from the ignition. erf.fire.prescribed_heat.flux adds a
constant heat flux over a disc to the fire heat flux, which the coupling then
injects like fire heat. Exec/RegTests/FirePrescribed checks both.
The geometry cases run on still air under slip walls with 2 m fire cells, so arrival errors are quoted in cell-crossing times \(h/R\).
The level set against geometry
Case |
Exact answer |
Measured |
|---|---|---|
|
arrival \((L - r_{ig})/R\) with \(L\) the taut string around a non-burnable disc |
lit region: mean \(|e|\) 0.07, 95th percentile 0.16; shadow: +0.44
against a disc half a cell larger than the nominal one, which the
cell-resolved mask makes it (+0.52 with |
|
arrival (distance to the V \(-\,w)/R\); meeting point at \(R/\sin(\theta/2)\) |
mean \(|e|\) 0.16 to 0.31 over the grid; meeting-point speed within 0.85 %, 0.02 % and 0.15 % at 30, 60 and 90 degrees |
|
area \(A_0 + P_0 r + \pi r^2\) (square) and \(A_0 + P_0 r + (2\pi - 4) r^2\) (cross), arrival = distance / R |
area within 0.21 (square) and 0.28 (cross) cell widths times the perimeter at 60 s; arrival mean \(|e|\) 0.14; the cross’s inner corners stay sharp |
|
union of two discs of radius \(r_{ig} + R t\) |
area 0.23 to 0.33 cell widths of perimeter short; arrival mean \(|e|\) 0.17, the same across the neck |
|
Snell’s law \(\sin\theta_2 / R_2 = \sin\theta_1 / R_1\) and the transmitted plane front |
transmitted angle 19.00 against 18.75 degrees (fast to slow) and 57.75 against 57.70 (slow to fast); \(|\nabla T|\) within 0.7 % of \(1/R_2\); arrival mean \(|e|\) 0.10 to 0.15 |
|
\(T = \operatorname{acosh}\left(1 + |g|^2 |p - s|^2 / (2 R(s) R(p))\right)/|g|\) |
arrival mean \(|e|\) 0.08, 95th percentile 0.17; the front’s extent along the gradient within 0.01 cells |
The level set lags the exact fronts by a fraction of a cell: its artificial viscosity slows a curved front by \(R\,\varepsilon\,\kappa\), about \(\varepsilon \ln(r_1/r_0)\) as a circle grows from \(r_0\) to \(r_1\), and thin ignitions are stamped to within a fraction of a cell. The checks allow half a cell-crossing time on average and one cell at the 95th percentile.
Rothermel on a slope
Slope_No_Wind burns Anderson fuel model 1 at 5.5 % on the planes
\(z = 0.3\,x\) and \(z = 0.6\,x\) in still air. On the isotropic path
(directional_ros = false) every direction spreads at
\(R_0 (1 + \phi_s)\), reduced by \(\sqrt{1 + s_n^2}\) for the slope
\(s_n\) along it by the ground projection; the four axis rates agree to
0.24 %. On the default directional path the backing fire and the flanks spread
at \(R_0\), their fronts within 0.05 cell of the exact ones.
Each deck is compared with the exact (viscosity) solution of its own level-set equation, evaluated with the Hopf formula \(T(\mathbf x) = \max_{\mathbf n} ((\mathbf x - \mathbf c)\cdot\mathbf n - r_0)/F(\mathbf n)\) for the map-view normal speed \(F\). Rates are checked to 3 % where the fit spans 20 cells or more, and fronts that travel fewer cells to half a cell on average and one at worst.
The directional head does not reach \(R_0 (1 + \phi_s)\). The directional path evaluates \(R(\mathbf n) = R_0 (1 + 5.275\,\beta^{-0.3} \max(\mathbf s \cdot \mathbf n, 0)^2)\), and for a rate that peaks this sharply about one direction the exact solution of \(\phi_t + R(\mathbf n) |\nabla\phi| = 0\) from a point ignition is the Wulff shape. Its head is a wedge of oblique facets whose tip runs at
0.183 m/s instead of 0.326 m/s at \(s = 0.6\). A straight line fire keeps \(\mathbf n = \hat{\mathbf x}\) and is not affected, which is why the line fire of Line Fire Verification meets Rothermel’s head rate. The scheme lands between the two, 0.257 m/s (52 % of the way from the Wulff tip speed to Rothermel’s head rate) at \(s = 0.6\) and 0.102 m/s (61 %) at \(s = 0.3\), and the check requires only that. The same argument applies to the wind factor wherever \(\phi_w (B - 1) > 1\).
The opt-in erf.fire.directional_shape = "ellipse" removes the shortfall. It
takes the normal speed from the support function of the ellipse with the same
head, back and flank rates, and an ellipse is its own Wulff shape. Its decks
ell_s30 and ell_s60 spread the head at 0.1077 and 0.3250 m/s, within
0.6 % of Rothermel’s head rate. Their backs and flanks stay within 0.26 cell of
the exact fronts, although the pointed back reads 4 to 5 % fast as a fitted rate
over the 7 to 9 cells it travels. Exec/RegTests/FireDirectionalShape measures
the same in a uniform 1.5 m/s wind on the same grass (\(\phi_w = 9.4\)). There
the default head runs at 0.185 m/s and the ellipse’s at 0.248 m/s, against
Rothermel’s 0.249 m/s and a Wulff tip of 0.142 m/s.
Fuel moisture
Moisture_Relaxation dries fuel model 1 from 20 % in still, dry air at 300 K
for two hours with moisture_dynamic = true. Each dead class relaxes as
\(\mathrm dM/\mathrm dt = (M_e - M)/\tau_{\mathrm{eff}}\), and Rothermel,
rebuilt from the moisture every step, holds the ignition still until the 1-hour
class falls below the 12 % moisture of extinction. Every class matches the
model’s forward-Euler steps to \(10^{-16}\) and the closed form to
\(5 \times 10^{-5}\); the rate of spread matches Rothermel at the 1-hour
moisture to six digits once it crosses extinction at 2754 s; the burned radius
follows the integral of that rate to 0.09 cells, reaching 76.2 m at two hours.
With the adsorption and desorption equilibria \(E_w = 0.0351\) and
\(E_d = 0.0600\) of this air, the hysteresis in
compute_emc_with_hysteresis sends fuel wetter than \(E_d\) towards it,
fuel drier than \(E_w\) towards that, and leaves fuel between the two alone
(Nelson 2000; Vejmelka et al. 2016), so drying fuel follows
\(M = E_d + (M_0 - E_d) e^{-t/\tau}\): 0.1062 after one hour and 0.0753
after two. The check was written against the reversed choice ERF carried until
September 2026, which sent drying fuel towards \(E_w\) and held it at
\(E_d\), \(\max(E_w + (M_0 - E_w) e^{-t/\tau}, E_d)\) = 0.0895 after one
hour; it still prints that value, and a binary from before the fix fails 44 of
its 48 checks.
References
Nelson, R. M. (2000). Prediction of diurnal change in 10-h fuel stick moisture content. Canadian Journal of Forest Research, 30, 1071-1087.
Rothermel, R. C. (1972). A mathematical model for predicting fire spread in wildland fuels. USDA Forest Service Research Paper INT-115.
Vejmelka, M., A. K. Kochanski and J. Mandel (2016). Data assimilation of dead fuel moisture observations from remote automated weather stations. International Journal of Wildland Fire, 25, 558-568.
Viegas, D. X., J. R. Raposo, D. A. Davim and C. G. Rossa (2012). Study of the jump fire produced by the interaction of two oblique fire fronts. Part 1. Analytical model and validation with no-slope laboratory experiments. International Journal of Wildland Fire, 21, 843-856.