Merge remote-tracking branch 'origin/release-v4.6.1'
[WRF.git] / chem / KPP / kpp / kpp-2.1 / int / tau_leap.f90
blobc069d867d00aa5d0ecad19cebb9c9fe039ad10f3
1 MODULE KPP_ROOT_Random
2 ! A module for random number generation from the following distributions:
4 ! Distribution Function/subroutine name
6 ! Normal (Gaussian) random_normal
7 ! Gamma random_gamma
8 ! Chi-squared random_chisq
9 ! Exponential random_exponential
10 ! Weibull random_Weibull
11 ! Beta random_beta
12 ! t random_t
13 ! Multivariate normal random_mvnorm
14 ! Generalized inverse Gaussian random_inv_gauss
15 ! Poisson random_Poisson
16 ! Binomial random_binomial1 *
17 ! random_binomial2 *
18 ! Negative binomial random_neg_binomial
19 ! von Mises random_von_Mises
20 ! Cauchy random_Cauchy
22 ! Generate a random ordering of the integers 1 .. N
23 ! random_order
24 ! Initialize (seed) the uniform random number generator for ANY compiler
25 ! seed_random_number
27 ! Lognormal - see note below.
29 ! ** Two functions are provided for the binomial distribution.
30 ! If the parameter values remain constant, it is recommended that the
31 ! first function is used (random_binomial1). If one or both of the
32 ! parameters change, use the second function (random_binomial2).
34 ! The compilers own random number generator, SUBROUTINE RANDOM_NUMBER(r),
35 ! is used to provide a source of uniformly distributed random numbers.
37 ! N.B. At this stage, only one random number is generated at each call to
38 ! one of the functions above.
40 ! The module uses the following functions which are included here:
41 ! bin_prob to calculate a single binomial probability
42 ! lngamma to calculate the logarithm to base e of the gamma function
44 ! Some of the code is adapted from Dagpunar's book:
45 ! Dagpunar, J. 'Principles of random variate generation'
46 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
48 ! In most of Dagpunar's routines, there is a test to see whether the value
49 ! of one or two floating-point parameters has changed since the last call.
50 ! These tests have been replaced by using a logical variable FIRST.
51 ! This should be set to .TRUE. on the first call using new values of the
52 ! parameters, and .FALSE. if the parameter values are the same as for the
53 ! previous call.
55 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
56 ! Lognormal distribution
57 ! If X has a lognormal distribution, then log(X) is normally distributed.
58 ! Here the logarithm is the natural logarithm, that is to base e, sometimes
59 ! denoted as ln. To generate random variates from this distribution, generate
60 ! a random deviate from the normal distribution with mean and variance equal
61 ! to the mean and variance of the logarithms of X, then take its exponential.
63 ! Relationship between the mean & variance of log(X) and the mean & variance
64 ! of X, when X has a lognormal distribution.
65 ! Let m = mean of log(X), and s^2 = variance of log(X)
66 ! Then
67 ! mean of X = exp(m + 0.5s^2)
68 ! variance of X = (mean(X))^2.[exp(s^2) - 1]
70 ! In the reverse direction (rarely used)
71 ! variance of log(X) = log[1 + var(X)/(mean(X))^2]
72 ! mean of log(X) = log(mean(X) - 0.5var(log(X))
74 ! N.B. The above formulae relate to population parameters; they will only be
75 ! approximate if applied to sample values.
76 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
78 ! Version 1.13, 2 October 2000
79 ! Changes from version 1.01
80 ! 1. The random_order, random_Poisson & random_binomial routines have been
81 ! replaced with more efficient routines.
82 ! 2. A routine, seed_random_number, has been added to seed the uniform random
83 ! number generator. This requires input of the required number of seeds
84 ! for the particular compiler from a specified I/O unit such as a keyboard.
85 ! 3. Made compatible with Lahey's ELF90.
86 ! 4. Marsaglia & Tsang algorithm used for random_gamma when shape parameter > 1.
87 ! 5. INTENT for array f corrected in random_mvnorm.
89 ! Author: Alan Miller
90 ! CSIRO Division of Mathematical & Information Sciences
91 ! Private Bag 10, Clayton South MDC
92 ! Clayton 3169, Victoria, Australia
93 ! Phone: (+61) 3 9545-8016 Fax: (+61) 3 9545-8080
94 ! e-mail: amiller @ bigpond.net.au
96 IMPLICIT NONE
97 REAL, PRIVATE :: zero = 0.0, half = 0.5, one = 1.0, two = 2.0, &
98 vsmall = TINY(1.0), vlarge = HUGE(1.0)
99 PRIVATE :: integral
100 INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12, 60)
103 CONTAINS
106 FUNCTION random_normal() RESULT(fn_val)
108 ! Adapted from the following Fortran 77 code
109 ! ALGORITHM 712, COLLECTED ALGORITHMS FROM ACM.
110 ! THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE,
111 ! VOL. 18, NO. 4, DECEMBER, 1992, PP. 434-435.
113 ! The function random_normal() returns a normally distributed pseudo-random
114 ! number with zero mean and unit variance.
116 ! The algorithm uses the ratio of uniforms method of A.J. Kinderman
117 ! and J.F. Monahan augmented with quadratic bounding curves.
119 REAL :: fn_val
121 ! Local variables
122 REAL :: s = 0.449871, t = -0.386595, a = 0.19600, b = 0.25472, &
123 r1 = 0.27597, r2 = 0.27846, u, v, x, y, q
125 ! Generate P = (u,v) uniform in rectangle enclosing acceptance region
128 CALL RANDOM_NUMBER(u)
129 CALL RANDOM_NUMBER(v)
130 v = 1.7156 * (v - half)
132 ! Evaluate the quadratic form
133 x = u - s
134 y = ABS(v) - t
135 q = x**2 + y*(a*y - b*x)
137 ! Accept P if inside inner ellipse
138 IF (q < r1) EXIT
139 ! Reject P if outside outer ellipse
140 IF (q > r2) CYCLE
141 ! Reject P if outside acceptance region
142 IF (v**2 < -4.0*LOG(u)*u**2) EXIT
143 END DO
145 ! Return ratio of P's coordinates as the normal deviate
146 fn_val = v/u
147 RETURN
149 END FUNCTION random_normal
153 FUNCTION random_gamma(s, first) RESULT(fn_val)
155 ! Adapted from Fortran 77 code from the book:
156 ! Dagpunar, J. 'Principles of random variate generation'
157 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
159 ! FUNCTION GENERATES A RANDOM GAMMA VARIATE.
160 ! CALLS EITHER random_gamma1 (S > 1.0)
161 ! OR random_exponential (S = 1.0)
162 ! OR random_gamma2 (S < 1.0).
164 ! S = SHAPE PARAMETER OF DISTRIBUTION (0 < REAL).
166 REAL, INTENT(IN) :: s
167 LOGICAL, INTENT(IN) :: first
168 REAL :: fn_val
170 IF (s <= zero) THEN
171 WRITE(*, *) 'SHAPE PARAMETER VALUE MUST BE POSITIVE'
172 STOP
173 END IF
175 IF (s > one) THEN
176 fn_val = random_gamma1(s, first)
177 ELSE IF (s < one) THEN
178 fn_val = random_gamma2(s, first)
179 ELSE
180 fn_val = random_exponential()
181 END IF
183 RETURN
184 END FUNCTION random_gamma
188 FUNCTION random_gamma1(s, first) RESULT(fn_val)
190 ! Uses the algorithm in
191 ! Marsaglia, G. and Tsang, W.W. (2000) `A simple method for generating
192 ! gamma variables', Trans. om Math. Software (TOMS), vol.26(3), pp.363-372.
194 ! Generates a random gamma deviate for shape parameter s >= 1.
196 REAL, INTENT(IN) :: s
197 LOGICAL, INTENT(IN) :: first
198 REAL :: fn_val
200 ! Local variables
201 REAL, SAVE :: c, d
202 REAL :: u, v, x
204 IF (first) THEN
205 d = s - one/3.
206 c = one/SQRT(9.0*d)
207 END IF
209 ! Start of main loop
212 ! Generate v = (1+cx)^3 where x is random normal; repeat if v <= 0.
215 x = random_normal()
216 v = (one + c*x)**3
217 IF (v > zero) EXIT
218 END DO
220 ! Generate uniform variable U
222 CALL RANDOM_NUMBER(u)
223 IF (u < one - 0.0331*x**4) THEN
224 fn_val = d*v
225 EXIT
226 ELSE IF (LOG(u) < half*x**2 + d*(one - v + LOG(v))) THEN
227 fn_val = d*v
228 EXIT
229 END IF
230 END DO
232 RETURN
233 END FUNCTION random_gamma1
237 FUNCTION random_gamma2(s, first) RESULT(fn_val)
239 ! Adapted from Fortran 77 code from the book:
240 ! Dagpunar, J. 'Principles of random variate generation'
241 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
243 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY) FROM
244 ! A GAMMA DISTRIBUTION WITH DENSITY PROPORTIONAL TO
245 ! GAMMA2**(S-1) * EXP(-GAMMA2),
246 ! USING A SWITCHING METHOD.
248 ! S = SHAPE PARAMETER OF DISTRIBUTION
249 ! (REAL < 1.0)
251 REAL, INTENT(IN) :: s
252 LOGICAL, INTENT(IN) :: first
253 REAL :: fn_val
255 ! Local variables
256 REAL :: r, x, w
257 REAL, SAVE :: a, p, c, uf, vr, d
259 IF (s <= zero .OR. s >= one) THEN
260 WRITE(*, *) 'SHAPE PARAMETER VALUE OUTSIDE PERMITTED RANGE'
261 STOP
262 END IF
264 IF (first) THEN ! Initialization, if necessary
265 a = one - s
266 p = a/(a + s*EXP(-a))
267 IF (s < vsmall) THEN
268 WRITE(*, *) 'SHAPE PARAMETER VALUE TOO SMALL'
269 STOP
270 END IF
271 c = one/s
272 uf = p*(vsmall/a)**s
273 vr = one - vsmall
274 d = a*LOG(a)
275 END IF
278 CALL RANDOM_NUMBER(r)
279 IF (r >= vr) THEN
280 CYCLE
281 ELSE IF (r > p) THEN
282 x = a - LOG((one - r)/(one - p))
283 w = a*LOG(x)-d
284 ELSE IF (r > uf) THEN
285 x = a*(r/p)**c
286 w = x
287 ELSE
288 fn_val = zero
289 RETURN
290 END IF
292 CALL RANDOM_NUMBER(r)
293 IF (one-r <= w .AND. r > zero) THEN
294 IF (r*(w + one) >= one) CYCLE
295 IF (-LOG(r) <= w) CYCLE
296 END IF
297 EXIT
298 END DO
300 fn_val = x
301 RETURN
303 END FUNCTION random_gamma2
307 FUNCTION random_chisq(ndf, first) RESULT(fn_val)
309 ! Generates a random variate from the chi-squared distribution with
310 ! ndf degrees of freedom
312 INTEGER, INTENT(IN) :: ndf
313 LOGICAL, INTENT(IN) :: first
314 REAL :: fn_val
316 fn_val = two * random_gamma(half*ndf, first)
317 RETURN
319 END FUNCTION random_chisq
323 FUNCTION random_exponential() RESULT(fn_val)
325 ! Adapted from Fortran 77 code from the book:
326 ! Dagpunar, J. 'Principles of random variate generation'
327 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
329 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY) FROM
330 ! A NEGATIVE EXPONENTIAL DlSTRIBUTION WlTH DENSITY PROPORTIONAL
331 ! TO EXP(-random_exponential), USING INVERSION.
333 REAL :: fn_val
335 ! Local variable
336 REAL :: r
339 CALL RANDOM_NUMBER(r)
340 IF (r > zero) EXIT
341 END DO
343 fn_val = -LOG(r)
344 RETURN
346 END FUNCTION random_exponential
350 FUNCTION random_Weibull(a) RESULT(fn_val)
352 ! Generates a random variate from the Weibull distribution with
353 ! probability density:
355 ! a-1 -x
356 ! f(x) = a.x e
358 REAL, INTENT(IN) :: a
359 REAL :: fn_val
361 ! For speed, there is no checking that a is not zero or very small.
363 fn_val = random_exponential() ** (one/a)
364 RETURN
366 END FUNCTION random_Weibull
370 FUNCTION random_beta(aa, bb, first) RESULT(fn_val)
372 ! Adapted from Fortran 77 code from the book:
373 ! Dagpunar, J. 'Principles of random variate generation'
374 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
376 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,1]
377 ! FROM A BETA DISTRIBUTION WITH DENSITY
378 ! PROPORTIONAL TO BETA**(AA-1) * (1-BETA)**(BB-1).
379 ! USING CHENG'S LOG LOGISTIC METHOD.
381 ! AA = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
382 ! BB = SHAPE PARAMETER FROM DISTRIBUTION (0 < REAL)
384 REAL, INTENT(IN) :: aa, bb
385 LOGICAL, INTENT(IN) :: first
386 REAL :: fn_val
388 ! Local variables
389 REAL, PARAMETER :: aln4 = 1.3862944
390 REAL :: a, b, g, r, s, x, y, z
391 REAL, SAVE :: d, f, h, t, c
392 LOGICAL, SAVE :: swap
394 IF (aa <= zero .OR. bb <= zero) THEN
395 WRITE(*, *) 'IMPERMISSIBLE SHAPE PARAMETER VALUE(S)'
396 STOP
397 END IF
399 IF (first) THEN ! Initialization, if necessary
400 a = aa
401 b = bb
402 swap = b > a
403 IF (swap) THEN
404 g = b
405 b = a
406 a = g
407 END IF
408 d = a/b
409 f = a+b
410 IF (b > one) THEN
411 h = SQRT((two*a*b - f)/(f - two))
412 t = one
413 ELSE
414 h = b
415 t = one/(one + (a/(vlarge*b))**b)
416 END IF
417 c = a+h
418 END IF
421 CALL RANDOM_NUMBER(r)
422 CALL RANDOM_NUMBER(x)
423 s = r*r*x
424 IF (r < vsmall .OR. s <= zero) CYCLE
425 IF (r < t) THEN
426 x = LOG(r/(one - r))/h
427 y = d*EXP(x)
428 z = c*x + f*LOG((one + d)/(one + y)) - aln4
429 IF (s - one > z) THEN
430 IF (s - s*z > one) CYCLE
431 IF (LOG(s) > z) CYCLE
432 END IF
433 fn_val = y/(one + y)
434 ELSE
435 IF (4.0*s > (one + one/d)**f) CYCLE
436 fn_val = one
437 END IF
438 EXIT
439 END DO
441 IF (swap) fn_val = one - fn_val
442 RETURN
443 END FUNCTION random_beta
447 FUNCTION random_t(m) RESULT(fn_val)
449 ! Adapted from Fortran 77 code from the book:
450 ! Dagpunar, J. 'Principles of random variate generation'
451 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
453 ! FUNCTION GENERATES A RANDOM VARIATE FROM A
454 ! T DISTRIBUTION USING KINDERMAN AND MONAHAN'S RATIO METHOD.
456 ! M = DEGREES OF FREEDOM OF DISTRIBUTION
457 ! (1 <= 1NTEGER)
459 INTEGER, INTENT(IN) :: m
460 REAL :: fn_val
462 ! Local variables
463 REAL, SAVE :: s, c, a, f, g
464 REAL :: r, x, v
466 REAL, PARAMETER :: three = 3.0, four = 4.0, quart = 0.25, &
467 five = 5.0, sixteen = 16.0
468 INTEGER :: mm = 0
470 IF (m < 1) THEN
471 WRITE(*, *) 'IMPERMISSIBLE DEGREES OF FREEDOM'
472 STOP
473 END IF
475 IF (m /= mm) THEN ! Initialization, if necessary
476 s = m
477 c = -quart*(s + one)
478 a = four/(one + one/s)**c
479 f = sixteen/a
480 IF (m > 1) THEN
481 g = s - one
482 g = ((s + one)/g)**c*SQRT((s+s)/g)
483 ELSE
484 g = one
485 END IF
486 mm = m
487 END IF
490 CALL RANDOM_NUMBER(r)
491 IF (r <= zero) CYCLE
492 CALL RANDOM_NUMBER(v)
493 x = (two*v - one)*g/r
494 v = x*x
495 IF (v > five - a*r) THEN
496 IF (m >= 1 .AND. r*(v + three) > f) CYCLE
497 IF (r > (one + v/s)**c) CYCLE
498 END IF
499 EXIT
500 END DO
502 fn_val = x
503 RETURN
504 END FUNCTION random_t
508 SUBROUTINE random_mvnorm(n, h, d, f, first, x, ier)
510 ! Adapted from Fortran 77 code from the book:
511 ! Dagpunar, J. 'Principles of random variate generation'
512 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
514 ! N.B. An extra argument, ier, has been added to Dagpunar's routine
516 ! SUBROUTINE GENERATES AN N VARIATE RANDOM NORMAL
517 ! VECTOR USING A CHOLESKY DECOMPOSITION.
519 ! ARGUMENTS:
520 ! N = NUMBER OF VARIATES IN VECTOR
521 ! (INPUT,INTEGER >= 1)
522 ! H(J) = J'TH ELEMENT OF VECTOR OF MEANS
523 ! (INPUT,REAL)
524 ! X(J) = J'TH ELEMENT OF DELIVERED VECTOR
525 ! (OUTPUT,REAL)
527 ! D(J*(J-1)/2+I) = (I,J)'TH ELEMENT OF VARIANCE MATRIX (J> = I)
528 ! (INPUT,REAL)
529 ! F((J-1)*(2*N-J)/2+I) = (I,J)'TH ELEMENT OF LOWER TRIANGULAR
530 ! DECOMPOSITION OF VARIANCE MATRIX (J <= I)
531 ! (OUTPUT,REAL)
533 ! FIRST = .TRUE. IF THIS IS THE FIRST CALL OF THE ROUTINE
534 ! OR IF THE DISTRIBUTION HAS CHANGED SINCE THE LAST CALL OF THE ROUTINE.
535 ! OTHERWISE SET TO .FALSE.
536 ! (INPUT,LOGICAL)
538 ! ier = 1 if the input covariance matrix is not +ve definite
539 ! = 0 otherwise
541 INTEGER, INTENT(IN) :: n
542 REAL, INTENT(IN) :: h(:), d(:) ! d(n*(n+1)/2)
543 REAL, INTENT(IN OUT) :: f(:) ! f(n*(n+1)/2)
544 REAL, INTENT(OUT) :: x(:)
545 LOGICAL, INTENT(IN) :: first
546 INTEGER, INTENT(OUT) :: ier
548 ! Local variables
549 INTEGER :: j, i, m
550 REAL :: y, v
551 INTEGER, SAVE :: n2
553 IF (n < 1) THEN
554 WRITE(*, *) 'SIZE OF VECTOR IS NON POSITIVE'
555 STOP
556 END IF
558 ier = 0
559 IF (first) THEN ! Initialization, if necessary
560 n2 = 2*n
561 IF (d(1) < zero) THEN
562 ier = 1
563 RETURN
564 END IF
566 f(1) = SQRT(d(1))
567 y = one/f(1)
568 DO j = 2,n
569 f(j) = d(1+j*(j-1)/2) * y
570 END DO
572 DO i = 2,n
573 v = d(i*(i-1)/2+i)
574 DO m = 1,i-1
575 v = v - f((m-1)*(n2-m)/2+i)**2
576 END DO
578 IF (v < zero) THEN
579 ier = 1
580 RETURN
581 END IF
583 v = SQRT(v)
584 y = one/v
585 f((i-1)*(n2-i)/2+i) = v
586 DO j = i+1,n
587 v = d(j*(j-1)/2+i)
588 DO m = 1,i-1
589 v = v - f((m-1)*(n2-m)/2+i)*f((m-1)*(n2-m)/2 + j)
590 END DO ! m = 1,i-1
591 f((i-1)*(n2-i)/2 + j) = v*y
592 END DO ! j = i+1,n
593 END DO ! i = 2,n
594 END IF
596 x(1:n) = h(1:n)
597 DO j = 1,n
598 y = random_normal()
599 DO i = j,n
600 x(i) = x(i) + f((j-1)*(n2-j)/2 + i) * y
601 END DO ! i = j,n
602 END DO ! j = 1,n
604 RETURN
605 END SUBROUTINE random_mvnorm
609 FUNCTION random_inv_gauss(h, b, first) RESULT(fn_val)
611 ! Adapted from Fortran 77 code from the book:
612 ! Dagpunar, J. 'Principles of random variate generation'
613 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
615 ! FUNCTION GENERATES A RANDOM VARIATE IN [0,INFINITY] FROM
616 ! A REPARAMETERISED GENERALISED INVERSE GAUSSIAN (GIG) DISTRIBUTION
617 ! WITH DENSITY PROPORTIONAL TO GIG**(H-1) * EXP(-0.5*B*(GIG+1/GIG))
618 ! USING A RATIO METHOD.
620 ! H = PARAMETER OF DISTRIBUTION (0 <= REAL)
621 ! B = PARAMETER OF DISTRIBUTION (0 < REAL)
623 REAL, INTENT(IN) :: h, b
624 LOGICAL, INTENT(IN) :: first
625 REAL :: fn_val
627 ! Local variables
628 REAL :: ym, xm, r, w, r1, r2, x
629 REAL, SAVE :: a, c, d, e
630 REAL, PARAMETER :: quart = 0.25
632 IF (h < zero .OR. b <= zero) THEN
633 WRITE(*, *) 'IMPERMISSIBLE DISTRIBUTION PARAMETER VALUES'
634 STOP
635 END IF
637 IF (first) THEN ! Initialization, if necessary
638 IF (h > quart*b*SQRT(vlarge)) THEN
639 WRITE(*, *) 'THE RATIO H:B IS TOO SMALL'
640 STOP
641 END IF
642 e = b*b
643 d = h + one
644 ym = (-d + SQRT(d*d + e))/b
645 IF (ym < vsmall) THEN
646 WRITE(*, *) 'THE VALUE OF B IS TOO SMALL'
647 STOP
648 END IF
650 d = h - one
651 xm = (d + SQRT(d*d + e))/b
652 d = half*d
653 e = -quart*b
654 r = xm + one/xm
655 w = xm*ym
656 a = w**(-half*h) * SQRT(xm/ym) * EXP(-e*(r - ym - one/ym))
657 IF (a < vsmall) THEN
658 WRITE(*, *) 'THE VALUE OF H IS TOO LARGE'
659 STOP
660 END IF
661 c = -d*LOG(xm) - e*r
662 END IF
665 CALL RANDOM_NUMBER(r1)
666 IF (r1 <= zero) CYCLE
667 CALL RANDOM_NUMBER(r2)
668 x = a*r2/r1
669 IF (x <= zero) CYCLE
670 IF (LOG(r1) < d*LOG(x) + e*(x + one/x) + c) EXIT
671 END DO
673 fn_val = x
675 RETURN
676 END FUNCTION random_inv_gauss
680 FUNCTION random_Poisson(mu, first) RESULT(ival)
681 !**********************************************************************
682 ! Translated to Fortran 90 by Alan Miller from:
683 ! RANLIB
685 ! Library of Fortran Routines for Random Number Generation
687 ! Compiled and Written by:
689 ! Barry W. Brown
690 ! James Lovato
692 ! Department of Biomathematics, Box 237
693 ! The University of Texas, M.D. Anderson Cancer Center
694 ! 1515 Holcombe Boulevard
695 ! Houston, TX 77030
697 ! This work was supported by grant CA-16672 from the National Cancer Institute.
699 ! GENerate POIsson random deviate
701 ! Function
703 ! Generates a single random deviate from a Poisson distribution with mean mu.
705 ! Arguments
707 ! mu --> The mean of the Poisson distribution from which
708 ! a random deviate is to be generated.
709 ! REAL mu
711 ! Method
713 ! For details see:
715 ! Ahrens, J.H. and Dieter, U.
716 ! Computer Generation of Poisson Deviates
717 ! From Modified Normal Distributions.
718 ! ACM Trans. Math. Software, 8, 2
719 ! (June 1982),163-179
721 ! TABLES: COEFFICIENTS A0-A7 FOR STEP F. FACTORIALS FACT
722 ! COEFFICIENTS A(K) - FOR PX = FK*V*V*SUM(A(K)*V**K)-DEL
724 ! SEPARATION OF CASES A AND B
726 ! .. Scalar Arguments ..
727 REAL, INTENT(IN) :: mu
728 LOGICAL, INTENT(IN) :: first
729 INTEGER :: ival
730 ! ..
731 ! .. Local Scalars ..
732 REAL :: b1, b2, c, c0, c1, c2, c3, del, difmuk, e, fk, fx, fy, g, &
733 omega, px, py, t, u, v, x, xx
734 REAL, SAVE :: s, d, p, q, p0
735 INTEGER :: j, k, kflag
736 LOGICAL, SAVE :: full_init
737 INTEGER, SAVE :: l, m
738 ! ..
739 ! .. Local Arrays ..
740 REAL, SAVE :: pp(35)
741 ! ..
742 ! .. Data statements ..
743 REAL, PARAMETER :: a0 = -.5, a1 = .3333333, a2 = -.2500068, a3 = .2000118, &
744 a4 = -.1661269, a5 = .1421878, a6 = -.1384794, &
745 a7 = .1250060
747 REAL, PARAMETER :: fact(10) = (/ 1., 1., 2., 6., 24., 120., 720., 5040., &
748 40320., 362880. /)
750 ! ..
751 ! .. Executable Statements ..
752 IF (mu > 10.0) THEN
753 ! C A S E A. (RECALCULATION OF S, D, L IF MU HAS CHANGED)
755 IF (first) THEN
756 s = SQRT(mu)
757 d = 6.0*mu*mu
759 ! THE POISSON PROBABILITIES PK EXCEED THE DISCRETE NORMAL
760 ! PROBABILITIES FK WHENEVER K >= M(MU). L=IFIX(MU-1.1484)
761 ! IS AN UPPER BOUND TO M(MU) FOR ALL MU >= 10 .
763 l = mu - 1.1484
764 full_init = .false.
765 END IF
768 ! STEP N. NORMAL SAMPLE - random_normal() FOR STANDARD NORMAL DEVIATE
770 g = mu + s*random_normal()
771 IF (g > 0.0) THEN
772 ival = g
774 ! STEP I. IMMEDIATE ACCEPTANCE IF ival IS LARGE ENOUGH
776 IF (ival>=l) RETURN
778 ! STEP S. SQUEEZE ACCEPTANCE - SAMPLE U
780 fk = ival
781 difmuk = mu - fk
782 CALL RANDOM_NUMBER(u)
783 IF (d*u >= difmuk*difmuk*difmuk) RETURN
784 END IF
786 ! STEP P. PREPARATIONS FOR STEPS Q AND H.
787 ! (RECALCULATIONS OF PARAMETERS IF NECESSARY)
788 ! .3989423=(2*PI)**(-.5) .416667E-1=1./24. .1428571=1./7.
789 ! THE QUANTITIES B1, B2, C3, C2, C1, C0 ARE FOR THE HERMITE
790 ! APPROXIMATIONS TO THE DISCRETE NORMAL PROBABILITIES FK.
791 ! C=.1069/MU GUARANTEES MAJORIZATION BY THE 'HAT'-FUNCTION.
793 IF (.NOT. full_init) THEN
794 omega = .3989423/s
795 b1 = .4166667E-1/mu
796 b2 = .3*b1*b1
797 c3 = .1428571*b1*b2
798 c2 = b2 - 15.*c3
799 c1 = b1 - 6.*b2 + 45.*c3
800 c0 = 1. - b1 + 3.*b2 - 15.*c3
801 c = .1069/mu
802 full_init = .true.
803 END IF
805 IF (g < 0.0) GO TO 50
807 ! 'SUBROUTINE' F IS CALLED (KFLAG=0 FOR CORRECT RETURN)
809 kflag = 0
810 GO TO 70
812 ! STEP Q. QUOTIENT ACCEPTANCE (RARE CASE)
814 40 IF (fy-u*fy <= py*EXP(px-fx)) RETURN
816 ! STEP E. EXPONENTIAL SAMPLE - random_exponential() FOR STANDARD EXPONENTIAL
817 ! DEVIATE E AND SAMPLE T FROM THE LAPLACE 'HAT'
818 ! (IF T <= -.6744 THEN PK < FK FOR ALL MU >= 10.)
820 50 e = random_exponential()
821 CALL RANDOM_NUMBER(u)
822 u = u + u - one
823 t = 1.8 + SIGN(e, u)
824 IF (t <= (-.6744)) GO TO 50
825 ival = mu + s*t
826 fk = ival
827 difmuk = mu - fk
829 ! 'SUBROUTINE' F IS CALLED (KFLAG=1 FOR CORRECT RETURN)
831 kflag = 1
832 GO TO 70
834 ! STEP H. HAT ACCEPTANCE (E IS REPEATED ON REJECTION)
836 60 IF (c*ABS(u) > py*EXP(px+e) - fy*EXP(fx+e)) GO TO 50
837 RETURN
839 ! STEP F. 'SUBROUTINE' F. CALCULATION OF PX, PY, FX, FY.
840 ! CASE ival < 10 USES FACTORIALS FROM TABLE FACT
842 70 IF (ival>=10) GO TO 80
843 px = -mu
844 py = mu**ival/fact(ival+1)
845 GO TO 110
847 ! CASE ival >= 10 USES POLYNOMIAL APPROXIMATION
848 ! A0-A7 FOR ACCURACY WHEN ADVISABLE
849 ! .8333333E-1=1./12. .3989423=(2*PI)**(-.5)
851 80 del = .8333333E-1/fk
852 del = del - 4.8*del*del*del
853 v = difmuk/fk
854 IF (ABS(v)>0.25) THEN
855 px = fk*LOG(one + v) - difmuk - del
856 ELSE
857 px = fk*v*v* (((((((a7*v+a6)*v+a5)*v+a4)*v+a3)*v+a2)*v+a1)*v+a0) - del
858 END IF
859 py = .3989423/SQRT(fk)
860 110 x = (half - difmuk)/s
861 xx = x*x
862 fx = -half*xx
863 fy = omega* (((c3*xx + c2)*xx + c1)*xx + c0)
864 IF (kflag <= 0) GO TO 40
865 GO TO 60
867 !---------------------------------------------------------------------------
868 ! C A S E B. mu < 10
869 ! START NEW TABLE AND CALCULATE P0 IF NECESSARY
871 ELSE
872 IF (first) THEN
873 m = MAX(1, INT(mu))
874 l = 0
875 p = EXP(-mu)
876 q = p
877 p0 = p
878 END IF
880 ! STEP U. UNIFORM SAMPLE FOR INVERSION METHOD
883 CALL RANDOM_NUMBER(u)
884 ival = 0
885 IF (u <= p0) RETURN
887 ! STEP T. TABLE COMPARISON UNTIL THE END PP(L) OF THE
888 ! PP-TABLE OF CUMULATIVE POISSON PROBABILITIES
889 ! (0.458=PP(9) FOR MU=10)
891 IF (l == 0) GO TO 150
892 j = 1
893 IF (u > 0.458) j = MIN(l, m)
894 DO k = j, l
895 IF (u <= pp(k)) GO TO 180
896 END DO
897 IF (l == 35) CYCLE
899 ! STEP C. CREATION OF NEW POISSON PROBABILITIES P
900 ! AND THEIR CUMULATIVES Q=PP(K)
902 150 l = l + 1
903 DO k = l, 35
904 p = p*mu / k
905 q = q + p
906 pp(k) = q
907 IF (u <= q) GO TO 170
908 END DO
909 l = 35
910 END DO
912 170 l = k
913 180 ival = k
914 RETURN
915 END IF
917 RETURN
918 END FUNCTION random_Poisson
922 FUNCTION random_binomial1(n, p, first) RESULT(ival)
924 ! FUNCTION GENERATES A RANDOM BINOMIAL VARIATE USING C.D.Kemp's method.
925 ! This algorithm is suitable when many random variates are required
926 ! with the SAME parameter values for n & p.
928 ! P = BERNOULLI SUCCESS PROBABILITY
929 ! (0 <= REAL <= 1)
930 ! N = NUMBER OF BERNOULLI TRIALS
931 ! (1 <= INTEGER)
932 ! FIRST = .TRUE. for the first call using the current parameter values
933 ! = .FALSE. if the values of (n,p) are unchanged from last call
935 ! Reference: Kemp, C.D. (1986). `A modal method for generating binomial
936 ! variables', Commun. Statist. - Theor. Meth. 15(3), 805-813.
938 INTEGER, INTENT(IN) :: n
939 REAL, INTENT(IN) :: p
940 LOGICAL, INTENT(IN) :: first
941 INTEGER :: ival
943 ! Local variables
945 INTEGER :: ru, rd
946 INTEGER, SAVE :: r0
947 REAL :: u, pd, pu
948 REAL, SAVE :: odds_ratio, p_r
949 REAL, PARAMETER :: zero = 0.0, one = 1.0
951 IF (first) THEN
952 r0 = (n+1)*p
953 p_r = bin_prob(n, p, r0)
954 odds_ratio = p / (one - p)
955 END IF
957 CALL RANDOM_NUMBER(u)
958 u = u - p_r
959 IF (u < zero) THEN
960 ival = r0
961 RETURN
962 END IF
964 pu = p_r
965 ru = r0
966 pd = p_r
967 rd = r0
969 rd = rd - 1
970 IF (rd >= 0) THEN
971 pd = pd * (rd+1) / (odds_ratio * (n-rd))
972 u = u - pd
973 IF (u < zero) THEN
974 ival = rd
975 RETURN
976 END IF
977 END IF
979 ru = ru + 1
980 IF (ru <= n) THEN
981 pu = pu * (n-ru+1) * odds_ratio / ru
982 u = u - pu
983 IF (u < zero) THEN
984 ival = ru
985 RETURN
986 END IF
987 END IF
988 END DO
990 ! This point should not be reached, but just in case:
992 ival = r0
993 RETURN
995 END FUNCTION random_binomial1
999 FUNCTION bin_prob(n, p, r) RESULT(fn_val)
1000 ! Calculate a binomial probability
1002 INTEGER, INTENT(IN) :: n, r
1003 REAL, INTENT(IN) :: p
1004 REAL :: fn_val
1006 ! Local variable
1007 REAL :: one = 1.0
1009 fn_val = EXP( lngamma(DBLE(n+1)) - lngamma(DBLE(r+1)) - lngamma(DBLE(n-r+1)) &
1010 + r*LOG(p) + (n-r)*LOG(one - p) )
1011 RETURN
1013 END FUNCTION bin_prob
1017 FUNCTION lngamma(x) RESULT(fn_val)
1019 ! Logarithm to base e of the gamma function.
1021 ! Accurate to about 1.e-14.
1022 ! Programmer: Alan Miller
1024 ! Latest revision of Fortran 77 version - 28 February 1988
1026 REAL (dp), INTENT(IN) :: x
1027 REAL (dp) :: fn_val
1029 ! Local variables
1031 REAL (dp) :: a1 = -4.166666666554424D-02, a2 = 2.430554511376954D-03, &
1032 a3 = -7.685928044064347D-04, a4 = 5.660478426014386D-04, &
1033 temp, arg, product, lnrt2pi = 9.189385332046727D-1, &
1034 pi = 3.141592653589793D0
1035 LOGICAL :: reflect
1037 ! lngamma is not defined if x = 0 or a negative integer.
1039 IF (x > 0.d0) GO TO 10
1040 IF (x /= INT(x)) GO TO 10
1041 fn_val = 0.d0
1042 RETURN
1044 ! If x < 0, use the reflection formula:
1045 ! gamma(x) * gamma(1-x) = pi * cosec(pi.x)
1047 10 reflect = (x < 0.d0)
1048 IF (reflect) THEN
1049 arg = 1.d0 - x
1050 ELSE
1051 arg = x
1052 END IF
1054 ! Increase the argument, if necessary, to make it > 10.
1056 product = 1.d0
1057 20 IF (arg <= 10.d0) THEN
1058 product = product * arg
1059 arg = arg + 1.d0
1060 GO TO 20
1061 END IF
1063 ! Use a polynomial approximation to Stirling's formula.
1064 ! N.B. The real Stirling's formula is used here, not the simpler, but less
1065 ! accurate formula given by De Moivre in a letter to Stirling, which
1066 ! is the one usually quoted.
1068 arg = arg - 0.5D0
1069 temp = 1.d0/arg**2
1070 fn_val = lnrt2pi + arg * (LOG(arg) - 1.d0 + &
1071 (((a4*temp + a3)*temp + a2)*temp + a1)*temp) - LOG(product)
1072 IF (reflect) THEN
1073 temp = SIN(pi * x)
1074 fn_val = LOG(pi/temp) - fn_val
1075 END IF
1076 RETURN
1077 END FUNCTION lngamma
1081 FUNCTION random_binomial2(n, pp, first) RESULT(ival)
1082 !**********************************************************************
1083 ! Translated to Fortran 90 by Alan Miller from:
1084 ! RANLIB
1086 ! Library of Fortran Routines for Random Number Generation
1088 ! Compiled and Written by:
1090 ! Barry W. Brown
1091 ! James Lovato
1093 ! Department of Biomathematics, Box 237
1094 ! The University of Texas, M.D. Anderson Cancer Center
1095 ! 1515 Holcombe Boulevard
1096 ! Houston, TX 77030
1098 ! This work was supported by grant CA-16672 from the National Cancer Institute.
1100 ! GENerate BINomial random deviate
1102 ! Function
1104 ! Generates a single random deviate from a binomial
1105 ! distribution whose number of trials is N and whose
1106 ! probability of an event in each trial is P.
1108 ! Arguments
1110 ! N --> The number of trials in the binomial distribution
1111 ! from which a random deviate is to be generated.
1112 ! INTEGER N
1114 ! P --> The probability of an event in each trial of the
1115 ! binomial distribution from which a random deviate
1116 ! is to be generated.
1117 ! REAL P
1119 ! FIRST --> Set FIRST = .TRUE. for the first call to perform initialization
1120 ! the set FIRST = .FALSE. for further calls using the same pair
1121 ! of parameter values (N, P).
1122 ! LOGICAL FIRST
1124 ! random_binomial2 <-- A random deviate yielding the number of events
1125 ! from N independent trials, each of which has
1126 ! a probability of event P.
1127 ! INTEGER random_binomial
1129 ! Method
1131 ! This is algorithm BTPE from:
1133 ! Kachitvichyanukul, V. and Schmeiser, B. W.
1134 ! Binomial Random Variate Generation.
1135 ! Communications of the ACM, 31, 2 (February, 1988) 216.
1137 !**********************************************************************
1139 !*****DETERMINE APPROPRIATE ALGORITHM AND WHETHER SETUP IS NECESSARY
1141 ! ..
1142 ! .. Scalar Arguments ..
1143 REAL, INTENT(IN) :: pp
1144 INTEGER, INTENT(IN) :: n
1145 LOGICAL, INTENT(IN) :: first
1146 INTEGER :: ival
1147 ! ..
1148 ! .. Local Scalars ..
1149 REAL :: alv, amaxp, f, f1, f2, u, v, w, w2, x, x1, x2, ynorm, z, z2
1150 REAL, PARAMETER :: zero = 0.0, half = 0.5, one = 1.0
1151 INTEGER :: i, ix, ix1, k, mp
1152 INTEGER, SAVE :: m
1153 REAL, SAVE :: p, q, xnp, ffm, fm, xnpq, p1, xm, xl, xr, c, al, xll, &
1154 xlr, p2, p3, p4, qn, r, g
1156 ! ..
1157 ! .. Executable Statements ..
1159 !*****SETUP, PERFORM ONLY WHEN PARAMETERS CHANGE
1161 IF (first) THEN
1162 p = MIN(pp, one-pp)
1163 q = one - p
1164 xnp = n * p
1165 END IF
1167 IF (xnp > 30.) THEN
1168 IF (first) THEN
1169 ffm = xnp + p
1170 m = ffm
1171 fm = m
1172 xnpq = xnp * q
1173 p1 = INT(2.195*SQRT(xnpq) - 4.6*q) + half
1174 xm = fm + half
1175 xl = xm - p1
1176 xr = xm + p1
1177 c = 0.134 + 20.5 / (15.3 + fm)
1178 al = (ffm-xl) / (ffm - xl*p)
1179 xll = al * (one + half*al)
1180 al = (xr - ffm) / (xr*q)
1181 xlr = al * (one + half*al)
1182 p2 = p1 * (one + c + c)
1183 p3 = p2 + c / xll
1184 p4 = p3 + c / xlr
1185 END IF
1187 !*****GENERATE VARIATE, Binomial mean at least 30.
1189 20 CALL RANDOM_NUMBER(u)
1190 u = u * p4
1191 CALL RANDOM_NUMBER(v)
1193 ! TRIANGULAR REGION
1195 IF (u <= p1) THEN
1196 ix = xm - p1 * v + u
1197 GO TO 110
1198 END IF
1200 ! PARALLELOGRAM REGION
1202 IF (u <= p2) THEN
1203 x = xl + (u-p1) / c
1204 v = v * c + one - ABS(xm-x) / p1
1205 IF (v > one .OR. v <= zero) GO TO 20
1206 ix = x
1207 ELSE
1209 ! LEFT TAIL
1211 IF (u <= p3) THEN
1212 ix = xl + LOG(v) / xll
1213 IF (ix < 0) GO TO 20
1214 v = v * (u-p2) * xll
1215 ELSE
1217 ! RIGHT TAIL
1219 ix = xr - LOG(v) / xlr
1220 IF (ix > n) GO TO 20
1221 v = v * (u-p3) * xlr
1222 END IF
1223 END IF
1225 !*****DETERMINE APPROPRIATE WAY TO PERFORM ACCEPT/REJECT TEST
1227 k = ABS(ix-m)
1228 IF (k <= 20 .OR. k >= xnpq/2-1) THEN
1230 ! EXPLICIT EVALUATION
1232 f = one
1233 r = p / q
1234 g = (n+1) * r
1235 IF (m < ix) THEN
1236 mp = m + 1
1237 DO i = mp, ix
1238 f = f * (g/i-r)
1239 END DO
1241 ELSE IF (m > ix) THEN
1242 ix1 = ix + 1
1243 DO i = ix1, m
1244 f = f / (g/i-r)
1245 END DO
1246 END IF
1248 IF (v > f) THEN
1249 GO TO 20
1250 ELSE
1251 GO TO 110
1252 END IF
1253 END IF
1255 ! SQUEEZING USING UPPER AND LOWER BOUNDS ON LOG(F(X))
1257 amaxp = (k/xnpq) * ((k*(k/3. + .625) + .1666666666666)/xnpq + half)
1258 ynorm = -k * k / (2.*xnpq)
1259 alv = LOG(v)
1260 IF (alv<ynorm - amaxp) GO TO 110
1261 IF (alv>ynorm + amaxp) GO TO 20
1263 ! STIRLING'S (actually de Moivre's) FORMULA TO MACHINE ACCURACY FOR
1264 ! THE FINAL ACCEPTANCE/REJECTION TEST
1266 x1 = ix + 1
1267 f1 = fm + one
1268 z = n + 1 - fm
1269 w = n - ix + one
1270 z2 = z * z
1271 x2 = x1 * x1
1272 f2 = f1 * f1
1273 w2 = w * w
1274 IF (alv - (xm*LOG(f1/x1) + (n-m+half)*LOG(z/w) + (ix-m)*LOG(w*p/(x1*q)) + &
1275 (13860.-(462.-(132.-(99.-140./f2)/f2)/f2)/f2)/f1/166320. + &
1276 (13860.-(462.-(132.-(99.-140./z2)/z2)/z2)/z2)/z/166320. + &
1277 (13860.-(462.-(132.-(99.-140./x2)/x2)/x2)/x2)/x1/166320. + &
1278 (13860.-(462.-(132.-(99.-140./w2)/w2)/w2)/w2)/w/166320.) > zero) THEN
1279 GO TO 20
1280 ELSE
1281 GO TO 110
1282 END IF
1284 ELSE
1285 ! INVERSE CDF LOGIC FOR MEAN LESS THAN 30
1286 IF (first) THEN
1287 qn = q ** n
1288 r = p / q
1289 g = r * (n+1)
1290 END IF
1292 90 ix = 0
1293 f = qn
1294 CALL RANDOM_NUMBER(u)
1295 100 IF (u >= f) THEN
1296 IF (ix > 110) GO TO 90
1297 u = u - f
1298 ix = ix + 1
1299 f = f * (g/ix - r)
1300 GO TO 100
1301 END IF
1302 END IF
1304 110 IF (pp > half) ix = n - ix
1305 ival = ix
1306 RETURN
1308 END FUNCTION random_binomial2
1313 FUNCTION random_neg_binomial(sk, p) RESULT(ival)
1315 ! Adapted from Fortran 77 code from the book:
1316 ! Dagpunar, J. 'Principles of random variate generation'
1317 ! Clarendon Press, Oxford, 1988. ISBN 0-19-852202-9
1319 ! FUNCTION GENERATES A RANDOM NEGATIVE BINOMIAL VARIATE USING UNSTORED
1320 ! INVERSION AND/OR THE REPRODUCTIVE PROPERTY.
1322 ! SK = NUMBER OF FAILURES REQUIRED (Dagpunar's words!)
1323 ! = the `power' parameter of the negative binomial
1324 ! (0 < REAL)
1325 ! P = BERNOULLI SUCCESS PROBABILITY
1326 ! (0 < REAL < 1)
1328 ! THE PARAMETER H IS SET SO THAT UNSTORED INVERSION ONLY IS USED WHEN P <= H,
1329 ! OTHERWISE A COMBINATION OF UNSTORED INVERSION AND
1330 ! THE REPRODUCTIVE PROPERTY IS USED.
1332 REAL, INTENT(IN) :: sk, p
1333 INTEGER :: ival
1335 ! Local variables
1336 ! THE PARAMETER ULN = -LOG(MACHINE'S SMALLEST REAL NUMBER).
1338 REAL, PARAMETER :: h = 0.7
1339 REAL :: q, x, st, uln, v, r, s, y, g
1340 INTEGER :: k, i, n
1342 IF (sk <= zero .OR. p <= zero .OR. p >= one) THEN
1343 WRITE(*, *) 'IMPERMISSIBLE DISTRIBUTION PARAMETER VALUES'
1344 STOP
1345 END IF
1347 q = one - p
1348 x = zero
1349 st = sk
1350 IF (p > h) THEN
1351 v = one/LOG(p)
1352 k = st
1353 DO i = 1,k
1355 CALL RANDOM_NUMBER(r)
1356 IF (r > zero) EXIT
1357 END DO
1358 n = v*LOG(r)
1359 x = x + n
1360 END DO
1361 st = st - k
1362 END IF
1364 s = zero
1365 uln = -LOG(vsmall)
1366 IF (st > -uln/LOG(q)) THEN
1367 WRITE(*, *) ' P IS TOO LARGE FOR THIS VALUE OF SK'
1368 STOP
1369 END IF
1371 y = q**st
1372 g = st
1373 CALL RANDOM_NUMBER(r)
1375 IF (y > r) EXIT
1376 r = r - y
1377 s = s + one
1378 y = y*p*g/s
1379 g = g + one
1380 END DO
1382 ival = x + s + half
1383 RETURN
1384 END FUNCTION random_neg_binomial
1388 FUNCTION random_von_Mises(k, first) RESULT(fn_val)
1390 ! Algorithm VMD from:
1391 ! Dagpunar, J.S. (1990) `Sampling from the von Mises distribution via a
1392 ! comparison of random numbers', J. of Appl. Statist., 17, 165-168.
1394 ! Fortran 90 code by Alan Miller
1395 ! CSIRO Division of Mathematical & Information Sciences
1397 ! Arguments:
1398 ! k (real) parameter of the von Mises distribution.
1399 ! first (logical) set to .TRUE. the first time that the function
1400 ! is called, or the first time with a new value
1401 ! for k. When first = .TRUE., the function sets
1402 ! up starting values and may be very much slower.
1404 REAL, INTENT(IN) :: k
1405 LOGICAL, INTENT(IN) :: first
1406 REAL :: fn_val
1408 ! Local variables
1410 INTEGER :: j, n
1411 INTEGER, SAVE :: nk
1412 REAL, PARAMETER :: pi = 3.14159265
1413 REAL, SAVE :: p(20), theta(0:20)
1414 REAL :: sump, r, th, lambda, rlast
1415 REAL (dp) :: dk
1417 IF (first) THEN ! Initialization, if necessary
1418 IF (k < zero) THEN
1419 WRITE(*, *) '** Error: argument k for random_von_Mises = ', k
1420 RETURN
1421 END IF
1423 nk = k + k + one
1424 IF (nk > 20) THEN
1425 WRITE(*, *) '** Error: argument k for random_von_Mises = ', k
1426 RETURN
1427 END IF
1429 dk = k
1430 theta(0) = zero
1431 IF (k > half) THEN
1433 ! Set up array p of probabilities.
1435 sump = zero
1436 DO j = 1, nk
1437 IF (j < nk) THEN
1438 theta(j) = ACOS(one - j/k)
1439 ELSE
1440 theta(nk) = pi
1441 END IF
1443 ! Numerical integration of e^[k.cos(x)] from theta(j-1) to theta(j)
1445 CALL integral(theta(j-1), theta(j), p(j), dk)
1446 sump = sump + p(j)
1447 END DO
1448 p(1:nk) = p(1:nk) / sump
1449 ELSE
1450 p(1) = one
1451 theta(1) = pi
1452 END IF ! if k > 0.5
1453 END IF ! if first
1455 CALL RANDOM_NUMBER(r)
1456 DO j = 1, nk
1457 r = r - p(j)
1458 IF (r < zero) EXIT
1459 END DO
1460 r = -r/p(j)
1463 th = theta(j-1) + r*(theta(j) - theta(j-1))
1464 lambda = k - j + one - k*COS(th)
1465 n = 1
1466 rlast = lambda
1469 CALL RANDOM_NUMBER(r)
1470 IF (r > rlast) EXIT
1471 n = n + 1
1472 rlast = r
1473 END DO
1475 IF (n .NE. 2*(n/2)) EXIT ! is n even?
1476 CALL RANDOM_NUMBER(r)
1477 END DO
1479 fn_val = SIGN(th, (r - rlast)/(one - rlast) - half)
1480 RETURN
1481 END FUNCTION random_von_Mises
1485 SUBROUTINE integral(a, b, result, dk)
1487 ! Gaussian integration of exp(k.cosx) from a to b.
1489 REAL (dp), INTENT(IN) :: dk
1490 REAL, INTENT(IN) :: a, b
1491 REAL, INTENT(OUT) :: result
1493 ! Local variables
1495 REAL (dp) :: xmid, range, x1, x2, &
1496 x(3) = (/0.238619186083197_dp, 0.661209386466265_dp, 0.932469514203152_dp/), &
1497 w(3) = (/0.467913934572691_dp, 0.360761573048139_dp, 0.171324492379170_dp/)
1498 INTEGER :: i
1500 xmid = (a + b)/2._dp
1501 range = (b - a)/2._dp
1503 result = 0._dp
1504 DO i = 1, 3
1505 x1 = xmid + x(i)*range
1506 x2 = xmid - x(i)*range
1507 result = result + w(i)*(EXP(dk*COS(x1)) + EXP(dk*COS(x2)))
1508 END DO
1510 result = result * range
1511 RETURN
1512 END SUBROUTINE integral
1516 FUNCTION random_Cauchy() RESULT(fn_val)
1518 ! Generate a random deviate from the standard Cauchy distribution
1520 REAL :: fn_val
1522 ! Local variables
1523 REAL :: v(2)
1526 CALL RANDOM_NUMBER(v)
1527 v = two*(v - half)
1528 IF (ABS(v(2)) < vsmall) CYCLE ! Test for zero
1529 IF (v(1)**2 + v(2)**2 < one) EXIT
1530 END DO
1531 fn_val = v(1) / v(2)
1533 RETURN
1534 END FUNCTION random_Cauchy
1538 SUBROUTINE random_order(order, n)
1540 ! Generate a random ordering of the integers 1 ... n.
1542 INTEGER, INTENT(IN) :: n
1543 INTEGER, INTENT(OUT) :: order(n)
1545 ! Local variables
1547 INTEGER :: i, j, k
1548 REAL :: wk
1550 DO i = 1, n
1551 order(i) = i
1552 END DO
1554 ! Starting at the end, swap the current last indicator with one
1555 ! randomly chosen from those preceeding it.
1557 DO i = n, 2, -1
1558 CALL RANDOM_NUMBER(wk)
1559 j = 1 + i * wk
1560 IF (j < i) THEN
1561 k = order(i)
1562 order(i) = order(j)
1563 order(j) = k
1564 END IF
1565 END DO
1567 RETURN
1568 END SUBROUTINE random_order
1572 SUBROUTINE seed_random_number(iounit)
1574 INTEGER, INTENT(IN) :: iounit
1576 ! Local variables
1578 INTEGER :: k
1579 INTEGER, ALLOCATABLE :: seed(:)
1581 CALL RANDOM_SEED(SIZE=k)
1582 ALLOCATE( seed(k) )
1584 WRITE(*, '(a, i2, a)')' Enter ', k, ' integers for random no. seeds: '
1585 READ(*, *) seed
1586 WRITE(iounit, '(a, (7i10))') ' Random no. seeds: ', seed
1587 CALL RANDOM_SEED(PUT=seed)
1589 DEALLOCATE( seed )
1591 RETURN
1592 END SUBROUTINE seed_random_number
1595 END MODULE KPP_ROOT_Random
1597 MODULE KPP_ROOT_Integrator
1598 USE KPP_ROOT_Random
1599 USE KPP_ROOT_Parameters, ONLY : NVAR, NFIX, NREACT
1600 USE KPP_ROOT_Global, ONLY : TIME, RCONST, Volume
1601 USE KPP_ROOT_Stoichiom
1602 USE KPP_ROOT_Stochastic
1603 USE KPP_ROOT_Rates
1604 USE KPP_ROOT_Random, ddp => dp
1605 IMPLICIT NONE
1607 CONTAINS
1609 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1610 SUBROUTINE TauLeap(Nsteps, Tau, T, SCT, NmlcV, NmlcF)
1611 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1613 ! Tau-leap stochastic integration
1614 ! INPUT:
1615 ! Nsteps = no. of tau-leap steps to be simulated
1616 ! Tau = time step length
1617 ! T = time
1618 ! SCT = stochastic rate constants
1619 ! NmlcV, NmlcF = no. of molecules for variable and fixed species
1620 ! OUTPUT:
1621 ! T = updated time (after Nsteps)
1622 ! NmlcV = updated no. of molecules for variable species
1625 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1626 IMPLICIT NONE
1627 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1629 KPP_REAL:: T, Tau
1630 INTEGER :: Nsteps
1631 INTEGER :: NmlcV(NVAR), NmlcF(NFIX)
1632 INTEGER :: i, j, irct, id, istep, Nfirings(NREACT)
1633 REAL :: mu
1634 KPP_REAL :: A(NREACT), SCT(NREACT), x
1635 LOGICAL, SAVE :: First = .TRUE.
1637 DO istep = 1, Nsteps
1639 ! Propensity vector
1640 CALL Propensity ( NmlcV, NmlcF, SCT, A )
1642 ! Index of next reaction
1643 DO irct = 1, NREACT
1644 mu = A(irct)*Tau
1645 Nfirings(irct) = random_Poisson(mu, First)
1646 First = .TRUE.
1647 END DO
1649 ! Update time with the leap interval
1650 T = T + Tau;
1652 ! Directly update state vector
1653 DO irct = 1, NREACT
1654 DO i = CCOL_STOICM(irct), CCOL_STOICM(irct+1)-1
1655 id = IROW_STOICM(i)
1656 NmlcV(id) = MAX(0, NmlcV(id) + Nfirings(irct)*INT(STOICM(i)))
1657 END DO
1658 END DO
1660 ! Update state vector
1661 ! DO irct = 1, NREACT
1662 ! DO j = 1, Nfirings(irct)
1663 ! CALL MoleculeChange( irct, NmlcV )
1664 ! END DO
1665 ! END DO
1667 END DO
1669 CONTAINS
1671 SUBROUTINE PropensityTemplate( T, NmlcV, NmlcF, Prop )
1672 KPP_REAL, INTENT(IN) :: T
1673 INTEGER, INTENT(IN) :: NmlcV(NVAR), NmlcF(NFIX)
1674 KPP_REAL, INTENT(OUT) :: Prop(NREACT)
1675 KPP_REAL :: Tsave
1676 ! Update the stochastic reaction rates, which may be time dependent
1677 Tsave = TIME
1678 TIME = T
1679 CALL Update_RCONST()
1680 CALL StochasticRates( RCONST, Volume, SCT )
1681 CALL Propensity ( NmlcV, NmlcF, SCT, Prop )
1682 TIME = Tsave
1683 END SUBROUTINE PropensityTemplate
1685 END SUBROUTINE TauLeap
1686 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1688 END MODULE KPP_ROOT_Integrator