Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : MODULE beta_gamma_psi
10 : ! not tested in the case where dp would stand for single precision
11 : ! Routines for the beta function are untested
12 :
13 : USE kinds, ONLY: dp
14 : #include "./base/base_uses.f90"
15 :
16 : IMPLICIT NONE
17 :
18 : PRIVATE
19 :
20 : PUBLIC :: psi
21 :
22 : CONTAINS
23 :
24 : ! **************************************************************************************************
25 : !> \brief ...
26 : !> \param i ...
27 : !> \return ...
28 : ! **************************************************************************************************
29 7564 : FUNCTION ipmpar(i) RESULT(fn_val)
30 : !-----------------------------------------------------------------------
31 :
32 : ! IPMPAR PROVIDES THE INTEGER MACHINE CONSTANTS FOR THE COMPUTER
33 : ! THAT IS USED. IT IS ASSUMED THAT THE ARGUMENT I IS AN INTEGER
34 : ! HAVING ONE OF THE VALUES 1-10. IPMPAR(I) HAS THE VALUE ...
35 :
36 : ! INTEGERS.
37 :
38 : ! ASSUME INTEGERS ARE REPRESENTED IN THE N-DIGIT, BASE-A FORM
39 :
40 : ! SIGN ( X(N-1)*A**(N-1) + ... + X(1)*A + X(0) )
41 :
42 : ! WHERE 0 .LE. X(I) .LT. A FOR I=0,...,N-1.
43 :
44 : ! IPMPAR(1) = A, THE BASE (radix).
45 :
46 : ! IPMPAR(2) = N, THE NUMBER OF BASE-A DIGITS (digits).
47 :
48 : ! IPMPAR(3) = A**N - 1, THE LARGEST MAGNITUDE (huge).
49 :
50 : ! FLOATING-POINT NUMBERS.
51 :
52 : ! IT IS ASSUMED THAT THE SINGLE AND DOUBLE PRECISION FLOATING
53 : ! POINT ARITHMETICS HAVE THE SAME BASE, SAY B, AND THAT THE
54 : ! NONZERO NUMBERS ARE REPRESENTED IN THE FORM
55 :
56 : ! SIGN (B**E) * (X(1)/B + ... + X(M)/B**M)
57 :
58 : ! WHERE X(I) = 0,1,...,B-1 FOR I=1,...,M,
59 : ! X(1) .GE. 1, AND EMIN .LE. E .LE. EMAX.
60 :
61 : ! IPMPAR(4) = B, THE BASE.
62 :
63 : ! SINGLE-PRECISION
64 :
65 : ! IPMPAR(5) = M, THE NUMBER OF BASE-B DIGITS.
66 :
67 : ! IPMPAR(6) = EMIN, THE SMALLEST EXPONENT E.
68 :
69 : ! IPMPAR(7) = EMAX, THE LARGEST EXPONENT E.
70 :
71 : ! DOUBLE-PRECISION
72 :
73 : ! IPMPAR(8) = M, THE NUMBER OF BASE-B DIGITS.
74 :
75 : ! IPMPAR(9) = EMIN, THE SMALLEST EXPONENT E.
76 :
77 : ! IPMPAR(10) = EMAX, THE LARGEST EXPONENT E.
78 :
79 : !-----------------------------------------------------------------------
80 :
81 : INTEGER, INTENT(IN) :: i
82 : INTEGER :: fn_val
83 :
84 7564 : SELECT CASE (i)
85 : CASE (1)
86 0 : fn_val = RADIX(i)
87 : CASE (2)
88 0 : fn_val = DIGITS(i)
89 : CASE (3)
90 7564 : fn_val = HUGE(i)
91 : CASE (4)
92 0 : fn_val = RADIX(1.0)
93 : CASE (5)
94 0 : fn_val = DIGITS(1.0)
95 : CASE (6)
96 0 : fn_val = MINEXPONENT(1.0)
97 : CASE (7)
98 0 : fn_val = MAXEXPONENT(1.0)
99 : CASE (8)
100 0 : fn_val = DIGITS(1.0e0_dp)
101 : CASE (9)
102 0 : fn_val = MINEXPONENT(1.0e0_dp)
103 : CASE (10)
104 0 : fn_val = MAXEXPONENT(1.0e0_dp)
105 : CASE DEFAULT
106 7564 : CPABORT("unknown case")
107 : END SELECT
108 :
109 7564 : END FUNCTION ipmpar
110 :
111 : ! **************************************************************************************************
112 : !> \brief ...
113 : !> \param i ...
114 : !> \return ...
115 : ! **************************************************************************************************
116 7564 : FUNCTION dpmpar(i) RESULT(fn_val)
117 : !-----------------------------------------------------------------------
118 :
119 : ! DPMPAR PROVIDES THE DOUBLE PRECISION MACHINE CONSTANTS FOR
120 : ! THE COMPUTER BEING USED. IT IS ASSUMED THAT THE ARGUMENT
121 : ! I IS AN INTEGER HAVING ONE OF THE VALUES 1, 2, OR 3. IF THE
122 : ! DOUBLE PRECISION ARITHMETIC BEING USED HAS M BASE B DIGITS AND
123 : ! ITS SMALLEST AND LARGEST EXPONENTS ARE EMIN AND EMAX, THEN
124 :
125 : ! DPMPAR(1) = B**(1 - M), THE MACHINE PRECISION,
126 :
127 : ! DPMPAR(2) = B**(EMIN - 1), THE SMALLEST MAGNITUDE,
128 :
129 : ! DPMPAR(3) = B**EMAX*(1 - B**(-M)), THE LARGEST MAGNITUDE.
130 : !-----------------------------------------------------------------------
131 :
132 : INTEGER, INTENT(IN) :: i
133 : REAL(dp) :: fn_val
134 :
135 : REAL(dp), PARAMETER :: one = 1._dp
136 :
137 : ! Local variable
138 :
139 15128 : SELECT CASE (i)
140 : CASE (1)
141 7564 : fn_val = EPSILON(one)
142 : CASE (2)
143 0 : fn_val = TINY(one)
144 : CASE (3)
145 7564 : fn_val = HUGE(one)
146 : END SELECT
147 :
148 7564 : END FUNCTION dpmpar
149 :
150 : ! **************************************************************************************************
151 : !> \brief ...
152 : !> \param l ...
153 : !> \return ...
154 : ! **************************************************************************************************
155 0 : FUNCTION dxparg(l) RESULT(fn_val)
156 : !--------------------------------------------------------------------
157 : ! IF L = 0 THEN DXPARG(L) = THE LARGEST POSITIVE W FOR WHICH
158 : ! DEXP(W) CAN BE COMPUTED.
159 : !
160 : ! IF L IS NONZERO THEN DXPARG(L) = THE LARGEST NEGATIVE W FOR
161 : ! WHICH THE COMPUTED VALUE OF DEXP(W) IS NONZERO.
162 : !
163 : ! NOTE... ONLY AN APPROXIMATE VALUE FOR DXPARG(L) IS NEEDED.
164 : !--------------------------------------------------------------------
165 : INTEGER, INTENT(IN) :: l
166 : REAL(dp) :: fn_val
167 :
168 : REAL(dp), PARAMETER :: one = 1._dp
169 :
170 : ! Local variable
171 :
172 0 : IF (l == 0) THEN
173 : fn_val = LOG(HUGE(one))
174 : ELSE
175 0 : fn_val = LOG(TINY(one))
176 : END IF
177 :
178 0 : END FUNCTION dxparg
179 :
180 : ! **************************************************************************************************
181 : !> \brief ...
182 : !> \param a ...
183 : !> \return ...
184 : ! **************************************************************************************************
185 0 : FUNCTION alnrel(a) RESULT(fn_val)
186 : !-----------------------------------------------------------------------
187 : ! EVALUATION OF THE FUNCTION LN(1 + A)
188 : !-----------------------------------------------------------------------
189 : REAL(dp), INTENT(IN) :: a
190 : REAL(dp) :: fn_val
191 :
192 : REAL(dp), PARAMETER :: half = 0.5e0_dp, one = 1.e0_dp, p1 = -.129418923021993e+01_dp, &
193 : p2 = .405303492862024e+00_dp, p3 = -.178874546012214e-01_dp, &
194 : q1 = -.162752256355323e+01_dp, q2 = .747811014037616e+00_dp, &
195 : q3 = -.845104217945565e-01_dp, two = 2.e0_dp, zero = 0.e0_dp
196 :
197 : REAL(dp) :: t, t2, w, x
198 :
199 : !--------------------------
200 :
201 0 : IF (ABS(a) <= 0.375e0_dp) THEN
202 0 : t = a/(a + two)
203 0 : t2 = t*t
204 0 : w = (((p3*t2 + p2)*t2 + p1)*t2 + one)/(((q3*t2 + q2)*t2 + q1)*t2 + one)
205 0 : fn_val = two*t*w
206 : ELSE
207 0 : x = one + a
208 0 : IF (a < zero) x = (a + half) + half
209 0 : fn_val = LOG(x)
210 : END IF
211 :
212 0 : END FUNCTION alnrel
213 :
214 : ! **************************************************************************************************
215 : !> \brief ...
216 : !> \param a ...
217 : !> \return ...
218 : ! **************************************************************************************************
219 0 : FUNCTION gam1(a) RESULT(fn_val)
220 : !-----------------------------------------------------------------------
221 : ! COMPUTATION OF 1/GAMMA(A+1) - 1 FOR -0.5 <= A <= 1.5
222 : !-----------------------------------------------------------------------
223 : REAL(dp), INTENT(IN) :: a
224 : REAL(dp) :: fn_val
225 :
226 : REAL(dp), PARAMETER :: p(7) = (/.577215664901533e+00_dp, -.409078193005776e+00_dp, &
227 : -.230975380857675e+00_dp, .597275330452234e-01_dp, .766968181649490e-02_dp, &
228 : -.514889771323592e-02_dp, .589597428611429e-03_dp/), q(5) = (/.100000000000000e+01_dp, &
229 : .427569613095214e+00_dp, .158451672430138e+00_dp, .261132021441447e-01_dp, &
230 : .423244297896961e-02_dp/), r(9) = (/-.422784335098468e+00_dp, -.771330383816272e+00_dp, &
231 : -.244757765222226e+00_dp, .118378989872749e+00_dp, .930357293360349e-03_dp, &
232 : -.118290993445146e-01_dp, .223047661158249e-02_dp, .266505979058923e-03_dp, &
233 : -.132674909766242e-03_dp/)
234 : REAL(dp), PARAMETER :: s1 = .273076135303957e+00_dp, s2 = .559398236957378e-01_dp
235 :
236 : REAL(dp) :: bot, d, t, top, w
237 :
238 0 : t = a
239 0 : d = a - 0.5e0_dp
240 0 : IF (d > 0.0e0_dp) t = d - 0.5e0_dp
241 :
242 0 : IF (t > 0.e0_dp) THEN
243 0 : top = (((((p(7)*t + p(6))*t + p(5))*t + p(4))*t + p(3))*t + p(2))*t + p(1)
244 0 : bot = (((q(5)*t + q(4))*t + q(3))*t + q(2))*t + 1.0e0_dp
245 0 : w = top/bot
246 0 : IF (d > 0.0e0_dp) THEN
247 0 : fn_val = (t/a)*((w - 0.5e0_dp) - 0.5e0_dp)
248 : ELSE
249 0 : fn_val = a*w
250 : END IF
251 0 : ELSE IF (t < 0.e0_dp) THEN
252 : top = (((((((r(9)*t + r(8))*t + r(7))*t + r(6))*t + r(5))*t &
253 0 : + r(4))*t + r(3))*t + r(2))*t + r(1)
254 0 : bot = (s2*t + s1)*t + 1.0e0_dp
255 0 : w = top/bot
256 0 : IF (d > 0.0e0_dp) THEN
257 0 : fn_val = t*w/a
258 : ELSE
259 0 : fn_val = a*((w + 0.5e0_dp) + 0.5e0_dp)
260 : END IF
261 : ELSE
262 : fn_val = 0.0e0_dp
263 : END IF
264 :
265 0 : END FUNCTION gam1
266 :
267 : ! **************************************************************************************************
268 : !> \brief ...
269 : !> \param a ...
270 : !> \param b ...
271 : !> \return ...
272 : ! **************************************************************************************************
273 0 : FUNCTION algdiv(a, b) RESULT(fn_val)
274 : !-----------------------------------------------------------------------
275 :
276 : ! COMPUTATION OF LN(GAMMA(B)/GAMMA(A+B)) WHEN B >= 8
277 :
278 : ! --------
279 :
280 : ! IN THIS ALGORITHM, DEL(X) IS THE FUNCTION DEFINED BY
281 : ! LN(GAMMA(X)) = (X - 0.5)*LN(X) - X + 0.5*LN(2*PI) + DEL(X).
282 :
283 : !-----------------------------------------------------------------------
284 : REAL(dp), INTENT(IN) :: a, b
285 : REAL(dp) :: fn_val
286 :
287 : REAL(dp), PARAMETER :: c0 = .833333333333333e-01_dp, c1 = -.277777777760991e-02_dp, &
288 : c2 = .793650666825390e-03_dp, c3 = -.595202931351870e-03_dp, &
289 : c4 = .837308034031215e-03_dp, c5 = -.165322962780713e-02_dp
290 :
291 : REAL(dp) :: c, d, h, s11, s3, s5, s7, s9, t, u, v, &
292 : w, x, x2
293 :
294 0 : IF (a > b) THEN
295 0 : h = b/a
296 0 : c = 1.0e0_dp/(1.0e0_dp + h)
297 0 : x = h/(1.0e0_dp + h)
298 0 : d = a + (b - 0.5e0_dp)
299 : ELSE
300 0 : h = a/b
301 0 : c = h/(1.0e0_dp + h)
302 0 : x = 1.0e0_dp/(1.0e0_dp + h)
303 0 : d = b + (a - 0.5e0_dp)
304 : END IF
305 :
306 : ! SET SN = (1 - X**N)/(1 - X)
307 :
308 0 : x2 = x*x
309 0 : s3 = 1.0e0_dp + (x + x2)
310 0 : s5 = 1.0e0_dp + (x + x2*s3)
311 0 : s7 = 1.0e0_dp + (x + x2*s5)
312 0 : s9 = 1.0e0_dp + (x + x2*s7)
313 0 : s11 = 1.0e0_dp + (x + x2*s9)
314 :
315 : ! SET W = DEL(B) - DEL(A + B)
316 :
317 0 : t = (1.0e0_dp/b)**2
318 0 : w = ((((c5*s11*t + c4*s9)*t + c3*s7)*t + c2*s5)*t + c1*s3)*t + c0
319 0 : w = w*(c/b)
320 :
321 : ! COMBINE THE RESULTS
322 :
323 0 : u = d*alnrel(a/b)
324 0 : v = a*(LOG(b) - 1.0e0_dp)
325 0 : IF (u > v) THEN
326 0 : fn_val = (w - v) - u
327 : ELSE
328 0 : fn_val = (w - u) - v
329 : END IF
330 :
331 0 : END FUNCTION algdiv
332 :
333 : ! **************************************************************************************************
334 : !> \brief ...
335 : !> \param x ...
336 : !> \return ...
337 : ! **************************************************************************************************
338 0 : FUNCTION rexp(x) RESULT(fn_val)
339 : !-----------------------------------------------------------------------
340 : ! EVALUATION OF THE FUNCTION EXP(X) - 1
341 : !-----------------------------------------------------------------------
342 : REAL(dp), INTENT(IN) :: x
343 : REAL(dp) :: fn_val
344 :
345 : REAL(dp), PARAMETER :: p1 = .914041914819518e-09_dp, p2 = .238082361044469e-01_dp, &
346 : q1 = -.499999999085958e+00_dp, q2 = .107141568980644e+00_dp, &
347 : q3 = -.119041179760821e-01_dp, q4 = .595130811860248e-03_dp
348 :
349 : REAL(dp) :: e
350 :
351 0 : IF (ABS(x) < 0.15e0_dp) THEN
352 0 : fn_val = x*(((p2*x + p1)*x + 1.0e0_dp)/((((q4*x + q3)*x + q2)*x + q1)*x + 1.0e0_dp))
353 0 : RETURN
354 : END IF
355 :
356 0 : IF (x < 0.0e0_dp) THEN
357 0 : IF (x > -37.0e0_dp) THEN
358 0 : fn_val = (EXP(x) - 0.5e0_dp) - 0.5e0_dp
359 : ELSE
360 : fn_val = -1.0e0_dp
361 : END IF
362 : ELSE
363 0 : e = EXP(x)
364 0 : fn_val = e*(0.5e0_dp + (0.5e0_dp - 1.0e0_dp/e))
365 : END IF
366 :
367 : END FUNCTION rexp
368 :
369 : ! **************************************************************************************************
370 : !> \brief ...
371 : !> \param a ...
372 : !> \param b ...
373 : !> \param x ...
374 : !> \param y ...
375 : !> \param w ...
376 : !> \param eps ...
377 : !> \param ierr ...
378 : ! **************************************************************************************************
379 0 : SUBROUTINE bgrat(a, b, x, y, w, eps, ierr)
380 : !-----------------------------------------------------------------------
381 : ! ASYMPTOTIC EXPANSION FOR IX(A,B) WHEN A IS LARGER THAN B.
382 : ! THE RESULT OF THE EXPANSION IS ADDED TO W. IT IS ASSUMED
383 : ! THAT A <= 15 AND B <= 1. EPS IS THE TOLERANCE USED.
384 : ! IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS.
385 : !-----------------------------------------------------------------------
386 : REAL(dp), INTENT(IN) :: a, b, x, y
387 : REAL(dp), INTENT(INOUT) :: w
388 : REAL(dp), INTENT(IN) :: eps
389 : INTEGER, INTENT(OUT) :: ierr
390 :
391 : REAL(dp), PARAMETER :: half = 0.5e0_dp, one = 1.e0_dp, &
392 : quarter = 0.25e0_dp, zero = 0.e0_dp
393 :
394 : INTEGER :: i, n
395 : REAL(dp) :: bm1, bp2n, c(30), cn, coef, d(30), dj, &
396 : j, l, lnx, n2, nu, q, r, s, sum, t, &
397 : t2, tol, u, v, z
398 :
399 0 : bm1 = (b - half) - half
400 0 : nu = a + half*bm1
401 0 : IF (y > 0.375e0_dp) THEN
402 0 : lnx = LOG(x)
403 : ELSE
404 0 : lnx = alnrel(-y)
405 : END IF
406 0 : z = -nu*lnx
407 0 : IF (b*z == zero) THEN
408 : ! THE EXPANSION CANNOT BE COMPUTED
409 0 : ierr = 1
410 0 : RETURN
411 : END IF
412 :
413 : ! COMPUTATION OF THE EXPANSION
414 : ! SET R = EXP(-Z)*Z**B/GAMMA(B)
415 :
416 0 : r = b*(one + gam1(b))*EXP(b*LOG(z))
417 0 : r = r*EXP(a*lnx)*EXP(half*bm1*lnx)
418 0 : u = algdiv(b, a) + b*LOG(nu)
419 0 : u = r*EXP(-u)
420 0 : IF (u == zero) THEN
421 : ! THE EXPANSION CANNOT BE COMPUTED
422 0 : ierr = 1
423 0 : RETURN
424 : END IF
425 0 : CALL grat1(b, z, r, q=q, eps=eps)
426 :
427 0 : tol = 15.0e0_dp*eps
428 0 : v = quarter*(one/nu)**2
429 0 : t2 = quarter*lnx*lnx
430 0 : l = w/u
431 0 : j = q/r
432 0 : sum = j
433 0 : t = one
434 0 : cn = one
435 0 : n2 = zero
436 0 : DO n = 1, 30
437 0 : bp2n = b + n2
438 0 : j = (bp2n*(bp2n + one)*j + (z + bp2n + one)*t)*v
439 0 : n2 = n2 + 2.0e0_dp
440 0 : t = t*t2
441 0 : cn = cn/(n2*(n2 + one))
442 0 : c(n) = cn
443 0 : s = zero
444 0 : IF (.NOT. (n == 1)) THEN
445 0 : coef = b - n
446 0 : DO i = 1, n - 1
447 0 : s = s + coef*c(i)*d(n - i)
448 0 : coef = coef + b
449 : END DO
450 : END IF
451 0 : d(n) = bm1*cn + s/n
452 0 : dj = d(n)*j
453 0 : sum = sum + dj
454 0 : IF (sum <= zero) THEN
455 : ! THE EXPANSION CANNOT BE COMPUTED
456 0 : ierr = 1
457 0 : RETURN
458 : END IF
459 0 : IF (ABS(dj) <= tol*(sum + l)) EXIT
460 : END DO
461 :
462 : ! ADD THE RESULTS TO W
463 :
464 0 : ierr = 0
465 0 : w = w + u*sum
466 :
467 : END SUBROUTINE bgrat
468 :
469 : ! **************************************************************************************************
470 : !> \brief ...
471 : !> \param a ...
472 : !> \param x ...
473 : !> \param r ...
474 : !> \param p ...
475 : !> \param q ...
476 : !> \param eps ...
477 : ! **************************************************************************************************
478 0 : SUBROUTINE grat1(a, x, r, p, q, eps)
479 : !-----------------------------------------------------------------------
480 : ! EVALUATION OF P(A,X) AND Q(A,X) WHERE A <= 1 AND
481 : ! THE INPUT ARGUMENT R HAS THE VALUE E**(-X)*X**A/GAMMA(A)
482 : !-----------------------------------------------------------------------
483 : REAL(dp), INTENT(IN) :: a, x, r
484 : REAL(dp), INTENT(OUT), OPTIONAL :: p, q
485 : REAL(dp), INTENT(IN) :: eps
486 :
487 : REAL(dp), PARAMETER :: half = 0.5e0_dp, one = 1.e0_dp, &
488 : quarter = 0.25e0_dp, three = 3.e0_dp, &
489 : two = 2.e0_dp, zero = 0.e0_dp
490 :
491 : REAL(dp) :: a2n, a2nm1, an, b2n, b2nm1, c, g, h, j, &
492 : l, pp, qq, sum, t, tol, w, z
493 :
494 0 : IF (a*x == zero) THEN
495 0 : IF (x <= a) THEN
496 : pp = zero
497 : qq = one
498 : ELSE
499 0 : pp = one
500 0 : qq = zero
501 : END IF
502 0 : IF (PRESENT(p)) p = pp
503 0 : IF (PRESENT(q)) q = qq
504 0 : RETURN
505 : END IF
506 0 : IF (a == half) THEN
507 0 : IF (x < quarter) THEN
508 0 : pp = ERF(SQRT(x))
509 0 : qq = half + (half - pp)
510 : ELSE
511 0 : qq = ERFC(SQRT(x))
512 0 : pp = half + (half - qq)
513 : END IF
514 0 : IF (PRESENT(p)) p = pp
515 0 : IF (PRESENT(q)) q = qq
516 0 : RETURN
517 : END IF
518 0 : IF (x < 1.1e0_dp) THEN
519 : ! TAYLOR SERIES FOR P(A,X)/X**A
520 :
521 0 : an = three
522 0 : c = x
523 0 : sum = x/(a + three)
524 0 : tol = three*eps/(a + one)
525 0 : an = an + one
526 0 : c = -c*(x/an)
527 0 : t = c/(a + an)
528 0 : sum = sum + t
529 0 : DO WHILE (ABS(t) > tol)
530 0 : an = an + one
531 0 : c = -c*(x/an)
532 0 : t = c/(a + an)
533 0 : sum = sum + t
534 : END DO
535 0 : j = a*x*((sum/6.0e0_dp - half/(a + two))*x + one/(a + one))
536 :
537 0 : z = a*LOG(x)
538 0 : h = gam1(a)
539 0 : g = one + h
540 0 : IF ((x < quarter .AND. z > -.13394e0_dp) .OR. a < x/2.59e0_dp) THEN
541 0 : l = rexp(z)
542 0 : qq = ((half + (half + l))*j - l)*g - h
543 0 : IF (qq <= zero) THEN
544 : pp = one
545 : qq = zero
546 : ELSE
547 0 : pp = half + (half - qq)
548 : END IF
549 : ELSE
550 0 : w = EXP(z)
551 0 : pp = w*g*(half + (half - j))
552 0 : qq = half + (half - pp)
553 : END IF
554 : ELSE
555 : ! CONTINUED FRACTION EXPANSION
556 :
557 0 : tol = 8.0e0_dp*eps
558 0 : a2nm1 = one
559 0 : a2n = one
560 0 : b2nm1 = x
561 0 : b2n = x + (one - a)
562 0 : c = one
563 : DO
564 0 : a2nm1 = x*a2n + c*a2nm1
565 0 : b2nm1 = x*b2n + c*b2nm1
566 0 : c = c + one
567 0 : a2n = a2nm1 + (c - a)*a2n
568 0 : b2n = b2nm1 + (c - a)*b2n
569 0 : a2nm1 = a2nm1/b2n
570 0 : b2nm1 = b2nm1/b2n
571 0 : a2n = a2n/b2n
572 0 : b2n = one
573 0 : IF (ABS(a2n - a2nm1/b2nm1) < tol*a2n) EXIT
574 : END DO
575 :
576 0 : qq = r*a2n
577 0 : pp = half + (half - qq)
578 : END IF
579 :
580 0 : IF (PRESENT(p)) p = pp
581 0 : IF (PRESENT(q)) q = qq
582 :
583 : END SUBROUTINE grat1
584 :
585 : ! **************************************************************************************************
586 : !> \brief ...
587 : !> \param mu ...
588 : !> \param x ...
589 : !> \return ...
590 : ! **************************************************************************************************
591 0 : FUNCTION esum(mu, x) RESULT(fn_val)
592 : !-----------------------------------------------------------------------
593 : ! EVALUATION OF EXP(MU + X)
594 : !-----------------------------------------------------------------------
595 : INTEGER, INTENT(IN) :: mu
596 : REAL(dp), INTENT(IN) :: x
597 : REAL(dp) :: fn_val
598 :
599 : REAL(dp) :: w
600 :
601 0 : IF (x > 0.0e0_dp) THEN
602 0 : IF (mu > 0 .OR. mu + x < 0.0_dp) THEN
603 0 : w = mu
604 0 : fn_val = EXP(w)*EXP(x)
605 : ELSE
606 0 : w = mu + x
607 0 : fn_val = EXP(w)
608 : END IF
609 : ELSE
610 0 : IF (mu < 0 .OR. mu + x < 0.0_dp) THEN
611 0 : w = mu
612 0 : fn_val = EXP(w)*EXP(x)
613 : ELSE
614 0 : w = mu + x
615 0 : fn_val = EXP(w)
616 : END IF
617 : END IF
618 :
619 0 : END FUNCTION esum
620 :
621 : ! **************************************************************************************************
622 : !> \brief ...
623 : !> \param x ...
624 : !> \return ...
625 : ! **************************************************************************************************
626 0 : FUNCTION rlog1(x) RESULT(fn_val)
627 : !-----------------------------------------------------------------------
628 : ! EVALUATION OF THE FUNCTION X - LN(1 + X)
629 : !-----------------------------------------------------------------------
630 : ! A = RLOG (0.7)
631 : ! B = RLOG (4/3)
632 : !------------------------
633 : REAL(dp), INTENT(IN) :: x
634 : REAL(dp) :: fn_val
635 :
636 : REAL(dp), PARAMETER :: a = .566749439387324e-01_dp, b = .456512608815524e-01_dp, &
637 : p0 = .333333333333333e+00_dp, p1 = -.224696413112536e+00_dp, &
638 : p2 = .620886815375787e-02_dp, q1 = -.127408923933623e+01_dp, q2 = .354508718369557e+00_dp
639 :
640 : REAL(dp) :: r, t, u, up2, w, w1
641 :
642 0 : IF (x < -0.39e0_dp .OR. x > 0.57e0_dp) THEN
643 0 : w = (x + 0.5e0_dp) + 0.5e0_dp
644 0 : fn_val = x - LOG(w)
645 0 : RETURN
646 : END IF
647 :
648 : ! ARGUMENT REDUCTION
649 :
650 0 : IF (x < -0.18e0_dp) THEN
651 0 : u = (x + 0.3e0_dp)/0.7e0_dp
652 0 : up2 = u + 2.0e0_dp
653 0 : w1 = a - u*0.3e0_dp
654 0 : ELSEIF (x > 0.18e0_dp) THEN
655 0 : t = 0.75e0_dp*x
656 0 : u = t - 0.25e0_dp
657 0 : up2 = t + 1.75e0_dp
658 0 : w1 = b + u/3.0e0_dp
659 : ELSE
660 0 : u = x
661 0 : up2 = u + 2.0e0_dp
662 0 : w1 = 0.0e0_dp
663 : END IF
664 :
665 : ! SERIES EXPANSION
666 :
667 0 : r = u/up2
668 0 : t = r*r
669 0 : w = ((p2*t + p1)*t + p0)/((q2*t + q1)*t + 1.0e0_dp)
670 0 : fn_val = r*(u - 2.0e0_dp*t*w) + w1
671 :
672 0 : END FUNCTION rlog1
673 :
674 : ! **************************************************************************************************
675 : !> \brief ...
676 : !> \param a ...
677 : !> \return ...
678 : ! **************************************************************************************************
679 0 : FUNCTION gamln1(a) RESULT(fn_val)
680 : !-----------------------------------------------------------------------
681 : ! EVALUATION OF LN(GAMMA(1 + A)) FOR -0.2 .LE. A .LE. 1.25
682 : !-----------------------------------------------------------------------
683 : REAL(dp), INTENT(IN) :: a
684 : REAL(dp) :: fn_val
685 :
686 : REAL(dp), PARAMETER :: p0 = .577215664901533e+00_dp, p1 = .844203922187225e+00_dp, &
687 : p2 = -.168860593646662e+00_dp, p3 = -.780427615533591e+00_dp, &
688 : p4 = -.402055799310489e+00_dp, p5 = -.673562214325671e-01_dp, &
689 : p6 = -.271935708322958e-02_dp, q1 = .288743195473681e+01_dp, &
690 : q2 = .312755088914843e+01_dp, q3 = .156875193295039e+01_dp, q4 = .361951990101499e+00_dp, &
691 : q5 = .325038868253937e-01_dp, q6 = .667465618796164e-03_dp, r0 = .422784335098467e+00_dp, &
692 : r1 = .848044614534529e+00_dp, r2 = .565221050691933e+00_dp, r3 = .156513060486551e+00_dp, &
693 : r4 = .170502484022650e-01_dp, r5 = .497958207639485e-03_dp
694 : REAL(dp), PARAMETER :: s1 = .124313399877507e+01_dp, s2 = .548042109832463e+00_dp, &
695 : s3 = .101552187439830e+00_dp, s4 = .713309612391000e-02_dp, s5 = .116165475989616e-03_dp
696 :
697 : REAL(dp) :: w, x
698 :
699 0 : IF (a < 0.6e0_dp) THEN
700 : w = ((((((p6*a + p5)*a + p4)*a + p3)*a + p2)*a + p1)*a + p0)/ &
701 0 : ((((((q6*a + q5)*a + q4)*a + q3)*a + q2)*a + q1)*a + 1.0e0_dp)
702 0 : fn_val = -a*w
703 : ELSE
704 0 : x = (a - 0.5e0_dp) - 0.5e0_dp
705 : w = (((((r5*x + r4)*x + r3)*x + r2)*x + r1)*x + r0)/ &
706 0 : (((((s5*x + s4)*x + s3)*x + s2)*x + s1)*x + 1.0e0_dp)
707 0 : fn_val = x*w
708 : END IF
709 :
710 0 : END FUNCTION gamln1
711 :
712 : ! **************************************************************************************************
713 : !> \brief ...
714 : !> \param xx ...
715 : !> \return ...
716 : ! **************************************************************************************************
717 7564 : FUNCTION psi(xx) RESULT(fn_val)
718 : !---------------------------------------------------------------------
719 :
720 : ! EVALUATION OF THE DIGAMMA FUNCTION
721 :
722 : ! -----------
723 :
724 : ! PSI(XX) IS ASSIGNED THE VALUE 0 WHEN THE DIGAMMA FUNCTION CANNOT
725 : ! BE COMPUTED.
726 :
727 : ! THE MAIN COMPUTATION INVOLVES EVALUATION OF RATIONAL CHEBYSHEV
728 : ! APPROXIMATIONS PUBLISHED IN MATH. COMP. 27, 123-127(1973) BY
729 : ! CODY, STRECOK AND THACHER.
730 :
731 : !---------------------------------------------------------------------
732 : ! PSI WAS WRITTEN AT ARGONNE NATIONAL LABORATORY FOR THE FUNPACK
733 : ! PACKAGE OF SPECIAL FUNCTION SUBROUTINES. PSI WAS MODIFIED BY
734 : ! A.H. MORRIS (NSWC).
735 : !---------------------------------------------------------------------
736 : REAL(dp), INTENT(IN) :: xx
737 : REAL(dp) :: fn_val
738 :
739 : REAL(dp), PARAMETER :: dx0 = 1.461632144968362341262659542325721325e0_dp, p1(7) = (/ &
740 : .895385022981970e-02_dp, .477762828042627e+01_dp, .142441585084029e+03_dp, &
741 : .118645200713425e+04_dp, .363351846806499e+04_dp, .413810161269013e+04_dp, &
742 : .130560269827897e+04_dp/), p2(4) = (/-.212940445131011e+01_dp, -.701677227766759e+01_dp, &
743 : -.448616543918019e+01_dp, -.648157123766197e+00_dp/), piov4 = .785398163397448e0_dp, q1(6)&
744 : = (/.448452573429826e+02_dp, .520752771467162e+03_dp, .221000799247830e+04_dp, &
745 : .364127349079381e+04_dp, .190831076596300e+04_dp, .691091682714533e-05_dp/)
746 : REAL(dp), PARAMETER :: q2(4) = (/.322703493791143e+02_dp, .892920700481861e+02_dp, &
747 : .546117738103215e+02_dp, .777788548522962e+01_dp/)
748 :
749 : INTEGER :: i, m, n, nq
750 : REAL(dp) :: aug, den, sgn, upper, w, x, xmax1, xmx0, &
751 : xsmall, z
752 :
753 : !---------------------------------------------------------------------
754 : ! PIOV4 = PI/4
755 : ! DX0 = ZERO OF PSI TO EXTENDED PRECISION
756 : !---------------------------------------------------------------------
757 : !---------------------------------------------------------------------
758 : ! COEFFICIENTS FOR RATIONAL APPROXIMATION OF
759 : ! PSI(X) / (X - X0), 0.5 <= X <= 3.0
760 : !---------------------------------------------------------------------
761 : !---------------------------------------------------------------------
762 : ! COEFFICIENTS FOR RATIONAL APPROXIMATION OF
763 : ! PSI(X) - LN(X) + 1 / (2*X), X > 3.0
764 : !---------------------------------------------------------------------
765 : !---------------------------------------------------------------------
766 : ! MACHINE DEPENDENT CONSTANTS ...
767 : ! XMAX1 = THE SMALLEST POSITIVE FLOATING POINT CONSTANT
768 : ! WITH ENTIRELY INTEGER REPRESENTATION. ALSO USED
769 : ! AS NEGATIVE OF LOWER BOUND ON ACCEPTABLE NEGATIVE
770 : ! ARGUMENTS AND AS THE POSITIVE ARGUMENT BEYOND WHICH
771 : ! PSI MAY BE REPRESENTED AS ALOG(X).
772 : ! XSMALL = ABSOLUTE ARGUMENT BELOW WHICH PI*COTAN(PI*X)
773 : ! MAY BE REPRESENTED BY 1/X.
774 : !---------------------------------------------------------------------
775 :
776 7564 : xmax1 = ipmpar(3)
777 7564 : xmax1 = MIN(xmax1, 1.0e0_dp/dpmpar(1))
778 7564 : xsmall = 1.e-9_dp
779 : !---------------------------------------------------------------------
780 7564 : x = xx
781 7564 : aug = 0.0e0_dp
782 7564 : IF (x < 0.5e0_dp) THEN
783 : !---------------------------------------------------------------------
784 : ! X .LT. 0.5, USE REFLECTION FORMULA
785 : ! PSI(1-X) = PSI(X) + PI * COTAN(PI*X)
786 : !---------------------------------------------------------------------
787 0 : IF (ABS(x) <= xsmall) THEN
788 0 : IF (x == 0.0e0_dp) THEN
789 : ! ERROR RETURN
790 7564 : fn_val = 0.0e0_dp
791 : RETURN
792 : END IF
793 : !---------------------------------------------------------------------
794 : ! 0 .LT. ABS(X) .LE. XSMALL. USE 1/X AS A SUBSTITUTE
795 : ! FOR PI*COTAN(PI*X)
796 : !---------------------------------------------------------------------
797 0 : aug = -1.0e0_dp/x
798 0 : x = 1.0e0_dp - x
799 : ELSE
800 : !---------------------------------------------------------------------
801 : ! REDUCTION OF ARGUMENT FOR COTAN
802 : !---------------------------------------------------------------------
803 0 : w = -x
804 0 : sgn = piov4
805 0 : IF (w <= 0.0e0_dp) THEN
806 0 : w = -w
807 0 : sgn = -sgn
808 : END IF
809 : !---------------------------------------------------------------------
810 : ! MAKE AN ERROR EXIT IF X .LE. -XMAX1
811 : !---------------------------------------------------------------------
812 0 : IF (w >= xmax1) THEN
813 : ! ERROR RETURN
814 7564 : fn_val = 0.0e0_dp
815 : RETURN
816 : END IF
817 0 : nq = INT(w)
818 0 : w = w - nq
819 0 : nq = INT(w*4.0e0_dp)
820 0 : w = 4.0e0_dp*(w - nq*.25e0_dp)
821 : !---------------------------------------------------------------------
822 : ! W IS NOW RELATED TO THE FRACTIONAL PART OF 4.0 * X.
823 : ! ADJUST ARGUMENT TO CORRESPOND TO VALUES IN FIRST
824 : ! QUADRANT AND DETERMINE SIGN
825 : !---------------------------------------------------------------------
826 0 : n = nq/2
827 0 : IF ((n + n) /= nq) w = 1.0e0_dp - w
828 0 : z = piov4*w
829 0 : m = n/2
830 0 : IF ((m + m) /= n) sgn = -sgn
831 : !---------------------------------------------------------------------
832 : ! DETERMINE FINAL VALUE FOR -PI*COTAN(PI*X)
833 : !---------------------------------------------------------------------
834 0 : n = (nq + 1)/2
835 0 : m = n/2
836 0 : m = m + m
837 0 : IF (m /= n) THEN
838 0 : aug = sgn*((SIN(z)/COS(z))*4.0e0_dp)
839 : ELSE
840 : !---------------------------------------------------------------------
841 : ! CHECK FOR SINGULARITY
842 : !---------------------------------------------------------------------
843 0 : IF (z == 0.0e0_dp) THEN
844 : ! ERROR RETURN
845 7564 : fn_val = 0.0e0_dp
846 : RETURN
847 : END IF
848 : !---------------------------------------------------------------------
849 : ! USE COS/SIN AS A SUBSTITUTE FOR COTAN, AND
850 : ! SIN/COS AS A SUBSTITUTE FOR TAN
851 : !---------------------------------------------------------------------
852 0 : aug = sgn*((COS(z)/SIN(z))*4.0e0_dp)
853 : END IF
854 0 : x = 1.0e0_dp - x
855 : END IF
856 : END IF
857 7564 : IF (x <= 3.0e0_dp) THEN
858 : !---------------------------------------------------------------------
859 : ! 0.5 .LE. X .LE. 3.0
860 : !---------------------------------------------------------------------
861 0 : den = x
862 0 : upper = p1(1)*x
863 :
864 0 : DO i = 1, 5
865 0 : den = (den + q1(i))*x
866 0 : upper = (upper + p1(i + 1))*x
867 : END DO
868 :
869 0 : den = (upper + p1(7))/(den + q1(6))
870 0 : xmx0 = x - dx0
871 0 : fn_val = den*xmx0 + aug
872 0 : RETURN
873 : END IF
874 : !---------------------------------------------------------------------
875 : ! IF X .GE. XMAX1, PSI = LN(X)
876 : !---------------------------------------------------------------------
877 7564 : IF (x < xmax1) THEN
878 : !---------------------------------------------------------------------
879 : ! 3.0 .LT. X .LT. XMAX1
880 : !---------------------------------------------------------------------
881 7564 : w = 1.0e0_dp/(x*x)
882 7564 : den = w
883 7564 : upper = p2(1)*w
884 :
885 30256 : DO i = 1, 3
886 22692 : den = (den + q2(i))*w
887 30256 : upper = (upper + p2(i + 1))*w
888 : END DO
889 :
890 7564 : aug = upper/(den + q2(4)) - 0.5e0_dp/x + aug
891 : END IF
892 7564 : fn_val = aug + LOG(x)
893 :
894 7564 : END FUNCTION psi
895 :
896 : ! **************************************************************************************************
897 : !> \brief ...
898 : !> \param a0 ...
899 : !> \param b0 ...
900 : !> \return ...
901 : ! **************************************************************************************************
902 0 : FUNCTION betaln(a0, b0) RESULT(fn_val)
903 : !-----------------------------------------------------------------------
904 : ! EVALUATION OF THE LOGARITHM OF THE BETA FUNCTION
905 : !-----------------------------------------------------------------------
906 : ! E = 0.5*LN(2*PI)
907 : !--------------------------
908 : REAL(dp), INTENT(IN) :: a0, b0
909 : REAL(dp) :: fn_val
910 :
911 : REAL(dp), PARAMETER :: e = .918938533204673e0_dp
912 :
913 : INTEGER :: i, n
914 : REAL(dp) :: a, b, c, h, u, v, w, z
915 :
916 : !--------------------------
917 :
918 0 : a = MIN(a0, b0)
919 0 : b = MAX(a0, b0)
920 : !-----------------------------------------------------------------------
921 : ! PROCEDURE WHEN A .GE. 8
922 : !-----------------------------------------------------------------------
923 0 : IF (a >= 8.0e0_dp) THEN
924 0 : w = bcorr(a, b)
925 0 : h = a/b
926 0 : c = h/(1.0e0_dp + h)
927 0 : u = -(a - 0.5e0_dp)*LOG(c)
928 0 : v = b*alnrel(h)
929 0 : IF (u > v) THEN
930 0 : fn_val = (((-0.5e0_dp*LOG(b) + e) + w) - v) - u
931 : ELSE
932 0 : fn_val = (((-0.5e0_dp*LOG(b) + e) + w) - u) - v
933 : END IF
934 : !-----------------------------------------------------------------------
935 : ! PROCEDURE WHEN A .LT. 1
936 : !-----------------------------------------------------------------------
937 0 : ELSEIF (a < 1.0e0_dp) THEN
938 0 : IF (b < 8.0e0_dp) THEN
939 0 : fn_val = LOG_GAMMA(a) + (LOG_GAMMA(b) - LOG_GAMMA(a + b))
940 : ELSE
941 0 : fn_val = LOG_GAMMA(a) + algdiv(a, b)
942 : END IF
943 : !-----------------------------------------------------------------------
944 : ! PROCEDURE WHEN 1 .LE. A .LT. 8
945 : !-----------------------------------------------------------------------
946 0 : ELSEIF (a <= 2.0e0_dp) THEN
947 0 : IF (b <= 2.0e0_dp) THEN
948 0 : fn_val = LOG_GAMMA(a) + LOG_GAMMA(b) - gsumln(a, b)
949 0 : RETURN
950 : END IF
951 0 : w = 0.0e0_dp
952 0 : IF (b < 8.0e0_dp) THEN
953 : ! REDUCTION OF B WHEN B .LT. 8
954 :
955 0 : n = INT(b - 1.0e0_dp)
956 0 : z = 1.0e0_dp
957 0 : DO i = 1, n
958 0 : b = b - 1.0e0_dp
959 0 : z = z*(b/(a + b))
960 : END DO
961 0 : fn_val = w + LOG(z) + (LOG_GAMMA(a) + (LOG_GAMMA(b) - gsumln(a, b)))
962 0 : RETURN
963 : END IF
964 0 : fn_val = LOG_GAMMA(a) + algdiv(a, b)
965 : ! REDUCTION OF A WHEN B .LE. 1000
966 0 : ELSEIF (b <= 1000.0e0_dp) THEN
967 0 : n = INT(a - 1.0e0_dp)
968 0 : w = 1.0e0_dp
969 0 : DO i = 1, n
970 0 : a = a - 1.0e0_dp
971 0 : h = a/b
972 0 : w = w*(h/(1.0e0_dp + h))
973 : END DO
974 0 : w = LOG(w)
975 0 : IF (b >= 8.0e0_dp) THEN
976 0 : fn_val = w + LOG_GAMMA(a) + algdiv(a, b)
977 0 : RETURN
978 : END IF
979 :
980 : ! REDUCTION OF B WHEN B .LT. 8
981 :
982 0 : n = INT(b - 1.0e0_dp)
983 0 : z = 1.0e0_dp
984 0 : DO i = 1, n
985 0 : b = b - 1.0e0_dp
986 0 : z = z*(b/(a + b))
987 : END DO
988 0 : fn_val = w + LOG(z) + (LOG_GAMMA(a) + (LOG_GAMMA(b) - gsumln(a, b)))
989 : ELSE
990 : ! REDUCTION OF A WHEN B .GT. 1000
991 :
992 0 : n = INT(a - 1.0e0_dp)
993 0 : w = 1.0e0_dp
994 0 : DO i = 1, n
995 0 : a = a - 1.0e0_dp
996 0 : w = w*(a/(1.0e0_dp + a/b))
997 : END DO
998 0 : fn_val = (LOG(w) - n*LOG(b)) + (LOG_GAMMA(a) + algdiv(a, b))
999 : END IF
1000 :
1001 : END FUNCTION betaln
1002 :
1003 : ! **************************************************************************************************
1004 : !> \brief ...
1005 : !> \param a ...
1006 : !> \param b ...
1007 : !> \return ...
1008 : ! **************************************************************************************************
1009 0 : FUNCTION gsumln(a, b) RESULT(fn_val)
1010 : !-----------------------------------------------------------------------
1011 : ! EVALUATION OF THE FUNCTION LN(GAMMA(A + B))
1012 : ! FOR 1 .LE. A .LE. 2 AND 1 .LE. B .LE. 2
1013 : !-----------------------------------------------------------------------
1014 : REAL(dp), INTENT(IN) :: a, b
1015 : REAL(dp) :: fn_val
1016 :
1017 : REAL(dp) :: x
1018 :
1019 0 : x = a + b - 2.e0_dp
1020 0 : IF (x <= 0.25e0_dp) THEN
1021 0 : fn_val = gamln1(1.0e0_dp + x)
1022 0 : ELSEIF (x <= 1.25e0_dp) THEN
1023 0 : fn_val = gamln1(x) + alnrel(x)
1024 : ELSE
1025 0 : fn_val = gamln1(x - 1.0e0_dp) + LOG(x*(1.0e0_dp + x))
1026 : END IF
1027 0 : END FUNCTION gsumln
1028 :
1029 : ! **************************************************************************************************
1030 : !> \brief ...
1031 : !> \param a0 ...
1032 : !> \param b0 ...
1033 : !> \return ...
1034 : ! **************************************************************************************************
1035 0 : FUNCTION bcorr(a0, b0) RESULT(fn_val)
1036 : !-----------------------------------------------------------------------
1037 :
1038 : ! EVALUATION OF DEL(A0) + DEL(B0) - DEL(A0 + B0) WHERE
1039 : ! LN(GAMMA(A)) = (A - 0.5)*LN(A) - A + 0.5*LN(2*PI) + DEL(A).
1040 : ! IT IS ASSUMED THAT A0 .GE. 8 AND B0 .GE. 8.
1041 :
1042 : !-----------------------------------------------------------------------
1043 : REAL(dp), INTENT(IN) :: a0, b0
1044 : REAL(dp) :: fn_val
1045 :
1046 : REAL(dp), PARAMETER :: c0 = .833333333333333e-01_dp, c1 = -.277777777760991e-02_dp, &
1047 : c2 = .793650666825390e-03_dp, c3 = -.595202931351870e-03_dp, &
1048 : c4 = .837308034031215e-03_dp, c5 = -.165322962780713e-02_dp
1049 :
1050 : REAL(dp) :: a, b, c, h, s11, s3, s5, s7, s9, t, w, &
1051 : x, x2
1052 :
1053 0 : a = MIN(a0, b0)
1054 0 : b = MAX(a0, b0)
1055 :
1056 0 : h = a/b
1057 0 : c = h/(1.0e0_dp + h)
1058 0 : x = 1.0e0_dp/(1.0e0_dp + h)
1059 0 : x2 = x*x
1060 :
1061 : ! SET SN = (1 - X**N)/(1 - X)
1062 :
1063 0 : s3 = 1.0e0_dp + (x + x2)
1064 0 : s5 = 1.0e0_dp + (x + x2*s3)
1065 0 : s7 = 1.0e0_dp + (x + x2*s5)
1066 0 : s9 = 1.0e0_dp + (x + x2*s7)
1067 0 : s11 = 1.0e0_dp + (x + x2*s9)
1068 :
1069 : ! SET W = DEL(B) - DEL(A + B)
1070 :
1071 0 : t = (1.0e0_dp/b)**2
1072 0 : w = ((((c5*s11*t + c4*s9)*t + c3*s7)*t + c2*s5)*t + c1*s3)*t + c0
1073 0 : w = w*(c/b)
1074 :
1075 : ! COMPUTE DEL(A) + W
1076 :
1077 0 : t = (1.0e0_dp/a)**2
1078 0 : fn_val = (((((c5*t + c4)*t + c3)*t + c2)*t + c1)*t + c0)/a + w
1079 : RETURN
1080 : END FUNCTION bcorr
1081 :
1082 : ! **************************************************************************************************
1083 : !> \brief ...
1084 : !> \param a ...
1085 : !> \param b ...
1086 : !> \param x ...
1087 : !> \param y ...
1088 : !> \param w ...
1089 : !> \param w1 ...
1090 : !> \param ierr ...
1091 : ! **************************************************************************************************
1092 0 : SUBROUTINE bratio(a, b, x, y, w, w1, ierr)
1093 : !-----------------------------------------------------------------------
1094 :
1095 : ! EVALUATION OF THE INCOMPLETE BETA FUNCTION IX(A,B)
1096 :
1097 : ! --------------------
1098 :
1099 : ! IT IS ASSUMED THAT A AND B ARE NONNEGATIVE, AND THAT X <= 1
1100 : ! AND Y = 1 - X. BRATIO ASSIGNS W AND W1 THE VALUES
1101 :
1102 : ! W = IX(A,B)
1103 : ! W1 = 1 - IX(A,B)
1104 :
1105 : ! IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS.
1106 : ! IF NO INPUT ERRORS ARE DETECTED THEN IERR IS SET TO 0 AND
1107 : ! W AND W1 ARE COMPUTED. OTHERWISE, IF AN ERROR IS DETECTED,
1108 : ! THEN W AND W1 ARE ASSIGNED THE VALUE 0 AND IERR IS SET TO
1109 : ! ONE OF THE FOLLOWING VALUES ...
1110 :
1111 : ! IERR = 1 IF A OR B IS NEGATIVE
1112 : ! IERR = 2 IF A = B = 0
1113 : ! IERR = 3 IF X .LT. 0 OR X .GT. 1
1114 : ! IERR = 4 IF Y .LT. 0 OR Y .GT. 1
1115 : ! IERR = 5 IF X + Y .NE. 1
1116 : ! IERR = 6 IF X = A = 0
1117 : ! IERR = 7 IF Y = B = 0
1118 :
1119 : !--------------------
1120 : ! WRITTEN BY ALFRED H. MORRIS, JR.
1121 : ! NAVAL SURFACE WARFARE CENTER
1122 : ! DAHLGREN, VIRGINIA
1123 : ! REVISED ... APRIL 1993
1124 : !-----------------------------------------------------------------------
1125 : REAL(dp), INTENT(IN) :: a, b, x, y
1126 : REAL(dp), INTENT(OUT) :: w, w1
1127 : INTEGER, INTENT(OUT) :: ierr
1128 :
1129 : INTEGER :: ierr1, ind, n
1130 : REAL(dp) :: a0, b0, eps, lambda, t, x0, y0, z
1131 :
1132 : !-----------------------------------------------------------------------
1133 : ! ****** EPS IS A MACHINE DEPENDENT CONSTANT. EPS IS THE SMALLEST
1134 : ! FLOATING POINT NUMBER FOR WHICH 1.0 + EPS .GT. 1.0
1135 :
1136 0 : eps = dpmpar(1)
1137 :
1138 0 : w = 0.0e0_dp
1139 0 : w1 = 0.0e0_dp
1140 0 : IF (a < 0.0e0_dp .OR. b < 0.0e0_dp) THEN
1141 0 : ierr = 1
1142 0 : RETURN
1143 : END IF
1144 0 : IF (a == 0.0e0_dp .AND. b == 0.0e0_dp) THEN
1145 0 : ierr = 2
1146 0 : RETURN
1147 : END IF
1148 0 : IF (x < 0.0e0_dp .OR. x > 1.0e0_dp) THEN
1149 0 : ierr = 3
1150 0 : RETURN
1151 : END IF
1152 0 : IF (y < 0.0e0_dp .OR. y > 1.0e0_dp) THEN
1153 0 : ierr = 4
1154 0 : RETURN
1155 : END IF
1156 0 : z = ((x + y) - 0.5e0_dp) - 0.5e0_dp
1157 0 : IF (ABS(z) > 3.0e0_dp*eps) THEN
1158 0 : ierr = 5
1159 0 : RETURN
1160 : END IF
1161 :
1162 0 : ierr = 0
1163 :
1164 0 : IF (x == 0.0e0_dp .OR. a == 0.0e0_dp) THEN
1165 0 : IF (x == 0.0e0_dp .AND. a == 0.0e0_dp) THEN
1166 0 : ierr = 6
1167 : ELSE
1168 : w = 0.0e0_dp
1169 0 : w1 = 1.0e0_dp
1170 : END IF
1171 0 : RETURN
1172 : END IF
1173 :
1174 0 : IF (y == 0.0e0_dp .OR. b == 0.0e0_dp) THEN
1175 0 : IF (y == 0.0e0_dp .AND. b == 0.0e0_dp) THEN
1176 0 : ierr = 7
1177 : ELSE
1178 0 : w = 1.0e0_dp
1179 : w1 = 0.0e0_dp
1180 : END IF
1181 0 : RETURN
1182 : END IF
1183 :
1184 0 : eps = MAX(eps, 1.e-15_dp)
1185 0 : IF (MAX(a, b) < 1.e-3_dp*eps) THEN
1186 : ! PROCEDURE FOR A AND B .LT. 1.E-3*EPS
1187 0 : w = b/(a + b)
1188 0 : w1 = a/(a + b)
1189 0 : RETURN
1190 : END IF
1191 :
1192 0 : ind = 0
1193 0 : a0 = a
1194 0 : b0 = b
1195 0 : x0 = x
1196 0 : y0 = y
1197 0 : IF (MIN(a0, b0) > 1.0e0_dp) GO TO 30
1198 :
1199 : ! PROCEDURE FOR A0 .LE. 1 OR B0 .LE. 1
1200 :
1201 0 : IF (x > 0.5e0_dp) THEN
1202 0 : ind = 1
1203 0 : a0 = b
1204 0 : b0 = a
1205 0 : x0 = y
1206 0 : y0 = x
1207 : END IF
1208 :
1209 0 : IF (b0 < MIN(eps, eps*a0)) GO TO 80
1210 0 : IF (a0 < MIN(eps, eps*b0) .AND. b0*x0 <= 1.0e0_dp) GO TO 90
1211 0 : IF (MAX(a0, b0) > 1.0e0_dp) GO TO 20
1212 0 : IF (a0 >= MIN(0.2e0_dp, b0)) GO TO 100
1213 0 : IF (x0**a0 <= 0.9e0_dp) GO TO 100
1214 0 : IF (x0 >= 0.3e0_dp) GO TO 110
1215 0 : n = 20
1216 0 : GO TO 130
1217 :
1218 0 : 20 IF (b0 <= 1.0e0_dp) GO TO 100
1219 0 : IF (x0 >= 0.3e0_dp) GO TO 110
1220 0 : IF (x0 < 0.1e0_dp .AND. (x0*b0)**a0 <= 0.7e0_dp) GO TO 100
1221 0 : IF (b0 > 15.0e0_dp) GO TO 131
1222 0 : n = 20
1223 0 : GO TO 130
1224 :
1225 : ! PROCEDURE FOR A0 .GT. 1 AND B0 .GT. 1
1226 :
1227 0 : 30 IF (a > b) THEN
1228 0 : lambda = (a + b)*y - b
1229 : ELSE
1230 0 : lambda = a - (a + b)*x
1231 : END IF
1232 :
1233 0 : IF (lambda < 0.0e0_dp) THEN
1234 0 : ind = 1
1235 0 : a0 = b
1236 0 : b0 = a
1237 0 : x0 = y
1238 0 : y0 = x
1239 0 : lambda = ABS(lambda)
1240 : END IF
1241 :
1242 0 : IF (b0 < 40.0e0_dp .AND. b0*x0 <= 0.7e0_dp) GO TO 100
1243 0 : IF (b0 < 40.0e0_dp) GO TO 140
1244 0 : IF (a0 > b0) GO TO 50
1245 0 : IF (a0 <= 100.0e0_dp) GO TO 120
1246 0 : IF (lambda > 0.03e0_dp*a0) GO TO 120
1247 0 : GO TO 180
1248 0 : 50 IF (b0 <= 100.0e0_dp) GO TO 120
1249 0 : IF (lambda > 0.03e0_dp*b0) GO TO 120
1250 0 : GO TO 180
1251 :
1252 : ! EVALUATION OF THE APPROPRIATE ALGORITHM
1253 :
1254 0 : 80 w = fpser(a0, b0, x0, eps)
1255 0 : w1 = 0.5e0_dp + (0.5e0_dp - w)
1256 0 : GO TO 220
1257 :
1258 0 : 90 w1 = apser(a0, b0, x0, eps)
1259 0 : w = 0.5e0_dp + (0.5e0_dp - w1)
1260 0 : GO TO 220
1261 :
1262 0 : 100 w = bpser(a0, b0, x0, eps)
1263 0 : w1 = 0.5e0_dp + (0.5e0_dp - w)
1264 0 : GO TO 220
1265 :
1266 0 : 110 w1 = bpser(b0, a0, y0, eps)
1267 0 : w = 0.5e0_dp + (0.5e0_dp - w1)
1268 0 : GO TO 220
1269 :
1270 0 : 120 w = bfrac(a0, b0, x0, y0, lambda, 15.0e0_dp*eps)
1271 0 : w1 = 0.5e0_dp + (0.5e0_dp - w)
1272 0 : GO TO 220
1273 :
1274 0 : 130 w1 = bup(b0, a0, y0, x0, n, eps)
1275 0 : b0 = b0 + n
1276 0 : 131 CALL bgrat(b0, a0, y0, x0, w1, eps, ierr1)
1277 0 : IF (ierr1 > 0) CPABORT("Error in BGRAT")
1278 0 : w = 0.5e0_dp + (0.5e0_dp - w1)
1279 0 : GO TO 220
1280 :
1281 0 : 140 n = INT(b0)
1282 0 : b0 = b0 - n
1283 0 : IF (b0 /= 0.0e0_dp) GO TO 141
1284 0 : n = n - 1
1285 0 : b0 = 1.0e0_dp
1286 0 : 141 w = bup(b0, a0, y0, x0, n, eps)
1287 0 : IF (x0 > 0.7e0_dp) GO TO 150
1288 0 : w = w + bpser(a0, b0, x0, eps)
1289 0 : w1 = 0.5e0_dp + (0.5e0_dp - w)
1290 0 : GO TO 220
1291 :
1292 0 : 150 IF (a0 > 15.0e0_dp) GO TO 151
1293 0 : n = 20
1294 0 : w = w + bup(a0, b0, x0, y0, n, eps)
1295 0 : a0 = a0 + n
1296 0 : 151 CALL bgrat(a0, b0, x0, y0, w, eps, ierr1)
1297 0 : w1 = 0.5e0_dp + (0.5e0_dp - w)
1298 0 : GO TO 220
1299 :
1300 0 : 180 w = basym(a0, b0, lambda, 100.0e0_dp*eps)
1301 0 : w1 = 0.5e0_dp + (0.5e0_dp - w)
1302 0 : GO TO 220
1303 :
1304 : ! TERMINATION OF THE PROCEDURE
1305 :
1306 0 : 220 IF (ind == 0) RETURN
1307 0 : t = w
1308 0 : w = w1
1309 0 : w1 = t
1310 :
1311 : END SUBROUTINE bratio
1312 :
1313 : ! **************************************************************************************************
1314 : !> \brief ...
1315 : !> \param a ...
1316 : !> \param b ...
1317 : !> \param x ...
1318 : !> \param eps ...
1319 : !> \return ...
1320 : ! **************************************************************************************************
1321 0 : FUNCTION fpser(a, b, x, eps) RESULT(fn_val)
1322 : !-----------------------------------------------------------------------
1323 :
1324 : ! EVALUATION OF I (A,B)
1325 : ! X
1326 :
1327 : ! FOR B .LT. MIN(EPS,EPS*A) AND X .LE. 0.5.
1328 :
1329 : !-----------------------------------------------------------------------
1330 : REAL(dp), INTENT(IN) :: a, b, x, eps
1331 : REAL(dp) :: fn_val
1332 :
1333 : REAL(dp) :: an, c, s, t, tol
1334 :
1335 : ! SET FPSER = X**A
1336 :
1337 0 : fn_val = 1.0e0_dp
1338 0 : IF (a > 1.e-3_dp*eps) THEN
1339 0 : fn_val = 0.0e0_dp
1340 0 : t = a*LOG(x)
1341 0 : IF (t < dxparg(1)) RETURN
1342 0 : fn_val = EXP(t)
1343 : END IF
1344 :
1345 : ! NOTE THAT 1/B(A,B) = B
1346 :
1347 0 : fn_val = (b/a)*fn_val
1348 0 : tol = eps/a
1349 0 : an = a + 1.0e0_dp
1350 0 : t = x
1351 0 : s = t/an
1352 0 : an = an + 1.0e0_dp
1353 0 : t = x*t
1354 0 : c = t/an
1355 0 : s = s + c
1356 0 : DO WHILE (ABS(c) > tol)
1357 0 : an = an + 1.0e0_dp
1358 0 : t = x*t
1359 0 : c = t/an
1360 0 : s = s + c
1361 : END DO
1362 :
1363 0 : fn_val = fn_val*(1.0e0_dp + a*s)
1364 :
1365 0 : END FUNCTION fpser
1366 :
1367 : ! **************************************************************************************************
1368 : !> \brief ...
1369 : !> \param a ...
1370 : !> \param b ...
1371 : !> \param x ...
1372 : !> \param eps ...
1373 : !> \return ...
1374 : ! **************************************************************************************************
1375 0 : FUNCTION apser(a, b, x, eps) RESULT(fn_val)
1376 : !-----------------------------------------------------------------------
1377 : ! APSER YIELDS THE INCOMPLETE BETA RATIO I(SUB(1-X))(B,A) FOR
1378 : ! A .LE. MIN(EPS,EPS*B), B*X .LE. 1, AND X .LE. 0.5. USED WHEN
1379 : ! A IS VERY SMALL. USE ONLY IF ABOVE INEQUALITIES ARE SATISFIED.
1380 : !-----------------------------------------------------------------------
1381 : REAL(dp), INTENT(IN) :: a, b, x, eps
1382 : REAL(dp) :: fn_val
1383 :
1384 : REAL(dp), PARAMETER :: g = .577215664901533e0_dp
1385 :
1386 : REAL(dp) :: aj, bx, c, j, s, t, tol
1387 :
1388 0 : bx = b*x
1389 0 : t = x - bx
1390 0 : IF (b*eps > 2.e-2_dp) THEN
1391 0 : c = LOG(bx) + g + t
1392 : ELSE
1393 0 : c = LOG(x) + psi(b) + g + t
1394 : END IF
1395 :
1396 0 : tol = 5.0e0_dp*eps*ABS(c)
1397 : j = 1.0e0_dp
1398 0 : s = 0.0e0_dp
1399 0 : j = j + 1.0e0_dp
1400 0 : t = t*(x - bx/j)
1401 0 : aj = t/j
1402 0 : s = s + aj
1403 0 : DO WHILE (ABS(aj) > tol)
1404 0 : t = t*(x - bx/j)
1405 0 : aj = t/j
1406 0 : s = s + aj
1407 : END DO
1408 :
1409 0 : fn_val = -a*(c + s)
1410 :
1411 0 : END FUNCTION apser
1412 :
1413 : ! **************************************************************************************************
1414 : !> \brief ...
1415 : !> \param a ...
1416 : !> \param b ...
1417 : !> \param x ...
1418 : !> \param eps ...
1419 : !> \return ...
1420 : ! **************************************************************************************************
1421 0 : FUNCTION bpser(a, b, x, eps) RESULT(fn_val)
1422 : !-----------------------------------------------------------------------
1423 : ! POWER SERIES EXPANSION FOR EVALUATING IX(A,B) WHEN B .LE. 1
1424 : ! OR B*X .LE. 0.7. EPS IS THE TOLERANCE USED.
1425 : !-----------------------------------------------------------------------
1426 : REAL(dp), INTENT(IN) :: a, b, x, eps
1427 : REAL(dp) :: fn_val
1428 :
1429 : INTEGER :: i, m
1430 : REAL(dp) :: a0, apb, b0, c, n, sum, t, tol, u, w, z
1431 :
1432 0 : fn_val = 0.0e0_dp
1433 0 : IF (x == 0.0e0_dp) RETURN
1434 : !-----------------------------------------------------------------------
1435 : ! COMPUTE THE FACTOR X**A/(A*BETA(A,B))
1436 : !-----------------------------------------------------------------------
1437 0 : a0 = MIN(a, b)
1438 0 : b0 = MAX(a, b)
1439 0 : IF (a0 >= 1.0e0_dp) THEN
1440 0 : z = a*LOG(x) - betaln(a, b)
1441 0 : fn_val = EXP(z)/a
1442 0 : ELSEIF (b0 >= 8.0e0_dp) THEN
1443 0 : u = gamln1(a0) + algdiv(a0, b0)
1444 0 : z = a*LOG(x) - u
1445 0 : fn_val = (a0/a)*EXP(z)
1446 0 : ELSEIF (b0 > 1.0e0_dp) THEN
1447 : ! PROCEDURE FOR A0 .LT. 1 AND 1 .LT. B0 .LT. 8
1448 :
1449 0 : u = gamln1(a0)
1450 0 : m = INT(b0 - 1.0e0_dp)
1451 0 : IF (m >= 1) THEN
1452 : c = 1.0e0_dp
1453 0 : DO i = 1, m
1454 0 : b0 = b0 - 1.0e0_dp
1455 0 : c = c*(b0/(a0 + b0))
1456 : END DO
1457 0 : u = LOG(c) + u
1458 : END IF
1459 :
1460 0 : z = a*LOG(x) - u
1461 0 : b0 = b0 - 1.0e0_dp
1462 0 : apb = a0 + b0
1463 0 : IF (apb > 1.0e0_dp) THEN
1464 0 : u = a0 + b0 - 1.e0_dp
1465 0 : t = (1.0e0_dp + gam1(u))/apb
1466 : ELSE
1467 0 : t = 1.0e0_dp + gam1(apb)
1468 : END IF
1469 0 : fn_val = EXP(z)*(a0/a)*(1.0e0_dp + gam1(b0))/t
1470 : ELSE
1471 :
1472 : ! PROCEDURE FOR A0 .LT. 1 AND B0 .LE. 1
1473 :
1474 0 : fn_val = x**a
1475 0 : IF (fn_val == 0.0e0_dp) RETURN
1476 :
1477 0 : apb = a + b
1478 0 : IF (apb > 1.0e0_dp) THEN
1479 0 : u = a + b - 1.e0_dp
1480 0 : z = (1.0e0_dp + gam1(u))/apb
1481 : ELSE
1482 0 : z = 1.0e0_dp + gam1(apb)
1483 : END IF
1484 :
1485 0 : c = (1.0e0_dp + gam1(a))*(1.0e0_dp + gam1(b))/z
1486 0 : fn_val = fn_val*c*(b/apb)
1487 : END IF
1488 :
1489 : ! PROCEDURE FOR A0 .LT. 1 AND B0 .GE. 8
1490 :
1491 0 : IF (fn_val == 0.0e0_dp .OR. a <= 0.1e0_dp*eps) RETURN
1492 : !-----------------------------------------------------------------------
1493 : ! COMPUTE THE SERIES
1494 : !-----------------------------------------------------------------------
1495 0 : sum = 0.0e0_dp
1496 0 : n = 0.0e0_dp
1497 0 : c = 1.0e0_dp
1498 0 : tol = eps/a
1499 0 : n = n + 1.0e0_dp
1500 0 : c = c*(0.5e0_dp + (0.5e0_dp - b/n))*x
1501 0 : w = c/(a + n)
1502 0 : sum = sum + w
1503 0 : DO WHILE (ABS(w) > tol)
1504 0 : n = n + 1.0e0_dp
1505 0 : c = c*(0.5e0_dp + (0.5e0_dp - b/n))*x
1506 0 : w = c/(a + n)
1507 0 : sum = sum + w
1508 : END DO
1509 0 : fn_val = fn_val*(1.0e0_dp + a*sum)
1510 :
1511 0 : END FUNCTION bpser
1512 :
1513 : ! **************************************************************************************************
1514 : !> \brief ...
1515 : !> \param a ...
1516 : !> \param b ...
1517 : !> \param x ...
1518 : !> \param y ...
1519 : !> \param n ...
1520 : !> \param eps ...
1521 : !> \return ...
1522 : ! **************************************************************************************************
1523 0 : FUNCTION bup(a, b, x, y, n, eps) RESULT(fn_val)
1524 : !-----------------------------------------------------------------------
1525 : ! EVALUATION OF IX(A,B) - IX(A+N,B) WHERE N IS A POSITIVE INTEGER.
1526 : ! EPS IS THE TOLERANCE USED.
1527 : !-----------------------------------------------------------------------
1528 : REAL(dp), INTENT(IN) :: a, b, x, y
1529 : INTEGER, INTENT(IN) :: n
1530 : REAL(dp), INTENT(IN) :: eps
1531 : REAL(dp) :: fn_val
1532 :
1533 : INTEGER :: i, k, kp1, mu, nm1
1534 : REAL(dp) :: ap1, apb, d, l, r, t, w
1535 :
1536 : ! OBTAIN THE SCALING FACTOR EXP(-MU) AND
1537 : ! EXP(MU)*(X**A*Y**B/BETA(A,B))/A
1538 :
1539 0 : apb = a + b
1540 0 : ap1 = a + 1.0e0_dp
1541 0 : mu = 0
1542 0 : d = 1.0e0_dp
1543 0 : IF (.NOT. (n == 1 .OR. a < 1.0e0_dp .OR. apb < 1.1e0_dp*ap1)) THEN
1544 0 : mu = INT(ABS(dxparg(1)))
1545 0 : k = INT(dxparg(0))
1546 0 : IF (k < mu) mu = k
1547 0 : t = mu
1548 0 : d = EXP(-t)
1549 : END IF
1550 :
1551 0 : fn_val = brcmp1(mu, a, b, x, y)/a
1552 0 : IF (n == 1 .OR. fn_val == 0.0e0_dp) RETURN
1553 0 : nm1 = n - 1
1554 0 : w = d
1555 :
1556 : ! LET K BE THE INDEX OF THE MAXIMUM TERM
1557 :
1558 0 : k = 0
1559 0 : IF (b > 1.0e0_dp) THEN
1560 0 : IF (y <= 1.e-4_dp) THEN
1561 0 : k = nm1
1562 0 : DO i = 1, k
1563 0 : l = i - 1
1564 0 : d = ((apb + l)/(ap1 + l))*x*d
1565 0 : w = w + d
1566 : END DO
1567 : IF (k == nm1) THEN
1568 0 : fn_val = fn_val*w
1569 0 : RETURN
1570 : END IF
1571 : ELSE
1572 0 : r = (b - 1.0e0_dp)*x/y - a
1573 0 : IF (r >= 1.0e0_dp) THEN
1574 0 : k = nm1
1575 0 : t = nm1
1576 0 : IF (r < t) k = INT(r)
1577 :
1578 : ! ADD THE INCREASING TERMS OF THE SERIES
1579 :
1580 0 : DO i = 1, k
1581 0 : l = i - 1
1582 0 : d = ((apb + l)/(ap1 + l))*x*d
1583 0 : w = w + d
1584 : END DO
1585 0 : IF (k == nm1) THEN
1586 0 : fn_val = fn_val*w
1587 0 : RETURN
1588 : END IF
1589 : END IF
1590 : END IF
1591 : END IF
1592 :
1593 : ! ADD THE REMAINING TERMS OF THE SERIES
1594 :
1595 0 : kp1 = k + 1
1596 0 : DO i = kp1, nm1
1597 0 : l = i - 1
1598 0 : d = ((apb + l)/(ap1 + l))*x*d
1599 0 : w = w + d
1600 0 : IF (d <= eps*w) EXIT
1601 : END DO
1602 :
1603 : ! TERMINATE THE PROCEDURE
1604 :
1605 0 : fn_val = fn_val*w
1606 :
1607 0 : END FUNCTION bup
1608 :
1609 : ! **************************************************************************************************
1610 : !> \brief ...
1611 : !> \param a ...
1612 : !> \param b ...
1613 : !> \param x ...
1614 : !> \param y ...
1615 : !> \param lambda ...
1616 : !> \param eps ...
1617 : !> \return ...
1618 : ! **************************************************************************************************
1619 0 : FUNCTION bfrac(a, b, x, y, lambda, eps) RESULT(fn_val)
1620 : !-----------------------------------------------------------------------
1621 : ! CONTINUED FRACTION EXPANSION FOR IX(A,B) WHEN A,B .GT. 1.
1622 : ! IT IS ASSUMED THAT LAMBDA = (A + B)*Y - B.
1623 : !-----------------------------------------------------------------------
1624 : REAL(dp), INTENT(IN) :: a, b, x, y, lambda, eps
1625 : REAL(dp) :: fn_val
1626 :
1627 : REAL(dp) :: alpha, an, anp1, beta, bn, bnp1, c, c0, &
1628 : c1, e, n, p, r, r0, s, t, w, yp1
1629 :
1630 0 : fn_val = brcomp(a, b, x, y)
1631 0 : IF (fn_val == 0.0e0_dp) RETURN
1632 :
1633 0 : c = 1.0e0_dp + lambda
1634 0 : c0 = b/a
1635 0 : c1 = 1.0e0_dp + 1.0e0_dp/a
1636 0 : yp1 = y + 1.0e0_dp
1637 :
1638 0 : n = 0.0e0_dp
1639 0 : p = 1.0e0_dp
1640 0 : s = a + 1.0e0_dp
1641 0 : an = 0.0e0_dp
1642 0 : bn = 1.0e0_dp
1643 0 : anp1 = 1.0e0_dp
1644 0 : bnp1 = c/c1
1645 0 : r = c1/c
1646 :
1647 : ! CONTINUED FRACTION CALCULATION
1648 :
1649 0 : DO WHILE (.TRUE.)
1650 0 : n = n + 1.0e0_dp
1651 0 : t = n/a
1652 0 : w = n*(b - n)*x
1653 0 : e = a/s
1654 0 : alpha = (p*(p + c0)*e*e)*(w*x)
1655 0 : IF (alpha <= 0.0e0_dp) THEN
1656 : ! TERMINATION
1657 0 : fn_val = fn_val*r
1658 0 : RETURN
1659 : END IF
1660 0 : e = (1.0e0_dp + t)/(c1 + t + t)
1661 0 : beta = n + w/s + e*(c + n*yp1)
1662 0 : p = 1.0e0_dp + t
1663 0 : s = s + 2.0e0_dp
1664 :
1665 : ! UPDATE AN, BN, ANP1, AND BNP1
1666 :
1667 0 : t = alpha*an + beta*anp1
1668 0 : an = anp1
1669 0 : anp1 = t
1670 0 : t = alpha*bn + beta*bnp1
1671 0 : bn = bnp1
1672 0 : bnp1 = t
1673 0 : r0 = r
1674 0 : r = anp1/bnp1
1675 0 : IF (ABS(r - r0) <= eps*r) THEN
1676 : ! TERMINATION
1677 0 : fn_val = fn_val*r
1678 0 : RETURN
1679 : END IF
1680 :
1681 : ! RESCALE AN, BN, ANP1, AND BNP1
1682 :
1683 0 : an = an/bnp1
1684 0 : bn = bn/bnp1
1685 0 : anp1 = r
1686 0 : bnp1 = 1.0e0_dp
1687 : END DO
1688 :
1689 : END FUNCTION bfrac
1690 :
1691 : ! **************************************************************************************************
1692 : !> \brief ...
1693 : !> \param a ...
1694 : !> \param b ...
1695 : !> \param x ...
1696 : !> \param y ...
1697 : !> \return ...
1698 : ! **************************************************************************************************
1699 0 : FUNCTION brcomp(a, b, x, y) RESULT(fn_val)
1700 : !-----------------------------------------------------------------------
1701 : ! EVALUATION OF X**A*Y**B/BETA(A,B)
1702 : !-----------------------------------------------------------------------
1703 : REAL(dp), INTENT(IN) :: a, b, x, y
1704 : REAL(dp) :: fn_val
1705 :
1706 : REAL(dp), PARAMETER :: const = 0.398942280401433e0_dp
1707 :
1708 : INTEGER :: i, n
1709 : REAL(dp) :: a0, apb, b0, c, e, h, lambda, lnx, lny, &
1710 : t, u, v, x0, y0, z
1711 :
1712 : !-----------------
1713 : ! CONST = 1/SQRT(2*PI)
1714 : !-----------------
1715 :
1716 0 : fn_val = 0.0e0_dp
1717 0 : IF (x == 0.0e0_dp .OR. y == 0.0e0_dp) RETURN
1718 0 : a0 = MIN(a, b)
1719 0 : IF (a0 >= 8.0e0_dp) THEN
1720 : !-----------------------------------------------------------------------
1721 : ! PROCEDURE FOR A .GE. 8 AND B .GE. 8
1722 : !-----------------------------------------------------------------------
1723 0 : IF (a > b) THEN
1724 0 : h = b/a
1725 0 : x0 = 1.0e0_dp/(1.0e0_dp + h)
1726 0 : y0 = h/(1.0e0_dp + h)
1727 0 : lambda = (a + b)*y - b
1728 : ELSE
1729 0 : h = a/b
1730 0 : x0 = h/(1.0e0_dp + h)
1731 0 : y0 = 1.0e0_dp/(1.0e0_dp + h)
1732 0 : lambda = a - (a + b)*x
1733 : END IF
1734 :
1735 0 : e = -lambda/a
1736 0 : IF (ABS(e) > 0.6e0_dp) THEN
1737 0 : u = e - LOG(x/x0)
1738 : ELSE
1739 0 : u = rlog1(e)
1740 : END IF
1741 :
1742 0 : e = lambda/b
1743 0 : IF (ABS(e) > 0.6e0_dp) THEN
1744 0 : v = e - LOG(y/y0)
1745 : ELSE
1746 0 : v = rlog1(e)
1747 : END IF
1748 :
1749 0 : z = EXP(-(a*u + b*v))
1750 0 : fn_val = const*SQRT(b*x0)*z*EXP(-bcorr(a, b))
1751 0 : RETURN
1752 : END IF
1753 :
1754 0 : IF (x > 0.375e0_dp) THEN
1755 0 : IF (y > 0.375e0_dp) THEN
1756 0 : lnx = LOG(x)
1757 0 : lny = LOG(y)
1758 : ELSE
1759 0 : lnx = alnrel(-y)
1760 0 : lny = LOG(y)
1761 : END IF
1762 : ELSE
1763 0 : lnx = LOG(x)
1764 0 : lny = alnrel(-x)
1765 : END IF
1766 :
1767 0 : z = a*lnx + b*lny
1768 0 : IF (a0 >= 1.0e0_dp) THEN
1769 0 : z = z - betaln(a, b)
1770 0 : fn_val = EXP(z)
1771 0 : RETURN
1772 : END IF
1773 : !-----------------------------------------------------------------------
1774 : ! PROCEDURE FOR A .LT. 1 OR B .LT. 1
1775 : !-----------------------------------------------------------------------
1776 0 : b0 = MAX(a, b)
1777 0 : IF (b0 >= 8.0e0_dp) THEN
1778 : ! ALGORITHM FOR B0 .GE. 8
1779 0 : u = gamln1(a0) + algdiv(a0, b0)
1780 0 : fn_val = a0*EXP(z - u)
1781 : END IF
1782 0 : IF (b0 <= 1.0e0_dp) THEN
1783 :
1784 : ! ALGORITHM FOR B0 .LE. 1
1785 :
1786 0 : fn_val = EXP(z)
1787 0 : IF (fn_val == 0.0e0_dp) RETURN
1788 :
1789 0 : apb = a + b
1790 0 : IF (apb > 1.0e0_dp) THEN
1791 0 : u = a + b - 1.e0_dp
1792 0 : z = (1.0e0_dp + gam1(u))/apb
1793 : ELSE
1794 0 : z = 1.0e0_dp + gam1(apb)
1795 : END IF
1796 :
1797 0 : c = (1.0e0_dp + gam1(a))*(1.0e0_dp + gam1(b))/z
1798 0 : fn_val = fn_val*(a0*c)/(1.0e0_dp + a0/b0)
1799 0 : RETURN
1800 : END IF
1801 :
1802 : ! ALGORITHM FOR 1 .LT. B0 .LT. 8
1803 :
1804 0 : u = gamln1(a0)
1805 0 : n = INT(b0 - 1.0e0_dp)
1806 0 : IF (n >= 1) THEN
1807 : c = 1.0e0_dp
1808 0 : DO i = 1, n
1809 0 : b0 = b0 - 1.0e0_dp
1810 0 : c = c*(b0/(a0 + b0))
1811 : END DO
1812 0 : u = LOG(c) + u
1813 : END IF
1814 :
1815 0 : z = z - u
1816 0 : b0 = b0 - 1.0e0_dp
1817 0 : apb = a0 + b0
1818 0 : IF (apb > 1.0e0_dp) THEN
1819 0 : u = a0 + b0 - 1.e0_dp
1820 0 : t = (1.0e0_dp + gam1(u))/apb
1821 : ELSE
1822 0 : t = 1.0e0_dp + gam1(apb)
1823 : END IF
1824 0 : fn_val = a0*EXP(z)*(1.0e0_dp + gam1(b0))/t
1825 :
1826 0 : END FUNCTION brcomp
1827 :
1828 : ! **************************************************************************************************
1829 : !> \brief ...
1830 : !> \param mu ...
1831 : !> \param a ...
1832 : !> \param b ...
1833 : !> \param x ...
1834 : !> \param y ...
1835 : !> \return ...
1836 : ! **************************************************************************************************
1837 0 : FUNCTION brcmp1(mu, a, b, x, y) RESULT(fn_val)
1838 : !-----------------------------------------------------------------------
1839 : ! EVALUATION OF EXP(MU) * (X**A*Y**B/BETA(A,B))
1840 : !-----------------------------------------------------------------------
1841 : INTEGER, INTENT(IN) :: mu
1842 : REAL(dp), INTENT(IN) :: a, b, x, y
1843 : REAL(dp) :: fn_val
1844 :
1845 : REAL(dp), PARAMETER :: const = 0.398942280401433e0_dp
1846 :
1847 : INTEGER :: i, n
1848 : REAL(dp) :: a0, apb, b0, c, e, h, lambda, lnx, lny, &
1849 : t, u, v, x0, y0, z
1850 :
1851 : !-----------------
1852 : ! CONST = 1/SQRT(2*PI)
1853 : !-----------------
1854 :
1855 0 : a0 = MIN(a, b)
1856 0 : IF (a0 >= 8.0e0_dp) THEN
1857 : !-----------------------------------------------------------------------
1858 : ! PROCEDURE FOR A .GE. 8 AND B .GE. 8
1859 : !-----------------------------------------------------------------------
1860 : IF (a > b) THEN
1861 0 : h = b/a
1862 0 : x0 = 1.0e0_dp/(1.0e0_dp + h)
1863 0 : y0 = h/(1.0e0_dp + h)
1864 0 : lambda = (a + b)*y - b
1865 : END IF
1866 0 : h = a/b
1867 0 : x0 = h/(1.0e0_dp + h)
1868 0 : y0 = 1.0e0_dp/(1.0e0_dp + h)
1869 0 : lambda = a - (a + b)*x
1870 :
1871 0 : e = -lambda/a
1872 0 : IF (ABS(e) > 0.6e0_dp) THEN
1873 0 : u = e - LOG(x/x0)
1874 : ELSE
1875 0 : u = rlog1(e)
1876 : END IF
1877 :
1878 0 : e = lambda/b
1879 0 : IF (ABS(e) <= 0.6e0_dp) THEN
1880 0 : v = rlog1(e)
1881 : ELSE
1882 0 : v = e - LOG(y/y0)
1883 : END IF
1884 :
1885 0 : z = esum(mu, -(a*u + b*v))
1886 0 : fn_val = const*SQRT(b*x0)*z*EXP(-bcorr(a, b))
1887 : END IF
1888 :
1889 0 : IF (x > 0.375e0_dp) THEN
1890 0 : IF (y > 0.375e0_dp) THEN
1891 0 : lnx = LOG(x)
1892 0 : lny = LOG(y)
1893 : ELSE
1894 0 : lnx = alnrel(-y)
1895 0 : lny = LOG(y)
1896 : END IF
1897 : ELSE
1898 0 : lnx = LOG(x)
1899 0 : lny = alnrel(-x)
1900 : END IF
1901 0 : z = a*lnx + b*lny
1902 0 : IF (a0 >= 1.0e0_dp) THEN
1903 0 : z = z - betaln(a, b)
1904 0 : fn_val = esum(mu, z)
1905 0 : RETURN
1906 : END IF
1907 : !-----------------------------------------------------------------------
1908 : ! PROCEDURE FOR A .LT. 1 OR B .LT. 1
1909 : !-----------------------------------------------------------------------
1910 0 : b0 = MAX(a, b)
1911 0 : IF (b0 >= 8.0e0_dp) THEN
1912 : ! ALGORITHM FOR B0 .GE. 8
1913 :
1914 0 : u = gamln1(a0) + algdiv(a0, b0)
1915 0 : fn_val = a0*esum(mu, z - u)
1916 0 : RETURN
1917 : END IF
1918 0 : IF (b0 <= 1.0e0_dp) THEN
1919 :
1920 : ! ALGORITHM FOR B0 .LE. 1
1921 :
1922 0 : fn_val = esum(mu, z)
1923 0 : IF (fn_val == 0.0e0_dp) RETURN
1924 :
1925 0 : apb = a + b
1926 0 : IF (apb > 1.0e0_dp) THEN
1927 0 : u = a + b - 1.e0_dp
1928 0 : z = (1.0e0_dp + gam1(u))/apb
1929 : ELSE
1930 0 : z = 1.0e0_dp + gam1(apb)
1931 : END IF
1932 :
1933 0 : c = (1.0e0_dp + gam1(a))*(1.0e0_dp + gam1(b))/z
1934 0 : fn_val = fn_val*(a0*c)/(1.0e0_dp + a0/b0)
1935 0 : RETURN
1936 : END IF
1937 :
1938 : ! ALGORITHM FOR 1 .LT. B0 .LT. 8
1939 :
1940 0 : u = gamln1(a0)
1941 0 : n = INT(b0 - 1.0e0_dp)
1942 0 : IF (n >= 1) THEN
1943 : c = 1.0e0_dp
1944 0 : DO i = 1, n
1945 0 : b0 = b0 - 1.0e0_dp
1946 0 : c = c*(b0/(a0 + b0))
1947 : END DO
1948 0 : u = LOG(c) + u
1949 : END IF
1950 :
1951 0 : z = z - u
1952 0 : b0 = b0 - 1.0e0_dp
1953 0 : apb = a0 + b0
1954 0 : IF (apb > 1.0e0_dp) THEN
1955 0 : u = a0 + b0 - 1.e0_dp
1956 0 : t = (1.0e0_dp + gam1(u))/apb
1957 : ELSE
1958 0 : t = 1.0e0_dp + gam1(apb)
1959 : END IF
1960 0 : fn_val = a0*esum(mu, z)*(1.0e0_dp + gam1(b0))/t
1961 :
1962 0 : END FUNCTION brcmp1
1963 :
1964 : ! **************************************************************************************************
1965 : !> \brief ...
1966 : !> \param a ...
1967 : !> \param b ...
1968 : !> \param lambda ...
1969 : !> \param eps ...
1970 : !> \return ...
1971 : ! **************************************************************************************************
1972 0 : FUNCTION basym(a, b, lambda, eps) RESULT(fn_val)
1973 : !-----------------------------------------------------------------------
1974 : ! ASYMPTOTIC EXPANSION FOR IX(A,B) FOR LARGE A AND B.
1975 : ! LAMBDA = (A + B)*Y - B AND EPS IS THE TOLERANCE USED.
1976 : ! IT IS ASSUMED THAT LAMBDA IS NONNEGATIVE AND THAT
1977 : ! A AND B ARE GREATER THAN OR EQUAL TO 15.
1978 : !-----------------------------------------------------------------------
1979 : REAL(dp), INTENT(IN) :: a, b, lambda, eps
1980 : REAL(dp) :: fn_val
1981 :
1982 : INTEGER, PARAMETER :: num = 20
1983 : REAL(dp), PARAMETER :: e0 = 1.12837916709551e0_dp, &
1984 : e1 = .353553390593274e0_dp
1985 :
1986 : INTEGER :: i, im1, imj, j, m, mm1, mmj, n, np1
1987 : REAL(dp) :: a0(21), b0(21), bsum, c(21), d(21), &
1988 : dsum, f, h, h2, hn, j0, j1, r, r0, r1, &
1989 : s, sum, t, t0, t1, u, w, w0, z, z0, &
1990 : z2, zn, znm1
1991 :
1992 : !------------------------
1993 : ! ****** NUM IS THE MAXIMUM VALUE THAT N CAN TAKE IN THE DO LOOP
1994 : ! ENDING AT STATEMENT 50. IT IS REQUIRED THAT NUM BE EVEN.
1995 : ! THE ARRAYS A0, B0, C, D HAVE DIMENSION NUM + 1.
1996 : !------------------------
1997 : ! E0 = 2/SQRT(PI)
1998 : ! E1 = 2**(-3/2)
1999 : !------------------------
2000 :
2001 0 : fn_val = 0.0e0_dp
2002 0 : IF (a >= b) THEN
2003 0 : h = b/a
2004 0 : r0 = 1.0e0_dp/(1.0e0_dp + h)
2005 0 : r1 = (b - a)/a
2006 0 : w0 = 1.0e0_dp/SQRT(b*(1.0e0_dp + h))
2007 : ELSE
2008 0 : h = a/b
2009 0 : r0 = 1.0e0_dp/(1.0e0_dp + h)
2010 0 : r1 = (b - a)/b
2011 0 : w0 = 1.0e0_dp/SQRT(a*(1.0e0_dp + h))
2012 : END IF
2013 :
2014 0 : f = a*rlog1(-lambda/a) + b*rlog1(lambda/b)
2015 0 : t = EXP(-f)
2016 0 : IF (t == 0.0e0_dp) RETURN
2017 0 : z0 = SQRT(f)
2018 0 : z = 0.5e0_dp*(z0/e1)
2019 0 : z2 = f + f
2020 :
2021 0 : a0(1) = (2.0e0_dp/3.0e0_dp)*r1
2022 0 : c(1) = -0.5e0_dp*a0(1)
2023 0 : d(1) = -c(1)
2024 0 : j0 = (0.5e0_dp/e0)*ERFC_SCALED(z0)
2025 0 : j1 = e1
2026 0 : sum = j0 + d(1)*w0*j1
2027 :
2028 0 : s = 1.0e0_dp
2029 0 : h2 = h*h
2030 0 : hn = 1.0e0_dp
2031 0 : w = w0
2032 0 : znm1 = z
2033 0 : zn = z2
2034 0 : DO n = 2, num, 2
2035 0 : hn = h2*hn
2036 0 : a0(n) = 2.0e0_dp*r0*(1.0e0_dp + h*hn)/(n + 2.0e0_dp)
2037 0 : np1 = n + 1
2038 0 : s = s + hn
2039 0 : a0(np1) = 2.0e0_dp*r1*s/(n + 3.0e0_dp)
2040 :
2041 0 : DO i = n, np1
2042 0 : r = -0.5e0_dp*(i + 1.0e0_dp)
2043 0 : b0(1) = r*a0(1)
2044 0 : DO m = 2, i
2045 : bsum = 0.0e0_dp
2046 : mm1 = m - 1
2047 0 : DO j = 1, mm1
2048 0 : mmj = m - j
2049 0 : bsum = bsum + (j*r - mmj)*a0(j)*b0(mmj)
2050 : END DO
2051 0 : b0(m) = r*a0(m) + bsum/m
2052 : END DO
2053 0 : c(i) = b0(i)/(i + 1.0e0_dp)
2054 :
2055 0 : dsum = 0.0e0_dp
2056 0 : im1 = i - 1
2057 0 : DO j = 1, im1
2058 0 : imj = i - j
2059 0 : dsum = dsum + d(imj)*c(j)
2060 : END DO
2061 0 : d(i) = -(dsum + c(i))
2062 : END DO
2063 :
2064 0 : j0 = e1*znm1 + (n - 1.0e0_dp)*j0
2065 0 : j1 = e1*zn + n*j1
2066 0 : znm1 = z2*znm1
2067 0 : zn = z2*zn
2068 0 : w = w0*w
2069 0 : t0 = d(n)*w*j0
2070 0 : w = w0*w
2071 0 : t1 = d(np1)*w*j1
2072 0 : sum = sum + (t0 + t1)
2073 0 : IF ((ABS(t0) + ABS(t1)) <= eps*sum) EXIT
2074 : END DO
2075 :
2076 0 : u = EXP(-bcorr(a, b))
2077 0 : fn_val = e0*t*u*sum
2078 :
2079 0 : END FUNCTION basym
2080 :
2081 : END MODULE beta_gamma_psi
|