Allocate and fill drag and, optionally, frontal-area-density fields.
Neither argument is defaulted on purpose: every caller must state whether the frontal-area field is needed, so that a new call site cannot silently allocate and fill it when forest biophysics is off, nor report a placeholder level in the coverage warning.
294 const auto&
dx = geom.CellSizeArray();
295 const auto&
prob_lo = geom.ProbLoArray();
297 bool all_boxes_touch_bottom =
true;
298 for (
int i = 0; i < ba.size(); i++) {
299 if (ba[i].smallEnd(2) != geom.Domain().smallEnd(2)) {
300 all_boxes_touch_bottom =
false;
342 warn_if_forest_grid_does_not_cover_targets(
343 *
m_forest_drag, geom, grid_xmin, grid_ymin, grid_dx, grid_dy,
344 grid_nx, grid_ny, level);
347 Gpu::DeviceVector<Real> lai_data_d(grid_size);
348 Gpu::DeviceVector<Real> height_data_d(grid_size);
349 Gpu::DeviceVector<Real> cd_data_d;
351 cd_data_d.resize(grid_size);
354 Gpu::copy(Gpu::hostToDevice, lai_data_h, lai_data_h + grid_size,
356 Gpu::copy(Gpu::hostToDevice, height_data_h, height_data_h + grid_size,
357 height_data_d.begin());
359 Gpu::copy(Gpu::hostToDevice, cd_data_h, cd_data_h + grid_size,
363 const Real* lai_data = lai_data_d.data();
364 const Real* height_data = height_data_d.data();
374 Box gtbx = mfi.growntilebox();
376 const Array4<Real> frontalArea = store_frontal_area
378 const Array4<const Real>& z_cc = z_phys_cc->const_array(mfi);
379 const Array4<const Real>& z_nd = z_phys_nd->const_array(mfi);
381 ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
386 const Real z_sfc = fourth_d * (z_nd(i, j, 0) + z_nd(i + 1, j, 0) +
387 z_nd(i, j + 1, 0) + z_nd(i + 1, j + 1, 0));
388 const Real z = amrex::max((z_cc(i, j, k) - z_sfc), zero_d);
391 x, grid_xmin, grid_dx, grid_nx);
393 y, grid_ymin, grid_dy, grid_ny);
395 if (x_stencil.inside && y_stencil.inside) {
396 const int ii_c = x_stencil.lower;
397 const int jj_c = y_stencil.lower;
398 const Real wx = x_stencil.weight;
399 const Real wy = y_stencil.weight;
402 Real lai00 = lai_data[jj_c * grid_nx + ii_c];
403 Real lai10 = lai_data[jj_c * grid_nx + (ii_c + 1)];
404 Real lai01 = lai_data[(jj_c + 1) * grid_nx + ii_c];
405 Real lai11 = lai_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
406 Real lai_interp = (lai00 * (one_d - wx) + lai10 * wx) * (one_d - wy) +
407 (lai01 * (one_d - wx) + lai11 * wx) * wy;
410 Real h00 = height_data[jj_c * grid_nx + ii_c];
411 Real h10 = height_data[jj_c * grid_nx + (ii_c + 1)];
412 Real h01 = height_data[(jj_c + 1) * grid_nx + ii_c];
413 Real h11 = height_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
414 Real height_interp = (h00 * (one_d - wx) + h10 * wx) * (one_d - wy) +
415 (h01 * (one_d - wx) + h11 * wx) * wy;
417 Real cd_interp = cd_const;
420 Real cd00 = cd_data[jj_c * grid_nx + ii_c];
421 Real cd10 = cd_data[jj_c * grid_nx + (ii_c + 1)];
422 Real cd01 = cd_data[(jj_c + 1) * grid_nx + ii_c];
423 Real cd11 = cd_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
424 cd_interp = (cd00 * (one_d - wx) + cd10 * wx) * (one_d - wy) +
425 (cd01 * (one_d - wx) + cd11 * wx) * wy;
429 if (z < height_interp && height_interp > zero_d && lai_interp > zero_d) {
433 if (tree_type == 1) {
434 af = lai_interp / height_interp;
436 const Real treeZm = laimax * height_interp;
437 af = lai_interp / (height_interp * lad_normalization);
439 Real ratio = (height_interp - treeZm) / (height_interp -
z);
441 factor = amrex::Math::powi<6>(ratio) *
442 std::exp(
Real(6.0) * (one_d - ratio));
444 factor = std::sqrt(ratio) *
445 std::exp(myhalf_d * (one_d - ratio));
449 levelDrag(i, j, k) = cd_interp * af * factor;
450 if (store_frontal_area) {
451 frontalArea(i, j, k) = af * factor;
466 for (
unsigned ii = 0; ii <
m_x_forest.size(); ++ii) {
468 Real treeZm = zero_d;
481 treeZm = laimaxf * hf;
482 af = laif / (hf * compute_lad_normalization(laimaxf));
486 Box gtbx = mfi.growntilebox();
488 const Array4<Real> frontalArea = store_frontal_area
490 const Array4<const Real>& z_cc = z_phys_cc->const_array(mfi);
491 const Array4<const Real>& z_nd = z_phys_nd->const_array(mfi);
493 ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
498 const Real z_sfc = fourth_d * (z_nd(i,j ,0) + z_nd(i+1,j ,0)
499 + z_nd(i,j+1,0) + z_nd(i+1,j+1,0));
502 const Real radius = std::sqrt((
x - xf) * (
x - xf) +
503 (
y - yf) * (
y - yf));
506 if ((
z <= hf) && (radius <= (myhalf_d * df))) {
508 Real ratio = (hf - treeZm) / (hf -
z);
510 factor = amrex::Math::powi<6>(ratio) *
511 std::exp(
Real(6.0) * (one_d - ratio));
512 }
else if (
z <= hf) {
513 factor = std::sqrt(ratio) *
514 std::exp(myhalf_d * (one_d - ratio));
517 levelDrag(i, j, k) = cdf * af * factor;
518 if (store_frontal_area) {
519 frontalArea(i, j, k) = af * factor;
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
const GpuArray< Real, AMREX_SPACEDIM > prob_lo
Definition: ERF_InitCustomPert_CloudChamber.H:33
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:30
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:35
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:29
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:34
bool m_need_frontal_area
Definition: ERF_ForestDrag.H:85
std::unique_ptr< amrex::MultiFab > m_frontal_area
Definition: ERF_ForestDrag.H:125
std::unique_ptr< amrex::MultiFab > m_forest_drag
Definition: ERF_ForestDrag.H:122
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE InterpolationStencil uniform_interpolation_stencil(amrex::Real coordinate, amrex::Real origin, amrex::Real spacing, int point_count) noexcept
Definition: ERF_GridUtils.H:173