LCOV - code coverage report
Current view: top level - physics/cosp2/optics - math_lib.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 70 95 73.7 %
Date: 2025-03-13 19:12:29 Functions: 2 3 66.7 %

          Line data    Source code
       1             : ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       2             : ! Copyright (c) 2015, Regents of the University of Colorado
       3             : ! All rights reserved.
       4             : !
       5             : ! Redistribution and use in source and binary forms, with or without modification, are 
       6             : ! permitted provided that the following conditions are met:
       7             : !
       8             : ! 1. Redistributions of source code must retain the above copyright notice, this list of 
       9             : !    conditions and the following disclaimer.
      10             : !
      11             : ! 2. Redistributions in binary form must reproduce the above copyright notice, this list
      12             : !    of conditions and the following disclaimer in the documentation and/or other 
      13             : !    materials provided with the distribution.
      14             : !
      15             : ! 3. Neither the name of the copyright holder nor the names of its contributors may be 
      16             : !    used to endorse or promote products derived from this software without specific prior
      17             : !    written permission.
      18             : !
      19             : ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
      20             : ! EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
      21             : ! MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
      22             : ! THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
      23             : ! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
      24             : ! OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
      25             : ! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      26             : ! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      27             : ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28             : !
      29             : ! History:
      30             : ! July 2006: John Haynes      - Initial version
      31             : ! May 2015:  Dustin Swales    - Modified for COSPv2.0
      32             : ! 
      33             : ! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
      34             : module math_lib
      35             :   USE COSP_KINDS,     ONLY: wp
      36             :   use mod_cosp_error, ONLY: errorMessage
      37             :   implicit none
      38             : 
      39             : contains
      40             :   ! ##########################################################################  
      41             :   !                           function PATH_INTEGRAL 
      42             :   ! ##########################################################################  
      43           0 :   function path_integral(f,s,i1,i2)
      44             :     use m_mrgrnk
      45             :     use array_lib
      46             :     implicit none
      47             :     ! ########################################################################
      48             :     ! Purpose:
      49             :     !   evalues the integral (f ds) between f(index=i1) and f(index=i2)
      50             :     !   using the AVINT procedure
      51             :     !
      52             :     ! Inputs:
      53             :     !   [f]    functional values
      54             :     !   [s]    abscissa values
      55             :     !   [i1]   index of lower limit
      56             :     !   [i2]   index of upper limit
      57             :     !
      58             :     ! Returns:
      59             :     !   result of path integral
      60             :     !
      61             :     ! Notes:
      62             :     !   [s] may be in forward or reverse numerical order
      63             :     !
      64             :     ! Requires:
      65             :     !   mrgrnk package
      66             :     !
      67             :     ! Created:
      68             :     !   02/02/06  John Haynes (haynes@atmos.colostate.edu)
      69             :     ! ########################################################################
      70             : 
      71             :     ! INPUTS
      72             :     real(wp),intent(in), dimension(:) :: &
      73             :          f,  & ! Functional values
      74             :          s     ! Abscissa values  
      75             :     integer, intent(in) :: &
      76             :          i1, & ! Index of lower limit
      77             :          i2    ! Index of upper limit
      78             : 
      79             :     ! OUTPUTS
      80             :     real(wp) :: path_integral  
      81             :   
      82             :     ! Internal variables
      83             :     real(wp) :: sumo, deltah, val
      84             :     integer :: nelm, j
      85           0 :     integer, dimension(i2-i1+1) :: idx
      86           0 :     real(wp), dimension(i2-i1+1) :: f_rev, s_rev
      87             : 
      88           0 :     nelm = i2-i1+1
      89           0 :     if (nelm > 3) then
      90           0 :        call mrgrnk(s(i1:i2),idx)
      91           0 :        s_rev = s(idx)
      92           0 :        f_rev = f(idx)
      93           0 :        call avint(f_rev(i1:i2),s_rev(i1:i2),(i2-i1+1), &
      94           0 :             s_rev(i1),s_rev(i2), val)
      95           0 :        path_integral = val
      96             :     else
      97             :        sumo = 0._wp
      98           0 :        do j=i1,i2
      99           0 :           deltah = abs(s(i1+1)-s(i1))
     100           0 :           sumo = sumo + f(j)*deltah
     101             :        enddo
     102             :        path_integral = sumo
     103             :     endif
     104             :     
     105             :     return
     106             :   end function path_integral
     107             :   
     108             :   ! ##########################################################################
     109             :   !                            subroutine AVINT
     110             :   ! ##########################################################################
     111    55900936 :   subroutine avint ( ftab, xtab, ntab, a_in, b_in, result )
     112             :     implicit none
     113             :     ! ########################################################################  
     114             :     ! Purpose:
     115             :     !   estimate the integral of unevenly spaced data
     116             :     !
     117             :     ! Inputs:
     118             :     !   [ftab]     functional values
     119             :     !   [xtab]     abscissa values
     120             :     !   [ntab]     number of elements of [ftab] and [xtab]
     121             :     !   [a]        lower limit of integration
     122             :     !   [b]        upper limit of integration
     123             :     !
     124             :     ! Outputs:
     125             :     !   [result]   approximate value of integral
     126             :     !
     127             :     ! Reference:
     128             :     !   From SLATEC libraries, in public domain
     129             :     !
     130             :     !***********************************************************************
     131             :     !
     132             :     !  AVINT estimates the integral of unevenly spaced data.
     133             :     !
     134             :     !  Discussion:
     135             :     !
     136             :     !    The method uses overlapping parabolas and smoothing.
     137             :     !
     138             :     !  Modified:
     139             :     !
     140             :     !    30 October 2000
     141             :     !    4 January 2008, A. Bodas-Salcedo. Error control for XTAB taken out of
     142             :     !                    loop to allow vectorization.
     143             :     !
     144             :     !  Reference:
     145             :     !
     146             :     !    Philip Davis and Philip Rabinowitz,
     147             :     !    Methods of Numerical Integration,
     148             :     !    Blaisdell Publishing, 1967.
     149             :     !
     150             :     !    P E Hennion,
     151             :     !    Algorithm 77,
     152             :     !    Interpolation, Differentiation and Integration,
     153             :     !    Communications of the Association for Computing Machinery,
     154             :     !    Volume 5, page 96, 1962.
     155             :     !
     156             :     !  Parameters:
     157             :     !
     158             :     !    Input, real ( kind = 8 ) FTAB(NTAB), the function values,
     159             :     !    FTAB(I) = F(XTAB(I)).
     160             :     !
     161             :     !    Input, real ( kind = 8 ) XTAB(NTAB), the abscissas at which the
     162             :     !    function values are given.  The XTAB's must be distinct
     163             :     !    and in ascending order.
     164             :     !
     165             :     !    Input, integer NTAB, the number of entries in FTAB and
     166             :     !    XTAB.  NTAB must be at least 3.
     167             :     !
     168             :     !    Input, real ( kind = 8 ) A, the lower limit of integration.  A should
     169             :     !    be, but need not be, near one endpoint of the interval
     170             :     !    (X(1), X(NTAB)).
     171             :     !
     172             :     !    Input, real ( kind = 8 ) B, the upper limit of integration.  B should
     173             :     !    be, but need not be, near one endpoint of the interval
     174             :     !    (X(1), X(NTAB)).
     175             :     !
     176             :     !    Output, real ( kind = 8 ) RESULT, the approximate value of the integral.
     177             :     ! ##########################################################################  
     178             : 
     179             :     ! INPUTS
     180             :     integer,intent(in) :: &
     181             :          ntab    ! Number of elements of [ftab] and [xtab]
     182             :     real(wp),intent(in) :: &
     183             :          a_in, & ! Lower limit of integration
     184             :          b_in    ! Upper limit of integration
     185             :     real(wp),intent(in),dimension(ntab) :: &
     186             :          ftab, & ! Functional values
     187             :          xtab    ! Abscissa value
     188             :     
     189             :     ! OUTPUTS
     190             :     real(wp),intent(out) :: result  ! Approximate value of integral
     191             : 
     192             :     ! Internal varaibles
     193             :     real(wp) :: a, atemp, b, btemp,ca,cb,cc,ctemp,sum1,syl,term1,term2,term3,x1,x2,x3
     194             :     integer  :: i,ihi,ilo,ind
     195             :     logical  :: lerror
     196             :   
     197    55900936 :     lerror = .false.
     198    55900936 :     a = a_in
     199    55900936 :     b = b_in  
     200             :   
     201    55900936 :     if ( ntab < 3 ) then
     202           0 :        call errorMessage('FATAL ERROR(optics/math_lib.f90:AVINT): Ntab is less than 3.')
     203           0 :        return
     204             :     end if
     205             :     
     206  4751579560 :     do i = 2, ntab
     207  4751579560 :        if ( xtab(i) <= xtab(i-1) ) then
     208             :           lerror = .true.
     209             :           exit
     210             :        end if
     211             :     end do
     212             :     
     213    55900936 :     if (lerror) then
     214           0 :        call errorMessage('FATAL ERROR(optics/math_lib.f90:AVINT): Xtab(i) is not greater than Xtab(i-1).')
     215           0 :        return
     216             :     end if
     217             :     
     218             : !ds    result = 0.0D+00
     219    55900936 :     result = 0._wp
     220             :     
     221    55900936 :     if ( a == b ) then
     222           0 :        call errorMessage('WARNING(optics/math_lib.f90:AVINT): A=B => integral=0')
     223           0 :        return
     224             :     end if
     225             :     
     226             :     !  If B < A, temporarily switch A and B, and store sign.
     227    55900936 :     if ( b < a ) then
     228             :        syl = b
     229             :        b = a
     230             :        a = syl
     231             :        ind = -1
     232             :     else
     233    55900936 :        syl = a
     234    55900936 :        ind = 1
     235             :     end if
     236             :     
     237             :     !  Bracket A and B between XTAB(ILO) and XTAB(IHI).
     238    55900936 :     ilo = 1
     239    55900936 :     ihi = ntab
     240             :     
     241    55900936 :     do i = 1, ntab
     242    55900936 :        if ( a <= xtab(i) ) then
     243             :           exit
     244             :        end if
     245    55900936 :        ilo = ilo + 1
     246             :     end do
     247             :     
     248    55900936 :     ilo = max ( 2, ilo )
     249    55900936 :     ilo = min ( ilo, ntab - 1 )
     250             :     
     251    55900936 :     do i = 1, ntab
     252    55900936 :        if ( xtab(i) <= b ) then
     253             :           exit
     254             :        end if
     255    55900936 :        ihi = ihi - 1
     256             :     end do
     257             :     
     258    55900936 :     ihi = min ( ihi, ntab - 1 )
     259    55900936 :     ihi = max ( ilo, ihi - 1 )
     260             :     
     261             :     !  Carry out approximate integration from XTAB(ILO) to XTAB(IHI).
     262    55900936 :     sum1 = 0._wp
     263             : !ds    sum1 = 0.0D+00
     264             :     
     265  4639777688 :     do i = ilo, ihi
     266             :        
     267  4583876752 :        x1 = xtab(i-1)
     268  4583876752 :        x2 = xtab(i)
     269  4583876752 :        x3 = xtab(i+1)
     270             :        
     271  4583876752 :        term1 = ftab(i-1) / ( ( x1 - x2 ) * ( x1 - x3 ) )
     272  4583876752 :        term2 = ftab(i)   / ( ( x2 - x1 ) * ( x2 - x3 ) )
     273  4583876752 :        term3 = ftab(i+1) / ( ( x3 - x1 ) * ( x3 - x2 ) )
     274             :        
     275  4583876752 :        atemp = term1 + term2 + term3
     276             :        
     277             :        btemp = - ( x2 + x3 ) * term1 &
     278             :             - ( x1 + x3 ) * term2 &
     279  4583876752 :             - ( x1 + x2 ) * term3
     280             :        
     281  4583876752 :        ctemp = x2 * x3 * term1 + x1 * x3 * term2 + x1 * x2 * term3
     282             :        
     283  4583876752 :        if ( i <= ilo ) then
     284             :           ca = atemp
     285             :           cb = btemp
     286             :           cc = ctemp
     287             :        else
     288  4527975816 :           ca = 0.5_wp * ( atemp + ca )
     289  4527975816 :           cb = 0.5_wp * ( btemp + cb )
     290  4527975816 :           cc = 0.5_wp * ( ctemp + cc )
     291             : !ds          ca = 0.5D+00 * ( atemp + ca )
     292             : !ds          cb = 0.5D+00 * ( btemp + cb )
     293             : !ds          cc = 0.5D+00 * ( ctemp + cc )
     294             :        end if
     295             :        
     296             :        sum1 = sum1 + ca * ( x2**3 - syl**3 ) / 3._wp &
     297  4583876752 :             + cb * 0.5_wp * ( x2**2 - syl**2 ) + cc * ( x2 - syl )
     298             : !ds       sum1 = sum1 + ca * ( x2**3 - syl**3 ) / 3.0D+00 &
     299             : !ds            + cb * 0.5D+00 * ( x2**2 - syl**2 ) + cc * ( x2 - syl )
     300             :        
     301  4583876752 :        ca = atemp
     302  4583876752 :        cb = btemp
     303  4583876752 :        cc = ctemp
     304             :        
     305  4639777688 :        syl = x2
     306             :        
     307             :     end do
     308             : 
     309             :     result = sum1 + ca * ( b**3 - syl**3 ) / 3._wp &
     310    55900936 :          + cb * 0.5_wp * ( b**2 - syl**2 ) + cc * ( b - syl )
     311             : !ds    result = sum1 + ca * ( b**3 - syl**3 ) / 3.0D+00 &
     312             : !ds         + cb * 0.5D+00 * ( b**2 - syl**2 ) + cc * ( b - syl )
     313             : 
     314             :     !  Restore original values of A and B, reverse sign of integral
     315             :     !  because of earlier switch.
     316    55900936 :     if ( ind /= 1 ) then
     317           0 :        ind = 1
     318           0 :        syl = b
     319           0 :        b = a
     320           0 :        a = syl
     321           0 :        result = -result
     322             :     end if
     323             :     
     324             :     return
     325             :   end subroutine avint
     326             :   ! ######################################################################################
     327             :   ! SUBROUTINE gamma
     328             :   ! Purpose:
     329             :   !   Returns the gamma function
     330             :   !
     331             :   ! Input:
     332             :   !   [x]   value to compute gamma function of
     333             :   !
     334             :   ! Returns:
     335             :   !   gamma(x)
     336             :   !
     337             :   ! Coded:
     338             :   !   02/02/06  John Haynes (haynes@atmos.colostate.edu)
     339             :   !   (original code of unknown origin)
     340             :   ! ######################################################################################
     341    28140854 :   function gamma(x)
     342             :     ! Inputs 
     343             :     real(wp), intent(in) :: x
     344             : 
     345             :     ! Outputs
     346             :     real(wp) :: gamma
     347             :     
     348             :     ! Local variables
     349             :     real(wp) :: pi,ga,z,r,gr
     350             :     integer  :: k,m1,m  
     351             :     
     352             :     ! Parameters
     353             :     real(wp),dimension(26),parameter :: &
     354             :          g = (/1.0,0.5772156649015329, -0.6558780715202538, -0.420026350340952e-1,     &
     355             :                0.1665386113822915,-0.421977345555443e-1,-0.96219715278770e-2,              &
     356             :                0.72189432466630e-2,-0.11651675918591e-2, -0.2152416741149e-3,                &
     357             :                0.1280502823882e-3, -0.201348547807e-4, -0.12504934821e-5, 0.11330272320e-5,  &
     358             :                -0.2056338417e-6, 0.61160950e-8,0.50020075e-8, -0.11812746e-8, 0.1043427e-9,   &
     359             :                0.77823e-11, -0.36968e-11, 0.51e-12, -0.206e-13, -0.54e-14, 0.14e-14, 0.1e-15/)  
     360             : !ds    real(wp),dimension(26),parameter :: &
     361             : !ds         g = (/1.0d0,0.5772156649015329d0, -0.6558780715202538d0, -0.420026350340952d-1,     &
     362             : !ds               0.1665386113822915d0,-0.421977345555443d-1,-0.96219715278770d-2,              &
     363             : !ds               0.72189432466630d-2,-0.11651675918591d-2, -0.2152416741149d-3,                &
     364             : !ds               0.1280502823882d-3, -0.201348547807d-4, -0.12504934821d-5, 0.11330272320d-5,  &
     365             : !ds               -0.2056338417d-6, 0.61160950d-8,0.50020075d-8, -0.11812746d-8, 0.1043427d-9,   &
     366             : !ds               0.77823d-11, -0.36968d-11, 0.51d-12, -0.206d-13, -0.54d-14, 0.14d-14, 0.1d-15/)  
     367             :     
     368    28140854 :     pi = acos(-1._wp)    
     369    28140854 :     if (x ==int(x)) then
     370    27932981 :        if (x > 0.0) then
     371    27932981 :           ga=1._wp
     372    27932981 :           m1=x-1
     373    84006816 :           do k=2,m1
     374    84006816 :              ga=ga*k
     375             :           enddo
     376             :        else
     377             :           ga=1._wp+300
     378             :        endif
     379             :     else
     380      207873 :        if (abs(x) > 1.0) then
     381      207873 :           z=abs(x)
     382      207873 :           m=int(z)
     383      207873 :           r=1._wp
     384     1039365 :           do k=1,m
     385     1039365 :              r=r*(z-k)
     386             :           enddo
     387      207873 :           z=z-m
     388             :        else
     389             :           z=x
     390             :        endif
     391      207873 :        gr=g(26)
     392     5404698 :        do k=25,1,-1
     393     5404698 :           gr=gr*z+g(k)
     394             :        enddo
     395      207873 :        ga=1._wp/(gr*z)
     396      207873 :        if (abs(x) > 1.0) then
     397      207873 :           ga=ga*r
     398      207873 :           if (x < 0.0) ga=-pi/(x*ga*sin(pi*x))
     399             :        endif
     400             :     endif
     401    28140854 :     gamma = ga
     402             :     return
     403             :   end function gamma
     404             : end module math_lib

Generated by: LCOV version 1.14