ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_HSEUtils.H
Go to the documentation of this file.
1 #ifndef ERF_HSEUTIL_H_
2 #define ERF_HSEUTIL_H_
3 
5 #include "ERF_Constants.H"
6 #include "ERF_EOS.H"
7 
8 /**
9  * Utility functions for calculating a hydrostatic equilibrium (HSE) base state
10 */
11 
12 namespace HSEutils
13 {
14  using namespace amrex;
15 
16  // to control Newton iterations in init_isentropic_hse*
17  const int MAX_ITER = 10;
18 #ifdef AMREX_USE_FLOAT
19  const amrex::Real TOL = Real(1.e-4);
20 #else
21  const amrex::Real TOL = Real(1.e-8);
22 #endif
23 
24  /**
25  * Function to calculate the hydrostatic density and pressure
26  * from Newton-Raphson iterations at constant Th & Qv
27  *
28  * @param[in] m_tol iteration tolerance
29  * @param[in] RdOCp Rd/Cp
30  * @param[out] dz change in vertical height
31  * @param[out] g magnitude of gravity
32  * @param[in] C sum of known terms in HSE balance
33  * @param[in] Th theta at the current cell center
34  * @param[in] qt total moisture (non-precip and precip)
35  * @param[in] qv water vapor
36  * @param[in] P pressure at cell center
37  * @param[in] rd dry density at cell center
38  * @param[in] F starting residual of non-linear eq
39  * @param[in] maintain_Th maintain theta or temperature?
40  */
41  AMREX_GPU_HOST_DEVICE
42  AMREX_FORCE_INLINE
43  void
44  Newton_Raphson_hse (const Real& m_tol,
45  const Real& RdoCp,
46  const Real& dz,
47  const Real& g,
48  const Real& C,
49  const Real& Th,
50  const Real& T,
51  const Real& qt,
52  const Real& qv,
53  Real& P,
54  Real& rd,
55  Real& F,
56  const bool& maintain_Th)
57  {
58  // A non-finite residual (or a non-positive initial guess) would make the
59  // convergence test below evaluate to false on the very first pass, so we
60  // would silently return the initial guess and leave, e.g., an all-zero
61  // base state. Trap that here rather than propagating it downstream.
62  if (!(P > amrex::Real(0)) || !(rd > amrex::Real(0)) || !std::isfinite(F)) {
63  AMREX_DEVICE_PRINTF("ERROR: HSE Newton started from an invalid state: P = %e, rd = %e, F = %e\n",
64  double(P), double(rd), double(F));
65  AMREX_DEVICE_PRINTF(" Check the surface pressure/temperature used to seed the integration%s\n", "");
66  }
67  AMREX_ALWAYS_ASSERT(P > amrex::Real(0) && rd > amrex::Real(0) && std::isfinite(F));
68 
69  int iter=0;
70  int max_iter=20;
71  // Written as !(|F| <= tol) so that a NaN residual enters the loop instead
72  // of being mistaken for convergence
73  while (!(std::abs(F)<=m_tol) && iter<max_iter) {
74  // Compute change in pressure
75  Real dRdP = (maintain_Th) ? iGamma * rd / P : rd / P;
76  Real dFdp = one + myhalf*dRdP*g*dz;
77  P -= F/dFdp;
78  if (P < Real(1.e3)) amrex::Warning("P < 1000 [Pa]; Domain height may be too large...");
80 
81  // Diagnose density and residual
82  rd = (maintain_Th) ? getRhogivenThetaPress(Th, P, RdoCp, qv) :
85  Real r_tot = rd * (one + qt);
86  F = P + myhalf*r_tot*g*dz + C;
87  ++iter;
88  }
89  if (iter>=max_iter) {
90  AMREX_DEVICE_PRINTF("WARNING: HSE Newton iterations did not converge to tolerance!\n%s", "");
91  AMREX_DEVICE_PRINTF("HSE Newton tol: %e %e\n",F,m_tol);
92  }
93  }
94 
95  /**
96  * Function to calculate the hydrostatic density and pressure with constant dz
97  *
98  * @param[in] r_sfc surface density
99  * @param[in] theta surface potential temperature
100  * @param[out] r hydrostatically balanced density profile
101  * @param[out] p hydrostatically balanced pressure profile
102  * @param[in] dz vertical grid spacing (constant)
103  * @param[in] klo z-index corresponding to the small end of the domain
104  * @param[in] khi z-index corresponding to the big end of the domain
105  */
106  AMREX_GPU_HOST_DEVICE
107  AMREX_FORCE_INLINE
108  void
110  const amrex::Real& theta,
111  amrex::Real* r,
112  amrex::Real* p,
113  const amrex::Real& dz,
114  const int klo, const int khi)
115  {
116  int kstart;
117 
118  // r_sfc / p_0 are the density / pressure at klo
119 
120  // Initial guess
121  Real myhalf_dz = myhalf*dz;
122  r[klo] = r_sfc;
123  p[klo] = p_0 - myhalf_dz * r[klo] * CONST_GRAV;
124 
125  if (klo == 0)
126  {
127  kstart = 1;
128 
129  // We do a Newton iteration to satisfy the EOS & HSE (with constant theta)
130  bool converged_hse = false;
131  Real p_hse;
132  Real p_eos;
133 
134  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
135  {
136  p_hse = p_0 - myhalf_dz * r[klo] * CONST_GRAV;
137  p_eos = getPgivenRTh(r[klo]*theta);
138 
139  Real A = p_hse - p_eos;
140 
141  Real dpdr = getdPdRgivenConstantTheta(r[klo],theta);
142 
143  Real drho = A / (dpdr + myhalf_dz * CONST_GRAV);
144 
145  r[klo] = r[klo] + drho;
146  p[klo] = getPgivenRTh(r[klo]*theta);
147 
148  if (std::abs(drho) < TOL)
149  {
150  converged_hse = true;
151  break;
152  }
153  }
154 
155  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << klo << std::endl;
156  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
157  } else {
158  kstart = klo; // because we need to solve for r[klo] here; r[klo-1] is what was passed in r_sfc
159  r[klo-1] = r_sfc; // r_sfc is really the interpolated density in the ghost cell in this case
160  p[klo-1] = getPgivenRTh(r[klo-1]*theta);
161  }
162 
163  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
164  for (int k = kstart; k <= khi; k++)
165  {
166  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
167  // to discretely satisfy HSE -- here we assume spatial_order = 2 -- we can generalize this later if needed
168  bool converged_hse = false;
169 
170  r[k] = r[k-1];
171 
172  Real p_eos = getPgivenRTh(r[k]*theta);
173  Real p_hse;
174 
175  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
176  {
177  Real r_avg = myhalf * (r[k-1]+r[k]);
178  p_hse = p[k-1] - dz * r_avg * CONST_GRAV;
179  p_eos = getPgivenRTh(r[k]*theta);
180 
181  Real A = p_hse - p_eos;
182 
183  Real dpdr = getdPdRgivenConstantTheta(r[k],theta);
184  // Gamma * p_0 * std::pow( (R_d * theta / p_0), Gamma) * std::pow(r[k], Gamma-one) ;
185 
186  Real drho = A / (dpdr + dz * CONST_GRAV);
187 
188  r[k] = r[k] + drho;
189  p[k] = getPgivenRTh(r[k]*theta);
190 
191  if (std::abs(drho) < TOL * r[k-1])
192  {
193  converged_hse = true;
194  // amrex::Print() << " converged " << std::endl;
195  break;
196  }
197  }
198 
199  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k << std::endl;
200  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
201  }
202  r[khi+1] = r[khi];
203  }
204 
205  /**
206  * Function to calculate the hydrostatic density and pressure with stretched dz
207  *
208  * @param[in] r_sfc surface density
209  * @param[in] theta surface potential temperature
210  * @param[out] r hydrostatically balanced density profile
211  * @param[out] p hydrostatically balanced pressure profile
212  * @param[in] stretched_dz vertical grid spacing (stretched)
213  * @param[in] klo z-index corresponding to the small end of the domain
214  * @param[in] khi z-index corresponding to the big end of the domain
215  */
216  AMREX_GPU_HOST_DEVICE
217  AMREX_FORCE_INLINE
218  void
220  const amrex::Real& theta,
221  amrex::Real* r,
222  amrex::Real* p,
223  const amrex::Real* stretched_dz,
224  const int klo, const int khi)
225  {
226  int kstart;
227 
228  // r_sfc / p_0 are the density / pressure at klo
229 
230  // Initial guess
231  r[klo] = r_sfc;
232  p[klo] = p_0 - myhalf*stretched_dz[klo] * r[klo] * CONST_GRAV;
233 
234  if (klo == 0)
235  {
236  kstart = 1;
237 
238  // We do a Newton iteration to satisfy the EOS & HSE (with constant theta)
239  bool converged_hse = false;
240  Real p_hse;
241  Real p_eos;
242 
243  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
244  {
245  p_hse = p_0 - myhalf*stretched_dz[klo] * r[klo] * CONST_GRAV;
246  p_eos = getPgivenRTh(r[klo]*theta);
247 
248  Real A = p_hse - p_eos;
249 
250  Real dpdr = getdPdRgivenConstantTheta(r[klo],theta);
251 
252  Real drho = A / (dpdr + myhalf*stretched_dz[klo] * CONST_GRAV);
253 
254  r[klo] = r[klo] + drho;
255  p[klo] = getPgivenRTh(r[klo]*theta);
256 
257  if (std::abs(drho) < TOL)
258  {
259  converged_hse = true;
260  break;
261  }
262  }
263 
264  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << klo << std::endl;
265  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
266  } else {
267  kstart = klo; // because we need to solve for r[klo] here; r[klo-1] is what was passed in r_sfc
268  r[klo-1] = r_sfc; // r_sfc is really the interpolated density in the ghost cell in this case
269  p[klo-1] = getPgivenRTh(r[klo-1]*theta);
270  }
271 
272  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
273  for (int k = kstart; k <= khi; k++)
274  {
275  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
276  // to discretely satisfy HSE -- here we assume spatial_order = 2 -- we can generalize this later if needed
277  bool converged_hse = false;
278 
279  r[k] = r[k-1];
280 
281  Real p_eos = getPgivenRTh(r[k]*theta);
282  Real p_hse;
283 
284  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
285  {
286  Real r_avg = myhalf * (r[k-1]+r[k]);
287  Real dz_avg = myhalf * (stretched_dz[k-1] + stretched_dz[k]);
288  p_hse = p[k-1] - dz_avg * r_avg * CONST_GRAV;
289  p_eos = getPgivenRTh(r[k]*theta);
290 
291  Real A = p_hse - p_eos;
292 
293  Real dpdr = getdPdRgivenConstantTheta(r[k],theta);
294  // Gamma * p_0 * std::pow( (R_d * theta / p_0), Gamma) * std::pow(r[k], Gamma-one) ;
295 
296  Real drho = A / (dpdr + dz_avg * CONST_GRAV);
297 
298  r[k] = r[k] + drho;
299  p[k] = getPgivenRTh(r[k]*theta);
300 
301  if (std::abs(drho) < TOL * r[k-1])
302  {
303  converged_hse = true;
304  // amrex::Print() << " converged " << std::endl;
305  break;
306  }
307  }
308 
309  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k << std::endl;
310  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
311  }
312  r[khi+1] = r[khi];
313  }
314 
315 
316  /**
317  * Function to calculate the hydrostatic density and pressure over terrain
318  *
319  * @param[in] i x-index
320  * @param[in] j y-index
321  * @param[in] r_sfc surface density
322  * @param[in] theta surface potential temperature
323  * @param[out] r hydrostatically balanced density profile
324  * @param[out] p hydrostatically balanced pressure profile
325  * @param[in] z_cc cell-center heights
326  * @param[in] khi z-index corresponding to the big end of the domain
327  */
328  AMREX_GPU_HOST_DEVICE
329  AMREX_FORCE_INLINE
330  void
332  int j,
333  const amrex::Real& r_sfc,
334  const amrex::Real& theta,
335  amrex::Real* r,
336  amrex::Real* p,
337  const amrex::Array4<amrex::Real const> z_cc,
338  const int& klo, const int& khi)
339  {
340  int kstart;
341 
342  if (klo == 0) {
343  //
344  // r_sfc / p_0 are the density / pressure at the surface
345  //
346  // Initial guess
347  int k0 = 0;
348 
349  // Where we start the lower iteration
350  kstart = 1;
351 
352  Real myhalf_dz = z_cc(i,j,k0);
353  r[k0] = r_sfc;
354  p[k0] = p_0 - myhalf_dz * r[k0] * CONST_GRAV;
355  {
356  // We do a Newton iteration to satisfy the EOS & HSE (with constant theta)
357  bool converged_hse = false;
358  Real p_hse;
359  Real p_eos;
360 
361  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
362  {
363  p_hse = p_0 - myhalf_dz * r[k0] * CONST_GRAV;
364  p_eos = getPgivenRTh(r[k0]*theta);
365 
366  Real A = p_hse - p_eos;
367 
368  Real dpdr = getdPdRgivenConstantTheta(r[k0],theta);
369 
370  Real drho = A / (dpdr + myhalf_dz * CONST_GRAV);
371 
372  r[k0] = r[k0] + drho;
373  p[k0] = getPgivenRTh(r[k0]*theta);
374 
375  if (std::abs(drho) < TOL)
376  {
377  converged_hse = true;
378  break;
379  }
380  }
381 
382  //if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k0 << std::endl;
383  //if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
384  }
385  } else {
386  kstart = klo; // because we need to solve for r[klo] here; r[klo-1] is what was passed in r_sfc
387  r[klo-1] = r_sfc; // r_sfc is really the interpolated density in the ghost cell in this case
388  p[klo-1] = getPgivenRTh(r[klo-1]*theta);
389  }
390 
391  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
392  for (int k = kstart; k <= khi; k++)
393  {
394  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
395  // to discretely satisfy HSE -- here we assume spatial_order = 2 -- we can generalize this later if needed
396  bool converged_hse = false;
397 
398  Real dz_loc = (z_cc(i,j,k) - z_cc(i,j,k-1));
399 
400  r[k] = r[k-1];
401 
402  Real p_eos = getPgivenRTh(r[k]*theta);
403  Real p_hse;
404 
405  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
406  {
407  p_hse = p[k-1] - dz_loc * myhalf * (r[k-1]+r[k]) * CONST_GRAV;
408  p_eos = getPgivenRTh(r[k]*theta);
409 
410  Real A = p_hse - p_eos;
411 
412  Real dpdr = getdPdRgivenConstantTheta(r[k],theta);
413 
414  Real drho = A / (dpdr + dz_loc * CONST_GRAV);
415 
416  r[k] = r[k] + drho;
417  p[k] = getPgivenRTh(r[k]*theta);
418 
419  if (std::abs(drho) < TOL * r[k-1])
420  {
421  converged_hse = true;
422  //amrex::Print() << " converged " << std::endl;
423  break;
424  }
425  }
426 
427  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k << std::endl;
428  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
429  }
430  }
431 
432 AMREX_FORCE_INLINE
433 AMREX_GPU_HOST_DEVICE
435 {
436  Real p_s = erf_esatw(T_b,use_empirical);
437  return p_s * Real(100.0);
438 }
439 
440 AMREX_FORCE_INLINE
441 AMREX_GPU_HOST_DEVICE
442 Real compute_relative_humidity (const Real p_b, const Real T_b, const bool use_empirical,
443  const int which_zone, const Real scaled_height)
444 {
445  if (which_zone > 0) {
446  if (which_zone == 1) { // z <= height
448  Real q_s = RdoRv*p_s/(p_b - p_s);
449  return Real(0.014)/q_s;
450  } else if (which_zone == 2) { // z > height and z <= z_tr; scaled_height = z/z_tr
451  return one - Real(0.75)*std::pow(scaled_height,Real(1.25));
452  } else { // z > z_tr
453  return fourth;
454  }
455  } else {
456  return one;
457  }
458 }
459 
460 AMREX_FORCE_INLINE
461 AMREX_GPU_HOST_DEVICE
462 Real vapor_mixing_ratio (const Real p_b, const Real T_b, const Real RH, const bool use_empirical,
463  int which_zone)
464 {
466  Real p_v = compute_vapor_pressure(p_s, RH);
467  Real q_v = RdoRv*p_v/(p_b - p_v);
468 
469  if (which_zone == 1) { // z <= height
470  return Real(0.014);
471  } else {
472  return q_v;
473  }
474 }
475 
476 AMREX_FORCE_INLINE
477 AMREX_GPU_HOST_DEVICE
478 Real compute_F_for_temp_in_zone(const Real T_b, const Real p_b, const Real q_t, const Real eq_pot_temp,
479  const bool use_empirical, const int which_zone, const Real scaled_height)
480 {
481  Real fac = Cp_d + Cp_l*q_t;
482  Real RH = compute_relative_humidity(p_b, T_b, use_empirical, which_zone, scaled_height);
483  Real q_v = vapor_mixing_ratio(p_b, T_b, RH, use_empirical, which_zone);
485  Real p_v = compute_vapor_pressure(p_s, RH);
486  return eq_pot_temp - T_b*std::pow((p_b - p_v)/p_0, -R_d/fac)*std::exp(L_v*q_v/(fac*T_b));
487 }
488 
489 AMREX_FORCE_INLINE
490 AMREX_GPU_HOST_DEVICE
491 Real compute_temperature (const Real p_b, const Real q_t, const Real eq_pot_temp, const bool use_empirical,
492  const int which_zone, const Real scaled_height)
493 {
494  Real T_b = Real(200.0), delta_T; // Initial guess
495 
496 #ifdef AMREX_USE_FLOAT
497  Real eps = Real(1.e-4) * T_b;
498 #else
499  Real eps = Real(1.e-10) * T_b;
500 #endif
501  for (int iter=0; iter<20; iter++)
502  {
503  Real F = compute_F_for_temp_in_zone(T_b , p_b, q_t, eq_pot_temp, use_empirical, which_zone, scaled_height);
504  Real F_plus_dF = compute_F_for_temp_in_zone(T_b+eps, p_b, q_t, eq_pot_temp, use_empirical, which_zone, scaled_height);
505  Real F_prime = (F_plus_dF - F)/eps;
506  delta_T = -F/F_prime;
507  T_b = T_b + delta_T;
508  }
509 
510  if (std::fabs(delta_T) > TOL * T_b) {
511  amrex::Abort("Newton Raphson for temperature could not converge");
512  }
513 
514  return T_b;
515 }
516 
517 AMREX_FORCE_INLINE
518 AMREX_GPU_HOST_DEVICE
520 {
521  Real T_dp, gamma, T;
522  T = T_b - Real(273.15);
523 
524  Real b = Real(18.678), c = Real(257.14), d = Real(234.5);
525  gamma = std::log(RH*std::exp((b - T/d)*T/(c + T)));
526 
527  T_dp = c*gamma/(b - gamma);
528 
529  return T_dp;
530 }
531 
532 AMREX_FORCE_INLINE
533 AMREX_GPU_HOST_DEVICE
534 Real compute_theta (const Real scaled_height, const Real theta_0,
535  const Real theta_tr, const Real z_tr, const Real T_tr)
536 {
537  if(scaled_height <= one) {
538  return theta_0 + (theta_tr - theta_0)*std::pow(scaled_height,Real(1.25));
539  } else {
540  return theta_tr*std::exp(CONST_GRAV/(Cp_d*T_tr)*z_tr*(scaled_height - one));
541  }
542 }
543 
544 AMREX_FORCE_INLINE
545 AMREX_GPU_HOST_DEVICE
546 void compute_rho (const Real& pressure, Real& theta, Real& rho, Real& q_v, Real& T_dp, Real& T_b,
547  const Real q_t, const Real eq_pot_temp, const bool use_empirical, const int which_zone,
548  const Real scaled_height, const bool T_from_theta,
549  const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
550 {
551 
552  if (T_from_theta) {
553  theta = compute_theta(scaled_height, theta_0, theta_tr, z_tr, T_tr);
554  T_b = getTgivenPandTh(pressure, theta, RdoCp);
555  } else {
556  T_b = compute_temperature(pressure, q_t, eq_pot_temp, use_empirical, which_zone, scaled_height);
557  theta = getThgivenTandP(T_b, pressure, RdoCp);
558  }
559 
560  Real RH = compute_relative_humidity(pressure, T_b, use_empirical, which_zone, scaled_height);
561 
562  q_v = vapor_mixing_ratio(pressure, T_b, RH, use_empirical, which_zone);
563 
564  rho = getRhogivenTandPress(T_b, pressure, q_v);
565 
566  if (T_from_theta) {
567  rho *= (one + q_v);
568  } else {
569  rho *= (one + q_t);
570  }
571 
572  T_dp = compute_dewpoint_temperature(T_b, RH);
573 }
574 
575 AMREX_FORCE_INLINE
576 AMREX_GPU_HOST_DEVICE
577 Real compute_F (const Real& p_k, const Real& p_k_minus_1, Real &theta_k, Real& rho_k, Real& q_v_k,
578  Real& T_dp, Real& T_b, const Real& dz, const Real& rho_k_minus_1, const Real q_t,
579  const Real eq_pot_temp, const bool use_empirical,
580  const int which_zone, const Real scaled_height, const bool T_from_theta,
581  const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
582 {
583  Real F;
584 
585  compute_rho(p_k, theta_k, rho_k, q_v_k, T_dp, T_b, q_t, eq_pot_temp, use_empirical, which_zone, scaled_height,
586  T_from_theta, theta_0, theta_tr, z_tr, T_tr);
587 
588  if(rho_k_minus_1 == amrex::Real(0)) // This loop is for the first point above the ground
589  {
590  F = p_k - p_k_minus_1 + rho_k*CONST_GRAV*dz/two;
591  }
592  else
593  {
594  F = p_k - p_k_minus_1 + myhalf * (rho_k + rho_k_minus_1)*CONST_GRAV*dz;
595  }
596 
597  return F;
598 }
599 
600 AMREX_FORCE_INLINE
601 AMREX_GPU_HOST_DEVICE
602 Real compute_p_k_in_zone (Real &p_k, const Real p_k_minus_1, Real &theta_k, Real& rho_k, Real& q_v_k,
603  Real& T_dp, Real& T_b, const Real dz, const Real rho_k_minus_1, const Real q_t,
604  const Real eq_pot_temp, const bool use_empirical,
605  const int which_zone, const Real scaled_height, const bool T_from_theta,
606  const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
607 {
608  Real delta_p_k;
609 
610 #ifdef AMREX_USE_FLOAT
611  Real eps = Real(1e-4);
612 #else
613  Real eps = Real(1e-10);
614 #endif
615 
616  for(int iter=0; iter<20; iter++)
617  {
618  Real F = compute_F(p_k , p_k_minus_1, theta_k, rho_k, q_v_k, T_dp, T_b, dz, rho_k_minus_1,
619  q_t, eq_pot_temp, use_empirical, which_zone, scaled_height, T_from_theta,
621  Real F_plus_dF = compute_F(p_k+eps, p_k_minus_1, theta_k, rho_k, q_v_k, T_dp, T_b, dz, rho_k_minus_1,
622  q_t, eq_pot_temp, use_empirical, which_zone, scaled_height, T_from_theta,
624  Real F_prime = (F_plus_dF - F)/eps;
625  delta_p_k = -F/F_prime;
626  p_k = p_k + delta_p_k;
627  }
628 
629  if (std::fabs(delta_p_k) > TOL) {
630  amrex::Abort("Newton Raphson for pressure could not converge");
631  }
632 
633  return p_k;
634 }
635 
636 AMREX_FORCE_INLINE
637 AMREX_GPU_HOST_DEVICE
638 void
640  const Real& dz, const int& khi, const Real q_t,
641  const Real eq_pot_temp, const bool use_empirical,
642  const bool T_from_theta = false,
643  const Real z_tr_1 = -one, const Real z_tr_2 = -one,
644  const Real theta_0 = amrex::Real(0), const Real theta_tr = amrex::Real(0), const Real T_tr = amrex::Real(0))
645 {
646  Real T_b, T_dp;
647 
648  int which_zone = -1;
649  Real scaled_height = amrex::Real(0);
650 
651  // Compute the quantities at z = myhalf*dz (first cell center)
652  p[0] = p_0;
653  if (z_tr_1 > amrex::Real(0)) {
654  Real z = myhalf * dz;
655  if (z <= z_tr_1) {
656  which_zone = 1;
657  } else if (z <= z_tr_2) {
658  which_zone = 2;
659  } else {
660  which_zone = 3;
661  }
662  scaled_height = z/z_tr_2;
663  }
664 
665  compute_p_k_in_zone(p[0], p_0, theta[0], r[0], q_v[0], T_dp, T_b, dz, amrex::Real(0), q_t, eq_pot_temp,
666  use_empirical, which_zone, scaled_height, T_from_theta,
667  theta_0, theta_tr, z_tr_2, T_tr);
668 
669  for (int k=1; k<=khi; k++)
670  {
671  p[k] = p[k-1];
672 
673  if (z_tr_1 > amrex::Real(0)) {
674  Real z = (k+myhalf) * dz;
675  if (z <= z_tr_1) {
676  which_zone = 1;
677  } else if (z <= z_tr_2) {
678  which_zone = 2;
679  } else {
680  which_zone = 3;
681  }
682  scaled_height = z/z_tr_2;
683  }
684 
685  compute_p_k_in_zone(p[k], p[k-1], theta[k], r[k], q_v[k], T_dp, T_b, dz, r[k-1], q_t, eq_pot_temp,
686  use_empirical, which_zone, scaled_height, T_from_theta,
687  theta_0, theta_tr, z_tr_2, T_tr);
688  }
689 
690  r[khi+1] = r[khi];
691 }
692 
693 } // namespace
694 
695 #endif
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:49
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real p_0
Definition: ERF_Constants.H:61
constexpr amrex::Real iGamma
Definition: ERF_Constants.H:69
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
constexpr amrex::Real Cp_l
Definition: ERF_Constants.H:51
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
constexpr amrex::Real L_v
Definition: ERF_Constants.H:59
constexpr amrex::Real RdoCp
Definition: ERF_Constants.H:54
constexpr amrex::Real RdoRv
Definition: ERF_Constants.H:57
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getdPdRgivenConstantTheta(const amrex::Real rho, const amrex::Real theta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:127
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 compute_vapor_pressure(const amrex::Real p_s, const amrex::Real RH)
Definition: ERF_EOS.H:181
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhogivenTandPress(const amrex::Real T, const amrex::Real p, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:113
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getThgivenTandP(const amrex::Real T, const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:18
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
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 int khi
Definition: ERF_InitCustomPert_Bubble.H:21
Real T
Definition: ERF_InitCustomPert_Bubble.H:106
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
RH
Definition: ERF_InitCustomPert_Bubble.H:108
rho
Definition: ERF_InitCustomPert_Bubble.H:107
amrex::Real gamma
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:9
Real eq_pot_temp
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:23
bool use_empirical
Definition: ERF_InitCustomPert_MultiSpeciesBubble.H:25
Real T_tr
Definition: ERF_InitCustomPert_SquallLine.H:43
Real q_t
Definition: ERF_InitCustomPert_SquallLine.H:24
Real theta_tr
Definition: ERF_InitCustomPert_SquallLine.H:47
Real theta_0
Definition: ERF_InitCustomPert_SquallLine.H:46
Real z_tr
Definition: ERF_InitCustomPert_SquallLine.H:36
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:123
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_HSEUtils.H:13
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void compute_rho(const Real &pressure, Real &theta, Real &rho, Real &q_v, Real &T_dp, Real &T_b, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const int which_zone, const Real scaled_height, const bool T_from_theta, const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
Definition: ERF_HSEUtils.H:546
const int MAX_ITER
Definition: ERF_HSEUtils.H:17
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_dewpoint_temperature(const Real T_b, const Real RH)
Definition: ERF_HSEUtils.H:519
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void init_isentropic_hse_stretched_dz(const amrex::Real &r_sfc, const amrex::Real &theta, amrex::Real *r, amrex::Real *p, const amrex::Real *stretched_dz, const int klo, const int khi)
Definition: ERF_HSEUtils.H:219
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real vapor_mixing_ratio(const Real p_b, const Real T_b, const Real RH, const bool use_empirical, int which_zone)
Definition: ERF_HSEUtils.H:462
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void init_isentropic_hse_constant_dz(const amrex::Real &r_sfc, const amrex::Real &theta, amrex::Real *r, amrex::Real *p, const amrex::Real &dz, const int klo, const int khi)
Definition: ERF_HSEUtils.H:109
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_saturation_pressure(const Real T_b, const bool use_empirical)
Definition: ERF_HSEUtils.H:434
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_p_k_in_zone(Real &p_k, const Real p_k_minus_1, Real &theta_k, Real &rho_k, Real &q_v_k, Real &T_dp, Real &T_b, const Real dz, const Real rho_k_minus_1, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const int which_zone, const Real scaled_height, const bool T_from_theta, const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
Definition: ERF_HSEUtils.H:602
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void init_isentropic_hse_no_terrain(Real *theta, Real *r, Real *p, Real *q_v, const Real &dz, const int &khi, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const bool T_from_theta=false, const Real z_tr_1=-one, const Real z_tr_2=-one, const Real theta_0=amrex::Real(0), const Real theta_tr=amrex::Real(0), const Real T_tr=amrex::Real(0))
Definition: ERF_HSEUtils.H:639
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_F_for_temp_in_zone(const Real T_b, const Real p_b, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const int which_zone, const Real scaled_height)
Definition: ERF_HSEUtils.H:478
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_temperature(const Real p_b, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const int which_zone, const Real scaled_height)
Definition: ERF_HSEUtils.H:491
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_relative_humidity(const Real p_b, const Real T_b, const bool use_empirical, const int which_zone, const Real scaled_height)
Definition: ERF_HSEUtils.H:442
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_F(const Real &p_k, const Real &p_k_minus_1, Real &theta_k, Real &rho_k, Real &q_v_k, Real &T_dp, Real &T_b, const Real &dz, const Real &rho_k_minus_1, const Real q_t, const Real eq_pot_temp, const bool use_empirical, const int which_zone, const Real scaled_height, const bool T_from_theta, const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
Definition: ERF_HSEUtils.H:577
const amrex::Real TOL
Definition: ERF_HSEUtils.H:21
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void init_isentropic_hse_terrain(int i, int j, const amrex::Real &r_sfc, const amrex::Real &theta, amrex::Real *r, amrex::Real *p, const amrex::Array4< amrex::Real const > z_cc, const int &klo, const int &khi)
Definition: ERF_HSEUtils.H:331
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
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_theta(const Real scaled_height, const Real theta_0, const Real theta_tr, const Real z_tr, const Real T_tr)
Definition: ERF_HSEUtils.H:534
@ theta
Definition: ERF_SLM.H:20
@ P
Definition: ERF_IndexDefines.H:166
@ qt
Definition: ERF_Kessler.H:29
@ qv
Definition: ERF_Kessler.H:30
@ p
Definition: ERF_WSM6.H:191
@ dz
Definition: ERF_AdvanceWSM6.cpp:104
Definition: ERF_ConsoleIO.cpp:15
real(c_double), parameter g
Definition: ERF_module_model_constants.F90:19