ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_MorrisonGammaFunction.H
Go to the documentation of this file.
1 #include <string>
2 #include <vector>
3 #include <memory>
4 #include <complex>
5 #include <cmath>
6 
7 #include <AMReX_Math.H>
8 #include <AMReX_FArrayBox.H>
9 #include <AMReX_Geometry.H>
10 #include <AMReX_TableData.H>
11 #include <AMReX_MultiFabUtil.H>
12 
13 #include "ERF.H"
14 #include "ERF_Constants.H"
15 #include "ERF_MicrophysicsUtils.H"
16 #include "ERF_IndexDefines.H"
17 #include "ERF_DataStruct.H"
18 #include "ERF_NullMoist.H"
19 #include "ERF_Morrison.H"
20 #ifdef ERF_USE_MORR_FORT
22 #endif
23 
24 using namespace amrex;
25 
26 constexpr Real xxx = Real(0.9189385332046727417803297);
27 /*
28 !------------------------------------------------------------------------------
29 
30  REAL(C_DOUBLE) FUNCTION GAMMA(X)
31 !----------------------------------------------------------------------
32 !
33 ! THIS ROUTINE CALCULATES THE GAMMA FUNCTION FOR A REAL(C_DOUBLE) ARGUMENT X.
34 ! COMPUTATION IS BASED ON AN ALGORITHM OUTLINED IN REFERENCE one
35 ! THE PROGRAM USES RATIONAL FUNCTIONS THAT APPROXIMATE THE GAMMA
36 ! FUNCTION TO AT LEAST 20 SIGNIFICANT DECIMAL DIGITS. COEFFICIENTS
37 ! FOR THE APPROXIMATION OVER THE INTERVAL (1,2) ARE UNPUBLISHED.
38 ! THOSE FOR THE APPROXIMATION FOR X .GE. 12 ARE FROM REFERENCE two
39 ! THE ACCURACY ACHIEVED DEPENDS ON THE ARITHMETIC SYSTEM, THE
40 ! COMPILER, THE INTRINSIC FUNCTIONS, AND PROPER SELECTION OF THE
41 ! MACHINE-DEPENDENT CONSTANTS.
42 !
43 !
44 !*******************************************************************
45 !*******************************************************************
46 !
47 ! EXPLANATION OF MACHINE-DEPENDENT CONSTANTS
48 !
49 ! BETA - RADIX FOR THE FLOATING-POINT REPRESENTATION
50 ! MAXEXP - THE SMALLEST POSITIVE POWER OF BETA THAT OVERFLOWS
51 ! XBIG - THE LARGEST ARGUMENT FOR WHICH GAMMA(X) IS REPRESENTABLE
52 ! IN THE MACHINE, I.E., THE SOLUTION TO THE EQUATION
53 ! GAMMA(XBIG) = BETA**MAXEXP
54 ! XINF - THE LARGEST MACHINE REPRESENTABLE FLOATING-POINT NUMBER;
55 ! APPROXIMATELY BETA**MAXEXP
56 ! EPS - THE SMALLEST POSITIVE FLOATING-POINT NUMBER SUCH THAT
57 ! one+EPS .GT. one
58 ! XMININ - THE SMALLEST POSITIVE FLOATING-POINT NUMBER SUCH THAT
59 ! 1/XMININ IS MACHINE REPRESENTABLE
60 !
61 ! APPROXIMATE VALUES FOR SOME IMPORTANT MACHINES ARE:
62 !
63 ! BETA MAXEXP XBIG
64 !
65 ! CRAY-1 (S.P.) 2 8191 Real(966.961)
66 ! CYBER 180/855
67 ! UNDER NOS (S.P.) 2 1070 Real(177.803)
68 ! IEEE (IBM/XT,
69 ! SUN, ETC.) (S.P.) 2 128 Real(35.040)
70 ! IEEE (IBM/XT,
71 ! SUN, ETC.) (D.P.) 2 1024 Real(171.624)
72 ! IBM 3033 (D.P.) 16 63 Real(57.574)
73 ! VAX D-FORMAT (D.P.) 2 127 Real(34.844)
74 ! VAX G-FORMAT (D.P.) 2 1023 Real(171.489)
75 !
76 ! XINF EPS XMININ
77 !
78 ! CRAY-1 (S.P.) Real(5.45E+2465) Real(7.11E-15) Real(1.84E-2466)
79 ! CYBER 180/855
80 ! UNDER NOS (S.P.) Real(1.26E+322) Real(3.55E-15) Real(3.14E-294)
81 ! IEEE (IBM/XT,
82 ! SUN, ETC.) (S.P.) Real(3.40E+38) Real(1.19E-7) Real(1.18E-38)
83 ! IEEE (IBM/XT,
84 ! SUN, ETC.) (D.P.) 1.79D+308 2.22D-16 2.23D-308
85 ! IBM 3033 (D.P.) 7.23D+75 2.22D-16 1.39D-76
86 ! VAX D-FORMAT (D.P.) 1.70D+38 1.39D-17 5.88D-39
87 ! VAX G-FORMAT (D.P.) 8.98D+307 1.11D-16 1.12D-308
88 !
89 !*******************************************************************
90 !*******************************************************************
91 !
92 ! ERROR RETURNS
93 !
94 ! THE PROGRAM RETURNS THE VALUE XINF FOR SINGULARITIES OR
95 ! WHEN OVERFLOW WOULD OCCUR. THE COMPUTATION IS BELIEVED
96 ! TO BE FREE OF UNDERFLOW AND OVERFLOW.
97 !
98 !
99 ! INTRINSIC FUNCTIONS REQUIRED ARE:
100 !
101 ! INT, DBLE, EXP, LOG, REAL(C_DOUBLE), SIN
102 !
103 !
104 ! REFERENCES: AN OVERVIEW OF SOFTWARE DEVELOPMENT FOR SPECIAL
105 ! FUNCTIONS W. J. CODY, LECTURE NOTES IN MATHEMATICS,
106 ! 506, NUMERICAL ANALYSIS DUNDEE, 1975, G. A. WATSON
107 ! (ED.), SPRINGER VERLAG, BERLIN, Real(1976.)
108 !
109 ! COMPUTER APPROXIMATIONS, HART, ET. AL., WILEY AND
110 ! SONS, NEW YORK, Real(1968.)
111 !
112 ! LATEST MODIFICATION: OCTOBER 12, 1989
113 !
114 ! AUTHORS: W. J. CODY AND L. STOLTZ
115 ! APPLIED MATHEMATICS DIVISION
116 ! ARGONNE NATIONAL LABORATORY
117 ! ARGONNE, IL 60439
118 !
119 !----------------------------------------------------------------------
120 */
121 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
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, res, sum, twelve, xbig, xden, xinf, xminin;
131  amrex::Real xnum, y, y1, ysq, z;
132  amrex::Real c[7];
133  amrex::Real p[8];
134  amrex::Real q[8];
135 
136  // Mathematical constants
137  twelve = Real(12.0);
138 
139  // Machine dependent parameters
140  xbig = Real(35.040);
141  xminin = Real(1.18e-38);
142  amrex::Real eps = Real(1.19e-7);
143  xinf = Real(3.4e38);
144 
145  // Numerator and denominator coefficients for rational minimax approximation over (1,2)
146  p[0] = -Real(1.71618513886549492533811e+0);
147  p[1] = Real(2.47656508055759199108314e+1);
148  p[2] = -Real(3.79804256470945635097577e+2);
149  p[3] = Real(6.29331155312818442661052e+2);
150  p[4] = Real(8.66966202790413211295064e+2);
151  p[5] = -Real(3.14512729688483675254357e+4);
152  p[6] = -Real(3.61444134186911729807069e+4);
153  p[7] = Real(6.64561438202405440627855e+4);
154 
155  q[0] = -Real(3.08402300119738975254353e+1);
156  q[1] = Real(3.15350626979604161529144e+2);
157  q[2] = -Real(1.01515636749021914166146e+3);
158  q[3] = -Real(3.10777167157231109440444e+3);
159  q[4] = Real(2.25381184209801510330112e+4);
160  q[5] = Real(4.75584627752788110767815e+3);
161  q[6] = -Real(1.34659959864969306392456e+5);
162  q[7] = -Real(1.15132259675553483497211e+5);
163 
164  // Coefficients for minimax approximation over (12, inf)
165  c[0] = -Real(1.910444077728e-03);
166  c[1] = Real(8.4171387781295e-04);
167  c[2] = -Real(5.952379913043012e-04);
168  c[3] = Real(7.93650793500350248e-04);
169  c[4] = -Real(2.777777777777681622553e-03);
170  c[5] = Real(8.333333333333333331554247e-02);
171  c[6] = Real(5.7083835261e-03);
172 
173  // Initialize variables
174  parity = false;
175  fact = one;
176  n = 0;
177  y = x;
178 
179 // printf("wrf_gamma: Initial y = %g\n", y);
180 
181  if (y <= Real(0)) {
182  // Argument is negative
183 // printf("wrf_gamma: Handling negative argument\n");
184  y = -x;
185  y1 = std::floor(y);
186  res = y - y1;
187  if (res != Real(0)) {
188  if (y1 != std::floor(y1 * myhalf) * Real(2))
189  parity = true;
190  Real pi=amrex::Math::pi<Real>();
191  fact = -pi / std::sin(pi * res);
192  y = y + one;
193 // printf("wrf_gamma: After reflection formula: y = %g, fact = %g, parity = %d\n",
194 // y, fact, parity);
195  }
196  else {
197 // printf("wrf_gamma: Singularity detected, returning xinf = %g\n", xinf);
198  res = xinf;
199  return res;
200  }
201  }
202 
203  // Argument is positive
204  if (y < eps) {
205  // Argument < eps
206 // printf("wrf_gamma: Small argument branch (y < eps)\n");
207  if (y >= xminin) {
208  res = one / y;
209 // printf("wrf_gamma: Small argument result: res = %g\n", res);
210  }
211  else {
212 // printf("wrf_gamma: Argument too small, returning xinf = %g\n", xinf);
213  res = xinf;
214  return res;
215  }
216  }
217  else if (y < twelve) {
218  // Medium range argument
219 // printf("wrf_gamma: Medium range branch (eps <= y < 12)\n");
220  y1 = y;
221  if (y < one) {
222  // Real(0) < argument < one
223 // printf("wrf_gamma: Sub-branch: 0 < y < 1\n");
224  z = y;
225  y = y + one;
226  }
227  else {
228  // one < argument < Real(12.0), reduce argument if necessary
229  n = static_cast<int>(y) - 1;
230 // printf("wrf_gamma: Sub-branch: 1 <= y < 12, n = %d\n", n);
231  y = y - static_cast<amrex::Real>(n);
232  z = y - one;
233  }
234 
235  // Evaluate approximation
236 // printf("wrf_gamma: Before approximation: z = %g, y = %g\n", z, y);
237  xnum = Real(0);
238  xden = one;
239  for (i = 0; i < 8; i++) {
240  xnum = (xnum + p[i]) * z;
241  xden = xden * z + q[i];
242  }
243  res = xnum / xden + one;
244 // printf("wrf_gamma: After approximation: res = %g\n", res);
245 
246  if (y1 < y) {
247  // Adjust result for case Real(0) < argument < one
248  res = res / y1;
249 // printf("wrf_gamma: Adjusted for y < 1: res = %g\n", res);
250  }
251  else if (y1 > y) {
252  // Adjust for two < argument < Real(12.0)
253 // printf("wrf_gamma: Adjusting for y > 2 with %d multiplications\n", n);
254  for (i = 0; i < n; i++) {
255  res = res * y;
256  y = y + one;
257 // printf("wrf_gamma: Multiplication %d: res = %g, y = %g\n", i+1, res, y);
258  }
259  }
260  }
261  else {
262  // Large argument
263 // printf("wrf_gamma: Large argument branch (y >= 12)\n");
264  if (y <= xbig) {
265  ysq = y * y;
266  sum = c[6];
267  for (i = 0; i < 6; i++) {
268  sum = sum / ysq + c[i];
269 // printf("wrf_gamma: Sum step %d: sum = %g\n", i+1, sum);
270  }
271  sum = sum / y - y + xxx;
272  sum = sum + (y - myhalf) * std::log(y);
273 // printf("wrf_gamma: Before exp: sum = %g\n", sum);
274  res = std::exp(sum);
275 // printf("wrf_gamma: After exp: res = %g\n", res);
276  }
277  else {
278 // printf("wrf_gamma: Argument too large, returning xinf = %g\n", xinf);
279  res = xinf;
280  return res;
281  }
282  }
283 
284  // Final adjustments
285  if (parity) {
286  res = -res;
287 // printf("wrf_gamma: Applied parity adjustment: res = %g\n", res);
288  }
289  if (fact != one) {
290  res = fact / res;
291 // printf("wrf_gamma: Applied reflection adjustment: res = %g\n", res);
292  }
293 
294 // printf("wrf_gamma: Final result = %g\n", res);
295  return res;
296 }
297 
298 // Gamma function using the custom wrf implementation of the gamma function
299 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
301  return wrf_gamma(x);
302 }
303  /**
304  * Helper function to calculate saturation vapor pressure for water or ice.
305  * This corresponds to the POLYSVP function in the Fortran code (line ~5580).
306  *
307  * @param[in] T Temperature in Kelvin
308  * @param[in] type 0 for liquid water, 1 for ice
309  * @return Saturation vapor pressure in Pascals
310  */
311 
constexpr amrex::Real one
Definition: ERF_Constants.H:7
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:11
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real wrf_gamma(amrex::Real x)
Definition: ERF_MorrisonGammaFunction.H:122
constexpr Real xxx
Definition: ERF_MorrisonGammaFunction.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real gamma_function(Real x)
Definition: ERF_MorrisonGammaFunction.H:300
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ q
Definition: ERF_WSM6.H:169
@ p
Definition: ERF_WSM6.H:176
Definition: ERF_ConsoleIO.cpp:12
real(c_double), parameter, private pi
Definition: ERF_module_mp_morr_two_moment.F90:100