Start-up checks of the atmosphere side of the fire coupling.
Verifies that ERF is configured so that a fire grid can be coupled to it, whichever fire engine runs on that grid:
- MOST surface layer is active with proper boundary conditions
- The level the fire grid refines exists and keeps its boxes
- No z-direction MPI decomposition (all z-levels on same rank)
- The level's boxes cover one rectangle
- Grid divisibility by refinement factor
Each engine checks its own inputs after these (FireEngine::verify_prerequisites).
All checks use AMREX_ALWAYS_ASSERT_WITH_MESSAGE for actionable diagnostics.
| int fire_anchor_level |
( |
int |
anchor_level, |
|
|
int |
finest_level |
|
) |
| |
The AMR level the fire grid refines: erf.fire.anchor_level, or the finest level when it is -1 (the default).
Aborts, naming the input, when the level is above the finest level.
- Parameters
-
| [in] | anchor_level | erf.fire.anchor_level (-1 = the finest level) |
| [in] | finest_level | Finest level of the run at start-up |
54 const int lev = (anchor_level < 0) ? finest_level : anchor_level;
55 if (lev > finest_level) {
56 Abort(
"[FIRE] erf.fire.anchor_level = " + std::to_string(anchor_level)
57 +
" is above the finest level of this run (" + std::to_string(finest_level)
58 +
"). Set it to a level from 0 to " + std::to_string(finest_level)
59 +
", or leave it unset for the finest level.");
Referenced by ERF::InitData_post().
Start-up check for an engine that reads the rain of every column (FireEngine::wants_surface_precip): the microphysics scheme must provide surface precipitation accumulators.
Aborts, naming the engine and erf.moisture_model, when the sources are empty (no moisture model, Kessler_NoRain, saturation adjustment only, ...). Called after the microphysics of the fire grid's level is initialised.
- Parameters
-
| [in] | engine_name | The engine's name (FireEngine::name) |
| [in] | sources | Microphysics::Get_Surface_Precip_Accumulation_Ptrs(lev) |
68 std::string moisture_model =
"None";
69 ParmParse pp_erf(
"erf");
70 pp_erf.query(
"moisture_model", moisture_model);
71 Abort(
"[FIRE] The fire engine \"" + engine_name +
"\" takes the rain of every column from the "
72 "microphysics surface precipitation accumulators, but erf.moisture_model = \"" + moisture_model
73 +
"\" provides none (Kessler, SAM, Morrison, WSM6 and WDM6 with precipitation do; Kessler_NoRain, "
74 "SatAdj, MoistNoCondensation and None do not). Choose one of those, or set the engine's inputs so "
75 "it does not read the rain.");
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool surface_precip_has_any_source(const SurfacePrecipAccumulationSources &src) noexcept
Definition: ERF_SurfacePrecipitation.H:61
Referenced by ERF::InitData_post().
| void verify_fire_prerequisites |
( |
const ERF & |
erf, |
|
|
int |
lev, |
|
|
const SurfaceLayer * |
surface_layer, |
|
|
int |
grid_ratio, |
|
|
bool |
needs_surface_layer = true |
|
) |
| |
Verify the ERF configuration the fire coupling needs.
Called once at startup from FireCoupler::initialize() after the SurfaceLayer is ready, before the engine's own checks. Aborts with clear diagnostic messages if any requirement is not met.
- Parameters
-
| [in] | erf | ERF instance (for grids, dmap, Geom access) |
| [in] | lev | AMR level the fire grid refines (fire_anchor_level) |
| [in] | surface_layer | Pointer to initialized SurfaceLayer |
| [in] | grid_ratio | erf.fire.grid_ratio, fire cells per atmospheric cell in x and y |
Checks performed (in order):
- SurfaceLayer pointer is not null (zlo.type = surface_layer), unless needs_surface_layer is false (FireEngine::needs_surface_layer)
- 0 <= lev <= finest level
- On a level above 0: static refinement (erf.regrid_int <= 0)
- Every box of the level spans its full height (no z-decomposition) 7b. The level's boxes cover one rectangle in x and y
- grid_ratio >= 1
- All boxes divisible by grid_ratio in x and y
- Distribution map size matches grid size
- Domain z, x and y indices start at 0
86 !needs_surface_layer || surface_layer !=
nullptr,
87 "fire module requires SurfaceLayer. "
88 "Check: phys_bc_type[zlo] == surface_layer AND erf.most.z0 is set");
94 "[FIRE] Internal error: the fire grid's level is outside 0..finest_level");
100 ParmParse pp_erf(
"erf");
102 pp_erf.query(
"regrid_int", regrid_int);
103 if (regrid_int > 0) {
104 Abort(
"[FIRE] The fire grid on level " + std::to_string(lev)
105 +
" is built once from that level's boxes, so the refinement must not change, but "
106 "erf.regrid_int = " + std::to_string(regrid_int) +
" regrids it. Use static refinement "
107 "boxes with erf.regrid_int = -1, or set erf.fire.anchor_level = 0.");
113 const BoxArray& ba = erf.boxArray(lev);
114 const Box& domain = erf.Geom(lev).Domain();
115 int domain_nz = domain.length(2);
117 for (
int i = 0; i < ba.size(); ++i) {
118 const Box& b = ba[i];
119 int box_nz = b.length(2);
121 std::string msg = std::string(
"[FIRE] Cannot decompose in z direction. ")
122 +
"Every box on level " + std::to_string(lev)
123 +
" must span the level's full height, since the fire model interpolates "
124 "through whole columns: set amr.max_grid_size_z = " + std::to_string(domain_nz)
125 +
" (or larger), and on a refined level use a refinement box that reaches the "
126 "domain top (erf.<box>.in_box_hi without a z bound)";
135 for (
int i = 0; i < ba.size(); ++i) {
141 const BoxArray ba_2d(std::move(bl_2d));
142 const Box region = ba_2d.minimalBox();
143 if (region.numPts() != ba_2d.numPts()) {
144 Abort(
"[FIRE] The boxes of level " + std::to_string(lev) +
" cover "
145 + std::to_string(ba_2d.numPts()) +
" of the " + std::to_string(region.numPts())
146 +
" columns of their bounding rectangle, but the fire grid needs one rectangle. "
147 "Refine one rectangle on that level (a single refinement box), or set "
148 "erf.fire.anchor_level to a level whose boxes form one.");
155 "[FIRE] Fire grid_ratio requires value >= 1. Set: erf.fire.grid_ratio >= 1");
160 for (
int i = 0; i < ba.size(); ++i) {
161 const Box& b = ba[i];
162 int nx = b.length(0);
163 int ny = b.length(1);
164 if (
nx % C != 0 ||
ny % C != 0) {
165 Abort(
"[FIRE] Box sizes not divisible by grid_ratio: box " + std::to_string(i)
166 +
" of level " + std::to_string(lev) +
" is " + std::to_string(
nx) +
" x "
167 + std::to_string(
ny) +
" cells, and every x,y box length on that level must "
168 "be divisible by erf.fire.grid_ratio = " + std::to_string(C) +
". "
169 + box_ratio_advice(C, lev));
176 erf.DistributionMap(lev).size() == erf.boxArray(lev).size(),
177 "[FIRE] Internal error: dmap size != grids size");
181 erf.Geom(lev).Domain().smallEnd(2) == 0,
182 "[FIRE] Domain z requires start at index 0");
194 erf.Geom(lev).Domain().smallEnd(0) == 0 && erf.Geom(lev).Domain().smallEnd(1) == 0,
195 "[FIRE] Domain x and y require start at index 0: the fire-to-atmosphere "
196 "index mapping assumes a zero-based domain");
const int nx
Definition: ERF_InitCustomPertVels_CloudChamber.H:14
const int ny
Definition: ERF_InitCustomPertVels_CloudChamber.H:15
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
Referenced by FireCoupler::initialize().