ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_FireWindExtract.H
Go to the documentation of this file.
1 #ifndef ERF_FIRE_WIND_EXTRACT_H
2 #define ERF_FIRE_WIND_EXTRACT_H
3 
4 #include <AMReX_MultiFab.H>
5 #include <AMReX_Geometry.H>
6 #include <cmath>
7 #include <ERF_FireGrid.H>
8 
9 /**
10  * @file ERF_FireWindExtract.H
11  * @brief Atmospheric wind sampled onto the fire grid
12  *
13  * The atmosphere side of the fire coupling: the wind of the atmospheric
14  * columns at a height above ground (a uniform height, or one per fire cell
15  * that the fire engine supplies), interpolated linearly in height and
16  * bilinearly or nearest between the surrounding columns, with an optional
17  * two-height log-law resampling; no MOST reconstruction is involved. A fire
18  * engine may read its wind through it. What the engine does with the wind
19  * afterwards (wind adjustment factors, terrain corrections) is the engine's.
20  */
21 
22 
23 /**
24  * @brief Extract wind from direct vertical interpolation on fire grid
25  *
26  * Maps atmospheric wind to fire grid at reference height by interpolating
27  * vertically through the atmospheric column at the fire cell location.
28  * Uses cell-center wind values (averaged from face-staggered data) and
29  * linearly interpolates to the target height above terrain.
30  *
31  * When z_ref_cell_mf is non-null, each fire cell is sampled at its own height
32  * from that field (for example a per-fuel wind height, as in the WRF-SFIRE
33  * fcwh convention) instead of the global z_ref.
34  *
35  * @param[out] fire_wind_ref u,v at z_ref on fire grid [m/s]
36  * @param[out] fire_wind_extract_z_mf Wind extraction height z_target [m]
37  * @param[in] xvel_mf x-velocity (face-staggered at i+1/2, j, k)
38  * @param[in] yvel_mf y-velocity (face-staggered at i, j+1/2, k)
39  * @param[in] z_phys_cc_mf Cell-center terrain height z_phys_cc[0] on atm grid
40  * @param[in] fg Fire grid
41  * @param[in] z_ref Global fallback wind reference height [m]
42  * @param[in] nz Number of vertical levels
43  * @param[in] z_ref_cell_mf Height above ground [m] to sample each fire cell
44  * at, on the fire grid; nullptr = the global z_ref
45  * @param[in] below_first_log Target below the lowest cell centre: false takes the
46  * lowest centre's wind as it is; true scales it
47  * with a neutral log profile of roughness z0_log,
48  * U(z) = U(z_1) ln(z/z0)/ln(z_1/z0)
49  *
50  * Algorithm per fire cell (i_f, j_f):
51  * 1. Map to atmospheric column: i_a = i_f / C, j_a = j_f / C
52  * 2. Get ground elevation: z_surf = fire_surface_z(i_f, j_f), the average of the
53  * four k = 0 nodes of atmospheric cell (i_a, j_a). Using z_phys_cc(i_a, j_a, 0)
54  * instead would sit half an atmospheric cell above the ground.
55  * 3. Lookup wind height:
56  * - If z_ref_cell_mf != nullptr: z_ref_cell = z_ref_cell_mf(i_f, j_f)
57  * - Otherwise: z_ref_cell = z_ref (global)
58  * 4. Compute target height: z_target = z_surf + z_ref_cell
59  * 5. Bisection on the column's z_phys_cc profile for k_lo such that
60  * z_phys_cc(i_a, j_a, k_lo) <= z_target < z_phys_cc(i_a, j_a, k_lo+1),
61  * clamped to [0, nz-2]; a target above the top takes the highest centre,
62  * a target below the first centre the lowest centre's wind scaled by the
63  * log profile (below_first_log) or as it is
64  * 6. Compute interpolation weight:
65  * alpha = (z_target - z_phys_cc(i_a, j_a, k_lo)) /
66  * (z_phys_cc(i_a, j_a, k_lo+1) - z_phys_cc(i_a, j_a, k_lo))
67  * Clamp alpha to [0, 1]
68  * 7. Average u/v from bracketing face values to get cell centers:
69  * u_cc(i,j,k) = 0.5 * (xvel(i,j,k) + xvel(i+1,j,k))
70  * v_cc(i,j,k) = 0.5 * (yvel(i,j,k) + yvel(i,j+1,k))
71  * 8. Interpolate: fw(i_f,j_f,0,0) = u_cc(k_lo) + alpha*(u_cc(k_lo+1) - u_cc(k_lo))
72  * fw(i_f,j_f,0,1) = v_cc(k_lo) + alpha*(v_cc(k_lo+1) - v_cc(k_lo))
73  * 9. Store z_target in fire_wind_extract_z_mf
74  *
75  * With wind_interp = 1 (bilinear, the default) steps 3-8 run for each of the
76  * four atmospheric columns surrounding the fire cell, every one sampled at the
77  * reference height above *its own* ground, and the results are blended with
78  * bilinear weights. With wind_interp = 0 only the column containing the cell is
79  * used, which makes the fire-grid wind piecewise constant on atmospheric cells.
80  *
81  * With col_open and col_roof given (2D atmospheric-column fields, one ghost
82  * cell) each bilinear weight is multiplied by the column's open fraction when
83  * its roof is above the cell's wind height, and the four weights are
84  * renormalised, so a column inside a building does not contribute its
85  * relaxed in-building velocity to the fire cells around it. A cell whose four
86  * columns are all closed keeps the plain weights; it is inside a footprint
87  * and masked anyway.
88  *
89  * With z_sample > 0 (an engine input) every column is sampled at
90  * z_sample above its ground instead of at the target height, and the result
91  * is brought down to the target height with a neutral log profile of
92  * roughness z0_log: U(z_ref) = U(z_sample) ln(z_ref / z0) / ln(z_sample / z0).
93  * This is the second interpolation option of the Community Fire Behavior
94  * Model (Jimenez y Munoz et al. 2026), meant to drive the fire with a wind
95  * taken above its own plume. fire_wind_extract_z then records the sampled
96  * height; the open-column test uses that height as well.
97  */
99  amrex::MultiFab& fire_wind_ref,
100  amrex::MultiFab& fire_wind_extract_z_mf,
101  const amrex::MultiFab& xvel_mf,
102  const amrex::MultiFab& yvel_mf,
103  const amrex::MultiFab& z_phys_cc_mf,
104  const amrex::MultiFab& fire_surface_z_mf,
105  const amrex::MultiFab& fire_col_ground_mf,
106  const FireGrid& fg,
107  amrex::Real z_ref,
108  int nz,
109  const amrex::MultiFab* z_ref_cell_mf = nullptr,
110  int wind_interp = 1,
111  const amrex::MultiFab* col_open = nullptr,
112  const amrex::MultiFab* col_roof = nullptr,
113  amrex::Real z_sample = 0.0,
114  amrex::Real z0_log = 0.1,
115  bool below_first_log = false);
116 
117 /**
118  * @brief The wind at the lowest cell centre of each atmospheric column, and
119  * its height above that column's ground
120  *
121  * For an engine that drives its fire with the k = 0 wind of the atmospheric
122  * columns rather than a wind interpolated to a height (LSFIRE does). The face
123  * velocities are averaged to the k = 0 cell centre; the height is that centre
124  * minus the column's ground, the mean of its four k = 0 nodes (the ground
125  * compute_fire_surface_height uses), or minus the domain floor without nodal
126  * heights.
127  *
128  * @param[out] u_k0, v_k0 Wind [m/s] on the k = 0 slabs of the level (one per box of
129  * the level, the BoxArray of FireForcing::T_k0), with any
130  * ghost cells: those are filled with FillBoundary
131  * @param[out] h_k0 Height of that wind above the column's ground [m], laid out as u_k0
132  * @param[in] xvel, yvel Face velocities of the level (FireForcing::xvel, yvel)
133  * @param[in] z_phys_cc Cell-centre height of the level [m]
134  * @param[in] z_phys_nd Nodal height of the level [m], or nullptr (flat floor)
135  * @param[in] geom Geometry of the level
136  */
138  amrex::MultiFab& u_k0,
139  amrex::MultiFab& v_k0,
140  amrex::MultiFab& h_k0,
141  const amrex::MultiFab& xvel,
142  const amrex::MultiFab& yvel,
143  const amrex::MultiFab& z_phys_cc,
144  const amrex::MultiFab* z_phys_nd,
145  const amrex::Geometry& geom);
146 
147 #endif
Fire grid data structure and construction.
void fill_fire_wind_from_interpolation(amrex::MultiFab &fire_wind_ref, amrex::MultiFab &fire_wind_extract_z_mf, const amrex::MultiFab &xvel_mf, const amrex::MultiFab &yvel_mf, const amrex::MultiFab &z_phys_cc_mf, const amrex::MultiFab &fire_surface_z_mf, const amrex::MultiFab &fire_col_ground_mf, const FireGrid &fg, amrex::Real z_ref, int nz, const amrex::MultiFab *z_ref_cell_mf=nullptr, int wind_interp=1, const amrex::MultiFab *col_open=nullptr, const amrex::MultiFab *col_roof=nullptr, amrex::Real z_sample=0.0, amrex::Real z0_log=0.1, bool below_first_log=false)
Extract wind from direct vertical interpolation on fire grid.
void extract_fire_wind_k0(amrex::MultiFab &u_k0, amrex::MultiFab &v_k0, amrex::MultiFab &h_k0, const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &z_phys_cc, const amrex::MultiFab *z_phys_nd, const amrex::Geometry &geom)
The wind at the lowest cell centre of each atmospheric column, and its height above that column's gro...
Definition: ERF_FireWindExtract.cpp:259
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ fg
Definition: ERF_AdvanceMorrison.cpp:111
@ xvel
Definition: ERF_IndexDefines.H:255
@ yvel
Definition: ERF_IndexDefines.H:256
2D horizontal fire computational grid
Definition: ERF_FireGrid.H:29