LCOV - code coverage report
Current view: top level - chemistry/aerosol - modal_aerosol_state_mod.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 155 217 71.4 %
Date: 2025-03-14 01:21:06 Functions: 20 26 76.9 %

          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             :      procedure :: wgtpct
      46             : 
      47             :      final :: destructor
      48             : 
      49             :   end type modal_aerosol_state
      50             : 
      51             :   interface modal_aerosol_state
      52             :      procedure :: constructor
      53             :   end interface modal_aerosol_state
      54             : 
      55             :   real(r8), parameter :: rh2odens = 1._r8/rhoh2o
      56             : 
      57             : contains
      58             : 
      59             :   !------------------------------------------------------------------------------
      60             :   !------------------------------------------------------------------------------
      61      407040 :   function constructor(state,pbuf) result(newobj)
      62             :     type(physics_state), target :: state
      63             :     type(physics_buffer_desc), pointer :: pbuf(:)
      64             : 
      65             :     type(modal_aerosol_state), pointer :: newobj
      66             : 
      67             :     integer :: ierr
      68             : 
      69      407040 :     allocate(newobj,stat=ierr)
      70      407040 :     if( ierr /= 0 ) then
      71      407040 :        nullify(newobj)
      72             :        return
      73             :     end if
      74             : 
      75      407040 :     newobj%state => state
      76      407040 :     newobj%pbuf => pbuf
      77             : 
      78      407040 :   end function constructor
      79             : 
      80             :   !------------------------------------------------------------------------------
      81             :   !------------------------------------------------------------------------------
      82      407040 :   subroutine destructor(self)
      83             :     type(modal_aerosol_state), intent(inout) :: self
      84             : 
      85      407040 :     nullify(self%state)
      86      407040 :     nullify(self%pbuf)
      87             : 
      88      407040 :   end subroutine destructor
      89             : 
      90             :   !------------------------------------------------------------------------------
      91             :   ! sets transported components
      92             :   ! This aerosol model with the state of the transported aerosol constituents
      93             :   ! (mass mixing ratios or number mixing ratios)
      94             :   !------------------------------------------------------------------------------
      95           0 :   subroutine set_transported( self, transported_array )
      96             :     class(modal_aerosol_state), intent(inout) :: self
      97             :     real(r8), intent(in) :: transported_array(:,:,:)
      98             :     ! to be implemented later
      99           0 :   end subroutine set_transported
     100             : 
     101             :   !------------------------------------------------------------------------------
     102             :   ! returns transported components
     103             :   ! This returns to current state of the transported aerosol constituents
     104             :   ! (mass mixing ratios or number mixing ratios)
     105             :   !------------------------------------------------------------------------------
     106           0 :   subroutine get_transported( self, transported_array )
     107             :     class(modal_aerosol_state), intent(in) :: self
     108             :     real(r8), intent(out) :: transported_array(:,:,:)
     109             :     ! to be implemented later
     110           0 :   end subroutine get_transported
     111             : 
     112             :   !------------------------------------------------------------------------
     113             :   ! Total aerosol mass mixing ratio for a bin in a given grid box location (column and layer)
     114             :   !------------------------------------------------------------------------
     115           0 :   function ambient_total_bin_mmr(self, aero_props, bin_ndx, col_ndx, lyr_ndx) result(mmr_tot)
     116             :     class(modal_aerosol_state), intent(in) :: self
     117             :     class(aerosol_properties), intent(in) :: aero_props
     118             :     integer, intent(in) :: bin_ndx      ! bin index
     119             :     integer, intent(in) :: col_ndx      ! column index
     120             :     integer, intent(in) :: lyr_ndx      ! vertical layer index
     121             : 
     122             :     real(r8) :: mmr_tot                 ! mass mixing ratios totaled for all species
     123           0 :     real(r8),pointer :: mmrptr(:,:)
     124             :     integer :: spec_ndx
     125             : 
     126           0 :     mmr_tot = 0._r8
     127             : 
     128           0 :     do spec_ndx=1,aero_props%nspecies(bin_ndx)
     129           0 :        call rad_cnst_get_aer_mmr(0, bin_ndx, spec_ndx, 'a', self%state, self%pbuf, mmrptr)
     130           0 :        mmr_tot = mmr_tot + mmrptr(col_ndx,lyr_ndx)
     131             :     end do
     132             : 
     133           0 :   end function ambient_total_bin_mmr
     134             : 
     135             :   !------------------------------------------------------------------------------
     136             :   ! returns ambient aerosol mass mixing ratio for a given species index and bin index
     137             :   !------------------------------------------------------------------------------
     138  1096994080 :   subroutine get_ambient_mmr_0list(self, species_ndx, bin_ndx, mmr)
     139             :     class(modal_aerosol_state), intent(in) :: self
     140             :     integer, intent(in) :: species_ndx  ! species index
     141             :     integer, intent(in) :: bin_ndx      ! bin index
     142             :     real(r8), pointer :: mmr(:,:)       ! mass mixing ratios (ncol,nlev)
     143             : 
     144  1096994080 :     call rad_cnst_get_aer_mmr(0, bin_ndx, species_ndx, 'a', self%state, self%pbuf, mmr)
     145  1096994080 :   end subroutine get_ambient_mmr_0list
     146             : 
     147             :   !------------------------------------------------------------------------------
     148             :   ! returns ambient aerosol mass mixing ratio for a given radiation diagnostics
     149             :   ! list index, species index and bin index
     150             :   !------------------------------------------------------------------------------
     151  2624517120 :   subroutine get_ambient_mmr_rlist(self, list_ndx, species_ndx, bin_ndx, mmr)
     152             :     class(modal_aerosol_state), intent(in) :: self
     153             :     integer, intent(in) :: list_ndx     ! rad climate list index
     154             :     integer, intent(in) :: species_ndx  ! species index
     155             :     integer, intent(in) :: bin_ndx      ! bin index
     156             :     real(r8), pointer :: mmr(:,:)       ! mass mixing ratios (ncol,nlev)
     157             : 
     158  2624517120 :     call rad_cnst_get_aer_mmr(list_ndx, bin_ndx, species_ndx, 'a', self%state, self%pbuf, mmr)
     159  2624517120 :   end subroutine get_ambient_mmr_rlist
     160             : 
     161             :   !------------------------------------------------------------------------------
     162             :   ! returns cloud-borne aerosol number mixing ratio for a given species index and bin index
     163             :   !------------------------------------------------------------------------------
     164  1049335840 :   subroutine get_cldbrne_mmr(self, species_ndx, bin_ndx, mmr)
     165             :     class(modal_aerosol_state), intent(in) :: self
     166             :     integer, intent(in) :: species_ndx  ! species index
     167             :     integer, intent(in) :: bin_ndx      ! bin index
     168             :     real(r8), pointer :: mmr(:,:)       ! mass mixing ratios (ncol,nlev)
     169             : 
     170  1049335840 :     call rad_cnst_get_aer_mmr(0, bin_ndx, species_ndx, 'c', self%state, self%pbuf, mmr)
     171  1049335840 :   end subroutine get_cldbrne_mmr
     172             : 
     173             :   !------------------------------------------------------------------------------
     174             :   ! returns ambient aerosol number mixing ratio for a given species index and bin index
     175             :   !------------------------------------------------------------------------------
     176   197340763 :   subroutine get_ambient_num(self, bin_ndx, num)
     177             :     class(modal_aerosol_state), intent(in) :: self
     178             :     integer, intent(in) :: bin_ndx     ! bin index
     179             :     real(r8), pointer   :: num(:,:)    ! number densities
     180             : 
     181   197340763 :     call rad_cnst_get_mode_num(0, bin_ndx, 'a', self%state, self%pbuf, num)
     182   197340763 :   end subroutine get_ambient_num
     183             : 
     184             :   !------------------------------------------------------------------------------
     185             :   ! returns cloud-borne aerosol number mixing ratio for a given species index and bin index
     186             :   !------------------------------------------------------------------------------
     187   192018523 :   subroutine get_cldbrne_num(self, bin_ndx, num)
     188             :     class(modal_aerosol_state), intent(in) :: self
     189             :     integer, intent(in) :: bin_ndx             ! bin index
     190             :     real(r8), pointer :: num(:,:)
     191             : 
     192   192018523 :     call rad_cnst_get_mode_num(0, bin_ndx, 'c', self%state, self%pbuf, num)
     193   192018523 :   end subroutine get_cldbrne_num
     194             : 
     195             :   !------------------------------------------------------------------------------
     196             :   ! returns interstitial and cloud-borne aerosol states
     197             :   !------------------------------------------------------------------------------
     198      403200 :   subroutine get_states( self, aero_props, raer, qqcw )
     199             :     class(modal_aerosol_state), intent(in) :: self
     200             :     class(aerosol_properties), intent(in) :: aero_props
     201             :     type(ptr2d_t), intent(out) :: raer(:)
     202             :     type(ptr2d_t), intent(out) :: qqcw(:)
     203             : 
     204             :     integer :: ibin,ispc, indx
     205             : 
     206     2419200 :     do ibin = 1, aero_props%nbins()
     207     2016000 :        indx = aero_props%indexer(ibin, 0)
     208     2016000 :        call self%get_ambient_num(ibin, raer(indx)%fld)
     209     2016000 :        call self%get_cldbrne_num(ibin, qqcw(indx)%fld)
     210    22982400 :        do ispc = 1, aero_props%nspecies(ibin)
     211    18547200 :           indx = aero_props%indexer(ibin, ispc)
     212    18547200 :           call self%get_ambient_mmr(ispc,ibin, raer(indx)%fld)
     213    20563200 :           call self%get_cldbrne_mmr(ispc,ibin, qqcw(indx)%fld)
     214             :        end do
     215             :     end do
     216             : 
     217      403200 :   end subroutine get_states
     218             : 
     219             :   !------------------------------------------------------------------------------
     220             :   ! return aerosol bin size weights for a given bin
     221             :   !------------------------------------------------------------------------------
     222    23466240 :   subroutine icenuc_size_wght_arr(self, bin_ndx, ncol, nlev, species_type, use_preexisting_ice, wght)
     223             :     class(modal_aerosol_state), intent(in) :: self
     224             :     integer, intent(in) :: bin_ndx                ! bin number
     225             :     integer, intent(in) :: ncol                ! number of columns
     226             :     integer, intent(in) :: nlev                ! number of vertical levels
     227             :     character(len=*), intent(in) :: species_type  ! species type
     228             :     logical, intent(in) :: use_preexisting_ice ! pre-existing ice flag
     229             :     real(r8), intent(out) :: wght(:,:)
     230             : 
     231             :     character(len=aero_name_len) :: modetype
     232    23466240 :     real(r8), pointer :: dgnum(:,:,:)    ! mode dry radius
     233             :     real(r8) :: sigmag_aitken
     234             :     integer :: i,k
     235             : 
     236    23466240 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     237             : 
     238 11587629312 :     wght = 0._r8
     239             : 
     240    46932480 :     select case ( trim(species_type) )
     241             :     case('dust')
     242     1451520 :        if (modetype=='coarse' .or. modetype=='coarse_dust') then
     243   238920192 :           wght(:ncol,:) = 1._r8
     244             :        end if
     245             :     case('sulfate')
     246     1935360 :        if (modetype=='aitken') then
     247      483840 :           if ( use_preexisting_ice ) then
     248   238920192 :              wght(:ncol,:) = 1._r8
     249             :           else
     250           0 :              call rad_cnst_get_mode_props(0, bin_ndx, sigmag=sigmag_aitken)
     251           0 :              call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUM' ), dgnum)
     252           0 :              do k = 1,nlev
     253           0 :                 do i = 1,ncol
     254           0 :                    if (dgnum(i,k,bin_ndx) > 0._r8) then
     255             :                       ! only allow so4 with D>0.1 um in ice nucleation
     256           0 :                       wght(i,k) = max(0._r8,(0.5_r8 - 0.5_r8* &
     257             :                            erf(log(0.1e-6_r8/dgnum(i,k,bin_ndx))/ &
     258           0 :                            (2._r8**0.5_r8*log(sigmag_aitken)))  ))
     259             :                    end if
     260             :                 end do
     261             :              end do
     262             :           endif
     263             :        endif
     264             :     case('black-c')
     265      967680 :        if (modetype=='accum') then
     266   238920192 :           wght(:ncol,:) = 1._r8
     267             :        endif
     268             :     case('sulfate_strat')
     269    46932480 :        if (modetype=='accum' .or. modetype=='coarse' .or. modetype=='coarse_strat') then
     270   358380288 :           wght(:ncol,:) = 1._r8
     271             :        endif
     272             :     end select
     273             : 
     274    23466240 :   end subroutine icenuc_size_wght_arr
     275             : 
     276             :   !------------------------------------------------------------------------------
     277             :   ! return aerosol bin size weights for a given bin, column and vertical layer
     278             :   !------------------------------------------------------------------------------
     279           0 :   subroutine icenuc_size_wght_val(self, bin_ndx, col_ndx, lyr_ndx, species_type, use_preexisting_ice, wght)
     280             :     class(modal_aerosol_state), intent(in) :: self
     281             :     integer, intent(in) :: bin_ndx                ! bin number
     282             :     integer, intent(in) :: col_ndx                ! column index
     283             :     integer, intent(in) :: lyr_ndx                ! vertical layer index
     284             :     character(len=*), intent(in) :: species_type  ! species type
     285             :     logical, intent(in) :: use_preexisting_ice    ! pre-existing ice flag
     286             :     real(r8), intent(out) :: wght
     287             : 
     288             :     character(len=aero_name_len) :: modetype
     289           0 :     real(r8), pointer :: dgnum(:,:,:)    ! mode dry radius
     290             :     real(r8) :: sigmag_aitken
     291             : 
     292           0 :     wght = 0._r8
     293             : 
     294           0 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     295             : 
     296           0 :     select case ( trim(species_type) )
     297             :     case('dust')
     298           0 :        if (modetype=='coarse' .or. modetype=='coarse_dust') then
     299           0 :           wght = 1._r8
     300             :        end if
     301             :     case('sulfate')
     302           0 :        if (modetype=='aitken') then
     303           0 :           if ( use_preexisting_ice ) then
     304           0 :              wght = 1._r8
     305             :           else
     306           0 :              call rad_cnst_get_mode_props(0, bin_ndx, sigmag=sigmag_aitken)
     307           0 :              call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUM' ), dgnum)
     308             : 
     309           0 :              if (dgnum(col_ndx,lyr_ndx,bin_ndx) > 0._r8) then
     310             :                 ! only allow so4 with D>0.1 um in ice nucleation
     311             :                 wght = max(0._r8,(0.5_r8 - 0.5_r8* &
     312             :                      erf(log(0.1e-6_r8/dgnum(col_ndx,lyr_ndx,bin_ndx))/ &
     313           0 :                      (2._r8**0.5_r8*log(sigmag_aitken)))  ))
     314             : 
     315             :              end if
     316             :           endif
     317             :        endif
     318             :     case('black-c')
     319           0 :        if (modetype=='accum') then
     320           0 :           wght = 1._r8
     321             :        endif
     322             :     case('sulfate_strat')
     323           0 :        if (modetype=='accum' .or. modetype=='coarse' .or. modetype=='coarse_strat') then
     324           0 :           wght = 1._r8
     325             :        endif
     326             :     end select
     327             : 
     328           0 :   end subroutine icenuc_size_wght_val
     329             : 
     330             :   !------------------------------------------------------------------------------
     331             :   ! returns aerosol type weights for a given aerosol type and bin
     332             :   !------------------------------------------------------------------------------
     333    12337920 :   subroutine icenuc_type_wght(self, bin_ndx, ncol, nlev, species_type, aero_props, rho, wght, cloud_borne)
     334             : 
     335             :     use aerosol_properties_mod, only: aerosol_properties
     336             : 
     337             :     class(modal_aerosol_state), intent(in) :: self
     338             :     integer, intent(in) :: bin_ndx                ! bin number
     339             :     integer, intent(in) :: ncol                   ! number of columns
     340             :     integer, intent(in) :: nlev                   ! number of vertical levels
     341             :     character(len=*), intent(in) :: species_type  ! species type
     342             :     class(aerosol_properties), intent(in) :: aero_props ! aerosol properties object
     343             :     real(r8), intent(in) :: rho(:,:)              ! air density (kg m-3)
     344             :     real(r8), intent(out) :: wght(:,:)            ! type weights
     345             :     logical, optional, intent(in) :: cloud_borne  ! if TRUE cloud-borne aerosols are used
     346             :                                                   ! otherwise ambient aerosols are used
     347             : 
     348             :     character(len=aero_name_len) :: modetype
     349             : 
     350    12337920 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     351             : 
     352  6092464896 :     wght = 0._r8
     353             : 
     354    12337920 :     if (species_type == 'dust') then
     355      725760 :        if (modetype=='coarse_dust') then
     356           0 :           wght(:ncol,:) = 1._r8
     357             :        else
     358      725760 :           call self%icenuc_type_wght_base(bin_ndx, ncol, nlev, species_type, aero_props, rho, wght, cloud_borne)
     359             :        end if
     360    11612160 :     else if (species_type == 'sulfate_strat') then
     361     1209600 :        if (modetype=='accum') then
     362   119460096 :           wght(:ncol,:) = 1._r8
     363      967680 :        elseif ( modetype=='coarse' .or. modetype=='coarse_strat') then
     364      483840 :           call self%icenuc_type_wght_base(bin_ndx, ncol, nlev, species_type, aero_props, rho, wght, cloud_borne)
     365             :        endif
     366             :     else
     367  5136784128 :        wght(:ncol,:) = 1._r8
     368             :     end if
     369             : 
     370    12337920 :   end subroutine icenuc_type_wght
     371             : 
     372             :   !------------------------------------------------------------------------------
     373             :   !------------------------------------------------------------------------------
     374    87798058 :   subroutine update_bin( self, bin_ndx, col_ndx, lyr_ndx, delmmr_sum, delnum_sum, tnd_ndx, dtime, tend )
     375             :     class(modal_aerosol_state), intent(in) :: self
     376             :     integer, intent(in) :: bin_ndx                ! bin number
     377             :     integer, intent(in) :: col_ndx                ! column index
     378             :     integer, intent(in) :: lyr_ndx                ! vertical layer index
     379             :     real(r8),intent(in) :: delmmr_sum             ! mass mixing ratio change summed over all species in bin
     380             :     real(r8),intent(in) :: delnum_sum             ! number mixing ratio change summed over all species in bin
     381             :     integer, intent(in) :: tnd_ndx                ! tendency index
     382             :     real(r8),intent(in) :: dtime                  ! time step size (sec)
     383             :     real(r8),intent(inout) :: tend(:,:,:)         ! tendency
     384             : 
     385    87798058 :     real(r8), pointer :: amb_num(:,:)
     386    87798058 :     real(r8), pointer :: cld_num(:,:)
     387             : 
     388    87798058 :     call self%get_ambient_num(bin_ndx, amb_num)
     389    87798058 :     call self%get_cldbrne_num(bin_ndx, cld_num)
     390             : 
     391             :     ! if there is no bin mass compute updates/tendencies for bin number
     392             :     ! -- apply the total number change to bin number
     393    87798058 :     if (tnd_ndx>0) then
     394    87798058 :        tend(col_ndx,lyr_ndx,tnd_ndx) = -delnum_sum/dtime
     395             :     else
     396           0 :        amb_num(col_ndx,lyr_ndx) = amb_num(col_ndx,lyr_ndx) - delnum_sum
     397             :     end if
     398             : 
     399             :     ! apply the total number change to bin number
     400    87798058 :     cld_num(col_ndx,lyr_ndx) = cld_num(col_ndx,lyr_ndx) + delnum_sum
     401             : 
     402    87798058 :   end subroutine update_bin
     403             : 
     404             :   !------------------------------------------------------------------------------
     405             :   ! returns the volume-weighted fractions of aerosol subset `bin_ndx` that can act
     406             :   ! as heterogeneous freezing nuclei
     407             :   !------------------------------------------------------------------------------
     408     9676800 :   function hetfrz_size_wght(self, bin_ndx, ncol, nlev) result(wght)
     409             :     class(modal_aerosol_state), intent(in) :: self
     410             :     integer, intent(in) :: bin_ndx             ! bin number
     411             :     integer, intent(in) :: ncol                ! number of columns
     412             :     integer, intent(in) :: nlev                ! number of vertical levels
     413             : 
     414             :     real(r8) :: wght(ncol,nlev)
     415             : 
     416             :     character(len=aero_name_len) :: modetype
     417             : 
     418  2389201920 :     wght(:,:) = 1._r8
     419             : 
     420     4838400 :     call rad_cnst_get_info(0, bin_ndx, mode_type=modetype)
     421             : 
     422     4838400 :     if (trim(modetype) == 'aitken') then
     423           0 :        wght(:,:) = 0._r8
     424             :     end if
     425             : 
     426     4838400 :   end function hetfrz_size_wght
     427             : 
     428             :   !------------------------------------------------------------------------------
     429             :   ! returns hygroscopicity for a given radiation diagnostic list number and
     430             :   ! bin number
     431             :   !------------------------------------------------------------------------------
     432           0 :   subroutine hygroscopicity(self, list_ndx, bin_ndx, kappa)
     433             :     class(modal_aerosol_state), intent(in) :: self
     434             :     integer, intent(in) :: list_ndx        ! rad climate list number
     435             :     integer, intent(in) :: bin_ndx         ! bin number
     436             :     real(r8), intent(out) :: kappa(:,:)    ! hygroscopicity (ncol,nlev)
     437             : 
     438           0 :     kappa = -huge(1._r8)
     439             : 
     440           0 :   end subroutine 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     1536000 :   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      768000 :     real(r8), pointer :: dgnumdry_m(:,:,:) ! number mode dry diameter for all modes
     461      768000 :     real(r8), pointer :: dgnumwet_m(:,:,:) ! number mode wet diameter for all modes
     462      768000 :     real(r8), pointer :: qaerwat_m(:,:,:)  ! aerosol water (g/g) for all modes
     463      768000 :     real(r8), pointer :: wetdens_m(:,:,:)  !
     464      768000 :     real(r8), pointer :: hygro_m(:,:,:)  !
     465      768000 :     real(r8), pointer :: dryvol_m(:,:,:)  !
     466      768000 :     real(r8), pointer :: dryrad_m(:,:,:)  !
     467      768000 :     real(r8), pointer :: drymass_m(:,:,:)  !
     468      768000 :     real(r8), pointer :: so4dryvol_m(:,:,:)  !
     469      768000 :     real(r8), pointer :: naer_m(:,:,:)  !
     470             : 
     471     1536000 :     nmodes = aero_props%nbins()
     472             : 
     473      768000 :     if (list_idx == 0) then
     474             :        ! water uptake and wet radius for the climate list has already been calculated
     475      768000 :        call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUMWET'), dgnumwet_m)
     476      768000 :        call pbuf_get_field(self%pbuf, pbuf_get_index('QAERWAT'),  qaerwat_m)
     477             : 
     478   379238400 :        dgnumwet(:ncol,:nlev) = dgnumwet_m(:ncol,:nlev,bin_idx)
     479   379238400 :        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     1536000 :   end subroutine water_uptake
     517             : 
     518             :   !------------------------------------------------------------------------------
     519             :   ! aerosol dry volume (m3/kg) for given radiation diagnostic list number and bin number
     520             :   !------------------------------------------------------------------------------
     521      768000 :   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      192000 :     real(r8), pointer :: mmr(:,:)
     534             :     real(r8) :: specdens              ! species density (kg/m3)
     535             : 
     536             :     integer :: ispec
     537             : 
     538    94809600 :     vol(:,:) = 0._r8
     539             : 
     540     1958400 :     do ispec = 1, aero_props%nspecies(list_idx,bin_idx)
     541     1766400 :        call self%get_ambient_mmr(list_idx, ispec, bin_idx, mmr)
     542     1766400 :        call aero_props%get(bin_idx, ispec, list_ndx=list_idx, density=specdens)
     543   872440320 :        vol(:ncol,:) = vol(:ncol,:) + mmr(:ncol,:)/specdens
     544             :     end do
     545             : 
     546      960000 :   end function dry_volume
     547             : 
     548             :   !------------------------------------------------------------------------------
     549             :   ! aerosol wet volume (m3/kg) for given radiation diagnostic list number and bin number
     550             :   !------------------------------------------------------------------------------
     551      768000 :   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      192000 :     real(r8) :: dryvol(ncol,nlev)
     564      384000 :     real(r8) :: watervol(ncol,nlev)
     565             : 
     566    94809600 :     dryvol = self%dry_volume(aero_props, list_idx, bin_idx, ncol, nlev)
     567    94809600 :     watervol = self%water_volume(aero_props, list_idx, bin_idx, ncol, nlev)
     568             : 
     569    94809600 :     vol = watervol + dryvol
     570             : 
     571      192000 :   end function wet_volume
     572             : 
     573             :   !------------------------------------------------------------------------------
     574             :   ! aerosol water volume (m3/kg) for given radiation diagnostic list number and bin number
     575             :   !------------------------------------------------------------------------------
     576     1536000 :   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      768000 :     real(r8) :: dgnumwet(ncol,nlev)
     589      384000 :     real(r8) :: qaerwat(ncol,nlev)
     590             : 
     591      384000 :     call self%water_uptake(aero_props, list_idx, bin_idx, ncol, nlev, dgnumwet, qaerwat)
     592             : 
     593   189619200 :     vol(:ncol,:nlev) = qaerwat(:ncol,:nlev)*rh2odens
     594   189619200 :     where (vol<0._r8)
     595             :        vol = 0._r8
     596             :     end where
     597             : 
     598      384000 :   end function water_volume
     599             : 
     600             :   !------------------------------------------------------------------------------
     601             :   ! aerosol wet diameter
     602             :   !------------------------------------------------------------------------------
     603     3225600 :   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      806400 :     real(r8), pointer :: dgnumwet(:,:,:)
     612             : 
     613      806400 :     call pbuf_get_field(self%pbuf, pbuf_get_index('DGNUMWET'), dgnumwet)
     614             : 
     615   398200320 :     diam(:ncol,:nlev) = dgnumwet(:ncol,:nlev,bin_idx)
     616             : 
     617      806400 :   end function wet_diameter
     618             : 
     619             :   !------------------------------------------------------------------------------
     620             :   ! prescribed aerosol activation fraction for convective cloud
     621             :   !------------------------------------------------------------------------------
     622     4112640 :   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     4112640 :     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  2030821632 :     f_act_conv_coarse(:,:) = 0.60_r8
     641     4112640 :     f_act_conv_coarse_dust = 0.40_r8
     642     4112640 :     f_act_conv_coarse_nacl = 0.80_r8
     643     4112640 :     if (modeptr_coarse > 0) then
     644     4112640 :        lcoardust = lptr_dust_a_amode(modeptr_coarse)
     645     4112640 :        lcoarnacl = lptr_nacl_a_amode(modeptr_coarse)
     646     4112640 :        if ((lcoardust > 0) .and. (lcoarnacl > 0)) then
     647   135717120 :           do k = 1, nlev
     648  2030821632 :              do i = 1, ncol
     649  1895104512 :                 tmpdust = max( 0.0_r8, self%state%q(i,k,lcoardust) )
     650  1895104512 :                 tmpnacl = max( 0.0_r8, self%state%q(i,k,lcoarnacl) )
     651  2026708992 :                 if ((tmpdust+tmpnacl) > 1.0e-30_r8) then
     652  1895104512 :                    f_act_conv_coarse(i,k) = (f_act_conv_coarse_dust*tmpdust &
     653  1895104512 :                         + 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     4112640 :     if (ibin == modeptr_pcarbon) then
     661   159280128 :        frac = 0.0_r8
     662     3790080 :     else if ((ibin == modeptr_finedust) .or. (ibin == modeptr_coardust)) then
     663           0 :        frac = 0.4_r8
     664             :     else
     665  1871541504 :        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     4112640 :     if (ibin == modeptr_coarse) then
     675   159280128 :        frac = f_act_conv_coarse
     676      322560 :        if (ispc>0) then
     677      241920 :           if (lmassptr_amode(ispc,ibin) == lptr_dust_a_amode(ibin)) then
     678    39820032 :              frac = f_act_conv_coarse_dust
     679      161280 :           else if (lmassptr_amode(ispc,ibin) == lptr_nacl_a_amode(ibin)) then
     680    39820032 :              frac = f_act_conv_coarse_nacl
     681             :           end if
     682             :        end if
     683             :     end if
     684             : 
     685     8225280 :   end function convcld_actfrac
     686             : 
     687             :   !------------------------------------------------------------------------------
     688             :   ! aerosol weight precent of H2SO4/H2O solution
     689             :   !------------------------------------------------------------------------------
     690      153600 :   function wgtpct(self, ncol, nlev) result(wtp)
     691             :     class(modal_aerosol_state), intent(in) :: self
     692             :     integer, intent(in) ::  ncol, nlev
     693             :     real(r8) :: wtp(ncol,nlev)  ! weight precent of H2SO4/H2O solution for given icol, ilev
     694             : 
     695    37923840 :     wtp(:,:) = -huge(1._r8)
     696             : 
     697     4189440 :   end function wgtpct
     698             : 
     699      407040 : end module modal_aerosol_state_mod

Generated by: LCOV version 1.14