LCOV - code coverage report
Current view: top level - chemistry/aerosol - modal_aerosol_state_mod.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 214 0.0 %
Date: 2025-01-13 21:54:50 Functions: 0 25 0.0 %

          Line data    Source code
       1             : module modal_aerosol_state_mod
       2             :   use shr_kind_mod, only: r8 => shr_kind_r8
       3             :   use shr_spfn_mod, only: erf => shr_spfn_erf
       4             :   use aerosol_state_mod, only: aerosol_state, ptr2d_t
       5             :   use rad_constituents, only: rad_cnst_get_aer_mmr, rad_cnst_get_mode_num, rad_cnst_get_info
       6             :   use rad_constituents, only: rad_cnst_get_mode_props
       7             :   use physics_buffer, only: physics_buffer_desc, pbuf_get_field, pbuf_get_index
       8             :   use physics_types, only: physics_state
       9             :   use aerosol_properties_mod, only: aerosol_properties, aero_name_len
      10             :   use physconst,  only: rhoh2o
      11             : 
      12             :   implicit none
      13             : 
      14             :   private
      15             : 
      16             :   public :: modal_aerosol_state
      17             : 
      18             :   type, extends(aerosol_state) :: modal_aerosol_state
      19             :      private
      20             :      type(physics_state), pointer :: state => null()
      21             :      type(physics_buffer_desc), pointer :: pbuf(:) => null()
      22             :    contains
      23             : 
      24             :      procedure :: get_transported
      25             :      procedure :: set_transported
      26             :      procedure :: ambient_total_bin_mmr
      27             :      procedure :: get_ambient_mmr_0list
      28             :      procedure :: get_ambient_mmr_rlist
      29             :      procedure :: get_cldbrne_mmr
      30             :      procedure :: get_ambient_num
      31             :      procedure :: get_cldbrne_num
      32             :      procedure :: get_states
      33             :      procedure :: icenuc_size_wght_arr
      34             :      procedure :: icenuc_size_wght_val
      35             :      procedure :: icenuc_type_wght
      36             :      procedure :: update_bin
      37             :      procedure :: hetfrz_size_wght
      38             :      procedure :: hygroscopicity
      39             :      procedure :: water_uptake
      40             :      procedure :: dry_volume
      41             :      procedure :: wet_volume
      42             :      procedure :: water_volume
      43             :      procedure :: wet_diameter
      44             :      procedure :: convcld_actfrac
      45             : 
      46             :      final :: destructor
      47             : 
      48             :   end type modal_aerosol_state
      49             : 
      50             :   interface modal_aerosol_state
      51             :      procedure :: constructor
      52             :   end interface modal_aerosol_state
      53             : 
      54             :   real(r8), parameter :: rh2odens = 1._r8/rhoh2o
      55             : 
      56             : contains
      57             : 
      58             :   !------------------------------------------------------------------------------
      59             :   !------------------------------------------------------------------------------
      60           0 :   function constructor(state,pbuf) result(newobj)
      61             :     type(physics_state), target :: state
      62             :     type(physics_buffer_desc), pointer :: pbuf(:)
      63             : 
      64             :     type(modal_aerosol_state), pointer :: newobj
      65             : 
      66             :     integer :: ierr
      67             : 
      68           0 :     allocate(newobj,stat=ierr)
      69           0 :     if( ierr /= 0 ) then
      70           0 :        nullify(newobj)
      71             :        return
      72             :     end if
      73             : 
      74           0 :     newobj%state => state
      75           0 :     newobj%pbuf => pbuf
      76             : 
      77           0 :   end function constructor
      78             : 
      79             :   !------------------------------------------------------------------------------
      80             :   !------------------------------------------------------------------------------
      81           0 :   subroutine destructor(self)
      82             :     type(modal_aerosol_state), intent(inout) :: self
      83             : 
      84           0 :     nullify(self%state)
      85           0 :     nullify(self%pbuf)
      86             : 
      87           0 :   end subroutine destructor
      88             : 
      89             :   !------------------------------------------------------------------------------
      90             :   ! sets transported components
      91             :   ! This aerosol model with the state of the transported aerosol constituents
      92             :   ! (mass mixing ratios or number mixing ratios)
      93             :   !------------------------------------------------------------------------------
      94           0 :   subroutine set_transported( self, transported_array )
      95             :     class(modal_aerosol_state), intent(inout) :: self
      96             :     real(r8), intent(in) :: transported_array(:,:,:)
      97             :     ! to be implemented later
      98           0 :   end subroutine set_transported
      99             : 
     100             :   !------------------------------------------------------------------------------
     101             :   ! returns transported components
     102             :   ! This returns to current state of the transported aerosol constituents
     103             :   ! (mass mixing ratios or number mixing ratios)
     104             :   !------------------------------------------------------------------------------
     105           0 :   subroutine get_transported( self, transported_array )
     106             :     class(modal_aerosol_state), intent(in) :: self
     107             :     real(r8), intent(out) :: transported_array(:,:,:)
     108             :     ! to be implemented later
     109           0 :   end subroutine get_transported
     110             : 
     111             :   !------------------------------------------------------------------------
     112             :   ! Total aerosol mass mixing ratio for a bin in a given grid box location (column and layer)
     113             :   !------------------------------------------------------------------------
     114           0 :   function ambient_total_bin_mmr(self, aero_props, bin_ndx, col_ndx, lyr_ndx) result(mmr_tot)
     115             :     class(modal_aerosol_state), intent(in) :: self
     116             :     class(aerosol_properties), intent(in) :: aero_props
     117             :     integer, intent(in) :: bin_ndx      ! bin index
     118             :     integer, intent(in) :: col_ndx      ! column index
     119             :     integer, intent(in) :: lyr_ndx      ! vertical layer index
     120             : 
     121             :     real(r8) :: mmr_tot                 ! mass mixing ratios totaled for all species
     122           0 :     real(r8),pointer :: mmrptr(:,:)
     123             :     integer :: spec_ndx
     124             : 
     125           0 :     mmr_tot = 0._r8
     126             : 
     127           0 :     do spec_ndx=1,aero_props%nspecies(bin_ndx)
     128           0 :        call rad_cnst_get_aer_mmr(0, bin_ndx, spec_ndx, 'a', self%state, self%pbuf, mmrptr)
     129           0 :        mmr_tot = mmr_tot + mmrptr(col_ndx,lyr_ndx)
     130             :     end do
     131             : 
     132           0 :   end function ambient_total_bin_mmr
     133             : 
     134             :   !------------------------------------------------------------------------------
     135             :   ! returns ambient aerosol mass mixing ratio for a given species index and bin index
     136             :   !------------------------------------------------------------------------------
     137           0 :   subroutine get_ambient_mmr_0list(self, species_ndx, bin_ndx, mmr)
     138             :     class(modal_aerosol_state), intent(in) :: self
     139             :     integer, intent(in) :: species_ndx  ! species index
     140             :     integer, intent(in) :: bin_ndx      ! bin index
     141             :     real(r8), pointer :: mmr(:,:)       ! mass mixing ratios (ncol,nlev)
     142             : 
     143           0 :     call rad_cnst_get_aer_mmr(0, bin_ndx, species_ndx, 'a', self%state, self%pbuf, mmr)
     144           0 :   end subroutine get_ambient_mmr_0list
     145             : 
     146             :   !------------------------------------------------------------------------------
     147             :   ! returns ambient aerosol mass mixing ratio for a given radiation diagnostics
     148             :   ! list index, species index and bin index
     149             :   !------------------------------------------------------------------------------
     150           0 :   subroutine get_ambient_mmr_rlist(self, list_ndx, species_ndx, bin_ndx, mmr)
     151             :     class(modal_aerosol_state), intent(in) :: self
     152             :     integer, intent(in) :: list_ndx     ! rad climate list index
     153             :     integer, intent(in) :: species_ndx  ! species index
     154             :     integer, intent(in) :: bin_ndx      ! bin index
     155             :     real(r8), pointer :: mmr(:,:)       ! mass mixing ratios (ncol,nlev)
     156             : 
     157           0 :     call rad_cnst_get_aer_mmr(list_ndx, bin_ndx, species_ndx, 'a', self%state, self%pbuf, mmr)
     158           0 :   end subroutine get_ambient_mmr_rlist
     159             : 
     160             :   !------------------------------------------------------------------------------
     161             :   ! returns cloud-borne aerosol number mixing ratio for a given species index and bin index
     162             :   !------------------------------------------------------------------------------
     163           0 :   subroutine get_cldbrne_mmr(self, species_ndx, bin_ndx, mmr)
     164             :     class(modal_aerosol_state), intent(in) :: self
     165             :     integer, intent(in) :: species_ndx  ! species index
     166             :     integer, intent(in) :: bin_ndx      ! bin index
     167             :     real(r8), pointer :: mmr(:,:)       ! mass mixing ratios (ncol,nlev)
     168             : 
     169           0 :     call rad_cnst_get_aer_mmr(0, bin_ndx, species_ndx, 'c', self%state, self%pbuf, mmr)
     170           0 :   end subroutine get_cldbrne_mmr
     171             : 
     172             :   !------------------------------------------------------------------------------
     173             :   ! returns ambient aerosol number mixing ratio for a given species index and bin index
     174             :   !------------------------------------------------------------------------------
     175           0 :   subroutine get_ambient_num(self, bin_ndx, num)
     176             :     class(modal_aerosol_state), intent(in) :: self
     177             :     integer, intent(in) :: bin_ndx     ! bin index
     178             :     real(r8), pointer   :: num(:,:)    ! number densities
     179             : 
     180           0 :     call rad_cnst_get_mode_num(0, bin_ndx, 'a', self%state, self%pbuf, num)
     181           0 :   end subroutine get_ambient_num
     182             : 
     183             :   !------------------------------------------------------------------------------
     184             :   ! returns cloud-borne aerosol number mixing ratio for a given species index and bin index
     185             :   !------------------------------------------------------------------------------
     186           0 :   subroutine get_cldbrne_num(self, bin_ndx, num)
     187             :     class(modal_aerosol_state), intent(in) :: self
     188             :     integer, intent(in) :: bin_ndx             ! bin index
     189             :     real(r8), pointer :: num(:,:)
     190             : 
     191           0 :     call rad_cnst_get_mode_num(0, bin_ndx, 'c', self%state, self%pbuf, num)
     192           0 :   end subroutine get_cldbrne_num
     193             : 
     194             :   !------------------------------------------------------------------------------
     195             :   ! returns interstitial and cloud-borne aerosol states
     196             :   !------------------------------------------------------------------------------
     197           0 :   subroutine get_states( self, aero_props, raer, qqcw )
     198             :     class(modal_aerosol_state), intent(in) :: self
     199             :     class(aerosol_properties), intent(in) :: aero_props
     200             :     type(ptr2d_t), intent(out) :: raer(:)
     201             :     type(ptr2d_t), intent(out) :: qqcw(:)
     202             : 
     203             :     integer :: ibin,ispc, indx
     204             : 
     205           0 :     do ibin = 1, aero_props%nbins()
     206           0 :        indx = aero_props%indexer(ibin, 0)
     207           0 :        call self%get_ambient_num(ibin, raer(indx)%fld)
     208           0 :        call self%get_cldbrne_num(ibin, qqcw(indx)%fld)
     209           0 :        do ispc = 1, aero_props%nspecies(ibin)
     210           0 :           indx = aero_props%indexer(ibin, ispc)
     211           0 :           call self%get_ambient_mmr(ispc,ibin, raer(indx)%fld)
     212           0 :           call self%get_cldbrne_mmr(ispc,ibin, qqcw(indx)%fld)
     213             :        end do
     214             :     end do
     215             : 
     216           0 :   end subroutine get_states
     217             : 
     218             :   !------------------------------------------------------------------------------
     219             :   ! return aerosol bin size weights for a given bin
     220             :   !------------------------------------------------------------------------------
     221           0 :   subroutine icenuc_size_wght_arr(self, bin_ndx, ncol, nlev, species_type, use_preexisting_ice, wght)
     222             :     class(modal_aerosol_state), intent(in) :: self
     223             :     integer, intent(in) :: bin_ndx                ! bin number
     224             :     integer, intent(in) :: ncol                ! number of columns
     225             :     integer, intent(in) :: nlev                ! number of vertical levels
     226             :     character(len=*), intent(in) :: species_type  ! species type
     227             :     logical, intent(in) :: use_preexisting_ice ! pre-existing ice flag
     228             :     real(r8), intent(out) :: wght(:,:)
     229             : 
     230             :     character(len=aero_name_len) :: modetype
     231           0 :     real(r8), pointer :: dgnum(:,:,:)    ! mode dry radius
     232             :     real(r8) :: sigmag_aitken
     233             :     integer :: i,k
     234             : 
     235           0 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     236             : 
     237           0 :     wght = 0._r8
     238             : 
     239           0 :     select case ( trim(species_type) )
     240             :     case('dust')
     241           0 :        if (modetype=='coarse' .or. modetype=='coarse_dust') then
     242           0 :           wght(:ncol,:) = 1._r8
     243             :        end if
     244             :     case('sulfate')
     245           0 :        if (modetype=='aitken') then
     246           0 :           if ( use_preexisting_ice ) then
     247           0 :              wght(:ncol,:) = 1._r8
     248             :           else
     249           0 :              call rad_cnst_get_mode_props(0, bin_ndx, sigmag=sigmag_aitken)
     250           0 :              call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUM' ), dgnum)
     251           0 :              do k = 1,nlev
     252           0 :                 do i = 1,ncol
     253           0 :                    if (dgnum(i,k,bin_ndx) > 0._r8) then
     254             :                       ! only allow so4 with D>0.1 um in ice nucleation
     255           0 :                       wght(i,k) = max(0._r8,(0.5_r8 - 0.5_r8* &
     256             :                            erf(log(0.1e-6_r8/dgnum(i,k,bin_ndx))/ &
     257           0 :                            (2._r8**0.5_r8*log(sigmag_aitken)))  ))
     258             :                    end if
     259             :                 end do
     260             :              end do
     261             :           endif
     262             :        endif
     263             :     case('black-c')
     264           0 :        if (modetype=='accum') then
     265           0 :           wght(:ncol,:) = 1._r8
     266             :        endif
     267             :     case('sulfate_strat')
     268           0 :        if (modetype=='accum' .or. modetype=='coarse' .or. modetype=='coarse_strat') then
     269           0 :           wght(:ncol,:) = 1._r8
     270             :        endif
     271             :     end select
     272             : 
     273           0 :   end subroutine icenuc_size_wght_arr
     274             : 
     275             :   !------------------------------------------------------------------------------
     276             :   ! return aerosol bin size weights for a given bin, column and vertical layer
     277             :   !------------------------------------------------------------------------------
     278           0 :   subroutine icenuc_size_wght_val(self, bin_ndx, col_ndx, lyr_ndx, species_type, use_preexisting_ice, wght)
     279             :     class(modal_aerosol_state), intent(in) :: self
     280             :     integer, intent(in) :: bin_ndx                ! bin number
     281             :     integer, intent(in) :: col_ndx                ! column index
     282             :     integer, intent(in) :: lyr_ndx                ! vertical layer index
     283             :     character(len=*), intent(in) :: species_type  ! species type
     284             :     logical, intent(in) :: use_preexisting_ice    ! pre-existing ice flag
     285             :     real(r8), intent(out) :: wght
     286             : 
     287             :     character(len=aero_name_len) :: modetype
     288           0 :     real(r8), pointer :: dgnum(:,:,:)    ! mode dry radius
     289             :     real(r8) :: sigmag_aitken
     290             : 
     291           0 :     wght = 0._r8
     292             : 
     293           0 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     294             : 
     295           0 :     select case ( trim(species_type) )
     296             :     case('dust')
     297           0 :        if (modetype=='coarse' .or. modetype=='coarse_dust') then
     298           0 :           wght = 1._r8
     299             :        end if
     300             :     case('sulfate')
     301           0 :        if (modetype=='aitken') then
     302           0 :           if ( use_preexisting_ice ) then
     303           0 :              wght = 1._r8
     304             :           else
     305           0 :              call rad_cnst_get_mode_props(0, bin_ndx, sigmag=sigmag_aitken)
     306           0 :              call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUM' ), dgnum)
     307             : 
     308           0 :              if (dgnum(col_ndx,lyr_ndx,bin_ndx) > 0._r8) then
     309             :                 ! only allow so4 with D>0.1 um in ice nucleation
     310             :                 wght = max(0._r8,(0.5_r8 - 0.5_r8* &
     311             :                      erf(log(0.1e-6_r8/dgnum(col_ndx,lyr_ndx,bin_ndx))/ &
     312           0 :                      (2._r8**0.5_r8*log(sigmag_aitken)))  ))
     313             : 
     314             :              end if
     315             :           endif
     316             :        endif
     317             :     case('black-c')
     318           0 :        if (modetype=='accum') then
     319           0 :           wght = 1._r8
     320             :        endif
     321             :     case('sulfate_strat')
     322           0 :        if (modetype=='accum' .or. modetype=='coarse' .or. modetype=='coarse_strat') then
     323           0 :           wght = 1._r8
     324             :        endif
     325             :     end select
     326             : 
     327           0 :   end subroutine icenuc_size_wght_val
     328             : 
     329             :   !------------------------------------------------------------------------------
     330             :   ! returns aerosol type weights for a given aerosol type and bin
     331             :   !------------------------------------------------------------------------------
     332           0 :   subroutine icenuc_type_wght(self, bin_ndx, ncol, nlev, species_type, aero_props, rho, wght, cloud_borne)
     333             : 
     334             :     use aerosol_properties_mod, only: aerosol_properties
     335             : 
     336             :     class(modal_aerosol_state), intent(in) :: self
     337             :     integer, intent(in) :: bin_ndx                ! bin number
     338             :     integer, intent(in) :: ncol                   ! number of columns
     339             :     integer, intent(in) :: nlev                   ! number of vertical levels
     340             :     character(len=*), intent(in) :: species_type  ! species type
     341             :     class(aerosol_properties), intent(in) :: aero_props ! aerosol properties object
     342             :     real(r8), intent(in) :: rho(:,:)              ! air density (kg m-3)
     343             :     real(r8), intent(out) :: wght(:,:)            ! type weights
     344             :     logical, optional, intent(in) :: cloud_borne  ! if TRUE cloud-borne aerosols are used
     345             :                                                   ! otherwise ambient aerosols are used
     346             : 
     347             :     character(len=aero_name_len) :: modetype
     348             : 
     349           0 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     350             : 
     351           0 :     wght = 0._r8
     352             : 
     353           0 :     if (species_type == 'dust') then
     354           0 :        if (modetype=='coarse_dust') then
     355           0 :           wght(:ncol,:) = 1._r8
     356             :        else
     357           0 :           call self%icenuc_type_wght_base(bin_ndx, ncol, nlev, species_type, aero_props, rho, wght, cloud_borne)
     358             :        end if
     359           0 :     else if (species_type == 'sulfate_strat') then
     360           0 :        if (modetype=='accum') then
     361           0 :           wght(:ncol,:) = 1._r8
     362           0 :        elseif ( modetype=='coarse' .or. modetype=='coarse_strat') then
     363           0 :           call self%icenuc_type_wght_base(bin_ndx, ncol, nlev, species_type, aero_props, rho, wght, cloud_borne)
     364             :        endif
     365             :     else
     366           0 :        wght(:ncol,:) = 1._r8
     367             :     end if
     368             : 
     369           0 :   end subroutine icenuc_type_wght
     370             : 
     371             :   !------------------------------------------------------------------------------
     372             :   !------------------------------------------------------------------------------
     373           0 :   subroutine update_bin( self, bin_ndx, col_ndx, lyr_ndx, delmmr_sum, delnum_sum, tnd_ndx, dtime, tend )
     374             :     class(modal_aerosol_state), intent(in) :: self
     375             :     integer, intent(in) :: bin_ndx                ! bin number
     376             :     integer, intent(in) :: col_ndx                ! column index
     377             :     integer, intent(in) :: lyr_ndx                ! vertical layer index
     378             :     real(r8),intent(in) :: delmmr_sum             ! mass mixing ratio change summed over all species in bin
     379             :     real(r8),intent(in) :: delnum_sum             ! number mixing ratio change summed over all species in bin
     380             :     integer, intent(in) :: tnd_ndx                ! tendency index
     381             :     real(r8),intent(in) :: dtime                  ! time step size (sec)
     382             :     real(r8),intent(inout) :: tend(:,:,:)         ! tendency
     383             : 
     384           0 :     real(r8), pointer :: amb_num(:,:)
     385           0 :     real(r8), pointer :: cld_num(:,:)
     386             : 
     387           0 :     call self%get_ambient_num(bin_ndx, amb_num)
     388           0 :     call self%get_cldbrne_num(bin_ndx, cld_num)
     389             : 
     390             :     ! if there is no bin mass compute updates/tendencies for bin number
     391             :     ! -- apply the total number change to bin number
     392           0 :     if (tnd_ndx>0) then
     393           0 :        tend(col_ndx,lyr_ndx,tnd_ndx) = -delnum_sum/dtime
     394             :     else
     395           0 :        amb_num(col_ndx,lyr_ndx) = amb_num(col_ndx,lyr_ndx) - delnum_sum
     396             :     end if
     397             : 
     398             :     ! apply the total number change to bin number
     399           0 :     cld_num(col_ndx,lyr_ndx) = cld_num(col_ndx,lyr_ndx) + delnum_sum
     400             : 
     401           0 :   end subroutine update_bin
     402             : 
     403             :   !------------------------------------------------------------------------------
     404             :   ! returns the volume-weighted fractions of aerosol subset `bin_ndx` that can act
     405             :   ! as heterogeneous freezing nuclei
     406             :   !------------------------------------------------------------------------------
     407           0 :   function hetfrz_size_wght(self, bin_ndx, ncol, nlev) result(wght)
     408             :     class(modal_aerosol_state), intent(in) :: self
     409             :     integer, intent(in) :: bin_ndx             ! bin number
     410             :     integer, intent(in) :: ncol                ! number of columns
     411             :     integer, intent(in) :: nlev                ! number of vertical levels
     412             : 
     413             :     real(r8) :: wght(ncol,nlev)
     414             : 
     415             :     character(len=aero_name_len) :: modetype
     416             : 
     417           0 :     wght(:,:) = 1._r8
     418             : 
     419           0 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     420             : 
     421           0 :     if (trim(modetype) == 'aitken') then
     422           0 :        wght(:,:) = 0._r8
     423             :     end if
     424             : 
     425           0 :   end function hetfrz_size_wght
     426             : 
     427             :   !------------------------------------------------------------------------------
     428             :   ! returns hygroscopicity for a given radiation diagnostic list number and
     429             :   ! bin number
     430             :   !------------------------------------------------------------------------------
     431           0 :   function hygroscopicity(self, list_ndx, bin_ndx) result(kappa)
     432             :     class(modal_aerosol_state), intent(in) :: self
     433             :     integer, intent(in) :: list_ndx        ! rad climate list number
     434             :     integer, intent(in) :: bin_ndx         ! bin number
     435             : 
     436             :     real(r8), pointer :: kappa(:,:)        ! hygroscopicity (ncol,nlev)
     437             : 
     438           0 :     nullify(kappa)
     439             : 
     440           0 :   end function hygroscopicity
     441             : 
     442             :   !------------------------------------------------------------------------------
     443             :   ! returns aerosol wet diameter and aerosol water concentration for a given
     444             :   ! radiation diagnostic list number and bin number
     445             :   !------------------------------------------------------------------------------
     446           0 :   subroutine water_uptake(self, aero_props, list_idx, bin_idx, ncol, nlev, dgnumwet, qaerwat)
     447             :     use modal_aero_wateruptake, only: modal_aero_wateruptake_dr
     448             :     use modal_aero_calcsize,    only: modal_aero_calcsize_diag
     449             : 
     450             :     class(modal_aerosol_state), intent(in) :: self
     451             :     class(aerosol_properties), intent(in) :: aero_props
     452             :     integer, intent(in) :: list_idx             ! rad climate/diags list number
     453             :     integer, intent(in) :: bin_idx              ! bin number
     454             :     integer, intent(in) :: ncol                 ! number of columns
     455             :     integer, intent(in) :: nlev                 ! number of levels
     456             :     real(r8),intent(out) :: dgnumwet(ncol,nlev) ! aerosol wet diameter (m)
     457             :     real(r8),intent(out) :: qaerwat(ncol,nlev)  ! aerosol water concentration (g/g)
     458             : 
     459             :     integer :: istat, nmodes
     460           0 :     real(r8), pointer :: dgnumdry_m(:,:,:) ! number mode dry diameter for all modes
     461           0 :     real(r8), pointer :: dgnumwet_m(:,:,:) ! number mode wet diameter for all modes
     462           0 :     real(r8), pointer :: qaerwat_m(:,:,:)  ! aerosol water (g/g) for all modes
     463           0 :     real(r8), pointer :: wetdens_m(:,:,:)  !
     464           0 :     real(r8), pointer :: hygro_m(:,:,:)  !
     465           0 :     real(r8), pointer :: dryvol_m(:,:,:)  !
     466           0 :     real(r8), pointer :: dryrad_m(:,:,:)  !
     467           0 :     real(r8), pointer :: drymass_m(:,:,:)  !
     468           0 :     real(r8), pointer :: so4dryvol_m(:,:,:)  !
     469           0 :     real(r8), pointer :: naer_m(:,:,:)  !
     470             : 
     471           0 :     nmodes = aero_props%nbins()
     472             : 
     473           0 :     if (list_idx == 0) then
     474             :        ! water uptake and wet radius for the climate list has already been calculated
     475           0 :        call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUMWET'), dgnumwet_m)
     476           0 :        call pbuf_get_field(self%pbuf, pbuf_get_index('QAERWAT'),  qaerwat_m)
     477             : 
     478           0 :        dgnumwet(:ncol,:nlev) = dgnumwet_m(:ncol,:nlev,bin_idx)
     479           0 :        qaerwat (:ncol,:nlev) =  qaerwat_m(:ncol,:nlev,bin_idx)
     480             : 
     481             :     else
     482             :        ! If doing a diagnostic calculation then need to calculate the wet radius
     483             :        ! and water uptake for the diagnostic modes
     484             :        allocate(dgnumdry_m(ncol,nlev,nmodes),  dgnumwet_m(ncol,nlev,nmodes), &
     485             :                 qaerwat_m(ncol,nlev,nmodes),   wetdens_m(ncol,nlev,nmodes), &
     486             :                 hygro_m(ncol,nlev,nmodes),     dryvol_m(ncol,nlev,nmodes), &
     487             :                 dryrad_m(ncol,nlev,nmodes),    drymass_m(ncol,nlev,nmodes),  &
     488           0 :                 so4dryvol_m(ncol,nlev,nmodes), naer_m(ncol,nlev,nmodes), stat=istat)
     489           0 :        if (istat > 0) then
     490           0 :           dgnumwet = -huge(1._r8)
     491           0 :           qaerwat = -huge(1._r8)
     492             :           return
     493             :        end if
     494             :        call modal_aero_calcsize_diag(self%state, self%pbuf, list_idx, dgnumdry_m, hygro_m, &
     495           0 :                                      dryvol_m, dryrad_m, drymass_m, so4dryvol_m, naer_m)
     496             :        call modal_aero_wateruptake_dr(self%state, self%pbuf, list_idx, dgnumdry_m, dgnumwet_m, &
     497             :                                       qaerwat_m, wetdens_m,  hygro_m, dryvol_m, dryrad_m, &
     498           0 :                                       drymass_m, so4dryvol_m, naer_m)
     499             : 
     500           0 :        dgnumwet(:ncol,:nlev) = dgnumwet_m(:ncol,:nlev,bin_idx)
     501           0 :        qaerwat (:ncol,:nlev) =  qaerwat_m(:ncol,:nlev,bin_idx)
     502             : 
     503           0 :        deallocate(dgnumdry_m)
     504           0 :        deallocate(dgnumwet_m)
     505           0 :        deallocate(qaerwat_m)
     506           0 :        deallocate(wetdens_m)
     507           0 :        deallocate(hygro_m)
     508           0 :        deallocate(dryvol_m)
     509           0 :        deallocate(dryrad_m)
     510           0 :        deallocate(drymass_m)
     511           0 :        deallocate(so4dryvol_m)
     512           0 :        deallocate(naer_m)
     513             :     endif
     514             : 
     515             : 
     516           0 :   end subroutine water_uptake
     517             : 
     518             :   !------------------------------------------------------------------------------
     519             :   ! aerosol dry volume (m3/kg) for given radiation diagnostic list number and bin number
     520             :   !------------------------------------------------------------------------------
     521           0 :   function dry_volume(self, aero_props, list_idx, bin_idx, ncol, nlev) result(vol)
     522             : 
     523             :     class(modal_aerosol_state), intent(in) :: self
     524             :     class(aerosol_properties), intent(in) :: aero_props
     525             : 
     526             :     integer, intent(in) :: list_idx  ! rad climate/diags list number
     527             :     integer, intent(in) :: bin_idx   ! bin number
     528             :     integer, intent(in) :: ncol      ! number of columns
     529             :     integer, intent(in) :: nlev      ! number of levels
     530             : 
     531             :     real(r8) :: vol(ncol,nlev)       ! m3/kg
     532             : 
     533           0 :     real(r8), pointer :: mmr(:,:)
     534             :     real(r8) :: specdens              ! species density (kg/m3)
     535             : 
     536             :     integer :: ispec
     537             : 
     538           0 :     vol(:,:) = 0._r8
     539             : 
     540           0 :     do ispec = 1, aero_props%nspecies(list_idx,bin_idx)
     541           0 :        call self%get_ambient_mmr(list_idx, ispec, bin_idx, mmr)
     542           0 :        call aero_props%get(bin_idx, ispec, list_ndx=list_idx, density=specdens)
     543           0 :        vol(:ncol,:) = vol(:ncol,:) + mmr(:ncol,:)/specdens
     544             :     end do
     545             : 
     546           0 :   end function dry_volume
     547             : 
     548             :   !------------------------------------------------------------------------------
     549             :   ! aerosol wet volume (m3/kg) for given radiation diagnostic list number and bin number
     550             :   !------------------------------------------------------------------------------
     551           0 :   function wet_volume(self, aero_props, list_idx, bin_idx, ncol, nlev) result(vol)
     552             : 
     553             :     class(modal_aerosol_state), intent(in) :: self
     554             :     class(aerosol_properties), intent(in) :: aero_props
     555             : 
     556             :     integer, intent(in) :: list_idx  ! rad climate/diags list number
     557             :     integer, intent(in) :: bin_idx   ! bin number
     558             :     integer, intent(in) :: ncol      ! number of columns
     559             :     integer, intent(in) :: nlev      ! number of levels
     560             : 
     561             :     real(r8) :: vol(ncol,nlev)       ! m3/kg
     562             : 
     563           0 :     real(r8) :: dryvol(ncol,nlev)
     564           0 :     real(r8) :: watervol(ncol,nlev)
     565             : 
     566           0 :     dryvol = self%dry_volume(aero_props, list_idx, bin_idx, ncol, nlev)
     567           0 :     watervol = self%water_volume(aero_props, list_idx, bin_idx, ncol, nlev)
     568             : 
     569           0 :     vol = watervol + dryvol
     570             : 
     571           0 :   end function wet_volume
     572             : 
     573             :   !------------------------------------------------------------------------------
     574             :   ! aerosol water volume (m3/kg) for given radiation diagnostic list number and bin number
     575             :   !------------------------------------------------------------------------------
     576           0 :   function water_volume(self, aero_props, list_idx, bin_idx, ncol, nlev) result(vol)
     577             : 
     578             :     class(modal_aerosol_state), intent(in) :: self
     579             :     class(aerosol_properties), intent(in) :: aero_props
     580             : 
     581             :     integer, intent(in) :: list_idx  ! rad climate/diags list number
     582             :     integer, intent(in) :: bin_idx   ! bin number
     583             :     integer, intent(in) :: ncol      ! number of columns
     584             :     integer, intent(in) :: nlev      ! number of levels
     585             : 
     586             :     real(r8) :: vol(ncol,nlev)       ! m3/kg
     587             : 
     588           0 :     real(r8) :: dgnumwet(ncol,nlev)
     589           0 :     real(r8) :: qaerwat(ncol,nlev)
     590             : 
     591           0 :     call self%water_uptake(aero_props, list_idx, bin_idx, ncol, nlev, dgnumwet, qaerwat)
     592             : 
     593           0 :     vol(:ncol,:nlev) = qaerwat(:ncol,:nlev)*rh2odens
     594           0 :     where (vol<0._r8)
     595             :        vol = 0._r8
     596             :     end where
     597             : 
     598           0 :   end function water_volume
     599             : 
     600             :   !------------------------------------------------------------------------------
     601             :   ! aerosol wet diameter
     602             :   !------------------------------------------------------------------------------
     603           0 :   function wet_diameter(self, bin_idx, ncol, nlev) result(diam)
     604             :     class(modal_aerosol_state), intent(in) :: self
     605             :     integer, intent(in) :: bin_idx   ! bin number
     606             :     integer, intent(in) :: ncol      ! number of columns
     607             :     integer, intent(in) :: nlev      ! number of levels
     608             : 
     609             :     real(r8) :: diam(ncol,nlev)
     610             : 
     611           0 :     real(r8), pointer :: dgnumwet(:,:,:)
     612             : 
     613           0 :     call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUMWET'), dgnumwet)
     614             : 
     615           0 :     diam(:ncol,:nlev) = dgnumwet(:ncol,:nlev,bin_idx)
     616             : 
     617           0 :   end function wet_diameter
     618             : 
     619             :   !------------------------------------------------------------------------------
     620             :   ! prescribed aerosol activation fraction for convective cloud
     621             :   !------------------------------------------------------------------------------
     622           0 :   function convcld_actfrac(self, ibin, ispc, ncol, nlev) result(frac)
     623             : 
     624             :     use modal_aero_data
     625             : 
     626             :     class(modal_aerosol_state), intent(in) :: self
     627             :     integer, intent(in) :: ibin   ! bin index
     628             :     integer, intent(in) :: ispc   ! species index
     629             :     integer, intent(in) :: ncol   ! number of columns
     630             :     integer, intent(in) :: nlev   ! number of vertical levels
     631             : 
     632             :     real(r8) :: frac(ncol,nlev)
     633             : 
     634           0 :     real(r8) :: f_act_conv_coarse(ncol,nlev)
     635             :     real(r8) :: f_act_conv_coarse_dust, f_act_conv_coarse_nacl
     636             :     real(r8) :: tmpdust, tmpnacl
     637             :     integer :: lcoardust, lcoarnacl
     638             :     integer :: i,k
     639             : 
     640           0 :     f_act_conv_coarse(:,:) = 0.60_r8
     641           0 :     f_act_conv_coarse_dust = 0.40_r8
     642           0 :     f_act_conv_coarse_nacl = 0.80_r8
     643           0 :     if (modeptr_coarse > 0) then
     644           0 :        lcoardust = lptr_dust_a_amode(modeptr_coarse)
     645           0 :        lcoarnacl = lptr_nacl_a_amode(modeptr_coarse)
     646           0 :        if ((lcoardust > 0) .and. (lcoarnacl > 0)) then
     647           0 :           do k = 1, nlev
     648           0 :              do i = 1, ncol
     649           0 :                 tmpdust = max( 0.0_r8, self%state%q(i,k,lcoardust) )
     650           0 :                 tmpnacl = max( 0.0_r8, self%state%q(i,k,lcoarnacl) )
     651           0 :                 if ((tmpdust+tmpnacl) > 1.0e-30_r8) then
     652           0 :                    f_act_conv_coarse(i,k) = (f_act_conv_coarse_dust*tmpdust &
     653           0 :                         + f_act_conv_coarse_nacl*tmpnacl)/(tmpdust+tmpnacl)
     654             :                 end if
     655             :              end do
     656             :           end do
     657             :        end if
     658             :     end if
     659             : 
     660           0 :     if (ibin == modeptr_pcarbon) then
     661           0 :        frac = 0.0_r8
     662           0 :     else if ((ibin == modeptr_finedust) .or. (ibin == modeptr_coardust)) then
     663           0 :        frac = 0.4_r8
     664             :     else
     665           0 :        frac = 0.8_r8
     666             :     end if
     667             : 
     668             :     ! set f_act_conv for interstitial (lphase=1) coarse mode species
     669             :     ! for the convective in-cloud, we conceptually treat the coarse dust and seasalt
     670             :     ! as being externally mixed, and apply f_act_conv = f_act_conv_coarse_dust/nacl to dust/seasalt
     671             :     ! number and sulfate are conceptually partitioned to the dust and seasalt
     672             :     ! on a mass basis, so the f_act_conv for number and sulfate are
     673             :     ! mass-weighted averages of the values used for dust/seasalt
     674           0 :     if (ibin == modeptr_coarse) then
     675           0 :        frac = f_act_conv_coarse
     676           0 :        if (ispc>0) then
     677           0 :           if (lmassptr_amode(ispc,ibin) == lptr_dust_a_amode(ibin)) then
     678           0 :              frac = f_act_conv_coarse_dust
     679           0 :           else if (lmassptr_amode(ispc,ibin) == lptr_nacl_a_amode(ibin)) then
     680           0 :              frac = f_act_conv_coarse_nacl
     681             :           end if
     682             :        end if
     683             :     end if
     684             : 
     685           0 :   end function convcld_actfrac
     686             : 
     687           0 : end module modal_aerosol_state_mod

Generated by: LCOV version 1.14