ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_InputSoundingData.H
Go to the documentation of this file.
1 #ifndef ERF_INPUT_SOUNDING_DATA_H_
2 #define ERF_INPUT_SOUNDING_DATA_H_
3 
4 #include <limits>
5 #include <string>
6 #include <iostream>
7 
8 #include <AMReX_ParmParse.H>
9 #include <AMReX_Print.H>
10 #include <AMReX_Gpu.H>
11 #include <AMReX_Geometry.H>
12 
13 #include <ERF_EOS.H>
14 #include <ERF_Constants.H>
15 #include <ERF_Interpolation_1D.H>
16 #include <ERF_HSEUtils.H>
17 
18 /**
19  * Data structure storing input sounding data. Also
20  * handles reading the input file for sounding data and
21  * hydrostatic column integration.
22  */
24 public:
25  /**
26  * @brief Construct input sounding metadata from the ERF input namespace.
27  */
29  {
30  amrex::ParmParse pp("erf");
31  pp.queryAdd("tau_nudging", tau_nudging);
32 
33  // Read in input_sounding filename
34  n_sounding_files = pp.countval("input_sounding_file");
35  if (n_sounding_files > 0) {
37  pp.queryarr("input_sounding_file", input_sounding_file, 0, n_sounding_files);
38  } else {
39  n_sounding_files = 1;
41  input_sounding_file[0] = "input_sounding";
42  }
43 
44  // Read in input_sounding times
45  n_sounding_times = pp.countval("input_sounding_time");
46 
47  if (n_sounding_times > 0) {
49  pp.queryarr("input_sounding_time", input_sounding_time, 0, n_sounding_times);
50  } else {
51  n_sounding_times = 1;
54  }
55 
56  // If we have more files than times or times than files we just use the minimum
57  int n = std::min(n_sounding_times, n_sounding_files);
58  n_sounding_files = n;
59  n_sounding_times = n;
60  input_sounding_file.resize(n);
61  input_sounding_time.resize(n);
62  }
63 
64  /**
65  * @brief Resize host and device sounding arrays for the configured sounding times.
66  */
67  void resize_arrays ()
68  {
70 
71  z_inp_sound.resize(ntimes);
72  theta_inp_sound.resize(ntimes);
73  qv_inp_sound.resize(ntimes);
74  U_inp_sound.resize(ntimes);
75  V_inp_sound.resize(ntimes);
76 
77  z_inp_sound_d.resize(ntimes);
78  theta_inp_sound_d.resize(ntimes);
79  qv_inp_sound_d.resize(ntimes);
80  U_inp_sound_d.resize(ntimes);
81  V_inp_sound_d.resize(ntimes);
82  }
83 
84  /**
85  * @brief Read and interpolate one input sounding profile onto level-0 heights.
86  * @param geom Geometry defining the level-0 vertical domain.
87  * @param zlevels_stag Staggered vertical coordinates used for interpolation.
88  * @param itime Sounding time/file index to read.
89  * @param is_moist Whether the selected physics permits nonzero water vapor.
90  */
91  void read_from_file (const amrex::Geometry &geom,
92  const amrex::Vector<amrex::Real>& zlevels_stag,
93  int itime, bool is_moist)
94  {
95  const int klo = 0;
96  const int khi = geom.Domain().bigEnd()[AMREX_SPACEDIM-1];
97  const int Nz = geom.Domain().size()[AMREX_SPACEDIM-1];
98 
99  const amrex::Real zbot = zlevels_stag[klo];
100  const amrex::Real ztop = zlevels_stag[khi+1];
101 
102  z_inp_sound[itime].resize(Nz+2);
103  theta_inp_sound[itime].resize(Nz+2);
104  qv_inp_sound[itime].resize(Nz+2);
105  U_inp_sound[itime].resize(Nz+2);
106  V_inp_sound[itime].resize(Nz+2);
107 
108  // Read the input_sounding file
109  amrex::Print() << "input_sounding file location : " << input_sounding_file[itime] << std::endl;
110  std::ifstream input_sounding_reader(input_sounding_file[itime]);
111  if(!input_sounding_reader.is_open()) {
112  amrex::Error("Error opening the input_sounding file\n");
113  }
114  else {
115  // Read the contents of the input_sounding file
116  amrex::Print() << "Successfully opened the input_sounding file. Now reading... " << std::endl;
117  std::string line;
118 
119  // First, read the input data into temp vectors; then, interpolate vectors to the
120  // domain lo/hi and cell centers (from level 0)
121  amrex::Vector<amrex::Real> z_inp_sound_tmp, theta_inp_sound_tmp, qv_inp_sound_tmp,
122  U_inp_sound_tmp, V_inp_sound_tmp;
123 
124  // Read surface quantities from the first line
125  std::getline(input_sounding_reader, line);
126  std::istringstream iss(line);
128  press_ref_inp_sound *= 100; // convert from hPa to Pa
129  qv_ref_inp_sound *= amrex::Real(0.001); // convert from g/kg to kg/kg
130 
131  // Add surface
132  z_inp_sound_tmp.push_back(zbot); // height above sea level [m]
133  theta_inp_sound_tmp.push_back(theta_ref_inp_sound);
134  qv_inp_sound_tmp.push_back(qv_ref_inp_sound);
135  U_inp_sound_tmp.push_back(0);
136  V_inp_sound_tmp.push_back(0);
137 
138  // *************************************************************************************************
139  // Make sure that if we specify surface values for temp in the inputs file and in the input sounding file,
140  // those values must match
141  // *************************************************************************************************
142  amrex::ParmParse pp_erf("erf");
143 
144  // Negative sentinel rather than the queryAdd return value: an absolute
145  // temperature is never negative, and the return value only reports whether
146  // the key existed before this call. ERF_SurfaceLayer.H parses the same key,
147  // so testing the return would report "specified" here whenever that site ran
148  // first. This was also an uninitialized read before.
149  amrex::Real surf_temp = amrex::Real(-1.0);
150  pp_erf.queryAdd("most.surf_temp", surf_temp);
151  bool surf_temp_specified = (surf_temp > amrex::Real(0.0));
152  if ( surf_temp_specified && (surf_temp != theta_inp_sound_tmp[0]) ) {
153  amrex::Print() << "Input sounding temp does not match most.surf_temp" << std::endl;
154  amrex::Print() << "Modify one or both to match." << std::endl;
155  amrex::Abort();
156  }
157 
158  // *************************************************************************************************
159  // Make sure that if we specify surface values for qv in the inputs file and in the input sounding file,
160  // those values must match
161  // *************************************************************************************************
162  // Negative sentinel, as for most.surf_temp above: a mixing ratio is never
163  // negative, and ERF_SurfaceLayer.H parses this same key.
164  amrex::Real surf_moist = amrex::Real(-1.0);
165  pp_erf.queryAdd("most.surf_moist", surf_moist);
166  bool surf_moist_specified = (surf_moist >= amrex::Real(0.0));
167  if ( surf_moist_specified && (surf_moist != qv_inp_sound_tmp[0]) ) {
168  amrex::Print() << "Input sounding qv does not match most.surf_moist" << std::endl;
169  amrex::Print() << "Modify one or both to match." << std::endl;
170  amrex::Abort();
171  }
172 
173  // Read the vertical profile at each given height
174  amrex::Real z, theta, qv, U, V;
175 
176  while(std::getline(input_sounding_reader, line)) {
177  std::istringstream iss_z(line);
178  iss_z >> z >> theta >> qv >> U >> V;
179 
180  // Dont read in non-zero qv if not using a moisture model
181  AMREX_ALWAYS_ASSERT(qv == zero || is_moist);
182 
183  if (z == zbot) {
184  AMREX_ALWAYS_ASSERT(theta == theta_inp_sound_tmp[0]);
185  AMREX_ALWAYS_ASSERT(qv*amrex::Real(0.001) == qv_inp_sound_tmp[0]); // convert from g/kg to kg/kg
186  U_inp_sound_tmp[0] = U;
187  V_inp_sound_tmp[0] = V;
188  } else {
189  AMREX_ALWAYS_ASSERT(z > z_inp_sound_tmp[z_inp_sound_tmp.size()-1]); // sounding is increasing in height
190  z_inp_sound_tmp.push_back(z);
191 
192  theta_inp_sound_tmp.push_back(theta);
193  qv_inp_sound_tmp.push_back(qv*amrex::Real(0.001)); // convert from g/kg to kg/kg
194  U_inp_sound_tmp.push_back(U);
195  V_inp_sound_tmp.push_back(V);
196  if (z >= ztop) break;
197  }
198  }
199 
200  // At this point, we have an input_sounding from zbot up to
201  // z_inp_sound_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
202  const int Ninp = z_inp_sound_tmp.size();
203  z_inp_sound[itime][0] = zbot;
204  theta_inp_sound[itime][0] = theta_inp_sound_tmp[0];
205  qv_inp_sound[itime][0] = qv_inp_sound_tmp[0];
206  U_inp_sound[itime][0] = U_inp_sound_tmp[0];
207  V_inp_sound[itime][0] = V_inp_sound_tmp[0];
208  for (int k=0; k < Nz; ++k) {
209  z_inp_sound[itime][k+1] = myhalf * (zlevels_stag[k] + zlevels_stag[k+1]);
210  theta_inp_sound[itime][k+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), theta_inp_sound_tmp.dataPtr(), z_inp_sound[itime][k+1], Ninp);
211  qv_inp_sound[itime][k+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), qv_inp_sound_tmp.dataPtr(), z_inp_sound[itime][k+1], Ninp);
212  U_inp_sound[itime][k+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), U_inp_sound_tmp.dataPtr(), z_inp_sound[itime][k+1], Ninp);
213  V_inp_sound[itime][k+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), V_inp_sound_tmp.dataPtr(), z_inp_sound[itime][k+1], Ninp);
214  }
215  z_inp_sound[itime][Nz+1] = ztop;
216  theta_inp_sound[itime][Nz+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), theta_inp_sound_tmp.dataPtr(), ztop, Ninp);
217  qv_inp_sound[itime][Nz+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), qv_inp_sound_tmp.dataPtr(), ztop, Ninp);
218  U_inp_sound[itime][Nz+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), U_inp_sound_tmp.dataPtr(), ztop, Ninp);
219  V_inp_sound[itime][Nz+1] = interpolate_1d(z_inp_sound_tmp.dataPtr(), V_inp_sound_tmp.dataPtr(), ztop, Ninp);
220  }
221 
222  amrex::Print() << "Successfully read the " << itime << "th input_sounding file..." << std::endl;
223  input_sounding_reader.close();
224 
225  host_to_device(itime);
226  }
227 
228  /**
229  * @brief Hydrostatically integrate density and pressure for one sounding.
230  * @param itime Sounding time/file index to integrate.
231  */
232  void calc_rho_p (int itime)
233  {
234  /* Calculate density and pressure, roughly following the procedure in
235  * WRF dyn_em/module_initialize_ideal.F. We integrate hydrostatically
236  * from the surface up through the air column to get the dry density
237  * and moist pressure.
238  */
239  const int Ninp = size(itime);
240  pm_integ.resize(Ninp);
241  rhod_integ.resize(Ninp);
242 
243  // evaluate surface quantities (k=0): total pressure and dry air
247  RdoCp,
249 
250  amrex::Print() << "ideal sounding init: surface dry air density = "
251  << std::setprecision(15)
252  << rhod_integ[0] << " kg/m^3" << std::endl;
253 
254  // Note:
255  // p_dry = rho_d R_d T
256  // p_tot = rho_m R_d T_v
257  // = rho_d(1 + q_v) R_d T_v
258 
259 #if 0 // Printing
260  // In this absence of moisture, this moist profile will match the
261  // following dry profile
262  amrex::Print() << "z p_m rho_d theta qv U V" << std::endl;
263  amrex::Print() << z_inp_sound[itime][0]
264  << " " << pm_integ[0]
265  << " " << rhod_integ[0]
266  << " " << theta_inp_sound[itime][0]
267  << " " << qv_inp_sound[itime][0]
268  << " " << U_inp_sound[itime][0]
269  << " " << V_inp_sound[itime][0]
270  << std::endl;
271 #endif
272 
273  // integrate from surface to domain top
274  amrex::Real dz, F, C;
275  amrex::Real T_hi;
276  amrex::Real rho_tot_hi, rho_tot_lo;
277  for (int k=1; k < size(itime); ++k)
278  {
279  // Vertical grid spacing
280  dz = z_inp_sound[itime][k] - z_inp_sound[itime][k-1];
281 
282  // The Newton residual F below is a pressure, so the tolerance it is
283  // tested against has to be scaled to the pressure being solved for.
284  // The iterate cannot do better than settle into a one-ulp limit
285  // cycle about the true root, which puts a hard floor of roughly
286  // ulp(p) on |F| -- 3.6e-12 for a 1.6e4 Pa pressure in double, and
287  // ~1e-2 Pa at 1e5 Pa in single. The fixed 1e-12 Pa tolerance used
288  // here previously sat below that floor, so the iteration burned all
289  // of its allowed passes and reported a spurious non-convergence
290  // warning for a column that had in fact converged to roundoff.
291 #ifdef AMREX_USE_FLOAT
292  const amrex::Real tol = amrex::Real(4)
294  * pm_integ[k-1];
295 #else
296  const amrex::Real tol = amrex::Real(1.0e-12);
297 #endif
298 
299  // Establish known constant
300  rho_tot_lo = rhod_integ[k-1] * (one + qv_inp_sound[itime][k-1]);
301  C = -pm_integ[k-1] + myhalf*rho_tot_lo*CONST_GRAV*dz;
302 
303  // Initial guess and residual
304  pm_integ[k] = pm_integ[k-1];
305  T_hi = getTgivenPandTh(pm_integ[k], theta_inp_sound[itime][k], RdoCp);
307  pm_integ[k],
308  RdoCp,
309  qv_inp_sound[itime][k]);
310  rho_tot_hi = rhod_integ[k] * (one + qv_inp_sound[itime][k]);
311  F = pm_integ[k] + myhalf*rho_tot_hi*CONST_GRAV*dz + C;
312 
313  // Do iterations
314  if (std::abs(F)>tol) {
315  bool maintain_Th = true;
317  CONST_GRAV, C, theta_inp_sound[itime][k], T_hi,
318  qv_inp_sound[itime][k], qv_inp_sound[itime][k],
319  pm_integ[k], rhod_integ[k], F, maintain_Th);
320  }
321 
322 #if 0 // Printing
323  amrex::Print() << z_inp_sound[itime][k]
324  << " " << pm_integ[k]
325  << " " << rhod_integ[k]
326  << " " << theta_inp_sound[itime][k]
327  << " " << qv_inp_sound[itime][k]
328  << " " << U_inp_sound[itime][k]
329  << " " << V_inp_sound[itime][k]
330  << std::endl;
331 #endif
332  }
333  // Note: at this point, the surface pressure, density of the dry air
334  // column is stored in pm_integ[0], rhod_integ[0]
335 
336  // update
337  host_to_device(itime);
338  }
339 
340  /**
341  * @brief Compute density and pressure for an isentropic sounding profile.
342  * @param itime Sounding time/file index to integrate.
343  */
344  void calc_rho_p_isentropic (int itime)
345  {
346  /* Calculate density and pressure assuming isentropic (constant theta)
347  background conditions. This does not use Newton-Raphson iterations
348  to calculate rho and p.
349  */
350  const int Ninp = size(itime);
351  pm_integ.resize(Ninp);
352  rhod_integ.resize(Ninp);
353 
354  // evaluate surface quantities (k=0): total pressure and dry air
358  RdoCp,
360 
361  const amrex::Real th0 = theta_ref_inp_sound;
362  const amrex::Real p0_pow = std::pow(p_0, (Gamma-1)/Gamma);
363 
364  amrex::Print() << "isentropic sounding init: surface dry air density = "
365  << std::setprecision(15)
366  << rhod_integ[0] << " kg/m^3" << std::endl;
367 
368 #if 0 // Printing
369  // In this absence of moisture, this moist profile will match the
370  // following dry profile
371  amrex::Print() << "z p_m rho_d theta qv U V" << std::endl;
372  amrex::Print() << z_inp_sound[itime][0]
373  << " " << pm_integ[0]
374  << " " << rhod_integ[0]
375  << " " << theta_inp_sound[itime][0]
376  << " " << qv_inp_sound[itime][0]
377  << " " << U_inp_sound[itime][0]
378  << " " << V_inp_sound[itime][0]
379  << std::endl;
380 #endif
381 
382  // integrate from surface to domain top
383  amrex::Real dz;
384  for (int k=1; k < size(itime); ++k)
385  {
386  // Vertical grid spacing
387  dz = z_inp_sound[itime][k] - z_inp_sound[itime][k-1];
388 
389  // Isentropic pressure at next level
390  amrex::Real qvmean = (assume_dry) ? zero : myhalf*(qv_inp_sound[itime][k-1] + qv_inp_sound[itime][k]);
391  amrex::Real thm0 = th0 * (one + RvoRd * qvmean);
392  amrex::Real plo_pow = std::pow(pm_integ[k-1], (Gamma-1)/Gamma);
393  pm_integ[k] = (Gamma-1)/Gamma *
394  (-CONST_GRAV * p0_pow / (R_d * thm0) * (1 + qvmean) * dz
395  + Gamma/(Gamma-1) * plo_pow);
396  pm_integ[k] = std::pow(pm_integ[k], Gamma / (Gamma-1));
397 
398  // Note: The pressure calculated here is copied to `p_inp_sound_d`
399  // and currently not used.
400 
401  // Get corresponding dry air density
403  pm_integ[k],
404  RdoCp,
405  qv_inp_sound[itime][k]);
406 
407 #if 0 // Printing
408  amrex::Print() << z_inp_sound[itime][k]
409  << " " << pm_integ[k]
410  << " " << rhod_integ[k]
411  << " " << theta_inp_sound[itime][k]
412  << " " << qv_inp_sound[itime][k]
413  << " " << U_inp_sound[itime][k]
414  << " " << V_inp_sound[itime][k]
415  << std::endl;
416 #endif
417  }
418  // Note: at this point, the surface pressure, density of the dry air
419  // column is stored in pm_integ[0], rhod_integ[0]
420 
421  // update
422  host_to_device(itime);
423  }
424 
425  /**
426  * @brief Copy host sounding arrays for one time index to device storage.
427  * @param itime Sounding time/file index to copy.
428  */
429  void host_to_device (int itime)
430  {
431  const int Ninp = size(itime);
432  z_inp_sound_d[itime].resize(Ninp);
433  theta_inp_sound_d[itime].resize(Ninp);
434  qv_inp_sound_d[itime].resize(Ninp);
435  U_inp_sound_d[itime].resize(Ninp);
436  V_inp_sound_d[itime].resize(Ninp);
437 
438  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
439  z_inp_sound[itime].begin(), z_inp_sound[itime].end(),
440  z_inp_sound_d[itime].begin());
441  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
442  theta_inp_sound[itime].begin(), theta_inp_sound[itime].end(),
443  theta_inp_sound_d[itime].begin());
444  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
445  qv_inp_sound[itime].begin(), qv_inp_sound[itime].end(),
446  qv_inp_sound_d[itime].begin());
447  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
448  U_inp_sound[itime].begin(), U_inp_sound[itime].end(),
449  U_inp_sound_d[itime].begin());
450  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
451  V_inp_sound[itime].begin(), V_inp_sound[itime].end(),
452  V_inp_sound_d[itime].begin());
453 
454  if (rhod_integ.size() > 0)
455  {
456  //amrex::Print() << "Copying rho_d, p_d to device" << std::endl;
457  rho_inp_sound_d.resize(size(itime)+2);
458  p_inp_sound_d.resize(size(itime)+2);
459  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
460  rhod_integ.begin(), rhod_integ.end(),
461  rho_inp_sound_d.begin());
462  amrex::Gpu::copy(amrex::Gpu::hostToDevice,
463  pm_integ.begin(), pm_integ.end(),
464  p_inp_sound_d.begin());
465  }
466  }
467 
468  /**
469  * @brief Return the number of interpolated samples for one sounding time.
470  * @param itime Sounding time/file index to query.
471  * @return Number of stored sounding profile levels.
472  */
473  int size (int itime) const
474  {
476  AMREX_ALWAYS_ASSERT(z_inp_sound[itime].size() == qv_inp_sound[itime].size());
477  AMREX_ALWAYS_ASSERT(z_inp_sound[itime].size() == U_inp_sound[itime].size());
478  AMREX_ALWAYS_ASSERT(z_inp_sound[itime].size() == V_inp_sound[itime].size());
479  return z_inp_sound[itime].size();
480  }
481 
482  void set_start_time(amrex::Real start_time)
483  {
484  for (int i = 0; i < n_sounding_times; i++)
485  {
486  input_sounding_time[i] += start_time;
487  }
488  }
489 
490  // Members
491  int ntimes;
492 
493  amrex::Real tau_nudging = amrex::Real(5.0); // time scale used for nudging
494 
495  amrex::Vector<std::string> input_sounding_file = {};
496  amrex::Vector<amrex::Real> input_sounding_time = {};
499 
500  bool assume_dry{false};
501 
502  // - read from file
504 
505  // This is a vector (over time) of Vectors
506  amrex::Vector<amrex::Vector<amrex::Real>> z_inp_sound, theta_inp_sound, qv_inp_sound, U_inp_sound, V_inp_sound;
507 
508  // This is a vector (over time) of DeviceVectors
509  amrex::Vector<amrex::Gpu::DeviceVector<amrex::Real>> z_inp_sound_d, theta_inp_sound_d, qv_inp_sound_d, U_inp_sound_d, V_inp_sound_d;
510 
511  // - moist profiles
512  amrex::Vector<amrex::Real> pm_integ; // from integrating up air column
513  // - dry profiles
514  amrex::Vector<amrex::Real> rhod_integ; // from integrating down air column
515  // - to set solution fields
516  amrex::Gpu::DeviceVector<amrex::Real> p_inp_sound_d, rho_inp_sound_d;
517 };
518 
519 /**
520  * @var InputSoundingData::ntimes
521  * @brief Number of sounding times represented in the arrays.
522  * @var InputSoundingData::tau_nudging
523  * @brief Nudging time scale for relaxing toward input sounding data.
524  * @var InputSoundingData::input_sounding_file
525  * @brief Sounding file path for each configured sounding time.
526  * @var InputSoundingData::input_sounding_time
527  * @brief Physical time associated with each input sounding file.
528  * @var InputSoundingData::n_sounding_files
529  * @brief Number of input sounding files.
530  * @var InputSoundingData::n_sounding_times
531  * @brief Number of input sounding times.
532  * @var InputSoundingData::assume_dry
533  * @brief Whether to ignore moisture in isentropic pressure integration.
534  * @var InputSoundingData::press_ref_inp_sound
535  * @brief Surface reference pressure read from the input sounding [Pa].
536  * @var InputSoundingData::theta_ref_inp_sound
537  * @brief Surface reference potential temperature read from the input sounding [K].
538  * @var InputSoundingData::qv_ref_inp_sound
539  * @brief Surface reference water vapor mixing ratio read from the input sounding [kg/kg].
540  * @var InputSoundingData::z_inp_sound
541  * @brief Interpolated host sounding heights for each sounding time [m].
542  * @var InputSoundingData::theta_inp_sound
543  * @brief Interpolated host potential temperature profiles [K].
544  * @var InputSoundingData::qv_inp_sound
545  * @brief Interpolated host water vapor mixing ratio profiles [kg/kg].
546  * @var InputSoundingData::U_inp_sound
547  * @brief Interpolated host x velocity profiles.
548  * @var InputSoundingData::V_inp_sound
549  * @brief Interpolated host y velocity profiles.
550  * @var InputSoundingData::z_inp_sound_d
551  * @brief Device sounding heights for each sounding time [m].
552  * @var InputSoundingData::theta_inp_sound_d
553  * @brief Device potential temperature profiles [K].
554  * @var InputSoundingData::qv_inp_sound_d
555  * @brief Device water vapor mixing ratio profiles [kg/kg].
556  * @var InputSoundingData::U_inp_sound_d
557  * @brief Device x velocity profiles.
558  * @var InputSoundingData::V_inp_sound_d
559  * @brief Device y velocity profiles.
560  * @var InputSoundingData::pm_integ
561  * @brief Hydrostatically integrated moist pressure profile.
562  * @var InputSoundingData::rhod_integ
563  * @brief Hydrostatically integrated dry density profile.
564  * @var InputSoundingData::p_inp_sound_d
565  * @brief Device pressure profile used to initialize solution fields.
566  * @var InputSoundingData::rho_inp_sound_d
567  * @brief Device density profile used to initialize solution fields.
568  */
569 #endif
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real p_0
Definition: ERF_Constants.H:61
constexpr amrex::Real RvoRd
Definition: ERF_Constants.H:56
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
constexpr amrex::Real RdoCp
Definition: ERF_Constants.H:54
constexpr amrex::Real Gamma
Definition: ERF_Constants.H:62
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhogivenThetaPress(const amrex::Real th, const amrex::Real p, const amrex::Real rdOcp, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:96
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenPandTh(const amrex::Real P, const amrex::Real th, const amrex::Real rdOcp)
Definition: ERF_EOS.H:32
const Real ztop
Definition: ERF_InitCustomPertVels_ParticleTests.H:4
ParmParse pp("prob")
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real interpolate_1d(const amrex::Real *alpha, const amrex::Real *beta, const amrex::Real alpha_interp, const int alpha_size)
Definition: ERF_Interpolation_1D.H:14
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void Newton_Raphson_hse(const Real &m_tol, const Real &RdoCp, const Real &dz, const Real &g, const Real &C, const Real &Th, const Real &T, const Real &qt, const Real &qv, Real &P, Real &rd, Real &F, const bool &maintain_Th)
Definition: ERF_HSEUtils.H:44
@ theta
Definition: ERF_SLM.H:20
@ qv
Definition: ERF_Kessler.H:30
@ U
Definition: ERF_IndexDefines.H:126
@ V
Definition: ERF_IndexDefines.H:127
@ dz
Definition: ERF_AdvanceWDM6.cpp:270
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
Definition: ERF_InputSoundingData.H:23
void host_to_device(int itime)
Copy host sounding arrays for one time index to device storage.
Definition: ERF_InputSoundingData.H:429
amrex::Gpu::DeviceVector< amrex::Real > rho_inp_sound_d
Device density profile used to initialize solution fields.
Definition: ERF_InputSoundingData.H:516
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > qv_inp_sound_d
Device water vapor mixing ratio profiles [kg/kg].
Definition: ERF_InputSoundingData.H:509
amrex::Vector< amrex::Vector< amrex::Real > > V_inp_sound
Interpolated host y velocity profiles.
Definition: ERF_InputSoundingData.H:506
amrex::Vector< amrex::Real > pm_integ
Hydrostatically integrated moist pressure profile.
Definition: ERF_InputSoundingData.H:512
amrex::Real qv_ref_inp_sound
Surface reference water vapor mixing ratio read from the input sounding [kg/kg].
Definition: ERF_InputSoundingData.H:503
amrex::Vector< amrex::Real > input_sounding_time
Physical time associated with each input sounding file.
Definition: ERF_InputSoundingData.H:496
void resize_arrays()
Resize host and device sounding arrays for the configured sounding times.
Definition: ERF_InputSoundingData.H:67
bool assume_dry
Whether to ignore moisture in isentropic pressure integration.
Definition: ERF_InputSoundingData.H:500
int n_sounding_times
Number of input sounding times.
Definition: ERF_InputSoundingData.H:498
amrex::Vector< amrex::Vector< amrex::Real > > theta_inp_sound
Interpolated host potential temperature profiles [K].
Definition: ERF_InputSoundingData.H:506
amrex::Vector< amrex::Real > rhod_integ
Hydrostatically integrated dry density profile.
Definition: ERF_InputSoundingData.H:514
void set_start_time(amrex::Real start_time)
Definition: ERF_InputSoundingData.H:482
void calc_rho_p(int itime)
Hydrostatically integrate density and pressure for one sounding.
Definition: ERF_InputSoundingData.H:232
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > V_inp_sound_d
Device y velocity profiles.
Definition: ERF_InputSoundingData.H:509
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > z_inp_sound_d
Device sounding heights for each sounding time [m].
Definition: ERF_InputSoundingData.H:509
void calc_rho_p_isentropic(int itime)
Compute density and pressure for an isentropic sounding profile.
Definition: ERF_InputSoundingData.H:344
int ntimes
Number of sounding times represented in the arrays.
Definition: ERF_InputSoundingData.H:491
void read_from_file(const amrex::Geometry &geom, const amrex::Vector< amrex::Real > &zlevels_stag, int itime, bool is_moist)
Read and interpolate one input sounding profile onto level-0 heights.
Definition: ERF_InputSoundingData.H:91
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > theta_inp_sound_d
Device potential temperature profiles [K].
Definition: ERF_InputSoundingData.H:509
amrex::Vector< amrex::Vector< amrex::Real > > U_inp_sound
Interpolated host x velocity profiles.
Definition: ERF_InputSoundingData.H:506
amrex::Real theta_ref_inp_sound
Surface reference potential temperature read from the input sounding [K].
Definition: ERF_InputSoundingData.H:503
amrex::Vector< std::string > input_sounding_file
Sounding file path for each configured sounding time.
Definition: ERF_InputSoundingData.H:495
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > U_inp_sound_d
Device x velocity profiles.
Definition: ERF_InputSoundingData.H:509
amrex::Gpu::DeviceVector< amrex::Real > p_inp_sound_d
Device pressure profile used to initialize solution fields.
Definition: ERF_InputSoundingData.H:516
amrex::Vector< amrex::Vector< amrex::Real > > z_inp_sound
Interpolated host sounding heights for each sounding time [m].
Definition: ERF_InputSoundingData.H:506
amrex::Vector< amrex::Vector< amrex::Real > > qv_inp_sound
Interpolated host water vapor mixing ratio profiles [kg/kg].
Definition: ERF_InputSoundingData.H:506
amrex::Real tau_nudging
Nudging time scale for relaxing toward input sounding data.
Definition: ERF_InputSoundingData.H:493
InputSoundingData()
Construct input sounding metadata from the ERF input namespace.
Definition: ERF_InputSoundingData.H:28
amrex::Real press_ref_inp_sound
Surface reference pressure read from the input sounding [Pa].
Definition: ERF_InputSoundingData.H:503
int size(int itime) const
Return the number of interpolated samples for one sounding time.
Definition: ERF_InputSoundingData.H:473
int n_sounding_files
Number of input sounding files.
Definition: ERF_InputSoundingData.H:497