LCOV - code coverage report
Current view: top level - chemistry/aerosol - carma_aerosol_properties_mod.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 288 0.0 %
Date: 2025-03-14 01:26:08 Functions: 0 29 0.0 %

          Line data    Source code
       1             : module carma_aerosol_properties_mod
       2             :   use shr_kind_mod, only: r8 => shr_kind_r8
       3             :   use physconst, only: pi
       4             :   use aerosol_properties_mod, only: aerosol_properties, aero_name_len
       5             :   use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_bin_props_by_idx, &
       6             :                               rad_cnst_get_info_by_bin, rad_cnst_get_info_by_bin_spec, rad_cnst_get_bin_props
       7             :   use infnan, only: nan, assignment(=)
       8             : 
       9             :   implicit none
      10             : 
      11             :   private
      12             : 
      13             :   public :: carma_aerosol_properties
      14             : 
      15             :   type, extends(aerosol_properties) :: carma_aerosol_properties
      16             :      private
      17             :      integer, allocatable :: ibl(:)
      18             :    contains
      19             :      procedure :: number_transported
      20             :      procedure :: get
      21             :      procedure :: amcube
      22             :      procedure :: actfracs
      23             :      procedure :: num_names
      24             :      procedure :: mmr_names
      25             :      procedure :: amb_num_name
      26             :      procedure :: amb_mmr_name
      27             :      procedure :: species_type
      28             :      procedure :: icenuc_updates_num
      29             :      procedure :: icenuc_updates_mmr
      30             :      procedure :: apply_number_limits
      31             :      procedure :: hetfrz_species
      32             :      procedure :: optics_params
      33             :      procedure :: nbins_rlist
      34             :      procedure :: nspecies_per_bin_rlist
      35             :      procedure :: alogsig_rlist
      36             :      procedure :: soluble
      37             :      procedure :: min_mass_mean_rad
      38             :      procedure :: bin_name
      39             :      procedure :: scav_diam
      40             :      procedure :: resuspension_resize
      41             :      procedure :: rebin_bulk_fluxes
      42             :      procedure :: hydrophilic
      43             : 
      44             :      final :: destructor
      45             :   end type carma_aerosol_properties
      46             : 
      47             :   interface carma_aerosol_properties
      48             :      procedure :: constructor
      49             :   end interface carma_aerosol_properties
      50             : 
      51             :   real(r8), parameter :: onethird = 1._r8/3._r8
      52             : 
      53             : contains
      54             : 
      55             :   !------------------------------------------------------------------------------
      56             :   !------------------------------------------------------------------------------
      57           0 :   function constructor() result(newobj)
      58             : 
      59             :     type(carma_aerosol_properties), pointer :: newobj
      60             : 
      61             :     integer :: l, m, nbins, ncnst_tot
      62           0 :     integer,allocatable :: nspecies(:)
      63           0 :     integer,allocatable :: nmasses(:)
      64           0 :     real(r8),allocatable :: alogsig(:)
      65           0 :     real(r8),allocatable :: f1(:)
      66           0 :     real(r8),allocatable :: f2(:)
      67             :     integer :: ierr
      68             : 
      69           0 :     integer, pointer :: ibl(:)
      70             :     integer :: ii, imx, imx_num, imx_mmr, ipr, ipr_num, ipr_mmr
      71             :     character(len=32) :: spectype
      72             :     character(len=32) :: bin_name
      73             :     character(len=32) :: bin_name_l    ! bin name of the larger bin
      74             : 
      75           0 :     integer, allocatable :: imx_bl(:)     ! index used to map pure sulfate bin to mixed sulfate bin
      76           0 :     integer, allocatable :: imx_mmr_bl(:) ! index used to map pure sulfate bin to mixed sulfate bin for mmr
      77           0 :     integer, allocatable :: imx_num_bl(:) ! index used to map pure sulfate bin to mixed sulfate bin for num
      78             : 
      79           0 :     allocate(newobj,stat=ierr)
      80           0 :     if( ierr /= 0 ) then
      81           0 :        nullify(newobj)
      82             :        return
      83             :     end if
      84             : 
      85           0 :     call rad_cnst_get_info( 0, nbins=nbins)
      86             : 
      87           0 :     allocate( nspecies(nbins),stat=ierr )
      88           0 :     if( ierr /= 0 ) then
      89           0 :        nullify(newobj)
      90             :        return
      91             :     end if
      92           0 :     allocate( nmasses(nbins),stat=ierr )
      93           0 :     if( ierr /= 0 ) then
      94           0 :        nullify(newobj)
      95             :        return
      96             :     end if
      97           0 :     allocate( alogsig(nbins),stat=ierr )
      98           0 :     if( ierr /= 0 ) then
      99           0 :        nullify(newobj)
     100             :        return
     101             :     end if
     102           0 :     allocate( f1(nbins),stat=ierr )
     103           0 :     if( ierr /= 0 ) then
     104           0 :        nullify(newobj)
     105             :        return
     106             :     end if
     107           0 :     allocate( f2(nbins),stat=ierr )
     108           0 :     if( ierr /= 0 ) then
     109           0 :        nullify(newobj)
     110             :        return
     111             :     end if
     112             : 
     113           0 :     ncnst_tot = 0
     114             : 
     115           0 :     do m = 1, nbins
     116           0 :        call rad_cnst_get_info_by_bin(0, m, nspec=nspecies(m))
     117           0 :        ncnst_tot = ncnst_tot + nspecies(m) + 1
     118           0 :        nmasses(m) = nspecies(m)
     119             :     end do
     120             : 
     121           0 :     alogsig(:) = log(2._r8)
     122           0 :     f1 = 1._r8
     123           0 :     f2 = 1._r8
     124             : 
     125           0 :     call newobj%initialize(nbins,ncnst_tot,nspecies,nmasses,alogsig,f1,f2,ierr)
     126           0 :     if( ierr /= 0 ) then
     127           0 :        nullify(newobj)
     128             :        return
     129             :     end if
     130           0 :     deallocate(nspecies)
     131           0 :     deallocate(nmasses)
     132           0 :     deallocate(alogsig)
     133           0 :     deallocate(f1)
     134           0 :     deallocate(f2)
     135             : 
     136           0 :     allocate(newobj%ibl(ncnst_tot),stat=ierr)
     137           0 :     if( ierr /= 0 ) then
     138           0 :        nullify(newobj)
     139             :        return
     140             :     end if
     141           0 :     ibl => newobj%ibl
     142             : 
     143           0 :     ibl = -1
     144             : 
     145           0 :     allocate(imx_num_bl(nbins),stat=ierr)
     146           0 :     if( ierr /= 0 ) then
     147           0 :        nullify(newobj)
     148             :        return
     149             :     end if
     150           0 :     allocate(imx_mmr_bl(nbins),stat=ierr)
     151           0 :     if( ierr /= 0 ) then
     152           0 :        nullify(newobj)
     153             :        return
     154             :     end if
     155           0 :     allocate(imx_bl(nbins),stat=ierr)
     156           0 :     if( ierr /= 0 ) then
     157           0 :        nullify(newobj)
     158             :        return
     159             :     end if
     160             : 
     161           0 :     imx = 0
     162           0 :     imx_mmr = 0
     163           0 :     imx_num = 0
     164           0 :     ipr = 0
     165           0 :     ipr_mmr = 0
     166           0 :     ipr_num = 0
     167             : 
     168           0 :     do m = 1,nbins
     169           0 :        bin_name = newobj%bin_name(0,m)
     170           0 :        bin_name_l = ' '
     171           0 :        if (m<nbins) then
     172           0 :           bin_name_l = newobj%bin_name(0,m+1)
     173             :        end if
     174             : 
     175           0 :        do l = 0,newobj%nspecies(m)
     176           0 :           ii = newobj%indexer(m,l)
     177           0 :           ibl(ii) = ii
     178             : 
     179             :           ! derive index  array for larger bin, for evaporation into larger bi
     180           0 :           if (l>0 .and. l<=newobj%nspecies(m)) then
     181           0 :              call newobj%species_type(m,l,spectype)
     182             :           else
     183           0 :              spectype = 'other'
     184             :           end if
     185             : 
     186             :           ! identification is required for pure and mixed aerosols, mixed aeroosols are moved to
     187             :           ! larger bin, pure aerosols are moved to mixed sulfate
     188             : 
     189           0 :           if (index(bin_name,'MXAER')>0 .and. index(bin_name_l,'MXAER')>0) then
     190             :              ! for mixed aerosols
     191             :              ! find larger bin
     192           0 :              ibl(ii) = newobj%indexer(m+1,l)
     193             :              ! define mixed aerosol sulfate index to be used for pure sulfate only
     194           0 :              if (trim(spectype) == 'sulfate') then
     195           0 :                 imx = imx + 1
     196           0 :                 imx_bl(imx) = ibl(ii)
     197             :              end if
     198           0 :              if (l == newobj%nspecies(m)+1) then !  only for mmr
     199           0 :                 imx_mmr = imx_mmr + 1
     200           0 :                 ibl(ii) = newobj%indexer(m+1,l)
     201           0 :                 imx_mmr_bl(imx_mmr) = ibl(ii)
     202             :              end if
     203           0 :              if (l == 0) then !  only for num
     204           0 :                 imx_num = imx_num + 1
     205           0 :                 ibl(ii) =  newobj%indexer(m+1,l)
     206           0 :                 imx_num_bl(imx_num) = ibl(ii)
     207             :              end if
     208             :           end if ! MXAER
     209             : 
     210           0 :           if (index(bin_name,'PRSUL')>0 .and. index(bin_name_l,'PRSUL')>0) then
     211             :              ! pure sulfate bins
     212           0 :              if (trim(spectype) == 'sulfate') then
     213           0 :                 ipr = ipr +1
     214           0 :                 ibl(ii) = imx_bl(ipr)
     215             :              end if
     216           0 :              if (l == newobj%nspecies(m)+1) then ! only for mmr reset counter to only go from 1-20 bins
     217           0 :                 ipr_mmr = ipr_mmr + 1
     218           0 :                 ibl(ii) = imx_mmr_bl(ipr_mmr)
     219             :              end if
     220           0 :              if (l == 0 ) then ! only for num reset counter to only go from 1-20 bins
     221           0 :                 ipr_num = ipr_num + 1
     222           0 :                 ibl(ii) = imx_num_bl(ipr_num)
     223             :              end if
     224             :           end if
     225           0 :           if (ibl(ii).eq.0) then
     226           0 :              ibl(ii) = ii
     227             :           end if
     228             :        end do
     229             :     end do
     230             : 
     231           0 :     deallocate(imx_mmr_bl, imx_num_bl, imx_bl)
     232             : 
     233           0 :   end function constructor
     234             : 
     235             :   !------------------------------------------------------------------------------
     236             :   !------------------------------------------------------------------------------
     237           0 :   subroutine destructor(self)
     238             :     type(carma_aerosol_properties), intent(inout) :: self
     239             : 
     240           0 :     call self%final()
     241             : 
     242           0 :   end subroutine destructor
     243             : 
     244             :   !------------------------------------------------------------------------------
     245             :   ! returns number of transported aerosol constituents
     246             :   !------------------------------------------------------------------------------
     247           0 :   integer function number_transported(self)
     248             :     class(carma_aerosol_properties), intent(in) :: self
     249             :     ! to be implemented later
     250           0 :     number_transported = -1
     251           0 :   end function number_transported
     252             : 
     253             :   !------------------------------------------------------------------------
     254             :   ! returns aerosol properties:
     255             :   !  density
     256             :   !  hygroscopicity
     257             :   !  species type
     258             :   !  species name
     259             :   !  short wave species refractive indices
     260             :   !  long wave species refractive indices
     261             :   !  species morphology
     262             :   !------------------------------------------------------------------------
     263           0 :   subroutine get(self, bin_ndx, species_ndx, list_ndx, density, hygro, &
     264             :                  spectype, specname, specmorph, refindex_sw, refindex_lw)
     265             : 
     266             :     class(carma_aerosol_properties), intent(in) :: self
     267             :     integer, intent(in) :: bin_ndx             ! bin index
     268             :     integer, intent(in) :: species_ndx         ! species index
     269             :     integer, optional, intent(in) :: list_ndx  ! climate or a diagnostic list number
     270             :     real(r8), optional, intent(out) :: density ! density (kg/m3)
     271             :     real(r8), optional, intent(out) :: hygro   ! hygroscopicity
     272             :     character(len=*), optional, intent(out) :: spectype  ! species type
     273             :     character(len=*), optional, intent(out) :: specname  ! species name
     274             :     character(len=*), optional, intent(out) :: specmorph ! species morphology
     275             :     complex(r8), pointer, optional, intent(out) :: refindex_sw(:) ! short wave species refractive indices
     276             :     complex(r8), pointer, optional, intent(out) :: refindex_lw(:) ! long wave species refractive indices
     277             : 
     278             :     integer :: ilist
     279             : 
     280           0 :     if (present(list_ndx)) then
     281           0 :        ilist = list_ndx
     282             :     else
     283           0 :        ilist = 0
     284             :     end if
     285             : 
     286           0 :     if (present(density)) then
     287           0 :        call rad_cnst_get_bin_props_by_idx(ilist, bin_ndx, species_ndx, density_aer=density)
     288             :     end if
     289           0 :     if (present(hygro)) then
     290           0 :        call rad_cnst_get_bin_props_by_idx(ilist, bin_ndx, species_ndx, hygro_aer=hygro)
     291             :     end if
     292           0 :     if (present(spectype)) then
     293           0 :        call rad_cnst_get_bin_props_by_idx(ilist, bin_ndx, species_ndx, spectype=spectype)
     294             :     end if
     295           0 :     if (present(refindex_sw)) then
     296           0 :        call rad_cnst_get_bin_props_by_idx(ilist, bin_ndx, species_ndx, refindex_aer_sw=refindex_sw)
     297             :     end if
     298           0 :     if (present(refindex_lw)) then
     299           0 :        call rad_cnst_get_bin_props_by_idx(ilist, bin_ndx, species_ndx, refindex_aer_lw=refindex_lw)
     300             :     end if
     301           0 :     if (present(specmorph)) then
     302           0 :        call rad_cnst_get_bin_props_by_idx(ilist, bin_ndx, species_ndx, specmorph=specmorph)
     303             :     end if
     304           0 :     if (present(specname)) then
     305           0 :        if (species_ndx>self%nspecies(bin_ndx)) then
     306           0 :           call rad_cnst_get_info_by_bin(0, bin_ndx,  mmr_name=specname)
     307             :        else
     308           0 :           call rad_cnst_get_info_by_bin_spec(ilist, bin_ndx, species_ndx, spec_name=specname)
     309             :        end if
     310             :     end if
     311             : 
     312           0 :   end subroutine get
     313             : 
     314             :   !------------------------------------------------------------------------
     315             :   ! returns optics type and table parameters
     316             :   !------------------------------------------------------------------------
     317           0 :   subroutine optics_params(self, list_ndx, bin_ndx, opticstype, extpsw, abspsw, asmpsw, absplw, &
     318             :        refrtabsw, refitabsw, refrtablw, refitablw, ncoef, prefr, prefi, sw_hygro_ext_wtp, &
     319             :        sw_hygro_ssa_wtp, sw_hygro_asm_wtp, lw_hygro_ext_wtp, wgtpct, nwtp, &
     320             :        sw_hygro_coreshell_ext, sw_hygro_coreshell_ssa, sw_hygro_coreshell_asm, lw_hygro_coreshell_ext, &
     321             :        corefrac, bcdust, kap, relh, nfrac, nbcdust, nkap, nrelh )
     322             : 
     323             :     class(carma_aerosol_properties), intent(in) :: self
     324             :     integer, intent(in) :: bin_ndx             ! bin index
     325             :     integer, intent(in) :: list_ndx            ! rad climate/diags list
     326             : 
     327             :     character(len=*), optional, intent(out) :: opticstype
     328             : 
     329             :     ! refactive index table parameters
     330             :     real(r8),  optional, pointer     :: extpsw(:,:,:,:) ! short wave specific extinction
     331             :     real(r8),  optional, pointer     :: abspsw(:,:,:,:) ! short wave specific absorption
     332             :     real(r8),  optional, pointer     :: asmpsw(:,:,:,:) ! short wave asymmetry factor
     333             :     real(r8),  optional, pointer     :: absplw(:,:,:,:) ! long wave specific absorption
     334             :     real(r8),  optional, pointer     :: refrtabsw(:,:)  ! table of short wave real refractive indices for aerosols
     335             :     real(r8),  optional, pointer     :: refitabsw(:,:)  ! table of short wave imaginary refractive indices for aerosols
     336             :     real(r8),  optional, pointer     :: refrtablw(:,:)  ! table of long wave real refractive indices for aerosols
     337             :     real(r8),  optional, pointer     :: refitablw(:,:)  ! table of long wave imaginary refractive indices for aerosols
     338             :     integer,   optional, intent(out) :: ncoef  ! number of chebychev polynomials
     339             :     integer,   optional, intent(out) :: prefr  ! number of real refractive indices in table
     340             :     integer,   optional, intent(out) :: prefi  ! number of imaginary refractive indices in table
     341             : 
     342             :     ! hygrowghtpct table parameters
     343             :     real(r8),  optional, pointer     :: sw_hygro_ext_wtp(:,:) ! short wave extinction table
     344             :     real(r8),  optional, pointer     :: sw_hygro_ssa_wtp(:,:) ! short wave single-scatter albedo table
     345             :     real(r8),  optional, pointer     :: sw_hygro_asm_wtp(:,:) ! short wave asymmetry table
     346             :     real(r8),  optional, pointer     :: lw_hygro_ext_wtp(:,:) ! long wave absorption table
     347             :     real(r8),  optional, pointer     :: wgtpct(:)   ! weight precent of H2SO4/H2O solution
     348             :     integer,   optional, intent(out) :: nwtp        ! number of weight precent values
     349             : 
     350             :     ! hygrocoreshell table parameters
     351             :     real(r8),  optional, pointer     :: sw_hygro_coreshell_ext(:,:,:,:,:) ! short wave extinction table
     352             :     real(r8),  optional, pointer     :: sw_hygro_coreshell_ssa(:,:,:,:,:) ! short wave single-scatter albedo table
     353             :     real(r8),  optional, pointer     :: sw_hygro_coreshell_asm(:,:,:,:,:) ! short wave asymmetry table
     354             :     real(r8),  optional, pointer     :: lw_hygro_coreshell_ext(:,:,:,:,:) ! long wave absorption table
     355             :     real(r8),  optional, pointer     :: corefrac(:) ! core fraction dimension values
     356             :     real(r8),  optional, pointer     :: bcdust(:)   ! bc/(bc + dust) fraction dimension values
     357             :     real(r8),  optional, pointer     :: kap(:)      ! hygroscopicity dimension values
     358             :     real(r8),  optional, pointer     :: relh(:)     ! relative humidity dimension values
     359             :     integer,   optional, intent(out) :: nfrac       ! core fraction dimension size
     360             :     integer,   optional, intent(out) :: nbcdust     ! bc/(bc + dust) fraction dimension size
     361             :     integer,   optional, intent(out) :: nkap        ! hygroscopicity dimension size
     362             :     integer,   optional, intent(out) :: nrelh       ! relative humidity dimension size
     363             : 
     364           0 :     if (present(extpsw)) then
     365           0 :        nullify(extpsw)
     366             :     end if
     367           0 :     if (present(abspsw)) then
     368           0 :        nullify(abspsw)
     369             :     end if
     370           0 :     if (present(asmpsw)) then
     371           0 :        nullify(asmpsw)
     372             :     end if
     373           0 :     if (present(absplw)) then
     374           0 :        nullify(absplw)
     375             :     end if
     376           0 :     if (present(refrtabsw)) then
     377           0 :        nullify(refrtabsw)
     378             :     end if
     379           0 :     if (present(refitabsw)) then
     380           0 :        nullify(refitabsw)
     381             :     end if
     382           0 :     if (present(refrtablw)) then
     383           0 :        nullify(refrtablw)
     384             :     end if
     385           0 :     if (present(refitablw)) then
     386           0 :        nullify(refitablw)
     387             :     end if
     388           0 :     if (present(ncoef)) then
     389           0 :        ncoef = huge(1)
     390             :     end if
     391           0 :     if (present(prefr)) then
     392           0 :        prefr = huge(1)
     393             :     end if
     394           0 :     if (present(prefi)) then
     395           0 :        prefi = huge(1)
     396             :     end if
     397             : 
     398             :     call rad_cnst_get_bin_props(list_ndx,bin_ndx, &
     399             :                                 opticstype=opticstype, &
     400             :                                 sw_hygro_ext_wtp=sw_hygro_ext_wtp, &
     401             :                                 sw_hygro_ssa_wtp=sw_hygro_ssa_wtp, &
     402             :                                 sw_hygro_asm_wtp=sw_hygro_asm_wtp, &
     403             :                                 lw_hygro_ext_wtp=lw_hygro_ext_wtp, &
     404             :                                 wgtpct=wgtpct, &
     405             :                                 nwtp=nwtp, &
     406             :                                 sw_hygro_coreshell_ext=sw_hygro_coreshell_ext, &
     407             :                                 sw_hygro_coreshell_ssa=sw_hygro_coreshell_ssa, &
     408             :                                 sw_hygro_coreshell_asm=sw_hygro_coreshell_asm, &
     409             :                                 lw_hygro_coreshell_ext=lw_hygro_coreshell_ext, &
     410             :                                 corefrac=corefrac, &
     411             :                                 bcdust=bcdust, &
     412             :                                 kap=kap, &
     413             :                                 relh=relh, &
     414             :                                 nbcdust=nbcdust, &
     415             :                                 nkap=nkap, &
     416             :                                 nrelh=nrelh, &
     417           0 :                                 nfrac=nfrac )
     418             : 
     419           0 :   end subroutine optics_params
     420             : 
     421             :   !------------------------------------------------------------------------------
     422             :   ! returns radius^3 (m3) of a given bin number
     423             :   !------------------------------------------------------------------------------
     424           0 :   pure elemental real(r8) function amcube(self, bin_ndx, volconc, numconc)
     425             : 
     426             :     class(carma_aerosol_properties), intent(in) :: self
     427             :     integer, intent(in) :: bin_ndx  ! bin number
     428             :     real(r8), intent(in) :: volconc ! volume conc (m3/m3)
     429             :     real(r8), intent(in) :: numconc ! number conc (1/m3)
     430             : 
     431           0 :     amcube = 3._r8/(4._r8*pi)*volconc/numconc
     432             : 
     433           0 :   end function amcube
     434             : 
     435             :   !------------------------------------------------------------------------------
     436             :   ! returns mass and number activation fractions
     437             :   !------------------------------------------------------------------------------
     438           0 :   subroutine actfracs(self, bin_ndx, smc, smax, fn, fm )
     439             :     class(carma_aerosol_properties), intent(in) :: self
     440             :     integer, intent(in) :: bin_ndx   ! bin index
     441             :     real(r8),intent(in) :: smc       ! critical supersaturation for particles of bin radius
     442             :     real(r8),intent(in) :: smax      ! maximum supersaturation for multiple competing aerosols
     443             :     real(r8),intent(out) :: fn       ! activation fraction for aerosol number
     444             :     real(r8),intent(out) :: fm       ! activation fraction for aerosol mass
     445             : 
     446           0 :     fn = 0._r8
     447           0 :     fm = 0._r8
     448             : 
     449           0 :     if (smc < smax) then
     450           0 :        fn = 1._r8
     451           0 :        fm = 1._r8
     452             :     end if
     453             : 
     454           0 :   end subroutine actfracs
     455             : 
     456             :   !------------------------------------------------------------------------
     457             :   ! returns constituents names of aerosol number mixing ratios
     458             :   !------------------------------------------------------------------------
     459           0 :   subroutine num_names(self, bin_ndx, name_a, name_c)
     460             :     class(carma_aerosol_properties), intent(in) :: self
     461             :     integer, intent(in) :: bin_ndx           ! bin number
     462             :     character(len=*), intent(out) :: name_a ! constituent name of ambient aerosol number dens
     463             :     character(len=*), intent(out) :: name_c ! constituent name of cloud-borne aerosol number dens
     464             : 
     465           0 :     call rad_cnst_get_info_by_bin(0, bin_ndx, num_name=name_a, num_name_cw=name_c)
     466             : 
     467           0 :   end subroutine num_names
     468             : 
     469             :   !------------------------------------------------------------------------
     470             :   ! returns constituents names of aerosol mass mixing ratios
     471             :   !------------------------------------------------------------------------
     472           0 :   subroutine mmr_names(self, bin_ndx, species_ndx, name_a, name_c)
     473             :     class(carma_aerosol_properties), intent(in) :: self
     474             :     integer, intent(in) :: bin_ndx           ! bin number
     475             :     integer, intent(in) :: species_ndx       ! species number
     476             :     character(len=*), intent(out) :: name_a ! constituent name of ambient aerosol MMR
     477             :     character(len=*), intent(out) :: name_c ! constituent name of cloud-borne aerosol MMR
     478             : 
     479           0 :     if (species_ndx>0) then
     480           0 :        call rad_cnst_get_info_by_bin_spec(0, bin_ndx, species_ndx, spec_name=name_a, spec_name_cw=name_c)
     481             :     else
     482           0 :        call rad_cnst_get_info_by_bin(0, bin_ndx,  mmr_name=name_a, mmr_name_cw=name_c)
     483             :     end if
     484             : 
     485           0 :   end subroutine mmr_names
     486             : 
     487             :   !------------------------------------------------------------------------
     488             :   ! returns constituent name of ambient aerosol number mixing ratios
     489             :   !------------------------------------------------------------------------
     490           0 :   subroutine amb_num_name(self, bin_ndx, name)
     491             :     class(carma_aerosol_properties), intent(in) :: self
     492             :     integer, intent(in) :: bin_ndx           ! bin number
     493             :     character(len=*), intent(out) :: name   ! constituent name of ambient aerosol number dens
     494             : 
     495           0 :     call rad_cnst_get_info_by_bin(0, bin_ndx, num_name=name)
     496             : 
     497           0 :   end subroutine amb_num_name
     498             : 
     499             :   !------------------------------------------------------------------------
     500             :   ! returns constituent name of ambient aerosol mass mixing ratios
     501             :   !------------------------------------------------------------------------
     502           0 :   subroutine amb_mmr_name(self, bin_ndx, species_ndx, name)
     503             :     class(carma_aerosol_properties), intent(in) :: self
     504             :     integer, intent(in) :: bin_ndx           ! bin number
     505             :     integer, intent(in) :: species_ndx       ! species number
     506             :     character(len=*), intent(out) :: name   ! constituent name of ambient aerosol MMR
     507             : 
     508           0 :     if (species_ndx>0) then
     509           0 :        call rad_cnst_get_info_by_bin_spec(0, bin_ndx, species_ndx, spec_name=name)
     510             :     else
     511           0 :        call rad_cnst_get_info_by_bin(0, bin_ndx,  mmr_name=name)
     512             :     end if
     513             : 
     514           0 :   end subroutine amb_mmr_name
     515             : 
     516             :   !------------------------------------------------------------------------
     517             :   ! returns species type
     518             :   !------------------------------------------------------------------------
     519           0 :   subroutine species_type(self, bin_ndx, species_ndx, spectype)
     520             :     class(carma_aerosol_properties), intent(in) :: self
     521             :     integer, intent(in) :: bin_ndx           ! bin number
     522             :     integer, intent(in) :: species_ndx       ! species number
     523             :     character(len=*), intent(out) :: spectype ! species type
     524             : 
     525           0 :     call rad_cnst_get_info_by_bin_spec(0, bin_ndx, species_ndx, spec_type=spectype)
     526             : 
     527           0 :   end subroutine species_type
     528             : 
     529             :   !------------------------------------------------------------------------------
     530             :   ! returns TRUE if Ice Nucleation tendencies are applied to given aerosol bin number
     531             :   !------------------------------------------------------------------------------
     532           0 :   function icenuc_updates_num(self, bin_ndx) result(res)
     533             :     class(carma_aerosol_properties), intent(in) :: self
     534             :     integer, intent(in) :: bin_ndx           ! bin number
     535             : 
     536             :     logical :: res
     537             : 
     538             :     character(len=aero_name_len) :: spectype
     539             :     integer :: spc_ndx
     540             : 
     541           0 :     res = .false.
     542             : 
     543           0 :     do spc_ndx = 1, self%nspecies(bin_ndx)
     544           0 :        call self%species_type( bin_ndx, spc_ndx, spectype)
     545           0 :        if (trim(spectype)=='dust') res = .true.
     546           0 :        if (trim(spectype)=='sulfate') res = .true.
     547             :     end do
     548             : 
     549           0 :   end function icenuc_updates_num
     550             : 
     551             :   !------------------------------------------------------------------------------
     552             :   ! returns TRUE if Ice Nucleation tendencies are applied to a given species within a bin
     553             :   !------------------------------------------------------------------------------
     554           0 :   function icenuc_updates_mmr(self, bin_ndx, species_ndx) result(res)
     555             :     class(carma_aerosol_properties), intent(in) :: self
     556             :     integer, intent(in) :: bin_ndx           ! bin number
     557             :     integer, intent(in) :: species_ndx       ! species number
     558             : 
     559             :     logical :: res
     560             : 
     561             :     character(len=aero_name_len) :: spectype
     562             : 
     563           0 :     res = .false.
     564             : 
     565           0 :     if (species_ndx==0) then
     566           0 :        res = self%icenuc_updates_num(bin_ndx)
     567             :     else
     568           0 :        call self%species_type( bin_ndx, species_ndx, spectype)
     569           0 :        if (trim(spectype)=='dust') res = .true.
     570           0 :        if (trim(spectype)=='sulfate') res = .true.
     571             :     end if
     572             : 
     573           0 :   end function icenuc_updates_mmr
     574             : 
     575             :   !------------------------------------------------------------------------------
     576             :   ! apply max / min to number concentration
     577             :   !------------------------------------------------------------------------------
     578           0 :   subroutine apply_number_limits( self, naerosol, vaerosol, istart, istop, m )
     579             :     class(carma_aerosol_properties), intent(in) :: self
     580             :     real(r8), intent(inout) :: naerosol(:)  ! number conc (1/m3)
     581             :     real(r8), intent(in)    :: vaerosol(:)  ! volume conc (m3/m3)
     582             :     integer,  intent(in) :: istart          ! start column index (1 <= istart <= istop <= pcols)
     583             :     integer,  intent(in) :: istop           ! stop column index
     584             :     integer,  intent(in) :: m               ! mode or bin index
     585             : 
     586           0 :   end subroutine apply_number_limits
     587             : 
     588             :   !------------------------------------------------------------------------------
     589             :   ! returns TRUE if species `spc_ndx` in aerosol subset `bin_ndx` contributes to
     590             :   ! the particles' ability to act as heterogeneous freezing nuclei
     591             :   !------------------------------------------------------------------------------
     592           0 :   function hetfrz_species(self, bin_ndx, spc_ndx) result(res)
     593             :     class(carma_aerosol_properties), intent(in) :: self
     594             :     integer, intent(in) :: bin_ndx  ! bin number
     595             :     integer, intent(in) :: spc_ndx  ! species number
     596             : 
     597             :     logical :: res
     598             : 
     599             :     character(len=aero_name_len) :: species_type
     600             : 
     601           0 :     res = .false.
     602             : 
     603           0 :     call self%species_type(bin_ndx, spc_ndx, species_type)
     604           0 :     if ( trim(species_type)=='black-c' .or. trim(species_type)=='dust' ) then
     605           0 :        res = .true.
     606             :     end if
     607             : 
     608           0 :   end function hetfrz_species
     609             : 
     610             :   !------------------------------------------------------------------------------
     611             :   ! returns TRUE if soluble
     612             :   !------------------------------------------------------------------------------
     613           0 :   logical function soluble(self,bin_ndx)
     614             :     class(carma_aerosol_properties), intent(in) :: self
     615             :     integer, intent(in) :: bin_ndx           ! bin number
     616             : 
     617           0 :     soluble = .true.
     618             : 
     619           0 :   end function soluble
     620             : 
     621             :   !------------------------------------------------------------------------------
     622             :   ! returns minimum mass mean radius (meters)
     623             :   !------------------------------------------------------------------------------
     624           0 :   function min_mass_mean_rad(self,bin_ndx,species_ndx) result(minrad)
     625             :     class(carma_aerosol_properties), intent(in) :: self
     626             :     integer, intent(in) :: bin_ndx           ! bin number
     627             :     integer, intent(in) :: species_ndx       ! species number
     628             : 
     629             :     real(r8) :: minrad  ! meters
     630             : 
     631           0 :     minrad = 0.0_r8
     632             : 
     633           0 :   end function min_mass_mean_rad
     634             : 
     635             :   !------------------------------------------------------------------------------
     636             :   ! returns the total number of bins for a given radiation list index
     637             :   !------------------------------------------------------------------------------
     638           0 :   function nbins_rlist(self, list_ndx)  result(res)
     639             :     class(carma_aerosol_properties), intent(in) :: self
     640             :     integer, intent(in) :: list_ndx  ! radiation list number
     641             : 
     642             :     integer :: res
     643             : 
     644           0 :     call rad_cnst_get_info(list_ndx, nbins=res)
     645             : 
     646           0 :   end function nbins_rlist
     647             : 
     648             :   !------------------------------------------------------------------------------
     649             :   ! returns number of species in a bin for a given radiation list index
     650             :   !------------------------------------------------------------------------------
     651           0 :   function nspecies_per_bin_rlist(self, list_ndx,  bin_ndx)  result(res)
     652             :     class(carma_aerosol_properties), intent(in) :: self
     653             :     integer, intent(in) :: list_ndx ! radiation list number
     654             :     integer, intent(in) :: bin_ndx  ! bin number
     655             : 
     656             :     integer :: res
     657             : 
     658           0 :     call rad_cnst_get_info_by_bin(list_ndx, bin_ndx, nspec=res)
     659             : 
     660           0 :   end function nspecies_per_bin_rlist
     661             : 
     662             :   !------------------------------------------------------------------------------
     663             :   ! returns the natural log of geometric standard deviation of the number
     664             :   ! distribution for radiation list number and aerosol bin
     665             :   !------------------------------------------------------------------------------
     666           0 :   function alogsig_rlist(self, list_ndx,  bin_ndx)  result(res)
     667             :     class(carma_aerosol_properties), intent(in) :: self
     668             :     integer, intent(in) :: list_ndx ! radiation list number
     669             :     integer, intent(in) :: bin_ndx  ! bin number
     670             : 
     671             :     real(r8) :: res
     672             : 
     673           0 :     res = self%alogsig(bin_ndx)
     674             : 
     675           0 :   end function alogsig_rlist
     676             : 
     677             :   !------------------------------------------------------------------------------
     678             :   ! returns name for a given radiation list number and aerosol bin
     679             :   !------------------------------------------------------------------------------
     680           0 :   function bin_name(self, list_ndx,  bin_ndx) result(name)
     681             :     class(carma_aerosol_properties), intent(in) :: self
     682             :     integer, intent(in) :: list_ndx ! radiation list number
     683             :     integer, intent(in) :: bin_ndx  ! bin number
     684             : 
     685             :     character(len=32) name
     686             : 
     687           0 :     call rad_cnst_get_info_by_bin(list_ndx, bin_ndx, bin_name=name)
     688             : 
     689           0 :   end function bin_name
     690             : 
     691             :   !------------------------------------------------------------------------------
     692             :   ! returns scavenging diameter (cm) for a given aerosol bin number
     693             :   !------------------------------------------------------------------------------
     694           0 :   function scav_diam(self, bin_ndx) result(diam)
     695             : 
     696             :     use carma_intr, only: carma_get_bin_rmass
     697             :     use carma_intr, only: carma_get_group_by_name
     698             : 
     699             :     class(carma_aerosol_properties), intent(in) :: self
     700             :     integer, intent(in) :: bin_ndx  ! bin number
     701             : 
     702             :     real(r8) :: diam ! cm
     703             : 
     704             :     real(r8) :: mass   ! the bin mass (g)
     705             :     real(r8) :: rho    ! density (kg/m3)
     706             :     integer :: ispec
     707             :     character(len=32) :: spectype
     708             : 
     709             :     character(len=aero_name_len) :: bin_name, shortname
     710             :     integer :: igroup, ibin, rc, nchr
     711             : 
     712           0 :     call rad_cnst_get_info_by_bin(0, bin_ndx, bin_name=bin_name)
     713             : 
     714           0 :     nchr = len_trim(bin_name)-2
     715           0 :     shortname = bin_name(:nchr)
     716             : 
     717           0 :     call carma_get_group_by_name(shortname, igroup, rc)
     718             : 
     719           0 :     read(bin_name(nchr+1:),*) ibin
     720             : 
     721           0 :     call carma_get_bin_rmass(igroup, ibin, mass, rc)
     722             : 
     723           0 :     do ispec = 1, self%nspecies(bin_ndx)
     724           0 :        call self%species_type(bin_ndx,ispec, spectype)
     725           0 :        if (trim(spectype) == 'sulfate') then
     726           0 :           call self%get(bin_ndx,ispec,density=rho)
     727             :        end if
     728             :     end do
     729             : 
     730             :     ! specdens kg/m3 to g/cm3, convert from radius to diameter
     731           0 :     diam = 2._r8*((0.75_r8*mass / pi  / (1.0e-3_r8*rho))**onethird)
     732             : 
     733           0 :   end function scav_diam
     734             : 
     735             :   !------------------------------------------------------------------------------
     736             :   ! adjust aerosol concentration tendencies to create larger sizes of aerosols
     737             :   ! during resuspension
     738             :   !------------------------------------------------------------------------------
     739           0 :   subroutine resuspension_resize(self, dcondt)
     740             :     class(carma_aerosol_properties), intent(in) :: self
     741             :     real(r8), intent(inout) :: dcondt(:)
     742             : 
     743             :     integer :: m
     744             : 
     745             :     ! move dcondt_prevap to larger bin
     746           0 :     do m = 1, self%ncnst_tot()
     747           0 :        if (self%ibl(m) /= m) then
     748           0 :           dcondt(self%ibl(m)) = dcondt(self%ibl(m)) + dcondt(m)
     749           0 :           dcondt(m) = 0._r8
     750             :        end if
     751             :     end do
     752             : 
     753           0 :   end subroutine resuspension_resize
     754             : 
     755             :   !------------------------------------------------------------------------------
     756             :   ! returns dust deposition fluxes rebinned to specified diameter limits
     757             :   !------------------------------------------------------------------------------
     758           0 :   subroutine rebin_bulk_fluxes(self, bulk_type, dep_fluxes, diam_edges, bulk_fluxes, &
     759             :                                error_code, error_string)
     760             : 
     761             :     class(carma_aerosol_properties), intent(in) :: self
     762             :     character(len=*),intent(in) :: bulk_type ! aerosol type to rebin
     763             :     real(r8), intent(in) :: dep_fluxes(:) ! kg/m2/sec
     764             :     real(r8), intent(in) :: diam_edges(:) ! meters
     765             :     real(r8), intent(out) :: bulk_fluxes(:) ! kg/m2/sec
     766             :        integer,  intent(out) :: error_code            ! error code (0 if no error)
     767             :        character(len=*), intent(out) :: error_string  ! error string
     768             : 
     769             :     real(r8) :: mflx, mflx_tot
     770             :     real(r8) :: rho, mass, frac, diam
     771             :     integer :: i, m,l,mm
     772             :     integer :: n_bulk_bins
     773             :     character(len=aero_name_len) :: spectype
     774             :     logical :: type_not_found
     775             : 
     776           0 :     error_code = 0
     777           0 :     error_string = ' '
     778             : 
     779           0 :     n_bulk_bins = size(bulk_fluxes)
     780             : 
     781           0 :     bulk_fluxes(:) = 0._r8
     782           0 :     type_not_found = .true.
     783             : 
     784           0 :     bin_loop: do m = 1,self%nbins()
     785             : 
     786           0 :        mflx_tot = 0._r8
     787           0 :        mflx = 0._r8
     788             : 
     789           0 :        species: do l = 1,self%nmasses(m)
     790           0 :           mm = self%indexer(m,l)
     791             : 
     792           0 :           if (l>self%nspecies(m)) then
     793             :              ! use mass flux for the entire bin (concentration element) if available
     794             :              ! -- override the total summed below
     795           0 :              mflx_tot = dep_fluxes(mm)
     796             :           else
     797             :              ! this sums up the total assuming all species are transported
     798           0 :              mflx_tot = mflx_tot + dep_fluxes(mm)
     799             : 
     800           0 :              call self%get(m,l,spectype=spectype)
     801             : 
     802           0 :              if (spectype==bulk_type) then
     803             :                 ! get mass flux and density of the specified type
     804           0 :                 mflx = dep_fluxes(mm)
     805           0 :                 call self%get(m,l,density=rho) ! kg/m3
     806           0 :                 type_not_found = .false.
     807             :              end if
     808             :           end if
     809             :        end do species
     810             : 
     811           0 :        if (mflx>0._r8 .and. mflx_tot>0._r8) then
     812             :           ! mass flux fraction
     813           0 :           frac = mflx/mflx_tot
     814             : 
     815             :           ! mass of the specified aerosol type
     816           0 :           mass = frac * bin_mass(m) ! kg
     817             : 
     818             :           ! diameter in meters
     819           0 :           diam = 2._r8*((0.75_r8*mass/pi/rho)**onethird)
     820             : 
     821             :           ! add the flux to the corresponding bulk bin
     822           0 :           blk_loop: do i = 1,n_bulk_bins-1
     823           0 :              if (diam>diam_edges(i) .and. diam<=diam_edges(i+1)) then
     824           0 :                 bulk_fluxes(i) = bulk_fluxes(i) + mflx
     825           0 :                 exit blk_loop
     826             :              end if
     827             :           end do blk_loop
     828             :        endif
     829             : 
     830             :     end do bin_loop
     831             : 
     832           0 :     if (type_not_found) then
     833           0 :        bulk_fluxes(:) = nan
     834           0 :        error_code = 1
     835           0 :        write(error_string,*) 'aerosol_properties::rebin_bulk_fluxes ERROR : ',trim(bulk_type),' not found'
     836             :     end if
     837             : 
     838             :   contains
     839             : 
     840             :     !---------------------------------------------------------------
     841             :     ! get mass of the specified bin in kg -- could be done at init time ...
     842             :     !---------------------------------------------------------------
     843           0 :     real(r8) function bin_mass(bin_ndx) ! (kg)
     844             :       use carma_intr, only: carma_get_bin_rmass, carma_get_group_by_name
     845             : 
     846             :       integer, intent(in) :: bin_ndx
     847             : 
     848             :       character(len=aero_name_len) :: bin_name, shortname
     849             :       integer :: ibin, igroup, rc, nchr
     850             :       real(r8) :: rmass
     851             : 
     852           0 :       call rad_cnst_get_info_by_bin(0, bin_ndx, bin_name=bin_name)
     853             : 
     854           0 :       nchr = len_trim(bin_name)-2
     855           0 :       shortname = bin_name(:nchr)
     856             : 
     857           0 :       call carma_get_group_by_name(shortname, igroup, rc)
     858             : 
     859           0 :       read(bin_name(nchr+1:),*) ibin
     860             : 
     861           0 :       call carma_get_bin_rmass(igroup, ibin, rmass, rc)
     862           0 :       bin_mass = rmass * 1.e-3_r8 ! g->kg
     863             : 
     864           0 :     end function bin_mass
     865             : 
     866             :   end subroutine rebin_bulk_fluxes
     867             : 
     868             :   !------------------------------------------------------------------------------
     869             :   ! Returns TRUE if bin is hydrophilic, otherwise FALSE
     870             :   !------------------------------------------------------------------------------
     871           0 :   logical function hydrophilic(self, bin_ndx)
     872             :     class(carma_aerosol_properties), intent(in) :: self
     873             :     integer, intent(in) :: bin_ndx ! bin number
     874             : 
     875           0 :     hydrophilic = .true.
     876             : 
     877           0 :   end function hydrophilic
     878             : 
     879           0 : end module carma_aerosol_properties_mod

Generated by: LCOV version 1.14