ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ProbCommon.H
Go to the documentation of this file.
1 #ifndef ERF_PROBCOMMON_H_
2 #define ERF_PROBCOMMON_H_
3 
4 #include <AMReX_ParmParse.H>
5 #include <AMReX_Geometry.H>
6 #include <AMReX_FArrayBox.H>
7 #include <AMReX_MultiFab.H>
8 
9 #include "ERF_DataStruct.H"
10 #include "ERF_EOS.H"
11 #include "ERF_HSEUtils.H"
12 #include "ERF_TileNoZ.H"
13 
16  amrex::Real T_0 = 300.0;
17 };
18 
19 template <typename T>
20 T erf_get_single_value (std::istream& is, int n)
21 {
22  T r = 0;
23  std::string line;
24  if (std::getline(is, line)) {
25  std::stringstream ss(line);
26  ss >> r;
27  if (ss.fail()) {
28  amrex::Abort("Failed to read");
29  }
30  if (ss >> r) {
31  amrex::Print() << "Trying to read line " << n << " in this file " << std::endl;
32  amrex::Abort("Wrong format: more than one number in this line");
33  }
34  } else {
35  amrex::Abort("Unable to read this line");
36  }
37  return r;
38 }
39 
40 void
41 init_my_custom_terrain (const amrex::Geometry& geom,
42  amrex::FArrayBox& terrain_fab,
43  const amrex::Real& time);
44 
45 /**
46  * Class to hold problem-specific routines
47 */
49 {
50 public:
51 
52  /**
53  * Virtual destructor to avoid data leakage with derived class
54  */
55  virtual ~ProblemBase () = default;
56 
57  /**
58  * Function to initialize the hydrostatic reference density
59  *
60  * @param[out] rho_hse hydrostatic reference density
61  * @param[in] z_phys_nd height coordinate at nodes
62  * @param[in] z_phys_cc height coordinate at cell centers
63  * @param[in] geom container for geometric information
64  */
65  virtual void
66  erf_init_dens_hse (amrex::MultiFab& /*rho_hse*/,
67  std::unique_ptr<amrex::MultiFab>& /*z_phys_nd*/,
68  std::unique_ptr<amrex::MultiFab>& /*z_phys_cc*/,
69  amrex::Geometry const& /*geom*/)
70  {
71  amrex::Print() << "Hydrostatically balanced density was NOT set"
72  << " -- an appropriate init_type should probably have been specified"
73  << " (e.g., input_sounding, WRFInput, or Metgrid)"
74  << std::endl;
75  amrex::Error("Should never call erf_init_dens_hse for "+name()+" problem");
76  }
77 
78  virtual void
79  erf_init_dens_hse_moist (amrex::MultiFab& /*rho_hse*/,
80  std::unique_ptr<amrex::MultiFab>& /*z_phys_nd*/,
81  amrex::Geometry const& /*geom*/)
82  {
83 
84  }
85 
86  /**
87  * Function to perform custom initialization of a test problem
88  *
89  * @param[in] bx cell-centered box on which to initialize scalars
90  * @param[in] xbx box on which to initialize x-component of velocity
91  * @param[in] ybx box on which to initialize y-component of velocity
92  * @param[in] zbx box on which to initialize z-component of velocity
93  * @param[out] state cell-centered variables to be filled in this routine
94  * @param[out] x_velocity x-component of velocity to be filled in this routine
95  * @param[out] y_velocity y-component of velocity to be filled in this routine
96  * @param[out] z_velocity z-component of velocity to be filled in this routine
97  * @param[out] r_hse hydrostatic reference density
98  * @param[out] p_hse hydrostatic reference pressure
99  * @param[in] z_nd height coordinate at nodes
100  * @param[in] z_cc height coordinate at cell centers
101  * @param[in] qv water vapor
102  * @param[in] qc cloud water
103  * @param[in] qi cloud ice
104  * @param[in] mf_m map factor on cell centers
105  * @param[in] mf_u map factor on x-faces
106  * @param[in] mf_v map factor on y-faces
107  * @param[in] sc SolverChoice structure that carries parameters
108  */
109  virtual void
110  init_custom_pert (const amrex::Box& /*bx*/,
111  const amrex::Box& /*xbx*/,
112  const amrex::Box& /*ybx*/,
113  const amrex::Box& /*zbx*/,
114  amrex::Array4<amrex::Real const> const& /*state*/,
115  amrex::Array4<amrex::Real > const& /*state_pert*/,
116  amrex::Array4<amrex::Real > const& /*x_vel_pert*/,
117  amrex::Array4<amrex::Real > const& /*y_vel_pert*/,
118  amrex::Array4<amrex::Real > const& /*z_vel_pert*/,
119  amrex::Array4<amrex::Real > const& /*r_hse*/,
120  amrex::Array4<amrex::Real > const& /*p_hse*/,
121  amrex::Array4<amrex::Real const> const& /*z_nd*/,
122  amrex::Array4<amrex::Real const> const& /*z_cc*/,
123  amrex::GeometryData const& /*geomdata*/,
124  amrex::Array4<amrex::Real const> const& /*mf_m*/,
125  amrex::Array4<amrex::Real const> const& /*mf_u*/,
126  amrex::Array4<amrex::Real const> const& /*mf_v*/,
127  const SolverChoice& /*sc*/,
128  const int /*lev*/)
129  {
130  amrex::Print() << "No perturbation to background fields supplied for "
131  << name() << " problem" << std::endl;
132  }
133 
134  /**
135  * Function to update user-specified temperature source terms that can
136  * vary with time and height.
137  *
138  * @param[in] time current time
139  * @param[out] rhotheta_source forcing profile
140  * @param[in] geom container for geometric information
141  * @param[in] z_phys_cc height coordinate at cell centers
142  */
143  virtual void
145  amrex::MultiFab* src,
146  const amrex::Geometry& /*geom*/,
147  std::unique_ptr<amrex::MultiFab>& /*z_phys_cc*/)
148  {
149  if (src->empty()) return;
150 
151  amrex::Warning("Temperature forcing not defined for "+name()+" problem");
152  for ( amrex::MFIter mfi(*src, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi )
153  {
154  const auto &box = mfi.tilebox();
155  const amrex::Array4<amrex::Real>& src_arr = src->array(mfi);
156  // src is a spatial function if erf.spatial_rhotheta_forcing = true
157  // otherwise, qsrc_arr is defined only in over Z (box x and y dimensions are 1)
158  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
159  // const amrex::Real z_cc = prob_lo[2] + (k+0.5)* dx[2];
160  // set RHS term of RhoTheta equation based on time, z_cc here
161  src_arr(i, j, k) = 0.0;
162  });
163  }
164  }
165 
166  /**
167  * Function to update user-specified moisture source terms that can
168  * vary with time and height.
169  *
170  * @param[in] time current time
171  * @param[out] rhoqt_source moisture forcing profile
172  * @param[in] geom container for geometric information
173  * @param[in] z_phys_cc height coordinate at cell centers
174  */
175  virtual void
177  amrex::MultiFab* qsrc,
178  const amrex::Geometry& /*geom*/,
179  std::unique_ptr<amrex::MultiFab>& /*z_phys_cc*/)
180  {
181  if (qsrc->empty()) return;
182 
183  amrex::Warning("Moisture forcing not defined for "+name()+" problem");
184  for ( amrex::MFIter mfi(*qsrc, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi )
185  {
186  const auto &box = mfi.tilebox();
187  const amrex::Array4<amrex::Real>& qsrc_arr = qsrc->array(mfi);
188  // src is a spatial function if erf.spatial_moisture_forcing = true
189  // otherwise, qsrc_arr is defined only in over Z (box x and y dimensions are 1)
190  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
191  // const amrex::Real z_cc = prob_lo[2] + (k+0.5)* dx[2];
192  // set RHS term of RhoQ1 equation based on time, z_cc here
193  qsrc_arr(i, j, k) = 0.0;
194  });
195  }
196  }
197 
198  /**
199  * Function to update the vertical velocity profile, used to add subsidence
200  * source terms for x-mom, y-mom, rho*theta, rho*Q1, and rho*Q2.
201  *
202  * TODO: Currently, this is only called by InitData, so there is no time
203  * dependence.
204  *
205  * @param[in] time current time
206  * @param[out] wbar w vel forcing profile
207  * @param[in] geom container for geometric information
208  * @param[in] z_phys_cc height coordinate at cell centers
209  */
210  virtual void
212  amrex::Vector<amrex::Real>& wbar,
213  amrex::Gpu::DeviceVector<amrex::Real>& d_wbar,
214  const amrex::MultiFab& /*state*/,
215  const amrex::Geometry& geom,
216  std::unique_ptr<amrex::MultiFab>& /*z_phys_cc*/)
217  {
218  if (wbar.empty()) return;
219 
220  amrex::Warning("Moisture forcing not defined for "+name()+" problem");
221 
222  const int khi = geom.Domain().bigEnd()[2];
223  // const amrex::Real* prob_lo = geom.ProbLo();
224  // const auto dx = geom.CellSize();
225  for (int k = 0; k <= khi; k++)
226  {
227  // const amrex::Real z_cc = prob_lo[2] + (k+0.5)* dx[2];
228  // set vertical velocity profile based on time, z_cc here
229  wbar[k] = 0.0;
230  }
231 
232  // Copy from host version to device version
233  amrex::Gpu::copy(amrex::Gpu::hostToDevice, wbar.begin(), wbar.end(), d_wbar.begin());
234  }
235 
236  /**
237  * Function to update user-specified geostrophic wind profile.
238  *
239  * @param[in] time current time
240  * @param[out] u_geos geostrophic wind profile
241  * @param[out] v_geos geostrophic wind profile
242  * @param[in] geom container for geometric information
243  * @param[in] z_phys_cc height coordinate at cell centers
244  */
245  virtual void
247  amrex::Vector<amrex::Real>& u_geos,
248  amrex::Gpu::DeviceVector<amrex::Real>& d_u_geos,
249  amrex::Vector<amrex::Real>& v_geos,
250  amrex::Gpu::DeviceVector<amrex::Real>& d_v_geos,
251  const amrex::Geometry& geom,
252  std::unique_ptr<amrex::MultiFab>& /*z_phys_cc*/)
253  {
254  if (u_geos.empty()) return;
255 
256  amrex::Warning("Geostrophic wind profile not defined for "+name()+" problem");
257 
258  const int khi = geom.Domain().bigEnd()[2];
259  // const amrex::Real* prob_lo = geom.ProbLo();
260  // const auto dx = geom.CellSize();
261  for (int k = 0; k <= khi; k++)
262  {
263  // const amrex::Real z_cc = prob_lo[2] + (k+0.5)* dx[2];
264  // set RHS term of RhoTheta equation based on time, z_cc here
265  u_geos[k] = 0.0;
266  v_geos[k] = 0.0;
267  }
268 
269  // Copy from host version to device version
270  amrex::Gpu::copy(amrex::Gpu::hostToDevice, u_geos.begin(), u_geos.end(), d_u_geos.begin());
271  amrex::Gpu::copy(amrex::Gpu::hostToDevice, v_geos.begin(), v_geos.end(), d_v_geos.begin());
272  }
273 
274  /**
275  * Function to perform custom initialization of buildings
276  *
277  * @param[in] geom container for geometric information
278  * @param[out] z_phys_nd height coordinate at nodes
279  * @param[in] time current time
280  */
281  void
282  init_buildings_surface (const amrex::Geometry& geom,
283  amrex::FArrayBox& buildings_fab,
284  const amrex::Real& time)
285  {
286  // Check if a valid text file exists for the buildings
287  std::string fname;
288  amrex::ParmParse pp("erf");
289  auto valid_fname = pp.query("buildings_file_name",fname);
290 
291  if (valid_fname) {
292  read_custom_terrain(fname,false,geom,buildings_fab,time);
293  } else {
294  init_my_custom_terrain(geom, buildings_fab, time);
295  }
296  }
297 
298 
299  /**
300  * Function to perform custom initialization of terrain
301  *
302  * @param[in] geom container for geometric information
303  * @param[out] z_phys_nd height coordinate at nodes
304  * @param[in] time current time
305  */
306  void
307  init_terrain_surface (const amrex::Geometry& geom,
308  amrex::FArrayBox& terrain_fab,
309  const amrex::Real& time)
310  {
311  // Check if a valid text file exists for the terrain
312  std::string fname, fname_usgs;
313  amrex::ParmParse pp("erf");
314  auto valid_fname = pp.query("terrain_file_name",fname);
315  auto valid_fname_USGS = pp.query("terrain_file_name_USGS",fname_usgs);
316 
317  bool is_usgs;
318 
319  if (valid_fname) {
320  is_usgs = false;
321  read_custom_terrain(fname,is_usgs,geom,terrain_fab,time);
322 
323  } else if (valid_fname_USGS) {
324  is_usgs = true;
325  read_custom_terrain(fname_usgs,is_usgs,geom,terrain_fab,time);
326 
327  } else {
328  init_my_custom_terrain (geom, terrain_fab, time);
329  }
330  }
331 
332  void
333  read_custom_terrain(const std::string& fname,
334  const bool is_usgs,
335  const amrex::Geometry& geom,
336  amrex::FArrayBox& terrain_fab,
337  const amrex::Real& /*time*/)
338  {
339  amrex::Vector<amrex::Real> m_xterrain,m_yterrain,m_zterrain;
340 
341  int nx = 0; int ny = 0;
342 
343  if (amrex::ParallelDescriptor::IOProcessor()) {
344  // Read terrain file
345  amrex::Print()<<"Reading terrain file: "<< fname<< std::endl;
346  std::ifstream file(fname);
347 
348  if (!file.is_open()) {
349  amrex::Abort("Error: Could not open the file " + fname+ "\n");
350  }
351 
352  // Check if file is empty
353  if (file.peek() == std::ifstream::traits_type::eof()) {
354  amrex::Abort("Error: The file " + fname+ " is empty.\n");
355  }
356 
357  amrex::Real value1,value2,value3;
358 
359  if (is_usgs) {
360  amrex::Real lat_min, lon_min;
361 
362  file >> lon_min >> lat_min;
363  if(std::fabs(lon_min) > 180.0) {
364  amrex::Error("The value of longitude for entry in the first line in " + fname
365  + " should not exceed 180. It is " + std::to_string(lon_min));
366  }
367  if(std::fabs(lat_min) > 90.0) {
368  amrex::Error("The value of latitude for entry in the first line in " + fname
369  + " should not exceed 90. It is " + std::to_string(lat_min));
370  }
371 
372  file >> nx >> ny;
373 
374  int counter = 0;
375  while (file >> value1 >> value2 >> value3) {
376  m_xterrain.push_back(value1);
377  if(counter%nx==0) {
378  m_yterrain.push_back(value2);
379  }
380  m_zterrain.push_back(value3);
381  counter += 1;
382  }
383  AMREX_ASSERT(m_xterrain.size() == static_cast<long int>(nx*ny));
384  AMREX_ASSERT(m_yterrain.size() == static_cast<long int>(ny));
385  AMREX_ASSERT(m_zterrain.size() == static_cast<long int>(nx*ny));
386 
387  } else {
388  int cnt = 1;
389  nx = erf_get_single_value<int>(file,cnt); cnt++;
390  ny = erf_get_single_value<int>(file,cnt); cnt++;
391  amrex::Print()<<"Expecting " << nx << " values of x, " <<
392  ny << " values of y, and " <<
393  nx*ny << " values of z" << std::endl;
394  AMREX_ALWAYS_ASSERT(nx > 0);
395  AMREX_ALWAYS_ASSERT(ny > 0);
396  m_xterrain.resize(nx);
397  m_yterrain.resize(ny);
398  m_zterrain.resize(nx * ny);
399  for (int n = 0; n < nx; n++) {
400  m_xterrain[n] = erf_get_single_value<amrex::Real>(file,cnt);
401  cnt++;
402  }
403  for (int n = 0; n < ny; n++) {
404  m_yterrain[n] = erf_get_single_value<amrex::Real>(file,cnt);
405  cnt++;
406  }
407  for (int n = 0; n < nx * ny; n++) {
408  m_zterrain[n] = erf_get_single_value<amrex::Real>(file,cnt);
409  cnt++;
410  }
411  }
412 
413  // Close the file after reading
414  file.close();
415  }
416 
417  amrex::ParallelDescriptor::Bcast(&nx,1,amrex::ParallelDescriptor::IOProcessorNumber());
418  amrex::ParallelDescriptor::Bcast(&ny,1,amrex::ParallelDescriptor::IOProcessorNumber());
419 
420  int nz = nx * ny;
421 
422  m_xterrain.resize(nx);
423  m_yterrain.resize(ny);
424  m_zterrain.resize(nz);
425 
426  amrex::ParallelDescriptor::Bcast(m_xterrain.data(),nx,amrex::ParallelDescriptor::IOProcessorNumber());
427  amrex::ParallelDescriptor::Bcast(m_yterrain.data(),ny,amrex::ParallelDescriptor::IOProcessorNumber());
428  amrex::ParallelDescriptor::Bcast(m_zterrain.data(),nz,amrex::ParallelDescriptor::IOProcessorNumber());
429 
430  // Copy data to the GPU
431  amrex::Gpu::DeviceVector<amrex::Real> d_xterrain(nx),d_yterrain(ny),d_zterrain(nz);
432  amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_xterrain.begin(), m_xterrain.end(), d_xterrain.begin());
433  amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_yterrain.begin(), m_yterrain.end(), d_yterrain.begin());
434  amrex::Gpu::copy(amrex::Gpu::hostToDevice, m_zterrain.begin(), m_zterrain.end(), d_zterrain.begin());
435 
436  amrex::Real* d_xt = d_xterrain.data();
437  amrex::Real* d_yt = d_yterrain.data();
438  amrex::Real* d_zt = d_zterrain.data();
439 
440  auto dx = geom.CellSizeArray();
441  auto ProbLoArr = geom.ProbLoArray();
442 
443  int ilo = geom.Domain().smallEnd(0);
444  int jlo = geom.Domain().smallEnd(1);
445  int klo = geom.Domain().smallEnd(2);
446  int ihi = geom.Domain().bigEnd(0) + 1;
447  int jhi = geom.Domain().bigEnd(1) + 1;
448 
449  amrex::Box zbx = terrain_fab.box();
450  amrex::Array4<amrex::Real> const& z_arr = terrain_fab.array();
451 
452  amrex::ParallelFor(zbx, [=] AMREX_GPU_DEVICE (int i, int j, int /*k*/)
453  {
454  // Clip indices for ghost cells
455  int ii = amrex::min(amrex::max(i,ilo),ihi);
456  int jj = amrex::min(amrex::max(j,jlo),jhi);
457 
458  // Location of nodes
459  amrex::Real x = ProbLoArr[0] + ii * dx[0] + 1e-3;
460  amrex::Real y = ProbLoArr[1] + jj * dx[1] + 1e-3;
461 
462  int ind11, ind12, ind21, ind22;
463  amrex::Real x1, x2, y1, y2;
464 
465  int iindex_terrain=-1;
466  int jindex_terrain=-1;
467  // *******************************************************************
468  // NOTE: usgs-format is contiguous in x
469  // *******************************************************************
470  if (is_usgs) {
471 
472  for (int it = 0; it < ny && jindex_terrain == -1; it++) {
473  if (d_yt[it] > y) {
474  jindex_terrain = it-1;
475  }
476  }
477  if (jindex_terrain == -1) {
478  jindex_terrain = ny-1;
479  }
480 
481  int gstart = (jindex_terrain )*nx;
482  int gend = (jindex_terrain+1)*nx-1;
483  for (int it = gstart; it <= gend && iindex_terrain == -1; it++) {
484  if (d_xt[it] > x) {
485  iindex_terrain = it-gstart;
486  }
487  }
488 
489  // Define the four values to interpolate between
490  ind11 = jindex_terrain*nx + iindex_terrain; // (x1,y1)
491  ind12 = ind11+nx; // (x1,y2)
492  ind21 = ind11+1; // (x2,y1)
493  ind22 = ind12+1; // (x2,y2)
494 
495  x1 = d_xt[ind11];
496  x2 = d_xt[ind21];
497  y1 = d_yt[jindex_terrain];
498  y2 = d_yt[jindex_terrain+1];
499 
500  amrex::Real denom = (x2-x1)*(y2-y1);
501  amrex::Real w_11 = (x2-x)*(y2-y)/denom; // (x1,y1)
502  amrex::Real w_12 = (x2-x)*(y-y1)/denom; // (x1,y2)
503  amrex::Real w_21 = (x-x1)*(y2-y)/denom; // (x2,y1)
504  amrex::Real w_22 = (x-x1)*(y-y1)/denom; // (x2,y2)
505 
506  // Do bilinear interpolation
507  z_arr(i,j,klo) = w_11*d_zt[ind11] + w_12*d_zt[ind12] + w_21*d_zt[ind21] + w_22*d_zt[ind22];
508 
509  } else {
510 
511  for (int it = 0; it < ny && jindex_terrain == -1; it++) {
512  if (d_yt[it] > y) {
513  jindex_terrain = it-1;
514  }
515  }
516  if (jindex_terrain == -1) {
517  jindex_terrain = ny-1;
518  }
519 
520  for (int it = 0; it < nx && iindex_terrain == -1; it++) {
521  if (d_xt[it] > x) {
522  iindex_terrain = it-1;
523  }
524  }
525  if (iindex_terrain == -1) {
526  iindex_terrain = nx-1;
527  }
528 
529  // Define the four values to interpolate between
530  x1 = d_xt[iindex_terrain];
531  x2 = d_xt[iindex_terrain+1];
532  y1 = d_yt[jindex_terrain];
533  y2 = d_yt[jindex_terrain+1];
534 
535 #if 1
536  // *******************************************************************
537  // NOTE: this format is contiguous in y to match the AMR-Wind read
538  // *******************************************************************
539  ind11 = iindex_terrain * ny + jindex_terrain; // (x1,y1)
540  ind21 = std::min(iindex_terrain+1,nx-1) * ny + jindex_terrain; // (x2,y1)
541 
542  ind12 = iindex_terrain * ny + std::min(jindex_terrain+1,ny-1); // (x1,y2)
543  ind22 = std::min(iindex_terrain+1,nx-1) * ny + std::min(jindex_terrain+1,ny-1); // (x1,y2)
544 #else
545  // *******************************************************************
546  // NOTE: this format is contiguous in x as an alternative
547  // *******************************************************************
548 
549  ind11 = jindex_terrain * nx + iindex_terrain; // (x1,y1)
550  ind12 = std::min(jindex_terrain+1,ny-1) * nx + iindex_terrain; // (x1,y2)
551 
552  ind21 = jindex_terrain * nx + std::min(iindex_terrain+1,nx-1); // (x2,y1)
553  ind22 = std::min(jindex_terrain+1,ny-1) * nx + std::min(iindex_terrain+1,nx-1); // (x2,y2)
554 #endif
555 
556  if (iindex_terrain == nx-1 && jindex_terrain == ny-1)
557  {
558  z_arr(i,j,klo) = d_zt[ind11];
559  }
560  else if (iindex_terrain != nx-1 && jindex_terrain == ny-1)
561  {
562  amrex::Real w_11 = (x2-x); // (x1,y1)
563  amrex::Real w_21 = (x-x1); // (x2,y1)
564  amrex::Real denom = (x2-x1);
565  z_arr(i,j,klo) = (w_11*d_zt[ind11] + w_21*d_zt[ind21])/denom;
566  }
567  else if (iindex_terrain == nx-1 && jindex_terrain != ny-1)
568  {
569  amrex::Real w_11 = (y2-y); // (x1,y1)
570  amrex::Real w_12 = (y-y1); // (x1,y2)
571  amrex::Real denom = (y2-y1);
572  z_arr(i,j,klo) = (w_11*d_zt[ind11] + w_12*d_zt[ind12])/denom;
573  }
574  else
575  {
576  amrex::Real w_11 = (x2-x)*(y2-y); // (x1,y1)
577  amrex::Real w_21 = (x-x1)*(y2-y); // (x2,y1)
578  amrex::Real w_12 = (x2-x)*(y-y1); // (x1,y2)
579  amrex::Real w_22 = (x-x1)*(y-y1); // (x2,y2)
580  amrex::Real denom = (x2-x1)*(y2-y1);
581  z_arr(i,j,klo) = (w_11*d_zt[ind11] + w_12*d_zt[ind12] + w_21*d_zt[ind21] + w_22*d_zt[ind22]) / denom;
582  }
583  } // usgs?
584  });
585  }
586 
587  /**
588  * Function to perform custom initialization of terrain
589  *
590  * Note: Terrain functionality can also be used to provide grid stretching.
591  *
592  * @param[in] geom container for geometric information
593  * @param[out] terrain_mf height coordinate at nodes
594  * @param[in] time current time
595  */
596  virtual void
597  init_custom_terrain (const amrex::Geometry& geom,
598  amrex::FArrayBox& terrain_fab,
599  const amrex::Real& time)
600  {
601  std::string custom_terrain_type = "None";
602  amrex::ParmParse pp_prob("prob"); pp_prob.query("custom_terrain_type",custom_terrain_type);
603 
604  if (custom_terrain_type != "None")
605  {
606  amrex::Print() << "Calling custom terrain initialization" << std::endl;
607  init_my_custom_terrain(geom,terrain_fab,time);
608 
609  } else {
610  amrex::Print() << "Initializing flat terrain" << std::endl;
611  terrain_fab.template setVal<amrex::RunOn::Device>(0.0);
612 
613  if (SolverChoice::mesh_type == MeshType::VariableDz) {
614  SolverChoice::set_mesh_type(MeshType::StretchedDz);
615  amrex::Print() << "Resetting mesh type to StretchedDz" << std::endl;
616  }
617  }
618  }
619 
620 #ifdef ERF_USE_TERRAIN_VELOCITY
621  virtual amrex::Real compute_terrain_velocity(const amrex::Real /*time*/)
622  {
623  amrex::Error("Should never call compute_terrain_velocity for "+name()+" problem");
624  }
625 #endif
626 
627  /**
628  * Function to define the quantities needed to impose Rayleigh damping
629  *
630  * @param[out] rayleigh_ptrs = {strength of Rayleigh damping, reference values for xvel/yvel/zvel/theta used to define Rayleigh damping}
631  * @param[in] geom container for geometric information
632  * @param[in] z_phys_cc height coordinate at cell centers
633  */
634  virtual void
635  erf_init_rayleigh (amrex::Vector<amrex::Vector<amrex::Real> >& /*rayleigh_ptrs*/,
636  amrex::Geometry const& /*geom*/,
637  std::unique_ptr<amrex::MultiFab>& /*z_phys_nd*/,
638  amrex::Real /*zdamp*/)
639  {
640  amrex::Error("Should never call erf_init_rayleigh for "+name()+" problem");
641  }
642 
643  /**
644  * Function to set uniform background density and potential temperature fields
645  */
646  void
647  init_uniform (const amrex::Box& bx, amrex::Array4<amrex::Real> const& state)
648  {
649  amrex::Real rho_0 = base_parms.rho_0;
650  amrex::Real T_0 = base_parms.T_0;
651  amrex::Print() << "Initializing uniform fields"
652  << " rho=" << rho_0 << " theta=" << T_0
653  << std::endl;
654 
655  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
656  {
657  state(i, j, k, Rho_comp) = rho_0;
658  state(i, j, k, RhoTheta_comp) = rho_0 * T_0;
659  });
660  }
661 
662 protected:
663  // Struct to store problem parameters
665 
666  /**
667  * Function to update default base parameters, currently only used for
668  * init_type == InitType::Uniform
669  */
671  base_parms.rho_0 = rho_0;
672  base_parms.T_0 = T_0;
673  }
674 
675  std::string name() { std::string prob_name; amrex::ParmParse pp("erf"); pp.query("prob_name",prob_name); return prob_name; }
676 };
677 
678 
679 /**
680  * Function to init the physical bounds of the domain
681  * and instantiate a Problem derived from ProblemBase
682 */
683 extern std::unique_ptr<ProblemBase> amrex_probinit (const amrex_real* problo,
684  const amrex_real* probhi) AMREX_ATTRIBUTE_WEAK;
685 #endif
@ wbar
Definition: ERF_DataStruct.H:97
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:233
T erf_get_single_value(std::istream &is, int n)
Definition: ERF_ProbCommon.H:20
void init_my_custom_terrain(const amrex::Geometry &geom, amrex::FArrayBox &terrain_fab, const amrex::Real &time)
std::unique_ptr< ProblemBase > amrex_probinit(const amrex_real *problo, const amrex_real *probhi) AMREX_ATTRIBUTE_WEAK
const Box zbx
Definition: ERF_SetupDiff.H:9
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_ProbCommon.H:49
virtual void init_custom_terrain(const amrex::Geometry &geom, amrex::FArrayBox &terrain_fab, const amrex::Real &time)
Definition: ERF_ProbCommon.H:597
virtual void update_w_subsidence(const amrex::Real &, amrex::Vector< amrex::Real > &wbar, amrex::Gpu::DeviceVector< amrex::Real > &d_wbar, const amrex::MultiFab &, const amrex::Geometry &geom, std::unique_ptr< amrex::MultiFab > &)
Definition: ERF_ProbCommon.H:211
virtual void update_rhoqt_sources(const amrex::Real &, amrex::MultiFab *qsrc, const amrex::Geometry &, std::unique_ptr< amrex::MultiFab > &)
Definition: ERF_ProbCommon.H:176
void init_uniform(const amrex::Box &bx, amrex::Array4< amrex::Real > const &state)
Definition: ERF_ProbCommon.H:647
void init_terrain_surface(const amrex::Geometry &geom, amrex::FArrayBox &terrain_fab, const amrex::Real &time)
Definition: ERF_ProbCommon.H:307
void read_custom_terrain(const std::string &fname, const bool is_usgs, const amrex::Geometry &geom, amrex::FArrayBox &terrain_fab, const amrex::Real &)
Definition: ERF_ProbCommon.H:333
void init_buildings_surface(const amrex::Geometry &geom, amrex::FArrayBox &buildings_fab, const amrex::Real &time)
Definition: ERF_ProbCommon.H:282
virtual void erf_init_rayleigh(amrex::Vector< amrex::Vector< amrex::Real > > &, amrex::Geometry const &, std::unique_ptr< amrex::MultiFab > &, amrex::Real)
Definition: ERF_ProbCommon.H:635
void init_base_parms(amrex::Real rho_0, amrex::Real T_0)
Definition: ERF_ProbCommon.H:670
virtual void update_rhotheta_sources(const amrex::Real &, amrex::MultiFab *src, const amrex::Geometry &, std::unique_ptr< amrex::MultiFab > &)
Definition: ERF_ProbCommon.H:144
virtual ~ProblemBase()=default
virtual void erf_init_dens_hse_moist(amrex::MultiFab &, std::unique_ptr< amrex::MultiFab > &, amrex::Geometry const &)
Definition: ERF_ProbCommon.H:79
std::string name()
Definition: ERF_ProbCommon.H:675
ProbParmDefaults base_parms
Definition: ERF_ProbCommon.H:664
virtual void init_custom_pert(const amrex::Box &, const amrex::Box &, const amrex::Box &, const amrex::Box &, amrex::Array4< amrex::Real const > const &, amrex::Array4< amrex::Real > const &, amrex::Array4< amrex::Real > const &, amrex::Array4< amrex::Real > const &, amrex::Array4< amrex::Real > const &, amrex::Array4< amrex::Real > const &, amrex::Array4< amrex::Real > const &, amrex::Array4< amrex::Real const > const &, amrex::Array4< amrex::Real const > const &, amrex::GeometryData const &, amrex::Array4< amrex::Real const > const &, amrex::Array4< amrex::Real const > const &, amrex::Array4< amrex::Real const > const &, const SolverChoice &, const int)
Definition: ERF_ProbCommon.H:110
virtual void erf_init_dens_hse(amrex::MultiFab &, std::unique_ptr< amrex::MultiFab > &, std::unique_ptr< amrex::MultiFab > &, amrex::Geometry const &)
Definition: ERF_ProbCommon.H:66
virtual void update_geostrophic_profile(const amrex::Real &, amrex::Vector< amrex::Real > &u_geos, amrex::Gpu::DeviceVector< amrex::Real > &d_u_geos, amrex::Vector< amrex::Real > &v_geos, amrex::Gpu::DeviceVector< amrex::Real > &d_v_geos, const amrex::Geometry &geom, std::unique_ptr< amrex::MultiFab > &)
Definition: ERF_ProbCommon.H:246
@ T
Definition: ERF_IndexDefines.H:110
Definition: ERF_ProbCommon.H:14
amrex::Real T_0
Definition: ERF_ProbCommon.H:16
amrex::Real rho_0
Definition: ERF_ProbCommon.H:15
Definition: ERF_DataStruct.H:129
static MeshType mesh_type
Definition: ERF_DataStruct.H:1048
static void set_mesh_type(MeshType new_mesh_type)
Definition: ERF_DataStruct.H:1051