LCOV - code coverage report
Current view: top level - physics/carma/base - sulfate_utils.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 71 85.9 %
Date: 2025-03-14 01:30:37 Functions: 3 3 100.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 sulfate_utils
       6             :   use carma_precision_mod
       7             :   use carma_enums_mod
       8             :   use carma_constants_mod
       9             :   use carma_types_mod
      10             :   use carmastate_mod
      11             :   use carma_mod
      12             :  
      13             :   implicit none
      14             :   
      15             :   ! Declare the public methods.
      16             :   public wtpct_tabaz
      17             :   public sulfate_density
      18             :   public sulfate_surf_tens
      19             :   
      20             :   real(kind=f), public:: dnwtp(46), dnc0(46), dnc1(46)
      21             :    
      22             :   data dnwtp / 0._f, 1._f, 5._f, 10._f, 20._f, 25._f, 30._f, 35._f, 40._f, &
      23             :      41._f, 45._f, 50._f, 53._f, 55._f, 56._f, 60._f, 65._f, 66._f, 70._f, &
      24             :      72._f, 73._f, 74._f, 75._f, 76._f, 78._f, 79._f, 80._f, 81._f, 82._f, &
      25             :      83._f, 84._f, 85._f, 86._f, 87._f, 88._f, 89._f, 90._f, 91._f, 92._f, &
      26             :      93._f, 94._f, 95._f, 96._f, 97._f, 98._f, 100._f /
      27             :      
      28             :    data dnc0 / 1._f, 1.13185_f, 1.17171_f, 1.22164_f, 1.3219_f, 1.37209_f,       &
      29             :      1.42185_f, 1.4705_f, 1.51767_f, 1.52731_f, 1.56584_f, 1.61834_f, 1.65191_f, &
      30             :      1.6752_f, 1.68708_f, 1.7356_f, 1.7997_f, 1.81271_f, 1.86696_f, 1.89491_f,   &
      31             :      1.9092_f, 1.92395_f, 1.93904_f, 1.95438_f, 1.98574_f, 2.00151_f, 2.01703_f, &
      32             :      2.03234_f, 2.04716_f, 2.06082_f, 2.07363_f, 2.08461_f, 2.09386_f, 2.10143_f,&
      33             :      2.10764_f, 2.11283_f, 2.11671_f, 2.11938_f, 2.12125_f, 2.1219_f, 2.12723_f, &
      34             :      2.12654_f, 2.12621_f, 2.12561_f, 2.12494_f, 2.12093_f /
      35             :      
      36             :    data dnc1 / 0._f,  -0.000435022_f, -0.000479481_f, -0.000531558_f, -0.000622448_f,&
      37             :      -0.000660866_f, -0.000693492_f, -0.000718251_f, -0.000732869_f, -0.000735755_f, &
      38             :      -0.000744294_f, -0.000761493_f, -0.000774238_f, -0.00078392_f, -0.000788939_f,  &
      39             :      -0.00080946_f, -0.000839848_f, -0.000845825_f, -0.000874337_f, -0.000890074_f,  &
      40             :      -0.00089873_f, -0.000908778_f, -0.000920012_f, -0.000932184_f, -0.000959514_f,  &
      41             :      -0.000974043_f, -0.000988264_f, -0.00100258_f, -0.00101634_f, -0.00102762_f,    &
      42             :      -0.00103757_f, -0.00104337_f, -0.00104563_f, -0.00104458_f, -0.00104144_f,      &
      43             :      -0.00103719_f, -0.00103089_f, -0.00102262_f, -0.00101355_f, -0.00100249_f,      &
      44             :      -0.00100934_f, -0.000998299_f, -0.000990961_f, -0.000985845_f, -0.000984529_f,  &
      45             :      -0.000989315_f /  
      46             : contains
      47             : 
      48             :   !!  This function calculates the weight % H2SO4 composition of 
      49             :   !!  sulfate aerosol, using Tabazadeh et. al. (GRL, 1931, 1997).
      50             :   !!  Rated for T=185-260K, activity=0.01-1.0
      51             :   !!
      52             :   !!  Argument list input:   
      53             :   !!    temp = temperature (K)
      54             :   !!    h2o_mass = water vapor mass concentration (g/cm3)
      55             :   !!    h2o_vp = water eq. vaper pressure (dynes/cm2)
      56             :   !!
      57             :   !!  Output:
      58             :   !!    wtpct_tabaz = weight % H2SO4 in H2O/H2SO4 particle (0-100)
      59             :   !!
      60             :   !!  Include global constants and variables (BK=Boltzman constant,
      61             :   !!   AVG=Avogadro's constant)
      62             :   !!
      63             :   !! @author Jason English
      64             :   !! @ version Apr-2010
      65  9414463709 :   function wtpct_tabaz(carma, temp, h2o_mass, h2o_vp, rc)
      66             :    
      67             :     real(kind=f)                         :: wtpct_tabaz
      68             :     type(carma_type), intent(in)         :: carma     !! the carma object
      69             :     real(kind=f), intent(in)             :: temp      !! temperature [K]
      70             :     real(kind=f), intent(in)             :: h2o_mass  !! water vapor mass concentration (g/cm3)
      71             :     real(kind=f), intent(in)             :: h2o_vp    !! water eq. vaper pressure (dynes/cm2) 
      72             :     integer, intent(inout)               :: rc        !! return code, negative indicates failure
      73             :       
      74             :     !  Declare variables for this routine only
      75             :     real(kind=f)     :: atab1,btab1,ctab1,dtab1,atab2,btab2,ctab2,dtab2
      76             :     real(kind=f)     :: h2o_num, p_h2o, vp_h2o
      77             :     real(kind=f)     :: contl, conth, contt, conwtp
      78             :     real(kind=f)     :: activ 
      79             :          
      80             :     ! Get number density of water (/cm3) from mass concentration (g/cm3)
      81  9414463709 :     h2o_num=h2o_mass*AVG/gwtmol(1)
      82             : 
      83             :     !  Get partial pressure of water (dynes/cm2) from concentration (/cm3)
      84             :     ! Ideal gas law: P=nkT
      85  9414463709 :     p_h2o=h2o_num*bk*temp
      86             : 
      87             :     !  Convert from dynes/cm2 to mb (hPa)
      88  9414463709 :     p_h2o=p_h2o/1000.0_f     ! partial pressure
      89  9414463709 :     vp_h2o=h2o_vp/1000.0_f   ! eq. vp
      90             : 
      91             :     !  Activity = water pp in mb / water eq. vp over pure water in mb
      92  9414463709 :     activ = p_h2o/vp_h2o
      93             :  
      94  9414463709 :     if (activ.lt.0.05_f) then
      95  4950544760 :       activ = max(activ,1.e-32_f)    ! restrict minimum activity
      96  4950544760 :       atab1     = 12.37208932_f 
      97  4950544760 :       btab1     = -0.16125516114_f
      98  4950544760 :       ctab1     = -30.490657554_f
      99  4950544760 :       dtab1     = -2.1133114241_f
     100  4950544760 :       atab2     = 13.455394705_f        
     101  4950544760 :       btab2     = -0.1921312255_f
     102  4950544760 :       ctab2     = -34.285174607_f
     103  4950544760 :       dtab2     = -1.7620073078_f
     104  4463918949 :     elseif (activ.ge.0.05_f.and.activ.le.0.85_f) then
     105             :       atab1     = 11.820654354_f
     106             :       btab1     = -0.20786404244_f
     107             :       ctab1     = -4.807306373_f
     108             :       dtab1     = -5.1727540348_f
     109             :       atab2     = 12.891938068_f        
     110             :       btab2     = -0.23233847708_f
     111             :       ctab2     = -6.4261237757_f
     112             :       dtab2     = -4.9005471319_f
     113   593230431 :     elseif (activ.gt.0.85_f) then
     114   593230431 :       activ = min(activ,1._f)      ! restrict maximum activity
     115   593230431 :       atab1     = -180.06541028_f
     116   593230431 :       btab1     = -0.38601102592_f
     117   593230431 :       ctab1     = -93.317846778_f
     118   593230431 :       dtab1     = 273.88132245_f
     119   593230431 :       atab2     = -176.95814097_f
     120   593230431 :       btab2     = -0.36257048154_f
     121   593230431 :       ctab2     = -90.469744201_f
     122   593230431 :       dtab2     = 267.45509988_f
     123             :     else
     124           0 :       if (do_print) write(LUNOPRT,*) 'invalid activity: activity,pp,vp=',activ, p_h2o
     125           0 :       rc = RC_ERROR
     126           0 :       return
     127             :     endif
     128             : 
     129  9414463709 :     contl = atab1*(activ**btab1)+ctab1*activ+dtab1
     130  9414463709 :     conth = atab2*(activ**btab2)+ctab2*activ+dtab2
     131             :       
     132  9414463709 :     contt = contl + (conth-contl) * ((temp -190._f)/70._f)
     133  9414463709 :     conwtp = (contt*98._f) + 1000._f
     134             : 
     135  9414463709 :     wtpct_tabaz = (100._f*contt*98._f)/conwtp
     136  9414463709 :     wtpct_tabaz = min(max(wtpct_tabaz,1._f),100._f) ! restrict between 1 and 100 %
     137             :       
     138  9414463709 :     return
     139             :   end function wtpct_tabaz
     140             :            
     141             :   !! Calculates specific gravity (g/cm3) of sulfate of 
     142             :   !! different compositions as a linear function of temperature,
     143             :   !! based of measurements of H2SO4/H2O solution densities made 
     144             :   !! at 0 to 100C tabulated in the International Critical Tables 
     145             :   !! (Washburn, ed., NRC, 1928). Measurements have confirmed that 
     146             :   !! this data may be linearly extrapolated to stratospheric 
     147             :   !! temperatures (180-380K) with excellent accuracy 
     148             :   !! (Beyer, Ravishankara, & Lovejoy, JGR, 1996).
     149             :   !!
     150             :   !! Argument list input:
     151             :   !!    wtp = aerosol composition in weight % H2SO4 (0-100)
     152             :   !!    temp = temperature in Kelvin
     153             :   !!
     154             :   !! Output:
     155             :   !!    sulfate_density (g/cm3) [function name]
     156             :   !!
     157             :   !! This function requires setup_sulfate_density to be run
     158             :   !! first to read in the density coefficients DNC0 and DNC1
     159             :   !! and the tabulated weight percents DNWTP.
     160             :   !!
     161             :   !! @author Mike Mills
     162             :   !! @version Mar-2013
     163  9150481871 :   function sulfate_density(carma, wtp, temp, rc)
     164             : 
     165             :   !! Include global constants and variables
     166             : 
     167             :     real(kind=f)                         :: sulfate_density
     168             :     type(carma_type), intent(in)         :: carma   !! the carma object
     169             :     real(kind=f), intent(in)             :: wtp     !! weight percent
     170             :     real(kind=f), intent(in)             :: temp    !! temperature 
     171             :     integer, intent(inout)               :: rc      !! return code, negative indicates failure
     172             :     
     173             :     ! Local declarations
     174             :     integer           :: i
     175             :     real(kind=f)      :: den1, den2
     176             :     real(kind=f)      :: frac, temp_loc
     177             : 
     178  9150481871 :     if (wtp .lt. 0.0_f .or. wtp .gt. 100.0_f) then
     179           0 :       if (do_print) write(LUNOPRT,*)'sulfate_density: Illegal value for wtp:',wtp
     180           0 :       rc = RC_ERROR
     181           0 :       return
     182             :     endif
     183             : 
     184             :     ! limit temperature to bounds of extrapolation
     185  9150481871 :     temp_loc=min(temp, 380.0_f)
     186  9150481871 :     temp_loc=max(temp_loc, 180.0_f)
     187             : 
     188  9150481871 :     i=1
     189             : 
     190 >20349*10^7 :     do while (wtp .gt. dnwtp(i))
     191 >19434*10^7 :      i=i+1
     192             :     end do
     193             : 
     194  9150481871 :     den2=dnc0(i)+dnc1(i)*temp_loc
     195             : 
     196  9150481871 :     if (i.eq.1 .or. wtp.eq.dnwtp(i)) then
     197  9150481871 :       sulfate_density=den2
     198             :       return
     199             :     endif
     200             : 
     201  9106589908 :     den1=dnc0(i-1)+dnc1(i-1)*temp_loc
     202  9106589908 :     frac=(dnwtp(i)-wtp)/(dnwtp(i)-dnwtp(i-1))
     203  9106589908 :     sulfate_density=den1*frac+den2*(1.0_f-frac)
     204             : 
     205  9106589908 :     return
     206             :   end function sulfate_density
     207             : 
     208             :   !!  Calculates surface tension (erg/cm2 = dyne/cm) of sulfate of 
     209             :   !!  different compositions as a linear function of temperature,
     210             :   !!  as described in Mills (Ph.D. Thesis, 1996), derived from
     211             :   !!  the measurements of Sabinina and Terpugow (1935).
     212             :   !!
     213             :   !!  Argument list input:
     214             :   !!     WTP = aerosol composition in weight % H2SO4 (0-100)
     215             :   !!     TEMP = temperature in Kelvin
     216             :   !!
     217             :   !!  Output:
     218             :   !!     sulfate_surf_tens (erg/cm2) [function name]
     219             :   !!
     220             :   !!  This function requires setup_sulfate_density to be run
     221             :   !!  first to read in the density coefficients DNC0 and DNC1
     222             :   !!  and the tabulated weight percents DNWTP.
     223             :   !!
     224             :   !! @author Mike Mills
     225             :   !! @version Mar-2013
     226   244727514 :   function sulfate_surf_tens(carma, wtp, temp, rc)  
     227             :   
     228             :     real(kind=f)                         :: sulfate_surf_tens
     229             :     type(carma_type), intent(in)         :: carma   !! the carma object
     230             :     real(kind=f), intent(in)             :: wtp     !! weight percent
     231             :     real(kind=f), intent(in)             :: temp    !! temperature 
     232             :     integer, intent(inout)               :: rc      !! return code, negative indicates failure
     233             :     
     234             :     ! Local declarations
     235             :     integer           :: i  
     236             :     real(kind=f)      :: sig1, sig2
     237             :     real(kind=f)      :: frac, temp_loc
     238             :     real(kind=f)      :: stwtp(15), stc0(15), stc1(15)
     239             :     
     240             :     data stwtp/0._f, 23.8141_f, 38.0279_f, 40.6856_f, 45.335_f, 52.9305_f, 56.2735_f, &
     241             :        & 59.8557_f, 66.2364_f, 73.103_f, 79.432_f, 85.9195_f, 91.7444_f, 97.6687_f, 100._f/
     242             :     
     243             :     data stc0/117.564_f, 103.303_f, 101.796_f, 100.42_f, 98.4993_f, 91.8866_f,     &
     244             :        & 88.3033_f, 86.5546_f, 84.471_f, 81.2939_f, 79.3556_f, 75.608_f, 70.0777_f,  &
     245             :        & 63.7412_f, 61.4591_f /
     246             :   
     247             :     data stc1/-0.153641_f, -0.0982007_f, -0.0872379_f, -0.0818509_f,           &
     248             :        & -0.0746702_f, -0.0522399_f, -0.0407773_f, -0.0357946_f, -0.0317062_f,   &
     249             :        & -0.025825_f, -0.0267212_f, -0.0269204_f, -0.0276187_f, -0.0302094_f,    &
     250             :        & -0.0303081_f /
     251             : 
     252             :     ! limit temperature to reasonable bounds of extrapolation
     253   244727514 :     temp_loc=min(temp, 380.0_f)
     254   244727514 :     temp_loc=max(temp_loc, 180.0_f)
     255             :        
     256   244727514 :     if (wtp .lt. 0.0_f .OR. wtp .gt. 100.0_f) then
     257           0 :       if (do_print) write(LUNOPRT,*)'sulfate_surf_tens: Illegal value for wtp:',wtp
     258           0 :       if (do_print) write(LUNOPRT,*)'sulfate_surf_tens: temp=',temp
     259           0 :       rc = RC_ERROR
     260           0 :       return
     261             :     endif
     262             :   
     263             :     i=1
     264             :   
     265  2019407037 :     do while (wtp.gt.stwtp(i))
     266  1774679523 :       i=i+1
     267             :     end do
     268             :   
     269   244727514 :     sig2=stc0(i)+stc1(i)*temp_loc
     270             :   
     271   244727514 :     if (i.eq.1 .or. wtp.eq.stwtp(i)) then
     272   244727514 :       sulfate_surf_tens=sig2
     273             :       return
     274             :     end if
     275             :   
     276   244727514 :     sig1=stc0(i-1)+stc1(i-1)*temp_loc
     277   244727514 :     frac=(stwtp(i)-wtp)/(stwtp(i)-stwtp(i-1))
     278   244727514 :     sulfate_surf_tens=sig1*frac+sig2*(1.0_f-frac)
     279             :   
     280   244727514 :     return
     281             :   end function sulfate_surf_tens
     282             :             
     283             : end module sulfate_utils

Generated by: LCOV version 1.14