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.
293 const auto&
dx = geom.CellSizeArray();
294 const auto&
prob_lo = geom.ProbLoArray();
296 bool all_boxes_touch_bottom =
true;
297 for (
int i = 0; i < ba.size(); i++) {
298 if (ba[i].smallEnd(2) != geom.Domain().smallEnd(2)) {
299 all_boxes_touch_bottom =
false;
341 warn_if_forest_grid_does_not_cover_targets(
342 *
m_forest_drag, geom, grid_xmin, grid_ymin, grid_dx, grid_dy,
343 grid_nx, grid_ny, level);
346 Gpu::DeviceVector<Real> lai_data_d(grid_size);
347 Gpu::DeviceVector<Real> height_data_d(grid_size);
348 Gpu::DeviceVector<Real> cd_data_d;
350 cd_data_d.resize(grid_size);
353 Gpu::copy(Gpu::hostToDevice, lai_data_h, lai_data_h + grid_size,
355 Gpu::copy(Gpu::hostToDevice, height_data_h, height_data_h + grid_size,
356 height_data_d.begin());
358 Gpu::copy(Gpu::hostToDevice, cd_data_h, cd_data_h + grid_size,
362 const Real* lai_data = lai_data_d.data();
363 const Real* height_data = height_data_d.data();
373 Box gtbx = mfi.growntilebox();
375 const Array4<Real> frontalArea = store_frontal_area
377 const Array4<const Real>& z_cc = z_phys_cc->const_array(mfi);
378 const Array4<const Real>& z_nd = z_phys_nd->const_array(mfi);
380 ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
385 const Real z_sfc = fourth_d * (z_nd(i, j, 0) + z_nd(i + 1, j, 0) +
386 z_nd(i, j + 1, 0) + z_nd(i + 1, j + 1, 0));
387 const Real z = amrex::max((z_cc(i, j, k) - z_sfc), zero_d);
390 x, grid_xmin, grid_dx, grid_nx);
392 y, grid_ymin, grid_dy, grid_ny);
394 if (x_stencil.inside && y_stencil.inside) {
395 const int ii_c = x_stencil.lower;
396 const int jj_c = y_stencil.lower;
397 const Real wx = x_stencil.weight;
398 const Real wy = y_stencil.weight;
401 Real lai00 = lai_data[jj_c * grid_nx + ii_c];
402 Real lai10 = lai_data[jj_c * grid_nx + (ii_c + 1)];
403 Real lai01 = lai_data[(jj_c + 1) * grid_nx + ii_c];
404 Real lai11 = lai_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
405 Real lai_interp = (lai00 * (one_d - wx) + lai10 * wx) * (one_d - wy) +
406 (lai01 * (one_d - wx) + lai11 * wx) * wy;
409 Real h00 = height_data[jj_c * grid_nx + ii_c];
410 Real h10 = height_data[jj_c * grid_nx + (ii_c + 1)];
411 Real h01 = height_data[(jj_c + 1) * grid_nx + ii_c];
412 Real h11 = height_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
413 Real height_interp = (h00 * (one_d - wx) + h10 * wx) * (one_d - wy) +
414 (h01 * (one_d - wx) + h11 * wx) * wy;
416 Real cd_interp = cd_const;
419 Real cd00 = cd_data[jj_c * grid_nx + ii_c];
420 Real cd10 = cd_data[jj_c * grid_nx + (ii_c + 1)];
421 Real cd01 = cd_data[(jj_c + 1) * grid_nx + ii_c];
422 Real cd11 = cd_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
423 cd_interp = (cd00 * (one_d - wx) + cd10 * wx) * (one_d - wy) +
424 (cd01 * (one_d - wx) + cd11 * wx) * wy;
428 if (z < height_interp && height_interp > zero_d && lai_interp > zero_d) {
432 if (tree_type == 1) {
433 af = lai_interp / height_interp;
435 const Real treeZm = laimax * height_interp;
436 af = lai_interp / (height_interp * lad_normalization);
438 Real ratio = (height_interp - treeZm) / (height_interp -
z);
440 factor = amrex::Math::powi<6>(ratio) *
441 std::exp(
Real(6.0) * (one_d - ratio));
443 factor = std::sqrt(ratio) *
444 std::exp(myhalf_d * (one_d - ratio));
448 levelDrag(i, j, k) = cd_interp * af * factor;
449 if (store_frontal_area) {
450 frontalArea(i, j, k) = af * factor;
465 for (
unsigned ii = 0; ii <
m_x_forest.size(); ++ii) {
467 Real treeZm = zero_d;
480 treeZm = laimaxf * hf;
481 af = laif / (hf * compute_lad_normalization(laimaxf));
485 Box gtbx = mfi.growntilebox();
487 const Array4<Real> frontalArea = store_frontal_area
489 const Array4<const Real>& z_cc = z_phys_cc->const_array(mfi);
490 const Array4<const Real>& z_nd = z_phys_nd->const_array(mfi);
492 ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(
int i,
int j,
int k) noexcept
497 const Real z_sfc = fourth_d * (z_nd(i,j ,0) + z_nd(i+1,j ,0)
498 + z_nd(i,j+1,0) + z_nd(i+1,j+1,0));
501 const Real radius = std::sqrt((
x - xf) * (
x - xf) +
502 (
y - yf) * (
y - yf));
505 if ((
z <= hf) && (radius <= (myhalf_d * df))) {
507 Real ratio = (hf - treeZm) / (hf -
z);
509 factor = amrex::Math::powi<6>(ratio) *
510 std::exp(
Real(6.0) * (one_d - ratio));
511 }
else if (
z <= hf) {
512 factor = std::sqrt(ratio) *
513 std::exp(myhalf_d * (one_d - ratio));
516 levelDrag(i, j, k) = cdf * af * factor;
517 if (store_frontal_area) {
518 frontalArea(i, j, k) = af * factor;
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
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);})
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