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