ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
HSEutils Namespace Reference

Functions

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)
 
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)
 
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)
 
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)
 
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_saturation_pressure (const Real T_b, const bool use_empirical)
 
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)
 
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)
 
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)
 
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)
 
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_dewpoint_temperature (const Real T_b, const Real RH)
 
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)
 
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)
 
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)
 
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)
 
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))
 

Variables

const int MAX_ITER = 10
 
const amrex::Real TOL = Real(1.e-8)
 

Detailed Description

Utility functions for calculating a hydrostatic equilibrium (HSE) base state

Function Documentation

◆ compute_dewpoint_temperature()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::compute_dewpoint_temperature ( const Real  T_b,
const Real  RH 
)
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 }
amrex::Real gamma
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:9
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ T
Definition: ERF_IndexDefines.H:128

Referenced by compute_rho().

Here is the caller graph for this function:

◆ compute_F()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::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 
)
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 }
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
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_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
@ dz
Definition: ERF_AdvanceWDM6.cpp:270

Referenced by compute_p_k_in_zone().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_F_for_temp_in_zone()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::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 
)
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 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:49
constexpr amrex::Real p_0
Definition: ERF_Constants.H:61
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
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_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_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_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

Referenced by compute_temperature().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_p_k_in_zone()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::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 
)
607 {
608  Real delta_p_k;
609 
610  // Perturbation used to form the difference quotient for dF/dp. It has to
611  // be scaled by p_k rather than fixed in Pa: the pressures here are O(1e5),
612  // and in single precision one ulp at that magnitude is already ~1e-2 Pa,
613  // so a fixed 1e-4 Pa perturbation rounds away entirely -- p_k + eps == p_k,
614  // the difference quotient is zero, and the iteration returns NaN. The
615  // double-precision perturbation is left exactly as it was so that results
616  // in double are unchanged.
617 #ifdef AMREX_USE_FLOAT
618  Real eps = Real(1.e-5) * std::abs(p_k);
619 #else
620  Real eps = Real(1e-10);
621 #endif
622 
623  for(int iter=0; iter<20; iter++)
624  {
625  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,
626  q_t, eq_pot_temp, use_empirical, which_zone, scaled_height, T_from_theta,
628  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,
629  q_t, eq_pot_temp, use_empirical, which_zone, scaled_height, T_from_theta,
631  Real F_prime = (F_plus_dF - F)/eps;
632  delta_p_k = -F/F_prime;
633  p_k = p_k + delta_p_k;
634  }
635 
636  // Convergence is measured on the last Newton step relative to p_k, for the
637  // same reason: an absolute tolerance in Pa that is smaller than an ulp of
638  // p_k can never be met in single precision. The double-precision value is
639  // set so that p_rel_tol * p_k reproduces the previous absolute tolerance of
640  // 1e-8 at the O(1e5) Pa pressures this is used at.
641 #ifdef AMREX_USE_FLOAT
642  const Real p_rel_tol = Real(1.e-5);
643 #else
644  const Real p_rel_tol = Real(1.e-13);
645 #endif
646  if (std::fabs(delta_p_k) > p_rel_tol * std::abs(p_k)) {
647  amrex::Abort("Newton Raphson for pressure could not converge");
648  }
649 
650  return p_k;
651 }
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

Referenced by init_isentropic_hse_no_terrain().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_relative_humidity()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::compute_relative_humidity ( const Real  p_b,
const Real  T_b,
const bool  use_empirical,
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 }
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14
constexpr amrex::Real RdoRv
Definition: ERF_Constants.H:57

Referenced by compute_F_for_temp_in_zone(), compute_rho(), and ParallelFor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_rho()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void HSEutils::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 
)
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 }
constexpr amrex::Real RdoCp
Definition: ERF_Constants.H:54
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 getTgivenPandTh(const amrex::Real P, const amrex::Real th, const amrex::Real rdOcp)
Definition: ERF_EOS.H:32
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real compute_dewpoint_temperature(const Real T_b, const Real RH)
Definition: ERF_HSEUtils.H:519
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_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
@ rho
Definition: ERF_Kessler.H:24

Referenced by compute_F().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_saturation_pressure()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::compute_saturation_pressure ( const Real  T_b,
const bool  use_empirical 
)
435 {
436  Real p_s = erf_esatw(T_b,use_empirical);
437  return p_s * Real(100.0);
438 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:123

Referenced by compute_F_for_temp_in_zone(), compute_relative_humidity(), and vapor_mixing_ratio().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_temperature()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::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 
)
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 }
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
const amrex::Real TOL
Definition: ERF_HSEUtils.H:21

Referenced by compute_rho(), and ShocPDF::diagnose_pdf().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_theta()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::compute_theta ( const Real  scaled_height,
const Real  theta_0,
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 }

Referenced by compute_rho().

Here is the caller graph for this function:

◆ init_isentropic_hse_constant_dz()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void HSEutils::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 
)

Function to calculate the hydrostatic density and pressure with constant dz

Parameters
[in]r_sfcsurface density
[in]thetasurface potential temperature
[out]rhydrostatically balanced density profile
[out]phydrostatically balanced pressure profile
[in]dzvertical grid spacing (constant)
[in]kloz-index corresponding to the small end of the domain
[in]khiz-index corresponding to the big end of the domain
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  }
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 getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
const int khi
Definition: ERF_InitCustomPert_Bubble.H:21
const int MAX_ITER
Definition: ERF_HSEUtils.H:17
@ p
Definition: ERF_WSM6.H:191

Referenced by erf_init_dens_hse_dry().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_isentropic_hse_no_terrain()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void HSEutils::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) 
)

Initialize an isentropic hydrostatic equilibrium base state without terrain.

Parameters
[out]thetaPotential temperature profile.
[out]rDensity profile.
[out]pPressure profile.
[out]q_vWater vapor mixing ratio profile.
[in]dzVertical grid spacing.
[in]khiTop index of the domain.
[in]q_tTotal water mixing ratio.
[in]eq_pot_tempEquilibrium potential temperature.
[in]use_empiricalUse empirical saturation formulas.
[in]T_from_thetaWhether temperature is derived from potential temperature.
[in]z_tr_1First transition height.
[in]z_tr_2Second transition height.
[in]theta_0Surface potential temperature.
[in]theta_trPotential temperature at transition height.
[in]T_trTemperature at transition height.
681 {
682  Real T_b, T_dp;
683 
684  int which_zone = -1;
685  Real scaled_height = amrex::Real(0);
686 
687  // Compute the quantities at z = myhalf*dz (first cell center)
688  p[0] = p_0;
689  if (z_tr_1 > amrex::Real(0)) {
690  Real z = myhalf * dz;
691  if (z <= z_tr_1) {
692  which_zone = 1;
693  } else if (z <= z_tr_2) {
694  which_zone = 2;
695  } else {
696  which_zone = 3;
697  }
698  scaled_height = z/z_tr_2;
699  }
700 
701  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,
702  use_empirical, which_zone, scaled_height, T_from_theta,
703  theta_0, theta_tr, z_tr_2, T_tr);
704 
705  for (int k=1; k<=khi; k++)
706  {
707  p[k] = p[k-1];
708 
709  if (z_tr_1 > amrex::Real(0)) {
710  Real z = (k+myhalf) * dz;
711  if (z <= z_tr_1) {
712  which_zone = 1;
713  } else if (z <= z_tr_2) {
714  which_zone = 2;
715  } else {
716  which_zone = 3;
717  }
718  scaled_height = z/z_tr_2;
719  }
720 
721  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,
722  use_empirical, which_zone, scaled_height, T_from_theta,
723  theta_0, theta_tr, z_tr_2, T_tr);
724  }
725 
726  r[khi+1] = r[khi];
727 }
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

Referenced by erf_init_dens_hse_moist(), and if().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_isentropic_hse_stretched_dz()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void HSEutils::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 
)

Function to calculate the hydrostatic density and pressure with stretched dz

Parameters
[in]r_sfcsurface density
[in]thetasurface potential temperature
[out]rhydrostatically balanced density profile
[out]phydrostatically balanced pressure profile
[in]stretched_dzvertical grid spacing (stretched)
[in]kloz-index corresponding to the small end of the domain
[in]khiz-index corresponding to the big end of the domain
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  }

Referenced by erf_init_dens_hse_dry().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ init_isentropic_hse_terrain()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void HSEutils::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 
)

Function to calculate the hydrostatic density and pressure over terrain

Parameters
[in]ix-index
[in]jy-index
[in]r_sfcsurface density
[in]thetasurface potential temperature
[out]rhydrostatically balanced density profile
[out]phydrostatically balanced pressure profile
[in]z_cccell-center heights
[in]khiz-index corresponding to the big end of the domain
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  }

Referenced by erf_init_dens_hse_dry().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Newton_Raphson_hse()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void HSEutils::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 
)

Function to calculate the hydrostatic density and pressure from Newton-Raphson iterations at constant Th & Qv

Parameters
[in]m_toliteration tolerance
[in]RdOCpRd/Cp
[out]dzchange in vertical height
[out]gmagnitude of gravity
[in]Csum of known terms in HSE balance
[in]Ththeta at the current cell center
[in]qttotal moisture (non-precip and precip)
[in]qvwater vapor
[in]Ppressure at cell center
[in]rddry density at cell center
[in]Fstarting residual of non-linear eq
[in]maintain_Thmaintain theta or temperature?
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  }
constexpr amrex::Real iGamma
Definition: ERF_Constants.H:69
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_ALWAYS_ASSERT(bx.length()[2]==khi+1)
@ P
Definition: ERF_IndexDefines.H:204
@ qt
Definition: ERF_Kessler.H:29
@ qv
Definition: ERF_Kessler.H:30
real(c_double), parameter g
Definition: ERF_module_model_constants.F90:19

Referenced by InputSoundingData::calc_rho_p(), and rebalance_columns().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ vapor_mixing_ratio()

AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE Real HSEutils::vapor_mixing_ratio ( const Real  p_b,
const Real  T_b,
const Real  RH,
const bool  use_empirical,
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 }

Referenced by compute_F_for_temp_in_zone(), sea_level_pressure_diagnostics::compute_from_erf_lowest_level_state(), compute_rho(), sea_level_pressure_diagnostics::fill_sea_level_pressure(), if(), ParallelFor(), and sea_level_pressure_diagnostics::specific_humidity_from_dry_mixing_ratio().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ MAX_ITER

◆ TOL