ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ERF_AdvanceMorrison.cpp File Reference
#include <string>
#include <vector>
#include <memory>
#include <complex>
#include <cmath>
#include <AMReX_Math.H>
#include <AMReX_FArrayBox.H>
#include <AMReX_Geometry.H>
#include <AMReX_TableData.H>
#include <AMReX_MultiFabUtil.H>
#include "ERF.H"
#include "ERF_Constants.H"
#include "ERF_MicrophysicsUtils.H"
#include "ERF_IndexDefines.H"
#include "ERF_DataStruct.H"
#include "ERF_NullMoist.H"
#include "ERF_Morrison.H"
Include dependency graph for ERF_AdvanceMorrison.cpp:

Functions

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real wrf_gamma (amrex::Real x)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real gamma_function (Real x)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_saturation_vapor_pressure (const amrex::Real T, const int type)
 

Variables

constexpr Real xxx = 0.9189385332046727417803297
 

Function Documentation

◆ calc_saturation_vapor_pressure()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_saturation_vapor_pressure ( const amrex::Real  T,
const int  type 
)

Helper function to calculate saturation vapor pressure for water or ice. This corresponds to the POLYSVP function in the Fortran code (line ~5580).

Parameters
[in]TTemperature in Kelvin
[in]type0 for liquid water, 1 for ice
Returns
Saturation vapor pressure in Pascals
318  {
319  amrex::Real polysvp = 0.0;
320  amrex::Real del_T = T - 273.15; // Convert to Celsius
321 
322  if (type == 1) { // Ice (lines ~5631-5644)
323  if (T >= 195.8) {
324  // Flatau et al. formula for ice
325  const amrex::Real a0i = 6.11147274;
326  const amrex::Real a1i = 0.503160820;
327  const amrex::Real a2i = 0.188439774e-1;
328  const amrex::Real a3i = 0.420895665e-3;
329  const amrex::Real a4i = 0.615021634e-5;
330  const amrex::Real a5i = 0.602588177e-7;
331  const amrex::Real a6i = 0.385852041e-9;
332  const amrex::Real a7i = 0.146898966e-11;
333  const amrex::Real a8i = 0.252751365e-14;
334 
335  polysvp = a0i + del_T*(a1i + del_T*(a2i + del_T*(a3i + del_T*(a4i + del_T*(a5i + del_T*(a6i + del_T*(a7i + a8i*del_T)))))));
336  polysvp *= 100.0; // Convert from hPa to Pa
337  } else {
338  // Goff-Gratch formula for ice at cold temperatures
339  polysvp = std::pow(10.0, (-9.09718*(273.16/T-1.0) - 3.56654*std::log10(273.16/T) +
340  0.876793*(1.0-T/273.16) + std::log10(6.1071))) * 100.0;
341  polysvp = 0.0;
342  } // T
343  } else { // Water (lines ~5648-5665)
344  if (T >= 202.0) {
345  // Flatau et al. formula for liquid water
346  const amrex::Real a0 = 6.11239921;
347  const amrex::Real a1 = 0.443987641;
348  const amrex::Real a2 = 0.142986287e-1;
349  const amrex::Real a3 = 0.264847430e-3;
350  const amrex::Real a4 = 0.302950461e-5;
351  const amrex::Real a5 = 0.206739458e-7;
352  const amrex::Real a6 = 0.640689451e-10;
353  const amrex::Real a7 = -0.952447341e-13;
354  const amrex::Real a8 = -0.976195544e-15;
355 
356  polysvp = a0 + del_T*(a1 + del_T*(a2 + del_T*(a3 + del_T*(a4 + del_T*(a5 + del_T*(a6 + del_T*(a7 + a8*del_T)))))));
357  polysvp *= 100.0; // Convert from hPa to Pa
358  } else {
359  // Goff-Gratch formula for water at cold temperatures
360  polysvp = std::pow(10.0, (-7.90298*(373.16/T-1.0) + 5.02808*std::log10(373.16/T) -
361  1.3816e-7*(std::pow(10.0, (11.344*(1.0-T/373.16)))-1.0) +
362  8.1328e-3*(std::pow(10.0, (-3.49149*(373.16/T-1.0)))-1.0) +
363  std::log10(1013.246))) * 100.0;
364  }
365  }
366 
367  return polysvp;
368  }
@ T
Definition: ERF_IndexDefines.H:110
real(c_double), parameter a2
Definition: ERF_module_model_constants.F90:95
real(c_double), parameter a3
Definition: ERF_module_model_constants.F90:96
real(c_double), parameter a4
Definition: ERF_module_model_constants.F90:97
real(c_double) function, public polysvp(T, TYPE)
Definition: ERF_module_mp_morr_two_moment.F90:4006

Referenced by Morrison::Advance().

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

◆ gamma_function()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real gamma_function ( Real  x)
304  {
305  return wrf_gamma(x);
306 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real wrf_gamma(amrex::Real x)
Definition: ERF_AdvanceMorrison.cpp:122

Referenced by Morrison::Advance().

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

◆ wrf_gamma()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real wrf_gamma ( amrex::Real  x)
123 {
124  // Debug: using printf since it's GPU compatible
125 // printf("wrf_gamma: Input value x = %g\n", x);
126 
127  // Local variables
128  int i, n;
129  bool parity = false;
130  amrex::Real fact, half, one, res, sum, twelve, two, xbig, xden, xinf, xminin;
131  amrex::Real xnum, y, y1, ysq, z, zero;
132  amrex::Real c[7];
133  amrex::Real p[8];
134  amrex::Real q[8];
135 
136  // Mathematical constants
137  one = 1.0;
138  half = 0.5;
139  twelve = 12.0;
140  two = 2.0;
141  zero = 0.0;
142 
143  // Machine dependent parameters
144  xbig = 35.040;
145  xminin = 1.18e-38;
146  amrex::Real eps = 1.19e-7;
147  xinf = 3.4e38;
148 
149  // Numerator and denominator coefficients for rational minimax approximation over (1,2)
150  p[0] = -1.71618513886549492533811e+0;
151  p[1] = 2.47656508055759199108314e+1;
152  p[2] = -3.79804256470945635097577e+2;
153  p[3] = 6.29331155312818442661052e+2;
154  p[4] = 8.66966202790413211295064e+2;
155  p[5] = -3.14512729688483675254357e+4;
156  p[6] = -3.61444134186911729807069e+4;
157  p[7] = 6.64561438202405440627855e+4;
158 
159  q[0] = -3.08402300119738975254353e+1;
160  q[1] = 3.15350626979604161529144e+2;
161  q[2] = -1.01515636749021914166146e+3;
162  q[3] = -3.10777167157231109440444e+3;
163  q[4] = 2.25381184209801510330112e+4;
164  q[5] = 4.75584627752788110767815e+3;
165  q[6] = -1.34659959864969306392456e+5;
166  q[7] = -1.15132259675553483497211e+5;
167 
168  // Coefficients for minimax approximation over (12, inf)
169  c[0] = -1.910444077728e-03;
170  c[1] = 8.4171387781295e-04;
171  c[2] = -5.952379913043012e-04;
172  c[3] = 7.93650793500350248e-04;
173  c[4] = -2.777777777777681622553e-03;
174  c[5] = 8.333333333333333331554247e-02;
175  c[6] = 5.7083835261e-03;
176 
177  // Initialize variables
178  parity = false;
179  fact = one;
180  n = 0;
181  y = x;
182 
183 // printf("wrf_gamma: Initial y = %g\n", y);
184 
185  if (y <= zero) {
186  // Argument is negative
187 // printf("wrf_gamma: Handling negative argument\n");
188  y = -x;
189  y1 = std::floor(y);
190  res = y - y1;
191  if (res != zero) {
192  if (y1 != std::floor(y1 * half) * two)
193  parity = true;
194  Real pi=amrex::Math::pi<Real>();
195  fact = -pi / std::sin(pi * res);
196  y = y + one;
197 // printf("wrf_gamma: After reflection formula: y = %g, fact = %g, parity = %d\n",
198 // y, fact, parity);
199  }
200  else {
201 // printf("wrf_gamma: Singularity detected, returning xinf = %g\n", xinf);
202  res = xinf;
203  return res;
204  }
205  }
206 
207  // Argument is positive
208  if (y < eps) {
209  // Argument < eps
210 // printf("wrf_gamma: Small argument branch (y < eps)\n");
211  if (y >= xminin) {
212  res = one / y;
213 // printf("wrf_gamma: Small argument result: res = %g\n", res);
214  }
215  else {
216 // printf("wrf_gamma: Argument too small, returning xinf = %g\n", xinf);
217  res = xinf;
218  return res;
219  }
220  }
221  else if (y < twelve) {
222  // Medium range argument
223 // printf("wrf_gamma: Medium range branch (eps <= y < 12)\n");
224  y1 = y;
225  if (y < one) {
226  // 0.0 < argument < 1.0
227 // printf("wrf_gamma: Sub-branch: 0 < y < 1\n");
228  z = y;
229  y = y + one;
230  }
231  else {
232  // 1.0 < argument < 12.0, reduce argument if necessary
233  n = static_cast<int>(y) - 1;
234 // printf("wrf_gamma: Sub-branch: 1 <= y < 12, n = %d\n", n);
235  y = y - static_cast<amrex::Real>(n);
236  z = y - one;
237  }
238 
239  // Evaluate approximation
240 // printf("wrf_gamma: Before approximation: z = %g, y = %g\n", z, y);
241  xnum = zero;
242  xden = one;
243  for (i = 0; i < 8; i++) {
244  xnum = (xnum + p[i]) * z;
245  xden = xden * z + q[i];
246  }
247  res = xnum / xden + one;
248 // printf("wrf_gamma: After approximation: res = %g\n", res);
249 
250  if (y1 < y) {
251  // Adjust result for case 0.0 < argument < 1.0
252  res = res / y1;
253 // printf("wrf_gamma: Adjusted for y < 1: res = %g\n", res);
254  }
255  else if (y1 > y) {
256  // Adjust for 2.0 < argument < 12.0
257 // printf("wrf_gamma: Adjusting for y > 2 with %d multiplications\n", n);
258  for (i = 0; i < n; i++) {
259  res = res * y;
260  y = y + one;
261 // printf("wrf_gamma: Multiplication %d: res = %g, y = %g\n", i+1, res, y);
262  }
263  }
264  }
265  else {
266  // Large argument
267 // printf("wrf_gamma: Large argument branch (y >= 12)\n");
268  if (y <= xbig) {
269  ysq = y * y;
270  sum = c[6];
271  for (i = 0; i < 6; i++) {
272  sum = sum / ysq + c[i];
273 // printf("wrf_gamma: Sum step %d: sum = %g\n", i+1, sum);
274  }
275  sum = sum / y - y + xxx;
276  sum = sum + (y - half) * std::log(y);
277 // printf("wrf_gamma: Before exp: sum = %g\n", sum);
278  res = std::exp(sum);
279 // printf("wrf_gamma: After exp: res = %g\n", res);
280  }
281  else {
282 // printf("wrf_gamma: Argument too large, returning xinf = %g\n", xinf);
283  res = xinf;
284  return res;
285  }
286  }
287 
288  // Final adjustments
289  if (parity) {
290  res = -res;
291 // printf("wrf_gamma: Applied parity adjustment: res = %g\n", res);
292  }
293  if (fact != one) {
294  res = fact / res;
295 // printf("wrf_gamma: Applied reflection adjustment: res = %g\n", res);
296  }
297 
298 // printf("wrf_gamma: Final result = %g\n", res);
299  return res;
300 }
constexpr Real xxx
Definition: ERF_AdvanceMorrison.cpp:26
real(c_double), parameter, private pi
Definition: ERF_module_mp_morr_two_moment.F90:100

Referenced by gamma_function().

Here is the caller graph for this function:

Variable Documentation

◆ xxx

constexpr Real xxx = 0.9189385332046727417803297
constexpr

Referenced by wrf_gamma().