ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ForestDrag Class Reference

#include <ERF_ForestDrag.H>

Collaboration diagram for ForestDrag:

Public Member Functions

 ForestDrag (std::string forestfile)
 
 ForestDrag (std::string lai_file, std::string height_file, std::string cd_file, int tree_type=1, amrex::Real laimax=0.8)
 
 ForestDrag (std::string lai_file, std::string height_file, amrex::Real cd_const, int tree_type=1, amrex::Real laimax=0.8)
 
 ~ForestDrag ()=default
 
void define_drag_field (const amrex::BoxArray &ba, const amrex::DistributionMapping &dm, amrex::Geometry &geom, amrex::MultiFab *z_phys_cc, amrex::MultiFab *z_phys_nd, bool need_frontal_area, int level)
 
amrex::MultiFab * get_drag_field ()
 
amrex::MultiFab * get_frontal_area ()
 

Private Member Functions

void read_netcdf_file (const std::string &filename, const std::string &varname, amrex::Vector< amrex::Real > &data, int &nx, int &ny, amrex::Real &dx, amrex::Real &dy, amrex::Real &xmin, amrex::Real &ymin)
 

Private Attributes

bool m_use_gridded_data {false}
 
bool m_need_frontal_area {true}
 
bool m_use_const_cd {false}
 
amrex::Real m_cd_const {0.0}
 
amrex::Vector< amrex::Real > m_type_forest
 
amrex::Vector< amrex::Real > m_x_forest
 
amrex::Vector< amrex::Real > m_y_forest
 
amrex::Vector< amrex::Real > m_height_forest
 
amrex::Vector< amrex::Real > m_diameter_forest
 
amrex::Vector< amrex::Real > m_cd_forest
 
amrex::Vector< amrex::Real > m_lai_forest
 
amrex::Vector< amrex::Real > m_laimax_forest
 
amrex::Vector< amrex::Real > m_gridded_lai
 
amrex::Vector< amrex::Real > m_gridded_height
 
amrex::Vector< amrex::Real > m_gridded_cd
 
int m_grid_nx {0}
 
int m_grid_ny {0}
 
amrex::Real m_grid_dx {0.0}
 
amrex::Real m_grid_dy {0.0}
 
amrex::Real m_grid_xmin {0.0}
 
amrex::Real m_grid_ymin {0.0}
 
int m_tree_type {1}
 
amrex::Real m_laimax {0.8}
 
amrex::Real m_lad_normalization {1.0}
 
std::unique_ptr< amrex::MultiFab > m_forest_drag
 
std::unique_ptr< amrex::MultiFab > m_frontal_area
 

Detailed Description

Build canopy leaf-area-density and momentum-drag fields.

The vertical leaf-area-density profiles follow Lalic and Mihailovic (2004), https://doi.org/10.1175/1520-0450(2004)043%3C0641:AERDLD%3E2.0.CO;2. Canopies may be supplied as discrete patches in a text file or as gridded LAI, height, and drag-coefficient NetCDF fields.

Constructor & Destructor Documentation

◆ ForestDrag() [1/3]

ForestDrag::ForestDrag ( std::string  forestfile)
explicit

Construct a discrete-patch canopy from a text file.

118 {
119  std::ifstream file(forestfile, std::ios::in);
120  if (!file.good()) {
121  Abort("Cannot find forest file: " + forestfile);
122  }
123  // TreeType xc yc height diameter cd lai laimax
124  Real value1, value2, value3, value4, value5, value6, value7, value8;
125  int row_number = 0;
126  while (file >> value1 >> value2 >> value3 >> value4 >> value5 >> value6 >>
127  value7 >> value8) {
128  ++row_number;
129  if (value1 == Real(2.0)) {
130  const std::string error = erf_forest_utils::validate_laimax(
131  value8, "Forest file '" + forestfile + "' row " +
132  std::to_string(row_number) + " column 8 (laimax)");
133  if (!error.empty()) {
134  Abort(error);
135  }
136  }
137  m_type_forest.push_back(value1);
138  m_x_forest.push_back(value2);
139  m_y_forest.push_back(value3);
140  m_height_forest.push_back(value4);
141  m_diameter_forest.push_back(value5);
142  m_cd_forest.push_back(value6);
143  m_lai_forest.push_back(value7);
144  m_laimax_forest.push_back(value8);
145  }
146  file.close();
147 }
amrex::Real Real
Definition: ERF_ShocInterface.H:19
amrex::Vector< amrex::Real > m_diameter_forest
Definition: ERF_ForestDrag.H:96
amrex::Vector< amrex::Real > m_laimax_forest
Definition: ERF_ForestDrag.H:99
amrex::Vector< amrex::Real > m_lai_forest
Definition: ERF_ForestDrag.H:98
amrex::Vector< amrex::Real > m_x_forest
Definition: ERF_ForestDrag.H:93
amrex::Vector< amrex::Real > m_height_forest
Definition: ERF_ForestDrag.H:95
amrex::Vector< amrex::Real > m_cd_forest
Definition: ERF_ForestDrag.H:97
amrex::Vector< amrex::Real > m_type_forest
Definition: ERF_ForestDrag.H:92
amrex::Vector< amrex::Real > m_y_forest
Definition: ERF_ForestDrag.H:94
std::string validate_laimax(const amrex::Real laimax, const std::string &source)
Definition: ERF_ForestUtils.H:36
Here is the call graph for this function:

◆ ForestDrag() [2/3]

ForestDrag::ForestDrag ( std::string  lai_file,
std::string  height_file,
std::string  cd_file,
int  tree_type = 1,
amrex::Real  laimax = 0.8 
)

Construct a gridded canopy with drag coefficient read from NetCDF.

Parameters
lai_fileNetCDF file containing the horizontal LAI field.
height_fileNetCDF file containing canopy height.
cd_fileNetCDF file containing the cd field.
tree_typeLAD profile selector (1 uniform, 2 Lalic–Mihailovic).
laimaxFractional height of maximum LAD for profile type 2.
216 {
217  m_use_gridded_data = true;
218  m_tree_type = tree_type;
219  m_laimax = laimax;
220 
222  tree_type == 1 || tree_type == 2,
223  "forest_tree_type must be 1 or 2");
224  if (tree_type == 2) {
225  const std::string error = erf_forest_utils::validate_laimax(
226  laimax, "erf.forest_laimax");
227  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(error.empty(), error.c_str());
228  m_lad_normalization = compute_lad_normalization(laimax);
229  }
230 
231 #ifdef ERF_USE_NETCDF
232  read_netcdf_file(lai_file, "LAI", m_gridded_lai,
236 
237  int nx_check, ny_check;
238  Real dx_check, dy_check, xmin_check, ymin_check;
239  read_netcdf_file(height_file, "height", m_gridded_height,
240  nx_check, ny_check, dx_check, dy_check,
241  xmin_check, ymin_check);
242 
245  const erf_grid_utils::UniformGridMetadata height_grid{
246  nx_check, ny_check, dx_check, dy_check, xmin_check, ymin_check};
247  std::string grid_error = erf_grid_utils::validate_matching_grid(
248  lai_grid, height_grid, "forest field 'LAI' in '" + lai_file + "'",
249  "forest field 'height' in '" + height_file + "'");
250  if (!grid_error.empty()) {
251  Abort(grid_error);
252  }
253 
254  read_netcdf_file(cd_file, "cd", m_gridded_cd,
255  nx_check, ny_check, dx_check, dy_check,
256  xmin_check, ymin_check);
257 
259  nx_check, ny_check, dx_check, dy_check, xmin_check, ymin_check};
261  lai_grid, cd_grid, "forest field 'LAI' in '" + lai_file + "'",
262  "forest field 'cd' in '" + cd_file + "'");
263  if (!grid_error.empty()) {
264  Abort(grid_error);
265  }
266 
267  Print() << "ForestDrag: Successfully read gridded forest data\n"
268  << " Grid size: " << m_grid_nx << " x " << m_grid_ny << "\n"
269  << " Grid spacing: dx=" << m_grid_dx << ", dy=" << m_grid_dy << "\n"
270  << " Domain: x=[" << m_grid_xmin << ", "
271  << (m_grid_xmin + (m_grid_nx-1)*m_grid_dx) << "], y=["
272  << m_grid_ymin << ", "
273  << (m_grid_ymin + (m_grid_ny-1)*m_grid_dy) << "]\n"
274  << " Tree type: " << m_tree_type << "\n"
275  << " LAImax: " << m_laimax << "\n";
276 
277 #else
278  amrex::ignore_unused(lai_file, height_file, cd_file);
279  Abort("ERF must be compiled with NetCDF support to use gridded forest data");
280 #endif
281 }
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
amrex::Real m_lad_normalization
Definition: ERF_ForestDrag.H:119
amrex::Real m_grid_xmin
Definition: ERF_ForestDrag.H:110
amrex::Real m_grid_dy
Definition: ERF_ForestDrag.H:109
int m_grid_nx
Definition: ERF_ForestDrag.H:106
void read_netcdf_file(const std::string &filename, const std::string &varname, amrex::Vector< amrex::Real > &data, int &nx, int &ny, amrex::Real &dx, amrex::Real &dy, amrex::Real &xmin, amrex::Real &ymin)
amrex::Vector< amrex::Real > m_gridded_lai
Definition: ERF_ForestDrag.H:102
int m_tree_type
Definition: ERF_ForestDrag.H:114
amrex::Vector< amrex::Real > m_gridded_height
Definition: ERF_ForestDrag.H:103
amrex::Real m_grid_dx
Definition: ERF_ForestDrag.H:108
amrex::Real m_laimax
Definition: ERF_ForestDrag.H:115
amrex::Vector< amrex::Real > m_gridded_cd
Definition: ERF_ForestDrag.H:104
bool m_use_gridded_data
Definition: ERF_ForestDrag.H:82
int m_grid_ny
Definition: ERF_ForestDrag.H:107
amrex::Real m_grid_ymin
Definition: ERF_ForestDrag.H:111
std::string validate_matching_grid(const UniformGridMetadata &reference, const UniformGridMetadata &candidate, const std::string &reference_description, const std::string &candidate_description)
Definition: ERF_GridUtils.H:129
Definition: ERF_GridUtils.H:19
Here is the call graph for this function:

◆ ForestDrag() [3/3]

ForestDrag::ForestDrag ( std::string  lai_file,
std::string  height_file,
amrex::Real  cd_const,
int  tree_type = 1,
amrex::Real  laimax = 0.8 
)

Construct a gridded canopy with a spatially constant drag coefficient.

Parameters
lai_fileNetCDF file containing the horizontal LAI field.
height_fileNetCDF file containing canopy height.
cd_constSpatially constant drag coefficient.
tree_typeLAD profile selector (1 uniform, 2 Lalic–Mihailovic).
laimaxFractional height of maximum LAD for profile type 2.
157 {
158  m_use_gridded_data = true;
159  m_use_const_cd = true;
160  m_cd_const = cd_const;
161  m_tree_type = tree_type;
162  m_laimax = laimax;
163 
165  tree_type == 1 || tree_type == 2,
166  "forest_tree_type must be 1 or 2");
167  if (tree_type == 2) {
168  const std::string error = erf_forest_utils::validate_laimax(
169  laimax, "erf.forest_laimax");
170  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(error.empty(), error.c_str());
171  m_lad_normalization = compute_lad_normalization(laimax);
172  }
173 
174 #ifdef ERF_USE_NETCDF
175  read_netcdf_file(lai_file, "LAI", m_gridded_lai,
179 
180  int nx_check, ny_check;
181  Real dx_check, dy_check, xmin_check, ymin_check;
182  read_netcdf_file(height_file, "height", m_gridded_height,
183  nx_check, ny_check, dx_check, dy_check,
184  xmin_check, ymin_check);
185 
188  const erf_grid_utils::UniformGridMetadata height_grid{
189  nx_check, ny_check, dx_check, dy_check, xmin_check, ymin_check};
190  const std::string height_grid_error = erf_grid_utils::validate_matching_grid(
191  lai_grid, height_grid, "forest field 'LAI' in '" + lai_file + "'",
192  "forest field 'height' in '" + height_file + "'");
193  if (!height_grid_error.empty()) {
194  Abort(height_grid_error);
195  }
196 
197  Print() << "ForestDrag: Gridded LAI/height + constant Cd=" << m_cd_const << "\n"
198  << " Grid size: " << m_grid_nx << " x " << m_grid_ny << "\n"
199  << " Grid spacing: dx=" << m_grid_dx << ", dy=" << m_grid_dy << "\n"
200  << " Tree type: " << m_tree_type << " LAImax: " << m_laimax << "\n";
201 
202 #else
203  amrex::ignore_unused(lai_file, height_file);
204  Abort("ERF must be compiled with NetCDF support to use gridded forest data");
205 #endif
206 }
amrex::Real m_cd_const
Definition: ERF_ForestDrag.H:89
bool m_use_const_cd
Definition: ERF_ForestDrag.H:88
Here is the call graph for this function:

◆ ~ForestDrag()

ForestDrag::~ForestDrag ( )
default

Member Function Documentation

◆ define_drag_field()

void ForestDrag::define_drag_field ( const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm,
amrex::Geometry &  geom,
amrex::MultiFab *  z_phys_cc,
amrex::MultiFab *  z_phys_nd,
bool  need_frontal_area,
int  level 
)

Allocate and fill drag and, optionally, frontal-area-density fields.

Parameters
need_frontal_areaAllocate the frontal-area-density field, which is only consumed by the fixed-leaf-temperature path.
levelLevel index, used only in diagnostic messages.

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.

291 {
292  m_need_frontal_area = need_frontal_area;
293  // Geometry params
294  const auto& dx = geom.CellSizeArray();
295  const auto& prob_lo = geom.ProbLoArray();
296 
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;
301  }
302  }
303  // The drag field reads each column's ground nodes at k = 0 from its own box
304  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(all_boxes_touch_bottom,
305  "Forest drag needs every box of the level to reach the ground: do not split the grids "
306  "in z (amr.max_grid_size in z at least the number of cells in z), and refine forested "
307  "levels from the ground up");
308 
309  // Allocate the forest drag MF and frontal area MF
310  // NOTE: 1 ghost cell for averaging to faces
311  m_forest_drag.reset();
312  m_forest_drag = std::make_unique<MultiFab>(ba,dm,1,1);
313  m_forest_drag->setVal(zero);
314 
315  m_frontal_area.reset();
316  if (m_need_frontal_area) {
317  m_frontal_area = std::make_unique<MultiFab>(ba,dm,1,1);
318  m_frontal_area->setVal(zero);
319  }
320 
321  // Copy namespace-scope constants into automatic-storage values before
322  // entering GPU lambdas. NVCC does not make these host-side constexpr
323  // variables available as device symbols automatically.
324  const Real zero_d = zero;
325  const Real one_d = one;
326  const Real myhalf_d = myhalf;
327  const Real fourth_d = fourth;
328  const bool store_frontal_area = m_need_frontal_area;
329 
330  if (m_use_gridded_data) {
331  // =====================================================================
332  // Gridded NetCDF mode: interpolate from gridded LAI/height/cd data
333  // =====================================================================
334 
335  const Real* lai_data_h = m_gridded_lai.data();
336  const Real* height_data_h = m_gridded_height.data();
337  const Real* cd_data_h = m_use_const_cd ? nullptr : m_gridded_cd.data();
338 
339  const int grid_nx = m_grid_nx;
340  const int grid_ny = m_grid_ny;
341  const Real grid_dx = m_grid_dx;
342  const Real grid_dy = m_grid_dy;
343  const Real grid_xmin = m_grid_xmin;
344  const Real grid_ymin = m_grid_ymin;
345 
346  warn_if_forest_grid_does_not_cover_targets(
347  *m_forest_drag, geom, grid_xmin, grid_ymin, grid_dx, grid_dy,
348  grid_nx, grid_ny, level);
349 
350  const int grid_size = m_grid_nx * m_grid_ny;
351  Gpu::DeviceVector<Real> lai_data_d(grid_size);
352  Gpu::DeviceVector<Real> height_data_d(grid_size);
353  Gpu::DeviceVector<Real> cd_data_d;
354  if (!m_use_const_cd) {
355  cd_data_d.resize(grid_size);
356  }
357 
358  Gpu::copy(Gpu::hostToDevice, lai_data_h, lai_data_h + grid_size,
359  lai_data_d.begin());
360  Gpu::copy(Gpu::hostToDevice, height_data_h, height_data_h + grid_size,
361  height_data_d.begin());
362  if (!m_use_const_cd) {
363  Gpu::copy(Gpu::hostToDevice, cd_data_h, cd_data_h + grid_size,
364  cd_data_d.begin());
365  }
366 
367  const Real* lai_data = lai_data_d.data();
368  const Real* height_data = height_data_d.data();
369  const Real* cd_data = m_use_const_cd ? nullptr : cd_data_d.data();
370  const Real cd_const = m_cd_const;
371  const bool use_const_cd = m_use_const_cd;
372 
373  const int tree_type = m_tree_type;
374  const Real laimax = m_laimax;
375  const Real lad_normalization = m_lad_normalization;
376 
377  for (MFIter mfi(*m_forest_drag); mfi.isValid(); ++mfi) {
378  Box gtbx = mfi.growntilebox();
379  const Array4<Real>& levelDrag = m_forest_drag->array(mfi);
380  const Array4<Real> frontalArea = store_frontal_area
381  ? m_frontal_area->array(mfi) : Array4<Real>{};
382  const Array4<const Real>& z_cc = z_phys_cc->const_array(mfi);
383  const Array4<const Real>& z_nd = z_phys_nd->const_array(mfi);
384 
385  ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
386  {
387  const Real x = prob_lo[0] + (i + myhalf_d) * dx[0];
388  const Real y = prob_lo[1] + (j + myhalf_d) * dx[1];
389 
390  const Real z_sfc = fourth_d * (z_nd(i, j, 0) + z_nd(i + 1, j, 0) +
391  z_nd(i, j + 1, 0) + z_nd(i + 1, j + 1, 0));
392  const Real z = amrex::max((z_cc(i, j, k) - z_sfc), zero_d);
393 
394  const auto x_stencil = erf_grid_utils::uniform_interpolation_stencil(
395  x, grid_xmin, grid_dx, grid_nx);
396  const auto y_stencil = erf_grid_utils::uniform_interpolation_stencil(
397  y, grid_ymin, grid_dy, grid_ny);
398 
399  if (x_stencil.inside && y_stencil.inside) {
400  const int ii_c = x_stencil.lower;
401  const int jj_c = y_stencil.lower;
402  const Real wx = x_stencil.weight;
403  const Real wy = y_stencil.weight;
404 
405  // Bilinear interpolation of LAI
406  Real lai00 = lai_data[jj_c * grid_nx + ii_c];
407  Real lai10 = lai_data[jj_c * grid_nx + (ii_c + 1)];
408  Real lai01 = lai_data[(jj_c + 1) * grid_nx + ii_c];
409  Real lai11 = lai_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
410  Real lai_interp = (lai00 * (one_d - wx) + lai10 * wx) * (one_d - wy) +
411  (lai01 * (one_d - wx) + lai11 * wx) * wy;
412 
413  // Bilinear interpolation of height
414  Real h00 = height_data[jj_c * grid_nx + ii_c];
415  Real h10 = height_data[jj_c * grid_nx + (ii_c + 1)];
416  Real h01 = height_data[(jj_c + 1) * grid_nx + ii_c];
417  Real h11 = height_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
418  Real height_interp = (h00 * (one_d - wx) + h10 * wx) * (one_d - wy) +
419  (h01 * (one_d - wx) + h11 * wx) * wy;
420 
421  Real cd_interp = cd_const;
422  if (!use_const_cd) {
423  // Bilinear interpolation of Cd from file.
424  Real cd00 = cd_data[jj_c * grid_nx + ii_c];
425  Real cd10 = cd_data[jj_c * grid_nx + (ii_c + 1)];
426  Real cd01 = cd_data[(jj_c + 1) * grid_nx + ii_c];
427  Real cd11 = cd_data[(jj_c + 1) * grid_nx + (ii_c + 1)];
428  cd_interp = (cd00 * (one_d - wx) + cd10 * wx) * (one_d - wy) +
429  (cd01 * (one_d - wx) + cd11 * wx) * wy;
430  }
431 
432  // Compute drag if within canopy
433  if (z < height_interp && height_interp > zero_d && lai_interp > zero_d) {
434  Real af;
435  Real factor = one_d;
436 
437  if (tree_type == 1) {
438  af = lai_interp / height_interp;
439  } else {
440  const Real treeZm = laimax * height_interp;
441  af = lai_interp / (height_interp * lad_normalization);
442 
443  Real ratio = (height_interp - treeZm) / (height_interp - z);
444  if (z < treeZm) {
445  factor = amrex::Math::powi<6>(ratio) *
446  std::exp(Real(6.0) * (one_d - ratio));
447  } else {
448  factor = std::sqrt(ratio) *
449  std::exp(myhalf_d * (one_d - ratio));
450  }
451  }
452 
453  levelDrag(i, j, k) = cd_interp * af * factor;
454  if (store_frontal_area) {
455  frontalArea(i, j, k) = af * factor;
456  }
457  }
458  }
459  });
460  } // mfi
461 
462  // Synchronize before DeviceVectors go out of scope
463  Gpu::synchronize();
464 
465  } else {
466  // =====================================================================
467  // Discrete patch mode: original implementation
468  // =====================================================================
469 
470  for (unsigned ii = 0; ii < m_x_forest.size(); ++ii) {
471  Real af;
472  Real treeZm = zero_d;
473  int tf = int(m_type_forest[ii]);
474  Real hf = m_height_forest[ii];
475  Real xf = m_x_forest[ii];
476  Real yf = m_y_forest[ii];
477  Real df = m_diameter_forest[ii];
478  Real cdf = m_cd_forest[ii];
479  Real laif = m_lai_forest[ii];
480  Real laimaxf = m_laimax_forest[ii];
481 
482  if (tf == 1) {
483  af = laif / hf;
484  } else {
485  treeZm = laimaxf * hf;
486  af = laif / (hf * compute_lad_normalization(laimaxf));
487  }
488 
489  for (MFIter mfi(*m_forest_drag); mfi.isValid(); ++mfi) {
490  Box gtbx = mfi.growntilebox();
491  const Array4<Real>& levelDrag = m_forest_drag->array(mfi);
492  const Array4<Real> frontalArea = store_frontal_area
493  ? m_frontal_area->array(mfi) : Array4<Real>{};
494  const Array4<const Real>& z_cc = z_phys_cc->const_array(mfi);
495  const Array4<const Real>& z_nd = z_phys_nd->const_array(mfi);
496 
497  ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
498  {
499  const Real x = prob_lo[0] + (i + myhalf_d) * dx[0];
500  const Real y = prob_lo[1] + (j + myhalf_d) * dx[1];
501 
502  const Real z_sfc = fourth_d * (z_nd(i,j ,0) + z_nd(i+1,j ,0)
503  + z_nd(i,j+1,0) + z_nd(i+1,j+1,0));
504  const Real z = std::max((z_cc(i,j,k)-z_sfc), amrex::Real(0));
505 
506  const Real radius = std::sqrt((x - xf) * (x - xf) +
507  (y - yf) * (y - yf));
508 
509  // Strictly below the tree top, as in the gridded mode: the
510  // type-2 profile tends to zero at z = hf, where its ratio
511  // would divide by zero. Overlapping patches add their drag.
512  Real factor = one_d;
513  if ((z < hf) && (radius <= (myhalf_d * df))) {
514  if (tf == 2) {
515  Real ratio = (hf - treeZm) / (hf - z);
516  if (z < treeZm) {
517  factor = amrex::Math::powi<6>(ratio) *
518  std::exp(Real(6.0) * (one_d - ratio));
519  } else {
520  factor = std::sqrt(ratio) *
521  std::exp(myhalf_d * (one_d - ratio));
522  }
523  }
524  levelDrag(i, j, k) += cdf * af * factor;
525  if (store_frontal_area) {
526  frontalArea(i, j, k) += af * factor;
527  }
528  }
529  });
530  } // mfi
531  } // ii (forest patch)
532 
533  } // end else (discrete patch mode)
534 
535  // Fillboundary for periodic ghost cell copy
536  m_forest_drag->FillBoundary(geom.periodicity());
537  if (m_frontal_area != nullptr) {
538  m_frontal_area->FillBoundary(geom.periodicity());
539  }
540 
541 } // define_drag_field
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
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:37
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:42
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
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:305
Here is the call graph for this function:

◆ get_drag_field()

amrex::MultiFab* ForestDrag::get_drag_field ( )
inline

Return the cell-centered product of drag coefficient and LAD.

74 { return m_forest_drag.get(); }

◆ get_frontal_area()

amrex::MultiFab* ForestDrag::get_frontal_area ( )
inline

Return cell-centered leaf/frontal area density without drag coefficient.

78 { return m_frontal_area.get(); }

◆ read_netcdf_file()

void ForestDrag::read_netcdf_file ( const std::string &  filename,
const std::string &  varname,
amrex::Vector< amrex::Real > &  data,
int &  nx,
int &  ny,
amrex::Real &  dx,
amrex::Real &  dy,
amrex::Real &  xmin,
amrex::Real &  ymin 
)
private

Member Data Documentation

◆ m_cd_const

amrex::Real ForestDrag::m_cd_const {0.0}
private

◆ m_cd_forest

amrex::Vector<amrex::Real> ForestDrag::m_cd_forest
private

◆ m_diameter_forest

amrex::Vector<amrex::Real> ForestDrag::m_diameter_forest
private

◆ m_forest_drag

std::unique_ptr<amrex::MultiFab> ForestDrag::m_forest_drag
private

Referenced by get_drag_field().

◆ m_frontal_area

std::unique_ptr<amrex::MultiFab> ForestDrag::m_frontal_area
private

Referenced by get_frontal_area().

◆ m_grid_dx

amrex::Real ForestDrag::m_grid_dx {0.0}
private

◆ m_grid_dy

amrex::Real ForestDrag::m_grid_dy {0.0}
private

◆ m_grid_nx

int ForestDrag::m_grid_nx {0}
private

◆ m_grid_ny

int ForestDrag::m_grid_ny {0}
private

◆ m_grid_xmin

amrex::Real ForestDrag::m_grid_xmin {0.0}
private

◆ m_grid_ymin

amrex::Real ForestDrag::m_grid_ymin {0.0}
private

◆ m_gridded_cd

amrex::Vector<amrex::Real> ForestDrag::m_gridded_cd
private

◆ m_gridded_height

amrex::Vector<amrex::Real> ForestDrag::m_gridded_height
private

◆ m_gridded_lai

amrex::Vector<amrex::Real> ForestDrag::m_gridded_lai
private

◆ m_height_forest

amrex::Vector<amrex::Real> ForestDrag::m_height_forest
private

◆ m_lad_normalization

amrex::Real ForestDrag::m_lad_normalization {1.0}
private

◆ m_lai_forest

amrex::Vector<amrex::Real> ForestDrag::m_lai_forest
private

◆ m_laimax

amrex::Real ForestDrag::m_laimax {0.8}
private

◆ m_laimax_forest

amrex::Vector<amrex::Real> ForestDrag::m_laimax_forest
private

◆ m_need_frontal_area

bool ForestDrag::m_need_frontal_area {true}
private

◆ m_tree_type

int ForestDrag::m_tree_type {1}
private

◆ m_type_forest

amrex::Vector<amrex::Real> ForestDrag::m_type_forest
private

◆ m_use_const_cd

bool ForestDrag::m_use_const_cd {false}
private

◆ m_use_gridded_data

bool ForestDrag::m_use_gridded_data {false}
private

◆ m_x_forest

amrex::Vector<amrex::Real> ForestDrag::m_x_forest
private

◆ m_y_forest

amrex::Vector<amrex::Real> ForestDrag::m_y_forest
private

The documentation for this class was generated from the following files: