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 }
Real T
Definition: ERF_InitCustomPert_Bubble.H:106
RH
Definition: ERF_InitCustomPert_Bubble.H:108
amrex::Real gamma
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:9
amrex::Real Real
Definition: ERF_ShocInterface.H:19

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_AdvanceWSM6.cpp:104

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 #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 }
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

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
rho
Definition: ERF_InitCustomPert_Bubble.H:107
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

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

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) 
)
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 }
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:166
@ 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