Regression Tests

The regtest/ directory contains a comprehensive suite of regression tests that exercise individual features and capabilities of the wildfire level-set solver. Each test is self-contained — it ships with an inputs.i configuration file and any required data files.

Running the Tests

Run a single test from the repository root:

cd regtest/basic_levelset
../../build/levelset inputs.i

Run all regression tests with CTest (after building):

cd build
ctest -L regtest --output-on-failure

# Or use the custom target
make regtest

# Run a specific test by name
ctest -R rothermel_fuel --output-on-failure

Build requirements vary by test; see the per-test sections below.

Test Descriptions

basic_levelset

Purpose: Verifies fundamental level-set advection with a constant velocity field.

The spherical initial condition is advected without distortion for 100 steps on a 64³ grid. Successful completion confirms that:

  • The WENO5-Z + RK3 advection kernel compiles and runs.

  • Reinitialization keeps \(|\nabla\phi| \approx 1\).

  • Plotfile output is written correctly.

Build: Default 3D build.

farsite_ellipse

Purpose: Verifies the FARSITE elliptical expansion model (Richards 1990).

A box (line) ignition expands under a constant wind field using fixed Richards coefficients (\(a = 1.0\), \(b = 0.4\), \(c = 0.2\)) and a fixed length-to-width ratio of 3.0. Confirms that the fire perimeter forms an ellipse with the expected elongation.

Build: Default 3D build.

rothermel_fuel

Purpose: Tests fire spread with NFFL fuel model FM1 (Short Grass).

The Rothermel (1972) model is evaluated with a standard fuel database entry, 6 % fuel moisture, and a moderate constant wind. Confirms that the Rothermel ROS field is computed for every cell and that different fuel models produce different spread rates.

Build: Default 3D build. Change rothermel.fuel_model to test FM1–FM13 or any Scott & Burgan 40 code.

cheney_gould_grassfire

Purpose: Tests the Cheney & Gould (1995/1998) empirical grassland fire spread model.

A spherical ignition on a flat 1 km × 1 km domain is propagated at 10 m/s wind (36 km/h) with 8 % dead fuel moisture and full curing (\(CF = 1\)). The expected head-fire ROS is ≈ 2.69 m/s from the piecewise formula:

\[R = (-0.020 + 0.640 \times 36) \times \exp(-0.108 \times 8) \times 1.0 \approx 2.69 \ \text{m/s}\]

Confirms that the Cheney–Gould model produces an asymmetric elliptical perimeter.

Build: Default 3D build.

terrain_wind

Purpose: Tests external terrain (Gaussian hill) and a spatially-varying wind field (2D only).

A 1000 m × 1000 m domain contains a Gaussian hill with σ = 150 m and peak elevation 100 m. The wind CSV has a base speed of 5 m/s with up to 50 % speed-up over the crest. Confirms:

  • Terrain slopes are correctly computed from an XYZ elevation file.

  • IDW interpolation of wind from the CSV to the AMReX grid works.

  • The fire accelerates upslope and over the crest.

Build: 2D build (-DLEVELSET_DIM_2D=ON).

anderson_lw

Purpose: Tests dynamic L/W ratio calculation based on wind speed (Anderson 1983).

The Anderson formula is evaluated at ≈ 10 mph wind (expected L/W ≈ 2.5) and the resulting ellipse coefficients \(a\), \(b\), \(c\) are applied to the FARSITE propagation.

\[L/W = 0.936 \exp(0.2566 U) + 0.461 \exp(-0.1548 U) - 0.397\]

Build: Default 3D build.

reinitialization

Purpose: Tests aggressive level-set reinitialization to maintain the signed-distance property.

Reinitialization is run every 5 steps for 30 iterations. Confirms that \(|\nabla\phi|\) remains close to 1.0 after prolonged advection.

Build: Default 3D build.

ellipse_sdf

Purpose: Tests the elliptical SDF initial condition.

An ellipsoidal initial fire region (semi-axes \(r_x = 0.25\), \(r_y = 0.15\), \(r_z = 0.10\)) is advected at constant velocity. Confirms that the elliptical SDF is constructed correctly and that shape is preserved under advection.

Build: Default 3D build.

eb_implicit

Purpose: Tests embedded boundary (EB) implicit function initial conditions.

An EB-defined ellipsoid is used as the initial fire region. Confirms that the AMReX EB infrastructure can initialise \(\phi\) from implicit-function geometries (sphere, ellipsoid, cylinder, plane).

Build: EB build recommended (-DLEVELSET_ENABLE_EB=ON).

firebrand_spotting

Purpose: Tests the probability-based stochastic firebrand spotting model.

Firebrands are generated probabilistically from the fire front, with landing distances sampled from a log-normal distribution. Confirms that spot ignitions appear ahead of the fire perimeter and that diagnostic fields (spot_prob, spot_count, spot_dist, spot_active) are written to every plotfile.

Build: Default 3D build.

albini_spotting

Purpose: Tests the Albini (1983) physics-based firebrand spotting model.

The Albini model lofts firebrands using:

\[H_z \;[\text{m}] = 12.2 \; I_B^{1/3}\]

and then integrates a 2-D horizontal trajectory through the wind field. Confirms that the lofting height, landing distance, and diagnostic fields (albini_Hz, albini_count, albini_dist, albini_active) are computed and written correctly.

Build: CPU or GPU builds (GPU-safe: trajectory runs on the host; device data is synchronized and copied to host-pinned memory before computation, then written back to device).

albini_spotting_3d_wind

Purpose: Tests the Albini spotting model driven by 3-D wind data from a massconsistent_amr plotfile.

A synthetic AMReX plotfile is generated by generate_plt_wind.py (an 8×8×4 grid with uniform u = 5 m/s, v = 0.5 m/s wind). The reader in src/plt_wind_reader.H loads the plotfile as flat 1-D GPU arrays of (x, y, z, u, v, w), computes a height-averaged 2-D wind, and bilinearly interpolates onto the fire-model grid for trajectory integration.

Requires Python 3 to generate the synthetic plt file (handled automatically by CTest as a fixture setup step).

Build: CPU or GPU builds (GPU-safe).

ember_cascade_flux

Purpose: Tests the flux-based ember cascade model (ember_cascade_flux.H) driven by a synthetic 3-D wind plotfile.

Physical scenario: a chaparral ignition (FM4, 7 % moisture) on a 600 m × 600 m domain burns under a 6 m/s westerly wind. generate_plt_wind.py creates a synthetic plt wind directory (8×8×4 grid, u = 6 m/s, v = 1 m/s) that the model reads via plt_wind_reader.H.

The test confirms that:

  • The Albini (1983) plume height is computed per fire-front cell.

  • The Gaussian landing-flux field is non-zero downwind of the fire.

  • The plotfile variables ember_cascade_flux and ember_cascade_ignition are written to every output step.

  • The model produces spot-fire ignitions (ember_cascade_ignition > 0) after the fire front reaches sufficient intensity.

Requires Python 3 for the setup step (same pattern as albini_spotting_3d_wind).

Build: CPU or GPU builds (GPU-safe).

crown_initiation

Purpose: Tests Van Wagner (1977) crown fire initiation.

The model checks whether the Byram fireline intensity exceeds the critical threshold:

\[I_o \;[\text{kW/m}] = 0.010 \; H_{\text{CBH}} \, (460 + 25.9 \, F_{\text{MC}})\]

Cells where crown fire initiates are classified as passive (1) or active (2) depending on whether the ROS exceeds the critical active-crown threshold. Confirms that crown_fraction and crown_activity fields are written to plotfiles.

Build: Default 3D build.

bulk_fuel_consumption

Purpose: Tests post-frontal bulk fuel consumption modelling.

The exponential consumption model:

\[f_c = f_{c,\min} + (f_{c,\max} - f_{c,\min})\left(1 - \exp\!\left(-\frac{t}{\tau_{\text{res}}}\right)\right)\]

is applied to cells inside the fire perimeter. Confirms that the fuel_consumption field increases monotonically with time behind the fire front.

Build: Default 3D build.

3d_sphere

Purpose: Tests full 3D fire spread simulation.

A sphere initial condition is propagated using the Rothermel model in a 48³ cell 3D domain with a 3D wind vector and an upslope terrain. Confirms that the 3D FARSITE elliptical expansion and terrain effects work in three dimensions.

Build: Default 3D build. Visualise results with ParaView or VisIt.

terrain_wind_preprocess

Purpose: Integration test for the wrf_wind_reader.py preprocessing tool.

Generates a terrain XYZ file and a wind CSV using the Python tool, then runs the solver with those files. Confirms that the WRF wind extraction and IDW interpolation pipeline produces valid inputs for the C++ solver.

Build: 2D build. Requires Python 3 with netCDF4, numpy, pyproj.

time_dependent_wind

Purpose: Tests time-varying wind fields (2D only).

Sequential wind CSV snapshots are loaded and linearly interpolated at each time step. Confirms that use_time_dependent_wind = 1 correctly advances through the wind time series.

Build: 2D build (-DLEVELSET_DIM_2D=ON).

balbi_viegas_heatflux

Purpose: Tests the Balbi (2009) model together with Viegas eruptive-fire diagnostics and the heat-flux-driven wind correction.

Confirms that fire_spread_model = balbi, viegas.enable = 1, and heat_flux.enable_upward = 1 all interoperate correctly.

Build: Default 3D build.

windninja_ridge_canyon

Purpose: Tests the WindNinja ridge/canyon empirical speed-up (Option 7).

A Gaussian hill terrain is combined with wind_terrain.model = windninja_ridge_canyon. Confirms that wind is accelerated on the upslope face and channelled in canyon geometry.

Build: 2D build.

terrain_gradient_correction

Purpose: Verifies that the level-set gradient \(|\nabla\phi|\) is computed on the terrain surface when a terrain file is present.

When terrain slopes are non-zero, godunov_norm_grad_phi replaces the flat grid spacings with terrain arc-length spacings:

\[\Delta x_\text{eff} = \Delta x\,\sqrt{1 + s_x^2}, \qquad \Delta y_\text{eff} = \Delta y\,\sqrt{1 + s_y^2}\]

where \(s_x = \partial z/\partial x\) and \(s_y = \partial z/\partial y\).

The test uses a steep Gaussian hill (\(H = 200\) m, \(\sigma = 100\) m) where the slope magnitude at the inflection ring reaches \(\approx 1.21\) (50°), giving an effective spacing factor of \(\sqrt{1 + 1.21^2} \approx 1.57\). A level-set run (propagation_method = levelset) exercises the corrected WENO3 Godunov gradient across the full hill profile. Confirms that the solver completes 100 steps without NaN/Inf and writes 4 plotfiles.

Build: 2D build (-DLEVELSET_DIM_2D=ON).

landfire_farsite

Purpose: Integration test for FARSITE with a real (or synthetic) LANDFIRE landscape.

The setup script regtest/landfire_farsite/create_landscape.py attempts to download LANDFIRE data; if offline, a synthetic Southern California chaparral landscape is generated as a fallback. FARSITE elliptical spread with Anderson dynamic L/W ratio is then run on the landscape.

Build: Default 3D build. Requires Python 3 with pip install requests rasterio numpy pyproj elevation.

gaussian_hill_wind_solver (Deprecated)

Deprecated since version The: mass-consistent wind solver has been moved to src/deprecated/ and is no longer built. This regression test is retained for historical reference only.

Purpose: Validated the terrain-following mass-consistent wind solver (wind_solver executable) over a Gaussian hill terrain.

A 10 × 10 × 10 cell Cartesian grid (dx = dy = dz = 30 m) covers a 300 m × 300 m × 300 m domain. The terrain is a Gaussian hill with peak elevation 50 m centred at (150, 150) m (σ = 60 m). A 10 m/s westerly reference wind at z_ref = 10 m with roughness length z₀ = 0.1 m is applied.

Successful completion confirmed that:

  • The log-law profile initialisation runs without error.

  • The AMReX MLMG (MLABecLaplacian) solver converges to the requested tolerance.

  • The maximum divergence after correction is substantially smaller than before.

  • An AMReX plotfile plt_wind_gaussian is written.

Build: This test is no longer active (wind solver deprecated).

Build Configurations Summary

Compatible tests

Build

CMake flags

All except 3d_sphere, terrain_wind, time_dependent_wind

3D (default)

cmake -S . -B build

terrain_wind, terrain_wind_preprocess, time_dependent_wind, windninja_ridge_canyon

2D

-DLEVELSET_DIM_2D=ON

eb_implicit

3D + EB

-DLEVELSET_ENABLE_EB=ON

albini_spotting, albini_spotting_3d_wind

CPU or GPU

GPU-safe: synchronizes device, runs host-side trajectory

Adding a New Regression Test

  1. Create regtest/<test_name>/ directory.

  2. Add inputs.i with the test parameters.

  3. Add a README.md documenting expected behavior.

  4. Register in CMakeLists.txt so CTest discovers it.

  5. Add a description to the main regtest/README.md and to this page.

New Feature Regression Tests

The following tests were added with the 2025 feature update. All use UTM Zone 11N, Southern California coordinates (reference: 330000 E, 3775000 N — Malibu / Santa Monica Mountains area).

fmc_seasonal (crown_fire/)

Purpose: Tests the FMC seasonal phenological schedule.

The foliar moisture content (FMC) used by the Van Wagner (1977) crown fire initiation model is updated each timestep from a built-in parametric curve representing Southern California chaparral phenology (green-up in spring, peak in summer, curing in autumn).

Key parameters:

fmc_schedule.enable            = 1
fmc_schedule.use_farsite_curve = 1
fmc_schedule.start_doy         = 200   # mid-July (summer peak)

Confirms that crown.FMC changes each timestep and that crown fire behaviour responds to the seasonal FMC change.

precip_wetting (moisture/)

Purpose: Tests precipitation-driven dead fuel moisture wetting.

Dead fuel moisture evolves under a constant light rain rate (2 mm/hr). The exponential wetting model drives 1-hr fuel moisture towards saturation (120%) with a 1-hr time constant, and 10-hr fuel with a 2-hr time constant.

Key parameters:

diurnal_moisture.enable              = 1
diurnal_moisture.precip_rain_rate_mm_hr = 2.0
diurnal_moisture.M_sat               = 1.20

Confirms that rothermel.M_d1 increases over time and fire spread rate decreases as fuel becomes wetter.

polygon_ignition (ignition/)

Purpose: Tests closed-polygon fire ignition rasterisation.

An irregular 8-vertex polygon (~20 m × 18 m) is rasterised into the level-set field using the winding-number algorithm. The interior is set to phi < 0 (burned) and the exterior to the Euclidean signed distance.

Key parameters:

source_type        = polygon
fire_polygon_file  = ignition_polygon.csv

Confirms that the rasterised initial perimeter closely follows the input polygon vertices and that the signed-distance function is correct inside and outside.

polyline_ignition (ignition/)

Purpose: Tests polyline (line fire) ignition rasterisation.

A 6-vertex east-west polyline is rasterised with a 6 m half-width, creating an initial line-fire ignition zone. Wind drives the fire northward from the ignition line.

Key parameters:

source_type       = polyline
fire_polygon_file = ignition_line.csv
polyline_width    = 6.0

wind_dir_schedule (wind/)

Purpose: Tests the compact wind direction / speed schedule.

Wind starts at 270° (westerly) at 3 m/s and backs to 180° (southerly) at 5 m/s over 2 hours. The schedule is read from a three-column CSV (time_s, speed_ms, dir_deg).

Key parameters:

wind_dir_schedule_file = wind_schedule.csv

Confirms that the wind vector changes direction and magnitude at each timestep, and that the fire footprint reflects the wind rotation.

waf_andrews (wind/)

Purpose: Tests the Andrews (2018) logarithmic Wind Adjustment Factor (WAF) together with the Maximum Effective Wind Speed (MEWS) cap.

The WAF converts the 20-ft reference wind to midflame height using Albini & Baughman (1979):

\[\text{WAF} = \frac{1.83}{\ln\!\left(\dfrac{20 + 0.36\,h}{0.13\,h}\right)}\]

For FM4 chaparral (\(h = 6\) ft): WAF ≈ 0.36; the 5 m/s ambient wind is reduced to ≈ 1.8 m/s at midflame height.

Key parameters:

rothermel.use_waf        = 1
rothermel.waf_formula    = andrews
rothermel.use_wind_limit = 1

Confirms that the solver runs with waf_formula = "andrews" and that fire spread is slower than without WAF, consistent with midflame wind sheltering.

Build: 2D build (-DLEVELSET_DIM_2D=ON).

waf_behaviorplus (wind/)

Purpose: Tests the BehavePlus linear Wind Adjustment Factor for open and shrub fuel models.

The BehavePlus linear formula:

\[\text{WAF} = 0.36 + 0.004\,h_\text{in} \quad [h_\text{in} = 12 h_\text{ft}]\]

gives WAF = 0.648 for FM4 (\(h = 72\) in). Compare with the Andrews logarithmic formula (WAF ≈ 0.36 for the same fuel): the BehavePlus formula produces higher midflame wind and therefore faster ROS for deep fuel beds.

Key parameters:

rothermel.use_waf          = 1
rothermel.waf_formula      = behaviorplus
rothermel.waf_canopy_alpha = 1.5
rothermel.use_wind_limit   = 1

Confirms that the solver runs with waf_formula = "behaviorplus", that the WAF value is computed from the linear formula, and that the fire spread rate is higher than the waf_andrews test for the same ambient wind.

Build: 2D build (-DLEVELSET_DIM_2D=ON).

scott_reinhardt_indices (diagnostics/)

Purpose: Tests the Scott & Reinhardt (2001) TI/CI diagnostic outputs.

A strong 8 m/s wind and low canopy base height (2.5 m) create active crown fire conditions. The plotfile torching_ratio and crowning_ratio fields (ecology components 4 and 5) should be ≥ 1.0 in the active fire zone.

\[\text{torching\_ratio} = I_B / I_o \qquad \text{crowning\_ratio} = R / R^\prime_{SA}\]

These dimensionless ratios are zero for surface fire, cross 1.0 when torching begins, and exceed 1.0 again for active crown fire, giving an easily interpreted diagnostic layer without inverting the Rothermel wind function.

Sub-folder Organisation

Starting from the 2025 release all regression tests reside in named sub-folders grouped by physical category:

All tests use UTM Zone 11N, Southern California reference coordinates (330 000 E, 3 775 000 N).