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 &T, const Real &qt, const Real &qv, Real &P, Real &rd, Real &F)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void init_isentropic_hse (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_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)
 

Variables

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

Detailed Description

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

Function Documentation

◆ init_isentropic_hse()

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

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]prob_lo_zsurface height
[in]khiz-index corresponding to the big end of the domain
95  {
96  int kstart;
97 
98  // r_sfc / p_0 are the density / pressure at klo
99 
100  // Initial guess
101  Real half_dz = 0.5*dz;
102  r[klo] = r_sfc;
103  p[klo] = p_0 - half_dz * r[klo] * CONST_GRAV;
104 
105  if (klo == 0)
106  {
107  kstart = 1;
108 
109  // We do a Newton iteration to satisfy the EOS & HSE (with constant theta)
110  bool converged_hse = false;
111  Real p_hse;
112  Real p_eos;
113 
114  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
115  {
116  p_hse = p_0 - half_dz * r[klo] * CONST_GRAV;
117  p_eos = getPgivenRTh(r[klo]*theta);
118 
119  Real A = p_hse - p_eos;
120 
121  Real dpdr = getdPdRgivenConstantTheta(r[klo],theta);
122 
123  Real drho = A / (dpdr + half_dz * CONST_GRAV);
124 
125  r[klo] = r[klo] + drho;
126  p[klo] = getPgivenRTh(r[klo]*theta);
127 
128  if (std::abs(drho) < TOL)
129  {
130  converged_hse = true;
131  break;
132  }
133  }
134 
135  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << klo << std::endl;
136  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
137  } else {
138  kstart = klo; // because we need to solve for r[klo] here; r[klo-1] is what was passed in r_sfc
139  r[klo-1] = r_sfc; // r_sfc is really the interpolated density in the ghost cell in this case
140  p[klo-1] = getPgivenRTh(r[klo-1]*theta);
141  }
142 
143  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
144  for (int k = kstart; k <= khi; k++)
145  {
146  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
147  // to discretely satisfy HSE -- here we assume spatial_order = 2 -- we can generalize this later if needed
148  bool converged_hse = false;
149 
150  r[k] = r[k-1];
151 
152  Real p_eos = getPgivenRTh(r[k]*theta);
153  Real p_hse;
154 
155  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
156  {
157  Real r_avg = 0.5 * (r[k-1]+r[k]);
158  p_hse = p[k-1] - dz * r_avg * CONST_GRAV;
159  p_eos = getPgivenRTh(r[k]*theta);
160 
161  Real A = p_hse - p_eos;
162 
163  Real dpdr = getdPdRgivenConstantTheta(r[k],theta);
164  // Gamma * p_0 * std::pow( (R_d * theta / p_0), Gamma) * std::pow(r[k], Gamma-1.0) ;
165 
166  Real drho = A / (dpdr + dz * CONST_GRAV);
167 
168  r[k] = r[k] + drho;
169  p[k] = getPgivenRTh(r[k]*theta);
170 
171  if (std::abs(drho) < TOL * r[k-1])
172  {
173  converged_hse = true;
174  // amrex::Print() << " converged " << std::endl;
175  break;
176  }
177  }
178 
179  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k << std::endl;
180  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
181  }
182  r[khi+1] = r[khi];
183  }
constexpr amrex::Real p_0
Definition: ERF_Constants.H:18
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:21
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=0.)
Definition: ERF_EOS.H:84
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getdPdRgivenConstantTheta(const amrex::Real rho, const amrex::Real theta, const amrex::Real qv=0.0)
Definition: ERF_EOS.H:130
const int MAX_ITER
Definition: ERF_HSEUtils.H:13
const amrex::Real TOL
Definition: ERF_HSEUtils.H:14
@ theta
Definition: ERF_MM5.H:20

Referenced by erf_init_dens_hse().

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
209 {
210  int kstart;
211 
212  if (klo == 0) {
213  //
214  // r_sfc / p_0 are the density / pressure at the surface
215  //
216  // Initial guess
217  int k0 = 0;
218 
219  // Where we start the lower iteration
220  kstart = 1;
221 
222  Real half_dz = z_cc(i,j,k0);
223  r[k0] = r_sfc;
224  p[k0] = p_0 - half_dz * r[k0] * CONST_GRAV;
225  {
226  // We do a Newton iteration to satisfy the EOS & HSE (with constant theta)
227  bool converged_hse = false;
228  Real p_hse;
229  Real p_eos;
230 
231  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
232  {
233  p_hse = p_0 - half_dz * r[k0] * CONST_GRAV;
234  p_eos = getPgivenRTh(r[k0]*theta);
235 
236  Real A = p_hse - p_eos;
237 
238  Real dpdr = getdPdRgivenConstantTheta(r[k0],theta);
239 
240  Real drho = A / (dpdr + half_dz * CONST_GRAV);
241 
242  r[k0] = r[k0] + drho;
243  p[k0] = getPgivenRTh(r[k0]*theta);
244 
245  if (std::abs(drho) < TOL)
246  {
247  converged_hse = true;
248  break;
249  }
250  }
251 
252  //if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k0 << std::endl;
253  //if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
254  }
255  } else {
256  kstart = klo; // because we need to solve for r[klo] here; r[klo-1] is what was passed in r_sfc
257  r[klo-1] = r_sfc; // r_sfc is really the interpolated density in the ghost cell in this case
258  p[klo-1] = getPgivenRTh(r[klo-1]*theta);
259  }
260 
261  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
262  for (int k = kstart; k <= khi; k++)
263  {
264  // To get values at k > 0 we do a Newton iteration to satisfy the EOS (with constant theta) and
265  // to discretely satisfy HSE -- here we assume spatial_order = 2 -- we can generalize this later if needed
266  bool converged_hse = false;
267 
268  Real dz_loc = (z_cc(i,j,k) - z_cc(i,j,k-1));
269 
270  r[k] = r[k-1];
271 
272  Real p_eos = getPgivenRTh(r[k]*theta);
273  Real p_hse;
274 
275  for (int iter = 0; iter < MAX_ITER && !converged_hse; iter++)
276  {
277  p_hse = p[k-1] - dz_loc * 0.5 * (r[k-1]+r[k]) * CONST_GRAV;
278  p_eos = getPgivenRTh(r[k]*theta);
279 
280  Real A = p_hse - p_eos;
281 
282  Real dpdr = getdPdRgivenConstantTheta(r[k],theta);
283 
284  Real drho = A / (dpdr + dz_loc * CONST_GRAV);
285 
286  r[k] = r[k] + drho;
287  p[k] = getPgivenRTh(r[k]*theta);
288 
289  if (std::abs(drho) < TOL * r[k-1])
290  {
291  converged_hse = true;
292  //amrex::Print() << " converged " << std::endl;
293  break;
294  }
295  }
296 
297  // if (!converged_hse) amrex::Print() << "DOING ITERATIONS AT K = " << k << std::endl;
298  // if (!converged_hse) amrex::Error("Didn't converge the iterations in init");
299  }
300 }

Referenced by erf_init_dens_hse().

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 &  T,
const Real &  qt,
const Real &  qv,
Real &  P,
Real &  rd,
Real &  F 
)

Function to calculate the hydrostatic density and pressure from Newton-Raphson iterations

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]Ttheta 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
46  {
47  int iter=0;
48  int max_iter=30;
49  Real eps = 1.0e-6;
50  Real ieps = 1.0e6;
51  do {
52  // Compute change in pressure
53  Real hi = getRhogivenThetaPress(T, P + eps, RdOCp, qv);
54  Real lo = getRhogivenThetaPress(T, P - eps, RdOCp, qv);
55  Real dFdp = 1.0 + 0.25*ieps*(hi - lo)*g*dz;
56  P -= F/dFdp;
57  if (P < 1.0e3) amrex::Warning("P < 1000 [Pa]; Domain height may be too large...");
58  AMREX_ALWAYS_ASSERT(P > 0.0);
59 
60  // Diagnose density and residual
61  rd = getRhogivenThetaPress(T, P, RdOCp, qv);
62  AMREX_ALWAYS_ASSERT(rd > 0.0);
63  Real r_tot = rd * (1. + qt);
64  F = P + 0.5*r_tot*g*dz + C;
65  ++iter;
66  }
67  while (std::abs(F)>m_tol && iter<max_iter);
68  if (iter>=max_iter) {
69  printf("WARNING: HSE Newton iterations did not converge to tolerance!\n");
70  printf("HSE Newton tol: %e %e\n",F,m_tol);
71  }
72  }
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=0.0)
Definition: ERF_EOS.H:99
@ qt
Definition: ERF_Kessler.H:35
@ qv
Definition: ERF_Kessler.H:36
@ T
Definition: ERF_IndexDefines.H:99

Referenced by InputSoundingData::calc_rho_p().

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

Variable Documentation

◆ MAX_ITER

const int HSEutils::MAX_ITER = 10

◆ TOL

const amrex::Real HSEutils::TOL = 1.e-8