| 1 | ! MATH_LIB: Mathematics procedures for F90 |
|---|
| 2 | ! Compiled/Modified: |
|---|
| 3 | ! 07/01/06 John Haynes (haynes@atmos.colostate.edu) |
|---|
| 4 | ! |
|---|
| 5 | ! gamma (function) |
|---|
| 6 | ! path_integral (function) |
|---|
| 7 | ! avint (subroutine) |
|---|
| 8 | |
|---|
| 9 | module math_lib |
|---|
| 10 | implicit none |
|---|
| 11 | |
|---|
| 12 | contains |
|---|
| 13 | |
|---|
| 14 | ! ---------------------------------------------------------------------------- |
|---|
| 15 | ! function GAMMA |
|---|
| 16 | ! ---------------------------------------------------------------------------- |
|---|
| 17 | function gamma(x) |
|---|
| 18 | implicit none |
|---|
| 19 | ! |
|---|
| 20 | ! Purpose: |
|---|
| 21 | ! Returns the gamma function |
|---|
| 22 | ! |
|---|
| 23 | ! Input: |
|---|
| 24 | ! [x] value to compute gamma function of |
|---|
| 25 | ! |
|---|
| 26 | ! Returns: |
|---|
| 27 | ! gamma(x) |
|---|
| 28 | ! |
|---|
| 29 | ! Coded: |
|---|
| 30 | ! 02/02/06 John Haynes (haynes@atmos.colostate.edu) |
|---|
| 31 | ! (original code of unknown origin) |
|---|
| 32 | |
|---|
| 33 | ! ----- INPUTS ----- |
|---|
| 34 | real*8, intent(in) :: x |
|---|
| 35 | |
|---|
| 36 | ! ----- OUTPUTS ----- |
|---|
| 37 | real*8 :: gamma |
|---|
| 38 | |
|---|
| 39 | ! ----- INTERNAL ----- |
|---|
| 40 | real*8 :: pi,ga,z,r,gr |
|---|
| 41 | real*8 :: g(26) |
|---|
| 42 | integer :: k,m1,m |
|---|
| 43 | |
|---|
| 44 | pi = acos(-1.) |
|---|
| 45 | if (x ==int(x)) then |
|---|
| 46 | if (x > 0.0) then |
|---|
| 47 | ga=1.0 |
|---|
| 48 | m1=x-1 |
|---|
| 49 | do k=2,m1 |
|---|
| 50 | ga=ga*k |
|---|
| 51 | enddo |
|---|
| 52 | else |
|---|
| 53 | ga=1.0+300 |
|---|
| 54 | endif |
|---|
| 55 | else |
|---|
| 56 | if (abs(x) > 1.0) then |
|---|
| 57 | z=abs(x) |
|---|
| 58 | m=int(z) |
|---|
| 59 | r=1.0 |
|---|
| 60 | do k=1,m |
|---|
| 61 | r=r*(z-k) |
|---|
| 62 | enddo |
|---|
| 63 | z=z-m |
|---|
| 64 | else |
|---|
| 65 | z=x |
|---|
| 66 | endif |
|---|
| 67 | data g/1.0,0.5772156649015329, & |
|---|
| 68 | -0.6558780715202538, -0.420026350340952d-1, & |
|---|
| 69 | 0.1665386113822915,-.421977345555443d-1, & |
|---|
| 70 | -.96219715278770d-2, .72189432466630d-2, & |
|---|
| 71 | -.11651675918591d-2, -.2152416741149d-3, & |
|---|
| 72 | .1280502823882d-3, -.201348547807d-4, & |
|---|
| 73 | -.12504934821d-5, .11330272320d-5, & |
|---|
| 74 | -.2056338417d-6, .61160950d-8, & |
|---|
| 75 | .50020075d-8, -.11812746d-8, & |
|---|
| 76 | .1043427d-9, .77823d-11, & |
|---|
| 77 | -.36968d-11, .51d-12, & |
|---|
| 78 | -.206d-13, -.54d-14, .14d-14, .1d-15/ |
|---|
| 79 | gr=g(26) |
|---|
| 80 | do k=25,1,-1 |
|---|
| 81 | gr=gr*z+g(k) |
|---|
| 82 | enddo |
|---|
| 83 | ga=1.0/(gr*z) |
|---|
| 84 | if (abs(x) > 1.0) then |
|---|
| 85 | ga=ga*r |
|---|
| 86 | if (x < 0.0) ga=-pi/(x*ga*sin(pi*x)) |
|---|
| 87 | endif |
|---|
| 88 | endif |
|---|
| 89 | gamma = ga |
|---|
| 90 | return |
|---|
| 91 | end function gamma |
|---|
| 92 | |
|---|
| 93 | ! ---------------------------------------------------------------------------- |
|---|
| 94 | ! function PATH_INTEGRAL |
|---|
| 95 | ! ---------------------------------------------------------------------------- |
|---|
| 96 | function path_integral(f,s,i1,i2) |
|---|
| 97 | use m_mrgrnk |
|---|
| 98 | use array_lib |
|---|
| 99 | implicit none |
|---|
| 100 | ! |
|---|
| 101 | ! Purpose: |
|---|
| 102 | ! evalues the integral (f ds) between f(index=i1) and f(index=i2) |
|---|
| 103 | ! using the AVINT procedure |
|---|
| 104 | ! |
|---|
| 105 | ! Inputs: |
|---|
| 106 | ! [f] functional values |
|---|
| 107 | ! [s] abscissa values |
|---|
| 108 | ! [i1] index of lower limit |
|---|
| 109 | ! [i2] index of upper limit |
|---|
| 110 | ! |
|---|
| 111 | ! Returns: |
|---|
| 112 | ! result of path integral |
|---|
| 113 | ! |
|---|
| 114 | ! Notes: |
|---|
| 115 | ! [s] may be in forward or reverse numerical order |
|---|
| 116 | ! |
|---|
| 117 | ! Requires: |
|---|
| 118 | ! mrgrnk package |
|---|
| 119 | ! |
|---|
| 120 | ! Created: |
|---|
| 121 | ! 02/02/06 John Haynes (haynes@atmos.colostate.edu) |
|---|
| 122 | |
|---|
| 123 | ! ----- INPUTS ----- |
|---|
| 124 | real*8, intent(in), dimension(:) :: f,s |
|---|
| 125 | integer, intent(in) :: i1, i2 |
|---|
| 126 | |
|---|
| 127 | ! ---- OUTPUTS ----- |
|---|
| 128 | real*8 :: path_integral |
|---|
| 129 | |
|---|
| 130 | ! ----- INTERNAL ----- |
|---|
| 131 | real*8 :: sumo, deltah, val |
|---|
| 132 | integer*4 :: nelm, j |
|---|
| 133 | integer*4, dimension(i2-i1+1) :: idx |
|---|
| 134 | real*8, dimension(i2-i1+1) :: f_rev, s_rev |
|---|
| 135 | |
|---|
| 136 | nelm = i2-i1+1 |
|---|
| 137 | if (nelm > 3) then |
|---|
| 138 | call mrgrnk(s(i1:i2),idx) |
|---|
| 139 | s_rev = s(idx) |
|---|
| 140 | f_rev = f(idx) |
|---|
| 141 | call avint(f_rev(i1:i2),s_rev(i1:i2),(i2-i1+1), & |
|---|
| 142 | s_rev(i1),s_rev(i2), val) |
|---|
| 143 | path_integral = val |
|---|
| 144 | else |
|---|
| 145 | sumo = 0. |
|---|
| 146 | do j=i1,i2 |
|---|
| 147 | deltah = abs(s(i1+1)-s(i1)) |
|---|
| 148 | sumo = sumo + f(j)*deltah |
|---|
| 149 | enddo |
|---|
| 150 | path_integral = sumo |
|---|
| 151 | endif |
|---|
| 152 | ! print *, sumo |
|---|
| 153 | |
|---|
| 154 | return |
|---|
| 155 | end function path_integral |
|---|
| 156 | |
|---|
| 157 | ! ---------------------------------------------------------------------------- |
|---|
| 158 | ! subroutine AVINT |
|---|
| 159 | ! ---------------------------------------------------------------------------- |
|---|
| 160 | subroutine avint ( ftab, xtab, ntab, a_in, b_in, result ) |
|---|
| 161 | implicit none |
|---|
| 162 | ! |
|---|
| 163 | ! Purpose: |
|---|
| 164 | ! estimate the integral of unevenly spaced data |
|---|
| 165 | ! |
|---|
| 166 | ! Inputs: |
|---|
| 167 | ! [ftab] functional values |
|---|
| 168 | ! [xtab] abscissa values |
|---|
| 169 | ! [ntab] number of elements of [ftab] and [xtab] |
|---|
| 170 | ! [a] lower limit of integration |
|---|
| 171 | ! [b] upper limit of integration |
|---|
| 172 | ! |
|---|
| 173 | ! Outputs: |
|---|
| 174 | ! [result] approximate value of integral |
|---|
| 175 | ! |
|---|
| 176 | ! Reference: |
|---|
| 177 | ! From SLATEC libraries, in public domain |
|---|
| 178 | ! |
|---|
| 179 | !*********************************************************************** |
|---|
| 180 | ! |
|---|
| 181 | ! AVINT estimates the integral of unevenly spaced data. |
|---|
| 182 | ! |
|---|
| 183 | ! Discussion: |
|---|
| 184 | ! |
|---|
| 185 | ! The method uses overlapping parabolas and smoothing. |
|---|
| 186 | ! |
|---|
| 187 | ! Modified: |
|---|
| 188 | ! |
|---|
| 189 | ! 30 October 2000 |
|---|
| 190 | ! 4 January 2008, A. Bodas-Salcedo. Error control for XTAB taken out of |
|---|
| 191 | ! loop to allow vectorization. |
|---|
| 192 | ! |
|---|
| 193 | ! Reference: |
|---|
| 194 | ! |
|---|
| 195 | ! Philip Davis and Philip Rabinowitz, |
|---|
| 196 | ! Methods of Numerical Integration, |
|---|
| 197 | ! Blaisdell Publishing, 1967. |
|---|
| 198 | ! |
|---|
| 199 | ! P E Hennion, |
|---|
| 200 | ! Algorithm 77, |
|---|
| 201 | ! Interpolation, Differentiation and Integration, |
|---|
| 202 | ! Communications of the Association for Computing Machinery, |
|---|
| 203 | ! Volume 5, page 96, 1962. |
|---|
| 204 | ! |
|---|
| 205 | ! Parameters: |
|---|
| 206 | ! |
|---|
| 207 | ! Input, real ( kind = 8 ) FTAB(NTAB), the function values, |
|---|
| 208 | ! FTAB(I) = F(XTAB(I)). |
|---|
| 209 | ! |
|---|
| 210 | ! Input, real ( kind = 8 ) XTAB(NTAB), the abscissas at which the |
|---|
| 211 | ! function values are given. The XTAB's must be distinct |
|---|
| 212 | ! and in ascending order. |
|---|
| 213 | ! |
|---|
| 214 | ! Input, integer NTAB, the number of entries in FTAB and |
|---|
| 215 | ! XTAB. NTAB must be at least 3. |
|---|
| 216 | ! |
|---|
| 217 | ! Input, real ( kind = 8 ) A, the lower limit of integration. A should |
|---|
| 218 | ! be, but need not be, near one endpoint of the interval |
|---|
| 219 | ! (X(1), X(NTAB)). |
|---|
| 220 | ! |
|---|
| 221 | ! Input, real ( kind = 8 ) B, the upper limit of integration. B should |
|---|
| 222 | ! be, but need not be, near one endpoint of the interval |
|---|
| 223 | ! (X(1), X(NTAB)). |
|---|
| 224 | ! |
|---|
| 225 | ! Output, real ( kind = 8 ) RESULT, the approximate value of the integral. |
|---|
| 226 | |
|---|
| 227 | integer, intent(in) :: ntab |
|---|
| 228 | |
|---|
| 229 | integer,parameter :: KR8 = selected_real_kind(15,300) |
|---|
| 230 | real ( kind = KR8 ), intent(in) :: a_in |
|---|
| 231 | real ( kind = KR8 ) a |
|---|
| 232 | real ( kind = KR8 ) atemp |
|---|
| 233 | real ( kind = KR8 ), intent(in) :: b_in |
|---|
| 234 | real ( kind = KR8 ) b |
|---|
| 235 | real ( kind = KR8 ) btemp |
|---|
| 236 | real ( kind = KR8 ) ca |
|---|
| 237 | real ( kind = KR8 ) cb |
|---|
| 238 | real ( kind = KR8 ) cc |
|---|
| 239 | real ( kind = KR8 ) ctemp |
|---|
| 240 | real ( kind = KR8 ), intent(in) :: ftab(ntab) |
|---|
| 241 | integer i |
|---|
| 242 | integer ihi |
|---|
| 243 | integer ilo |
|---|
| 244 | integer ind |
|---|
| 245 | real ( kind = KR8 ), intent(out) :: result |
|---|
| 246 | real ( kind = KR8 ) sum1 |
|---|
| 247 | real ( kind = KR8 ) syl |
|---|
| 248 | real ( kind = KR8 ) term1 |
|---|
| 249 | real ( kind = KR8 ) term2 |
|---|
| 250 | real ( kind = KR8 ) term3 |
|---|
| 251 | real ( kind = KR8 ) x1 |
|---|
| 252 | real ( kind = KR8 ) x2 |
|---|
| 253 | real ( kind = KR8 ) x3 |
|---|
| 254 | real ( kind = KR8 ), intent(in) :: xtab(ntab) |
|---|
| 255 | logical lerror |
|---|
| 256 | |
|---|
| 257 | lerror = .false. |
|---|
| 258 | a = a_in |
|---|
| 259 | b = b_in |
|---|
| 260 | |
|---|
| 261 | if ( ntab < 3 ) then |
|---|
| 262 | write ( *, '(a)' ) ' ' |
|---|
| 263 | write ( *, '(a)' ) 'AVINT - Fatal error!' |
|---|
| 264 | write ( *, '(a,i6)' ) ' NTAB is less than 3. NTAB = ', ntab |
|---|
| 265 | stop |
|---|
| 266 | end if |
|---|
| 267 | |
|---|
| 268 | do i = 2, ntab |
|---|
| 269 | if ( xtab(i) <= xtab(i-1) ) then |
|---|
| 270 | lerror = .true. |
|---|
| 271 | exit |
|---|
| 272 | end if |
|---|
| 273 | end do |
|---|
| 274 | |
|---|
| 275 | if (lerror) then |
|---|
| 276 | write ( *, '(a)' ) ' ' |
|---|
| 277 | write ( *, '(a)' ) 'AVINT - Fatal error!' |
|---|
| 278 | write ( *, '(a)' ) ' XTAB(I) is not greater than XTAB(I-1).' |
|---|
| 279 | write ( *, '(a,i6)' ) ' Here, I = ', i |
|---|
| 280 | write ( *, '(a,g14.6)' ) ' XTAB(I-1) = ', xtab(i-1) |
|---|
| 281 | write ( *, '(a,g14.6)' ) ' XTAB(I) = ', xtab(i) |
|---|
| 282 | stop |
|---|
| 283 | end if |
|---|
| 284 | |
|---|
| 285 | result = 0.0D+00 |
|---|
| 286 | |
|---|
| 287 | if ( a == b ) then |
|---|
| 288 | write ( *, '(a)' ) ' ' |
|---|
| 289 | write ( *, '(a)' ) 'AVINT - Warning!' |
|---|
| 290 | write ( *, '(a)' ) ' A = B, integral=0.' |
|---|
| 291 | return |
|---|
| 292 | end if |
|---|
| 293 | ! |
|---|
| 294 | ! If B < A, temporarily switch A and B, and store sign. |
|---|
| 295 | ! |
|---|
| 296 | if ( b < a ) then |
|---|
| 297 | syl = b |
|---|
| 298 | b = a |
|---|
| 299 | a = syl |
|---|
| 300 | ind = -1 |
|---|
| 301 | else |
|---|
| 302 | syl = a |
|---|
| 303 | ind = 1 |
|---|
| 304 | end if |
|---|
| 305 | ! |
|---|
| 306 | ! Bracket A and B between XTAB(ILO) and XTAB(IHI). |
|---|
| 307 | ! |
|---|
| 308 | ilo = 1 |
|---|
| 309 | ihi = ntab |
|---|
| 310 | |
|---|
| 311 | do i = 1, ntab |
|---|
| 312 | if ( a <= xtab(i) ) then |
|---|
| 313 | exit |
|---|
| 314 | end if |
|---|
| 315 | ilo = ilo + 1 |
|---|
| 316 | end do |
|---|
| 317 | |
|---|
| 318 | ilo = max ( 2, ilo ) |
|---|
| 319 | ilo = min ( ilo, ntab - 1 ) |
|---|
| 320 | |
|---|
| 321 | do i = 1, ntab |
|---|
| 322 | if ( xtab(i) <= b ) then |
|---|
| 323 | exit |
|---|
| 324 | end if |
|---|
| 325 | ihi = ihi - 1 |
|---|
| 326 | end do |
|---|
| 327 | |
|---|
| 328 | ihi = min ( ihi, ntab - 1 ) |
|---|
| 329 | ihi = max ( ilo, ihi - 1 ) |
|---|
| 330 | ! |
|---|
| 331 | ! Carry out approximate integration from XTAB(ILO) to XTAB(IHI). |
|---|
| 332 | ! |
|---|
| 333 | sum1 = 0.0D+00 |
|---|
| 334 | |
|---|
| 335 | do i = ilo, ihi |
|---|
| 336 | |
|---|
| 337 | x1 = xtab(i-1) |
|---|
| 338 | x2 = xtab(i) |
|---|
| 339 | x3 = xtab(i+1) |
|---|
| 340 | |
|---|
| 341 | term1 = ftab(i-1) / ( ( x1 - x2 ) * ( x1 - x3 ) ) |
|---|
| 342 | term2 = ftab(i) / ( ( x2 - x1 ) * ( x2 - x3 ) ) |
|---|
| 343 | term3 = ftab(i+1) / ( ( x3 - x1 ) * ( x3 - x2 ) ) |
|---|
| 344 | |
|---|
| 345 | atemp = term1 + term2 + term3 |
|---|
| 346 | |
|---|
| 347 | btemp = - ( x2 + x3 ) * term1 & |
|---|
| 348 | - ( x1 + x3 ) * term2 & |
|---|
| 349 | - ( x1 + x2 ) * term3 |
|---|
| 350 | |
|---|
| 351 | ctemp = x2 * x3 * term1 + x1 * x3 * term2 + x1 * x2 * term3 |
|---|
| 352 | |
|---|
| 353 | if ( i <= ilo ) then |
|---|
| 354 | ca = atemp |
|---|
| 355 | cb = btemp |
|---|
| 356 | cc = ctemp |
|---|
| 357 | else |
|---|
| 358 | ca = 0.5D+00 * ( atemp + ca ) |
|---|
| 359 | cb = 0.5D+00 * ( btemp + cb ) |
|---|
| 360 | cc = 0.5D+00 * ( ctemp + cc ) |
|---|
| 361 | end if |
|---|
| 362 | |
|---|
| 363 | sum1 = sum1 & |
|---|
| 364 | + ca * ( x2**3 - syl**3 ) / 3.0D+00 & |
|---|
| 365 | + cb * 0.5D+00 * ( x2**2 - syl**2 ) & |
|---|
| 366 | + cc * ( x2 - syl ) |
|---|
| 367 | |
|---|
| 368 | ca = atemp |
|---|
| 369 | cb = btemp |
|---|
| 370 | cc = ctemp |
|---|
| 371 | |
|---|
| 372 | syl = x2 |
|---|
| 373 | |
|---|
| 374 | end do |
|---|
| 375 | |
|---|
| 376 | result = sum1 & |
|---|
| 377 | + ca * ( b**3 - syl**3 ) / 3.0D+00 & |
|---|
| 378 | + cb * 0.5D+00 * ( b**2 - syl**2 ) & |
|---|
| 379 | + cc * ( b - syl ) |
|---|
| 380 | ! |
|---|
| 381 | ! Restore original values of A and B, reverse sign of integral |
|---|
| 382 | ! because of earlier switch. |
|---|
| 383 | ! |
|---|
| 384 | if ( ind /= 1 ) then |
|---|
| 385 | ind = 1 |
|---|
| 386 | syl = b |
|---|
| 387 | b = a |
|---|
| 388 | a = syl |
|---|
| 389 | result = -result |
|---|
| 390 | end if |
|---|
| 391 | |
|---|
| 392 | return |
|---|
| 393 | end subroutine avint |
|---|
| 394 | |
|---|
| 395 | end module math_lib |
|---|