LCOV - code coverage report
Current view: top level - physics/carma/base - planck.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 74 0.0 %
Date: 2025-03-14 01:30:37 Functions: 0 5 0.0 %

          Line data    Source code
       1             : ! Include shortname defintions, so that the F77 code does not have to be modified to
       2             : ! reference the CARMA structure.
       3             : #include "carma_globaer.h"
       4             : 
       5             : module planck
       6             : 
       7             : contains
       8             : 
       9             :   !! This routine calculates the planck intensity.
      10             :   !!
      11             :   !! This algorithm is based upon eqn 1.2.4 from Liou[2002].
      12             :   !!
      13             :   !! @author Chuck Bardeen
      14             :   !! @version Jan-2010
      15           0 :   function planckIntensity(wvl, temp)
      16             :   
      17             :     ! types
      18             :     use carma_precision_mod
      19             :     use carma_enums_mod
      20             :     use carma_constants_mod
      21             :     use carma_types_mod
      22             :     use carmastate_mod
      23             :     use carma_mod
      24             :   
      25             :     implicit none
      26             :   
      27             :     real(kind=f), intent(in)             :: wvl     !! wavelength (cm)
      28             :     real(kind=f), intent(in)             :: temp    !! temperature (K)
      29             :     real(kind=f)                         :: planckIntensity  !! Planck intensity (erg/s/cm2/sr/cm)
      30             :   
      31             :     ! Local declarations
      32             :     
      33             :     real(kind=f), parameter              :: C = 2.9979e10_f     ! Speed of light [cm/s]       
      34             :     real(kind=f), parameter              :: H = 6.62608e-27_f   ! Planck constant [erg s]
      35             :     
      36             :     ! Calculate the planck intensity.
      37           0 :     planckIntensity = 2._f * H * C**2 / ((wvl**5) * (exp(H * C / (BK * wvl * temp)) - 1._f))
      38             :     
      39             :     ! Return the planck intensity to the caller.
      40             :     return
      41           0 :   end function
      42             :   
      43             : 
      44             :   !! This routine calculates the total planck intensity from the specified
      45             :   !! wavelength to a wavelength of 0.
      46             :   !!
      47             :   !! This algorithm is based upon Widger and Woodall, BAMS, 1976 as
      48             :   !! indicated at http://www.spectralcalc.com/blackbody/appendixA.html.
      49             :   !!
      50             :   !! @author Chuck Bardeen
      51             :   !! @version Aug-2011
      52           0 :   function planckIntensityWidger1976(wvl, temp, miniter)
      53             :   
      54             :     ! types
      55           0 :     use carma_precision_mod
      56             :     use carma_enums_mod
      57             :     use carma_constants_mod
      58             :     use carma_types_mod
      59             :     use carmastate_mod
      60             :     use carma_mod
      61             :   
      62             :     implicit none
      63             :  
      64             :     real(kind=f), intent(in)             :: wvl     !! band center wavelength (cm)
      65             :     real(kind=f), intent(in)             :: temp    !! temperature (K)
      66             :     integer, intent(in)                  :: miniter !! minimum iterations
      67             :     real(kind=f)                         :: planckIntensityWidger1976  !! Planck intensity (erg/s/cm2/sr/cm)
      68             : 
      69             :     ! Local Variables
      70             :     real(kind=f), parameter              :: C  = 299792458.0_f     ! Speed of light [m/s]       
      71             :     real(kind=f), parameter              :: H  = 6.6260693e-34_f   ! Planck constant [J s]
      72             :     real(kind=f), parameter              :: BZ = 1.380658e-23_f    ! Boltzman constant
      73             : 
      74             :     real(kind=f)                         :: c1, x, x2, x3, sumJ, dn, sigma
      75             :     integer                              :: iter, n
      76             : 
      77           0 :     sigma = 1._f / wvl
      78             :     
      79           0 :     c1 = H * C / BZ
      80           0 :     x  = c1 * 100._f * sigma / temp
      81           0 :     x2 = x * x
      82           0 :     x3 = x2 * x
      83             : 
      84             :     ! Use fewer iterations, since speed is more important than accuracy for
      85             :     ! the particle heating code, and even with fewer iterations the results
      86             :     ! with CAM bands still show good accuracy.
      87             : !    iter = min(512, int(2._f + 20._f / x))
      88           0 :     iter = min(miniter, int(2._f + 20._f / x))
      89             : 
      90           0 :     sumJ = 0._f
      91             : 
      92           0 :     do n = 1, iter
      93           0 :       dn  = 1._f / n
      94           0 :       sumJ = sumJ + exp(-n*x) * (x3 + (3.0_f * x2 + 6.0_f * (x + dn) * dn) * dn) * dn
      95             :     end do
      96             : 
      97             :     ! Convert results from W/m2/sr to erg/cm2/s/sr 
      98           0 :     planckIntensityWidger1976 = 2.0_f * H * (C**2) * ((temp / c1) ** 4) * sumJ * 1e7_f / 1e4_f
      99             : 
     100             :     return
     101           0 :   end function
     102             : 
     103             :  
     104             :   !! This routine calculates the average planck intensity in the wavelength
     105             :   !! band defined by wvl and dwvl.
     106             :   !!
     107             :   !! This algorithm is based upon Widger and Woodall, BAMS, 1976 as
     108             :   !! indicated at http://www.spectralcalc.com/blackbody/appendixA.html.
     109             :   !!
     110             :   !! @author Chuck Bardeen
     111             :   !! @version Aug-2011
     112           0 :   function planckBandIntensityWidger1976(wvl, dwvl, temp, miniter)
     113             :   
     114             :     ! types
     115           0 :     use carma_precision_mod
     116             :     use carma_enums_mod
     117             :     use carma_constants_mod
     118             :     use carma_types_mod
     119             :     use carmastate_mod
     120             :     use carma_mod
     121             :   
     122             :     implicit none
     123             :   
     124             :     real(kind=f), intent(in)             :: wvl     !! band center wavelength (cm)
     125             :     real(kind=f), intent(in)             :: dwvl    !! band width (cm)
     126             :     real(kind=f), intent(in)             :: temp    !! temperature (K)
     127             :     integer, intent(in)                  :: miniter !! minimum iterations
     128             :     real(kind=f)                         :: planckBandIntensityWidger1976  !! Planck intensity (erg/s/cm2/sr/cm)
     129             :     
     130             :     ! Calculate the integral from the edges to 0 and subtract.
     131             :     planckBandIntensityWidger1976 = &
     132             :          (planckIntensityWidger1976(wvl + (dwvl / 2._f), temp, miniter) &
     133           0 :          - planckIntensityWidger1976(wvl - (dwvl / 2._f), temp, miniter)) / dwvl
     134             : 
     135             :     return 
     136           0 :   end function
     137             : 
     138             : 
     139             :   !! This routine calculates the average planck intensity in the wavelength
     140             :   !! band defined by wvl and dwvl.
     141             :   !!
     142             :   !! This algorithm does a brute force integral by dividing the band into
     143             :   !! small sub-bands. This routine can be slow.
     144             :   !!
     145             :   !! @author Chuck Bardeen
     146             :   !! @version Aug-2011
     147           0 :   function planckBandIntensity(wvl, dwvl, temp, iter)
     148             :   
     149             :     ! types
     150           0 :     use carma_precision_mod
     151             :     use carma_enums_mod
     152             :     use carma_constants_mod
     153             :     use carma_types_mod
     154             :     use carmastate_mod
     155             :     use carma_mod
     156             : 
     157             :     implicit none
     158             :   
     159             :     real(kind=f), intent(in)             :: wvl     !! band center wavelength (cm)
     160             :     real(kind=f), intent(in)             :: dwvl    !! band width (cm)
     161             :     real(kind=f), intent(in)             :: temp    !! temperature (K)
     162             :     integer, intent(in)                  :: iter    !! number of iterations
     163             :     real(kind=f)                         :: planckBandIntensity  !! Planck intensity (erg/s/cm2/sr/cm)
     164             :     
     165             :     ! Local Variables
     166             :     real(kind=f)                         :: wstart    ! Starting wavelength (cm)
     167             :     real(kind=f)                         :: ddwave    ! sub-band width (cm)
     168             :     integer                              :: i
     169             : 
     170           0 :     wstart = wvl - (dwvl / 2._f)
     171           0 :     ddwave = dwvl / iter
     172             : 
     173           0 :     planckBandIntensity = 0._f
     174             : 
     175           0 :     do i = 1, iter
     176           0 :       planckBandIntensity = planckBandIntensity + planckIntensity(wstart + (i - 0.5_f) * ddwave, temp) * ddwave
     177             :     end do
     178             :  
     179           0 :     planckBandIntensity = planckBandIntensity / dwvl
     180             : 
     181             :     return
     182           0 :   end function
     183             :   
     184             :   
     185             :   !! This routine calculates the average planck intensity in the wavelength
     186             :   !! band defined by wvl and dwvl.
     187             :   !!
     188             :   !! error computed on full spectrum compared to planck function.  Band-levels may be different
     189             :   !! 8.9%   error with   5 quadrature points in [100 micrometer, 1 millimeter]
     190             :   !! 1.7%   error with  10 quadrature points in [100 micrometer, 1 millimeter]
     191             :   !! 0.001% error with 100 quadrature points in [100 micrometer, 1 millimeter]
     192             :   !!
     193             :   !! NOTE: This code was design to work with the CAM RRTMG band structure, it may not work as
     194             :   !! well with arbitrary bands.
     195             :   !!
     196             :   !! NOTE: For most RRTMG bands, 3 quadrature points are probably sufficient, but testing is
     197             :   !! left to the reader.
     198             :   !!
     199             :   !! @author Andrew Conley, Chuck Bardeen
     200             :   !! @version Aug-2011
     201           0 :   function planckBandIntensityConley2011(wvl, dwvl, temp, iter)
     202             : 
     203             :     ! types
     204           0 :     use carma_precision_mod
     205             :     use carma_enums_mod
     206             :     use carma_constants_mod
     207             :     use carma_types_mod
     208             :     use carmastate_mod
     209             :     use carma_mod
     210             : 
     211             :     implicit none
     212             :   
     213             :     real(kind=f), intent(in)             :: wvl     !! band center wavelength (cm)
     214             :     real(kind=f), intent(in)             :: dwvl    !! band width (cm)
     215             :     real(kind=f), intent(in)             :: temp    !! temperature (K)
     216             :     integer, intent(in)                  :: iter    !! number of iterations
     217             :     real(kind=f)                         :: planckBandIntensityConley2011  !! Planck intensity (erg/s/cm2/sr/cm)
     218             :     
     219             :     real(kind=f) :: half = 0.5_f
     220             :     real(kind=f) :: third= 1._f / 3._f
     221             :     real(kind=f) :: sixth= 1._f / 6._f
     222             :     real(kind=f) :: tfth = 1._f /24._f
     223             :     
     224             :     real(kind=f) :: k = 1.3806488e-23_f    ! boltzmann J/K
     225             :     real(kind=f) :: c = 2.99792458e8_f     ! light m/s
     226             :     real(kind=f) :: h = 6.62606957e-34_f   ! planck J s
     227             :     real(kind=f) :: sigma = 5.670373e-8_f  ! stef-bolt W/m/m/k/k/k/k
     228             :     
     229             :     real(kind=f) :: lambda1                ! wavelength m (lower bound)
     230             :     real(kind=f) :: lambda2                ! wavelength m (upper bound)
     231             :     
     232             :     ! quadrature iteration
     233             :     integer  :: i,inumber 
     234             :     
     235             :     ! internal temporary variables
     236             :     real(kind=f) :: fr1, fr2         ! frequency bounds of partition
     237             :     real(kind=f) :: kt               ! k_boltzmann * temperature
     238             :     real(kind=f) :: l1,l2            ! lower and upper bounds of (wavelength)
     239             :     real(kind=f) :: dellam           ! fraction multiplier for next lambda interval
     240             :     real(kind=f) :: t1,t3            ! 2nd and 4th order terms
     241             :     real(kind=f) :: total, total2    ! 2nd and 4th order cumulative partial integral
     242             :     real(kind=f) :: e,d,em1i,di,ci   ! exponential terms appearing in integral
     243             :     real(kind=f) :: dfr,m,a,o,tt,mi  ! terms appearing in integral
     244             :     real(kind=f) :: argexp           ! argument to exponent
     245             :     real(kind=f) :: coeff            ! front coefficient of integral
     246             :     real(kind=f) :: planck           ! planck function
     247             :     
     248           0 :     inumber = iter ! number of partitions
     249             :     
     250             :     !initialize
     251           0 :     total  = 0._f ! partial (cumulative) integral (4th order)
     252             : !    total2 = 0._f ! partial (cumulative) integral (2nd order)
     253             : 
     254           0 :     kt = k*temp
     255           0 :     lambda1 = (wvl - (dwvl / 2._f)) * 1e-2_f
     256           0 :     lambda2 = (wvl + (dwvl / 2._f)) * 1e-2_f
     257           0 :     ci = 1._f/c
     258             :     
     259           0 :     if (inumber .gt. 1) then
     260           0 :       l1  = lambda1
     261           0 :       dellam = exp(log(lambda1/lambda2)/inumber)
     262           0 :       l2 = l1/dellam
     263           0 :       fr1 = c/l2
     264           0 :       fr2 = c/l1
     265             :     else
     266           0 :       dellam = 1._f ! meaningless
     267           0 :       l1 = lambda1
     268           0 :       l2 = lambda2
     269           0 :       fr1 = c/l2
     270           0 :       fr2 = c/l1
     271             :     endif
     272             :     
     273             :     ! accumulate integral by stepping (backwards) through partions of frequency
     274           0 :     do i = 1,inumber
     275             :     
     276             :       ! constants
     277           0 :       dfr = half * (fr2-fr1)  ! half-range freq interval
     278           0 :       m   = half * (fr1+fr2)  ! mean freq
     279           0 :       mi  = 1._f/m
     280           0 :       a   = h/kt              ! alpha
     281             :     
     282           0 :       argexp = a*m 
     283           0 :       if (argexp .lt. 0.5_f) then
     284             :         e = 1._f + &
     285             :                     argexp + &
     286             :                     (argexp*argexp)*half  + &
     287             :                     (argexp*argexp*argexp)*sixth + &
     288           0 :                     (argexp*argexp*argexp*argexp)*tfth
     289           0 :         em1i = 1._f/(e - 1._f )
     290           0 :         di = e*em1i
     291           0 :       else if (argexp .lt. 20.0_f) then
     292           0 :         e = exp(argexp)        
     293           0 :         em1i = 1._f/(e - 1._f )
     294           0 :         di = e*em1i
     295             :       else 
     296           0 :         e = 1.e+20_f ! exp(20) is large.  Use this for frequency >> Temperature
     297             :         em1i = 1.e-20_f
     298             :         di = 1._f
     299             :       endif
     300             :     
     301             :       ! frontpiece
     302           0 :       coeff = 2._f*h*m*m*m*ci*ci*em1i
     303             :     
     304             :       ! integrals
     305           0 :       o = fr2-fr1                     ! int 1 deps
     306           0 :       tt = 2._f*(dfr*dfr*dfr)*third   ! int eps^2 deps
     307             :     
     308             :       ! term and 4th order correction
     309           0 :       t1 = 1._f
     310           0 :       t3 = 3._f*mi*mi - 3._f*a*di*mi + a*a*di*di - half*a*a*di
     311             :       ! t3 could be made more stable by placing (-) terms in denominator of pade approx.
     312             :      
     313             :       ! sum it up.  Total is 4th order, total2 is 2nd order
     314           0 :       total = total + coeff*(o*t1+tt*t3)
     315             : !      total2 = total2 + coeff*o*t1
     316             : 
     317           0 :       fr2 = fr1
     318           0 :       fr1 = fr1 * dellam
     319             :     enddo
     320             :      
     321             :     ! Convert to erg/cm2/s/sr/cm
     322           0 :     planckBandIntensityConley2011 = total * 1e7_f / 1e4_f / dwvl
     323             :      
     324             :     return
     325           0 :   end function
     326             : 
     327             : end module planck

Generated by: LCOV version 1.14