LCOV - code coverage report
Current view: | top level - chemistry/utils - modal_aero_calcsize.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 0 | 175 | 0.0 %
Date: | 2025-01-13 21:54:50 |  | Functions: | 0 | 5 | 0.0 %

              Line data    Source code
           1             : module modal_aero_calcsize
           2             :
           3             : !   RCE 07.04.13:  Adapted from MIRAGE2 code
           4             :
           5             : use shr_kind_mod,     only: r8 => shr_kind_r8
           6             : use spmd_utils,       only: masterproc
           7             : use physconst,        only: pi, rhoh2o, gravit
           8             :
           9             : use ppgrid,           only: pcols, pver
          10             : use physics_types,    only: physics_state, physics_ptend
          11             : use physics_buffer,   only: physics_buffer_desc, pbuf_get_index, pbuf_old_tim_idx, pbuf_get_field
          12             :
          13             : use phys_control,     only: phys_getopts
          14             : use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_aer_mmr, rad_cnst_get_aer_props, &
          15             :                             rad_cnst_get_mode_props, rad_cnst_get_mode_num
          16             :
          17             : use cam_logfile,      only: iulog
          18             : use cam_abortutils,   only: endrun
          19             : use cam_history,      only: addfld, add_default, fieldname_len, horiz_only, outfld
          20             : use constituents,     only: pcnst, cnst_name
          21             : use modal_aero_wateruptake, only: modal_strat_sulfate
          22             :
          23             : use ref_pres,         only: top_lev => clim_modal_aero_top_lev
          24             :
          25             : #ifdef MODAL_AERO
          26             :
          27             : ! these are the variables needed for the diagnostic calculation of dry radius
          28             : use modal_aero_data, only: ntot_amode, nspec_amode, nspec_max, &
          29             :                            numptr_amode, &
          30             :                            alnsg_amode, &
          31             :                            voltonumbhi_amode, voltonumblo_amode, &
          32             :                            dgnum_amode, dgnumhi_amode, dgnumlo_amode
          33             :
          34             :
          35             : ! these variables are needed for the prognostic calculations to exchange mass
          36             : ! between modes
          37             : use modal_aero_data,  only: numptrcw_amode, mprognum_amode, qqcw_get_field, lmassptrcw_amode, &
          38             :            lmassptr_amode, modeptr_accum, modeptr_aitken, &
          39             :            specmw_amode, specdens_amode, voltonumb_amode, &
          40             :            cnst_name_cw
          41             :
          42             : use modal_aero_rename, only: lspectooa_renamexf, lspecfrma_renamexf, lspectooc_renamexf, lspecfrmc_renamexf, &
          43             :            modetoo_renamexf, nspecfrm_renamexf, npair_renamexf, modefrm_renamexf
          44             :
          45             :
          46             : #endif
          47             :
          48             :
          49             : implicit none
          50             : private
          51             : save
          52             :
          53             : public modal_aero_calcsize_init, modal_aero_calcsize_sub, modal_aero_calcsize_diag
          54             : public :: modal_aero_calcsize_reg
          55             :
          56             : logical :: do_adjust_default
          57             : logical :: do_aitacc_transfer_default
          58             :
          59             : integer :: dgnum_idx     = -1
          60             : integer :: hygro_idx     = -1
          61             : integer :: dryvol_idx    = -1
          62             : integer :: dryrad_idx    = -1
          63             : integer :: drymass_idx   = -1
          64             : integer :: so4dryvol_idx = -1
          65             : integer :: naer_idx      = -1
          66             : integer :: sulfeq_idx    = -1
          67             :
          68             :
          69             : !===============================================================================
          70             : contains
          71             : !===============================================================================
          72             :
          73           0 : subroutine modal_aero_calcsize_reg()
          74             :   use physics_buffer,   only: pbuf_add_field, dtype_r8
          75             :   use rad_constituents, only: rad_cnst_get_info
          76             :
          77             :   integer :: nmodes
          78             :
          79           0 :   call rad_cnst_get_info(0, nmodes=nmodes)
          80             :
          81           0 :   call pbuf_add_field('DGNUM', 'global',  dtype_r8, (/pcols, pver, nmodes/), dgnum_idx)
          82             :
          83           0 :   call pbuf_add_field('HYGRO',     'phys_pkg', dtype_r8, (/pcols,pver,nmodes/), hygro_idx)
          84           0 :   call pbuf_add_field('DRYVOL',    'phys_pkg', dtype_r8, (/pcols,pver,nmodes/), dryvol_idx)
          85           0 :   call pbuf_add_field('DRYRAD',    'phys_pkg', dtype_r8, (/pcols,pver,nmodes/), dryrad_idx)
          86           0 :   call pbuf_add_field('DRYMASS',   'phys_pkg', dtype_r8, (/pcols,pver,nmodes/), drymass_idx)
          87           0 :   call pbuf_add_field('SO4DRYVOL', 'phys_pkg', dtype_r8, (/pcols,pver,nmodes/), so4dryvol_idx)
          88           0 :   call pbuf_add_field('NAER',      'phys_pkg', dtype_r8, (/pcols,pver,nmodes/), naer_idx)
          89             :
          90           0 : end subroutine modal_aero_calcsize_reg
          91             :
          92             : !===============================================================================
          93             : !===============================================================================
          94             :
          95           0 : subroutine modal_aero_calcsize_init(pbuf2d)
          96           0 :    use time_manager,  only: is_first_step
          97             :    use physics_buffer,only: pbuf_set_field
          98             :
          99             :    !-----------------------------------------------------------------------
         100             :    !
         101             :    ! Purpose:
         102             :    !    set do_adjust_default and do_aitacc_transfer_default flags
         103             :    !    create history fields for column tendencies associated with
         104             :    !       modal_aero_calcsize
         105             :    !
         106             :    ! Author: R. Easter
         107             :    !
         108             :    !-----------------------------------------------------------------------
         109             :
         110             :    type(physics_buffer_desc), pointer :: pbuf2d(:,:)
         111             :
         112             :    ! local
         113             :    integer  :: ipair, iq
         114             :    integer  :: jac
         115             :    integer  :: lsfrm, lstoo
         116             :    integer  :: n, nacc, nait
         117             :    logical  :: history_aerosol
         118             :
         119             :    character(len=fieldname_len)   :: tmpnamea, tmpnameb
         120             :    character(len=fieldname_len+3) :: fieldname
         121             :    character(128)                 :: long_name
         122             :    character(8)                   :: unit
         123             :    !-----------------------------------------------------------------------
         124             :
         125           0 :    call phys_getopts(history_aerosol_out=history_aerosol)
         126             :
         127             :    ! init entities required for both prescribed and prognostic modes
         128             :
         129           0 :    if (is_first_step()) then
         130             :       ! initialize fields in physics buffer
         131           0 :       call pbuf_set_field(pbuf2d, dgnum_idx, 0.0_r8)
         132             :    endif
         133             :
         134             : #ifndef MODAL_AERO
         135           0 :    do_adjust_default          = .false.
         136           0 :    do_aitacc_transfer_default = .false.
         137             : #else
         138             :    !  do_adjust_default allows adjustment to be turned on/off
         139             :    do_adjust_default = .true.
         140             :
         141             :    !  do_aitacc_transfer_default allows aitken <--> accum mode transfer to be turned on/off
         142             :    !  *** it can only be true when aitken & accum modes are both present
         143             :    !      and have prognosed number and diagnosed surface/sigmag
         144             :    nait = modeptr_aitken
         145             :    nacc = modeptr_accum
         146             :    do_aitacc_transfer_default = .false.
         147             :    if ((modeptr_aitken > 0) .and.   &
         148             :       (modeptr_accum  > 0) .and.   &
         149             :       (modeptr_aitken /= modeptr_accum)) then
         150             :       do_aitacc_transfer_default = .true.
         151             :       if (mprognum_amode(nait) <= 0) do_aitacc_transfer_default = .false.
         152             :       if (mprognum_amode(nacc) <= 0) do_aitacc_transfer_default = .false.
         153             :    end if
         154             :
         155             :    if ( .not. do_adjust_default ) return
         156             :
         157             :    !  define history fields for number-adjust source-sink for all modes
         158             :    do n = 1, ntot_amode
         159             :       if (mprognum_amode(n) <= 0) cycle
         160             :
         161             :       do jac = 1, 2
         162             :          if (jac == 1) then
         163             :             tmpnamea = cnst_name(numptr_amode(n))
         164             :          else
         165             :             tmpnamea = cnst_name_cw(numptrcw_amode(n))
         166             :          end if
         167             :          unit = '#/m2/s'
         168             :          fieldname = trim(tmpnamea) // '_sfcsiz1'
         169             :          long_name = trim(tmpnamea) // ' calcsize number-adjust column source'
         170             :          call addfld( fieldname, horiz_only, 'A', unit, long_name )
         171             :          if (history_aerosol) then
         172             :             call add_default(fieldname, 1, ' ')
         173             :          end if
         174             :          if ( masterproc ) write(*,'(2a)') 'calcsize addfld - ', fieldname
         175             :
         176             :          fieldname = trim(tmpnamea) // '_sfcsiz2'
         177             :          long_name = trim(tmpnamea) // ' calcsize number-adjust column sink'
         178             :          call addfld( fieldname, horiz_only, 'A', unit, long_name )
         179             :          if (history_aerosol) then
         180             :             call add_default(fieldname, 1, ' ')
         181             :          end if
         182             :          if ( masterproc ) write(*,'(2a)') 'calcsize addfld - ', fieldname
         183             :       end do   ! jac = ...
         184             :    end do   ! n = ...
         185             :
         186             :    if ( .not. do_aitacc_transfer_default ) return
         187             :
         188             :    ! check that renaming ipair=1 is aitken-->accum
         189             :    ipair = 1
         190             :    if ((modefrm_renamexf(ipair) .ne. nait) .or.   &
         191             :       (modetoo_renamexf(ipair) .ne. nacc)) then
         192             :       write( 6, '(//2a//)' )   &
         193             :          '*** modal_aero_calcaersize_init error -- ',   &
         194             :          'modefrm/too_renamexf(1) are wrong'
         195             :       call endrun( 'modal_aero_calcaersize_init error' )
         196             :    end if
         197             :
         198             :    ! define history fields for aitken-accum transfer
         199             :    do iq = 1, nspecfrm_renamexf(ipair)
         200             :
         201             :       ! jac=1 does interstitial ("_a"); jac=2 does activated ("_c");
         202             :       do jac = 1, 2
         203             :
         204             :          ! the lspecfrma_renamexf (and lspecfrmc_renamexf) are aitken species
         205             :          ! the lspectooa_renamexf (and lspectooc_renamexf) are accum  species
         206             :          if (jac .eq. 1) then
         207             :             lsfrm = lspecfrma_renamexf(iq,ipair)
         208             :             lstoo = lspectooa_renamexf(iq,ipair)
         209             :          else
         210             :             lsfrm = lspecfrmc_renamexf(iq,ipair)
         211             :             lstoo = lspectooc_renamexf(iq,ipair)
         212             :          end if
         213             :          if ((lsfrm <= 0) .or. (lstoo <= 0)) cycle
         214             :
         215             :          if (jac .eq. 1) then
         216             :             tmpnamea = cnst_name(lsfrm)
         217             :             tmpnameb = cnst_name(lstoo)
         218             :          else
         219             :             tmpnamea = cnst_name_cw(lsfrm)
         220             :             tmpnameb = cnst_name_cw(lstoo)
         221             :          end if
         222             :
         223             :          unit = 'kg/m2/s'
         224             :          if ((tmpnamea(1:3) == 'num') .or. &
         225             :             (tmpnamea(1:3) == 'NUM')) unit = '#/m2/s'
         226             :          fieldname = trim(tmpnamea) // '_sfcsiz3'
         227             :          long_name = trim(tmpnamea) // ' calcsize aitken-to-accum adjust column tendency'
         228             :          call addfld( fieldname, horiz_only, 'A', unit, long_name )
         229             :          if (history_aerosol) then
         230             :             call add_default(fieldname, 1, ' ')
         231             :          end if
         232             :          if ( masterproc ) write(*,'(2a)') 'calcsize addfld - ', fieldname
         233             :
         234             :          fieldname = trim(tmpnameb) // '_sfcsiz3'
         235             :          long_name = trim(tmpnameb) // ' calcsize aitken-to-accum adjust column tendency'
         236             :          call addfld( fieldname, horiz_only, 'A', unit, long_name )
         237             :          if (history_aerosol) then
         238             :             call add_default(fieldname, 1, ' ')
         239             :          end if
         240             :          if ( masterproc ) write(*,'(2a)') 'calcsize addfld - ', fieldname
         241             :
         242             :          fieldname = trim(tmpnamea) // '_sfcsiz4'
         243             :          long_name = trim(tmpnamea) // ' calcsize accum-to-aitken adjust column tendency'
         244             :          call addfld( fieldname, horiz_only, 'A', unit, long_name )
         245             :          if (history_aerosol) then
         246             :             call add_default(fieldname, 1, ' ')
         247             :          end if
         248             :          if ( masterproc ) write(*,'(2a)') 'calcsize addfld - ', fieldname
         249             :
         250             :          fieldname = trim(tmpnameb) // '_sfcsiz4'
         251             :          long_name = trim(tmpnameb) // ' calcsize accum-to-aitken adjust column tendency'
         252             :          call addfld( fieldname, horiz_only, 'A', unit, long_name )
         253             :          if (history_aerosol) then
         254             :             call add_default(fieldname, 1, ' ')
         255             :          end if
         256             :          if ( masterproc ) write(*,'(2a)') 'calcsize addfld - ', fieldname
         257             :
         258             :       end do   ! jac = ...
         259             :    end do   ! iq = ...
         260             :
         261             : #endif
         262             :
         263           0 : end subroutine modal_aero_calcsize_init
         264             :
         265             : !===============================================================================
         266             :
         267           0 : subroutine modal_aero_calcsize_sub(state, ptend, deltat, pbuf, do_adjust_in, &
         268             :    do_aitacc_transfer_in)
         269             :
         270             :    !-----------------------------------------------------------------------
         271             :    !
         272             :    ! Calculates aerosol size distribution parameters
         273             :    !    mprognum_amode >  0
         274             :    !       calculate Dgnum from mass, number, and fixed sigmag
         275             :    !    mprognum_amode <= 0
         276             :    !       calculate number from mass, fixed Dgnum, and fixed sigmag
         277             :    !
         278             :    ! Also (optionally) adjusts prognostic number to
         279             :    !    be within bounds determined by mass, Dgnum bounds, and sigma bounds
         280             :    !
         281             :    ! Author: R. Easter
         282             :    !
         283             :    !-----------------------------------------------------------------------
         284             :
         285             :    ! arguments
         286             :    type(physics_state), target, intent(in)    :: state       ! Physics state variables
         287             :
         288             :    type(physics_ptend), target, intent(inout)   :: ptend       ! indivdual parameterization tendencies
         289             :
         290             :    real(r8),                    intent(in)    :: deltat      ! model time-step size (s)
         291             :    type(physics_buffer_desc),   pointer       :: pbuf(:)     ! physics buffer
         292             :
         293             :    logical, optional :: do_adjust_in
         294             :    logical, optional :: do_aitacc_transfer_in
         295             :
         296             : #ifdef MODAL_AERO
         297             :
         298             :    ! local
         299             :
         300             :    logical :: do_adjust
         301             :    logical :: do_aitacc_transfer
         302             :
         303             :    integer  :: lchnk                ! chunk identifier
         304             :    integer  :: ncol                 ! number of columns
         305             :
         306             :    real(r8), pointer :: t(:,:)      ! Temperature in Kelvin
         307             :    real(r8), pointer :: pmid(:,:)   ! pressure at model levels (Pa)
         308             :    real(r8), pointer :: pdel(:,:)   ! pressure thickness of levels
         309             :    real(r8), pointer :: q(:,:,:)    ! Tracer MR array
         310             :
         311             :    logical,  pointer :: dotend(:)   ! flag for doing tendency
         312             :    real(r8), pointer :: dqdt(:,:,:) ! TMR tendency array
         313             :
         314             :    real(r8), pointer :: dgncur_a(:,:,:)
         315             :
         316             :    integer  :: i, icol_diag, iduma, ipair, iq
         317             :    integer  :: ixfer_acc2ait, ixfer_ait2acc
         318             :    integer  :: ixfer_acc2ait_sv(pcols,pver), ixfer_ait2acc_sv(pcols,pver)
         319             :    integer  :: j, jac, jsrflx, k
         320             :    integer  :: l, l1, la, lc, lna, lnc, lsfrm, lstoo
         321             :    integer  :: n, nacc, nait
         322             :
         323             :    integer, save  :: idiagaa = 1
         324             :
         325             :    logical  :: dotendqqcw(pcnst)
         326             :    logical  :: noxf_acc2ait(nspec_max)
         327             :
         328             :    character(len=fieldname_len)   :: tmpnamea, tmpnameb
         329             :    character(len=fieldname_len+3) :: fieldname
         330             :
         331             :    real(r8), parameter :: third = 1.0_r8/3.0_r8
         332             :    real(r8), pointer :: fldcw(:,:)
         333             :    real(r8) :: delnum_a2, delnum_c2            !  work variables
         334             :    real(r8) :: delnum_a3, delnum_c3, delnum_t3 !  work variables
         335             :    real(r8) :: deltatinv                     ! 1/deltat
         336             :    real(r8) :: dgncur_c(pcols,pver,ntot_amode)
         337             :    real(r8) :: dgnyy, dgnxx                  ! dgnumlo/hi of current mode
         338             :    real(r8) :: dqqcwdt(pcols,pver,pcnst)     ! cloudborne TMR tendency array
         339             :    real(r8) :: drv_a, drv_c, drv_t           ! dry volume (cm3/mol_air)
         340             :    real(r8) :: drv_t0
         341             :    real(r8) :: drv_a_noxf, drv_c_noxf, drv_t_noxf
         342             :    real(r8) :: drv_a_acc, drv_c_acc
         343             :    real(r8) :: drv_a_accsv(pcols,pver), drv_c_accsv(pcols,pver)
         344             :    real(r8) :: drv_a_aitsv(pcols,pver), drv_c_aitsv(pcols,pver)
         345             :    real(r8) :: drv_a_sv(pcols,pver,ntot_amode), drv_c_sv(pcols,pver,ntot_amode)
         346             :    real(r8) :: dryvol_a(pcols,pver)          ! interstital aerosol dry
         347             :    ! volume (cm^3/mol_air)
         348             :    real(r8) :: dryvol_c(pcols,pver)          ! activated aerosol dry volume
         349             :    real(r8) :: duma, dumb, dumc, dumd        ! work variables
         350             :    real(r8) :: dumfac, dummwdens             ! work variables
         351             :    real(r8) :: frelaxadj                     ! relaxation factor applied
         352             :    ! to size bounds
         353             :    real(r8) :: fracadj                       ! deltat/tadj
         354             :    real(r8) :: num_a0, num_c0, num_t0        ! initial number (#/mol_air)
         355             :    real(r8) :: num_a1, num_c1                ! working number (#/mol_air)
         356             :    real(r8) :: num_a2, num_c2, num_t2        ! working number (#/mol_air)
         357             :    real(r8) :: num_a, num_c, num_t           ! final number (#/mol_air)
         358             :    real(r8) :: num_t_noxf
         359             :    real(r8) :: numbnd                        ! bounded number
         360             :    real(r8) :: num_a_acc, num_c_acc
         361             :    real(r8) :: num_a_accsv(pcols,pver), num_c_accsv(pcols,pver)
         362             :    real(r8) :: num_a_aitsv(pcols,pver), num_c_aitsv(pcols,pver)
         363             :    real(r8) :: num_a_sv(pcols,pver,ntot_amode), num_c_sv(pcols,pver,ntot_amode)
         364             :    real(r8) :: pdel_fac                      !
         365             :    real(r8) :: tadj                          ! adjustment time scale
         366             :    real(r8) :: tadjinv                       ! 1/tadj
         367             :    real(r8) :: v2ncur_a(pcols,pver,ntot_amode)
         368             :    real(r8) :: v2ncur_c(pcols,pver,ntot_amode)
         369             :    real(r8) :: v2nyy, v2nxx, v2nzz           ! voltonumblo/hi of current mode
         370             :    real(r8) :: v2nyyrl, v2nxxrl              ! relaxed voltonumblo/hi
         371             :    real(r8) :: xfercoef
         372             :    real(r8) :: xfercoef_num_acc2ait, xfercoef_vol_acc2ait
         373             :    real(r8) :: xfercoef_num_ait2acc, xfercoef_vol_ait2acc
         374             :    real(r8) :: xferfrac_num_acc2ait, xferfrac_vol_acc2ait
         375             :    real(r8) :: xferfrac_num_ait2acc, xferfrac_vol_ait2acc
         376             :    real(r8) :: xfertend, xfertend_num(2,2)
         377             :
         378             :    integer, parameter :: nsrflx = 4    ! last dimension of qsrflx
         379             :    real(r8) :: qsrflx(pcols,pcnst,nsrflx,2)
         380             :    ! process-specific column tracer tendencies
         381             :    ! 3rd index --
         382             :    !    1="standard" number adjust gain;
         383             :    !    2="standard" number adjust loss;
         384             :    !    3=aitken-->accum renaming; 4=accum-->aitken)
         385             :    ! 4th index --
         386             :    !    1="a" species; 2="c" species
         387             :    !-----------------------------------------------------------------------
         388             :
         389             :    if (present(do_adjust_in)) then
         390             :       do_adjust = do_adjust_in
         391             :    else
         392             :       do_adjust = do_adjust_default
         393             :    end if
         394             :
         395             :    if (present(do_aitacc_transfer_in)) then
         396             :       do_aitacc_transfer = do_aitacc_transfer_in
         397             :    else
         398             :       do_aitacc_transfer = do_aitacc_transfer_default
         399             :    end if
         400             :
         401             :    lchnk = state%lchnk
         402             :    ncol  = state%ncol
         403             :
         404             :    t    => state%t
         405             :    pmid => state%pmid
         406             :    pdel => state%pdel
         407             :    q    => state%q
         408             :
         409             :    dotend => ptend%lq
         410             :    dqdt   => ptend%q
         411             :
         412             :    call pbuf_get_field(pbuf, dgnum_idx, dgncur_a)
         413             :
         414             :    dotendqqcw(:) = .false.
         415             :    dqqcwdt(:,:,:) = 0.0_r8
         416             :    qsrflx(:,:,:,:) = 0.0_r8
         417             :
         418             :    nait = modeptr_aitken
         419             :    nacc = modeptr_accum
         420             :
         421             :    deltatinv = 1.0_r8/(deltat*(1.0_r8 + 1.0e-15_r8))
         422             :    ! tadj = adjustment time scale for number, surface when they are prognosed
         423             :    !           currently set to deltat
         424             :    tadj = deltat
         425             :    tadj = 86400
         426             :    tadj = max( tadj, deltat )
         427             :    tadjinv = 1.0_r8/(tadj*(1.0_r8 + 1.0e-15_r8))
         428             :    fracadj = deltat*tadjinv
         429             :    fracadj = max( 0.0_r8, min( 1.0_r8, fracadj ) )
         430             :
         431             :
         432             :    !
         433             :    !
         434             :    ! the "do 40000" loop does the original (pre jan-2006)
         435             :    !   number adjustment, one mode at a time
         436             :    ! this artificially adjusts number when mean particle size is too large
         437             :    !   or too small
         438             :    !
         439             :    !
         440             :    do n = 1, ntot_amode
         441             :
         442             :
         443             :       ! initialize all parameters to the default values for the mode
         444             :       do k=top_lev,pver
         445             :          do i=1,ncol
         446             :             !    sgcur_a(i,k,n) = sigmag_amode(n)
         447             :             !    sgcur_c(i,k,n) = sigmag_amode(n)
         448             :             dgncur_a(i,k,n) = dgnum_amode(n)
         449             :             dgncur_c(i,k,n) = dgnum_amode(n)
         450             :             v2ncur_a(i,k,n) = voltonumb_amode(n)
         451             :             v2ncur_c(i,k,n) = voltonumb_amode(n)
         452             :             dryvol_a(i,k) = 0.0_r8
         453             :             dryvol_c(i,k) = 0.0_r8
         454             :          end do
         455             :       end do
         456             :
         457             :       ! compute dry volume mixrats =
         458             :       !      sum_over_components{ component_mass mixrat / density }
         459             :       do l1 = 1, nspec_amode(n)
         460             :          ! need qmass*dummwdens = (kg/kg-air) * [1/(kg/m3)] = m3/kg-air
         461             :          dummwdens = 1.0_r8 / specdens_amode(l1,n)
         462             :          la = lmassptr_amode(l1,n)
         463             :          do k=top_lev,pver
         464             :             do i=1,ncol
         465             :                dryvol_a(i,k) = dryvol_a(i,k)    &
         466             :                   + max(0.0_r8,q(i,k,la))*dummwdens
         467             :             end do
         468             :          end do
         469             :
         470             :          fldcw => qqcw_get_field(pbuf,lmassptrcw_amode(l1,n),lchnk)
         471             :          do k=top_lev,pver
         472             :             do i=1,ncol
         473             :                dryvol_c(i,k) = dryvol_c(i,k)    &
         474             :                   + max(0.0_r8,fldcw(i,k))*dummwdens
         475             :             end do
         476             :          end do
         477             :       end do
         478             :
         479             :       ! set "short-hand" number pointers
         480             :       lna = numptr_amode(n)
         481             :       lnc = numptrcw_amode(n)
         482             :       fldcw => qqcw_get_field(pbuf,numptrcw_amode(n),lchnk,.true.)
         483             :
         484             :
         485             :       ! go to section for appropriate number/surface diagnosed/prognosed options
         486             :       if (mprognum_amode(n) <= 0) then
         487             :
         488             :          ! option 1 -- number diagnosed (fixed dgnum and sigmag)
         489             :          !    compute number tendencies that will bring numbers to their
         490             :          !    current diagnosed values
         491             :          !
         492             :          if (lna > 0) then
         493             :             dotend(lna) = .true.
         494             :             do k=top_lev,pver
         495             :                do i=1,ncol
         496             :                   dqdt(i,k,lna) = (dryvol_a(i,k)*voltonumb_amode(n)   &
         497             :                      - q(i,k,lna)) * deltatinv
         498             :                end do
         499             :             end do
         500             :          end if
         501             :          if (lnc > 0) then
         502             :             dotendqqcw(lnc) = .true.
         503             :             do k=top_lev,pver
         504             :                do i=1,ncol
         505             :                   dqqcwdt(i,k,lnc) = (dryvol_c(i,k)*voltonumb_amode(n)   &
         506             :                      - fldcw(i,k)) * deltatinv
         507             :                end do
         508             :             end do
         509             :          end if
         510             :       else
         511             :
         512             :
         513             :          !
         514             :          ! option 2 -- number prognosed (variable dgnum, fixed sigmag)
         515             :          !       Compute number tendencies to adjust numbers if they are outside
         516             :          !    the limits determined by current volume and dgnumlo/hi
         517             :          !       The interstitial and activated aerosol fractions can, at times,
         518             :          !    be the lower or upper tail of the "total" distribution.  Thus they
         519             :          !    can be expected to have a greater range of size parameters than
         520             :          !    what is specified for the total distribution (via dgnumlo/hi)
         521             :          !       When both the interstitial and activated dry volumes are positive,
         522             :          !    the adjustment strategy is to (1) adjust the interstitial and activated
         523             :          !    numbers towards relaxed bounds, then (2) adjust the total/combined
         524             :          !    number towards the primary bounds.
         525             :          !
         526             :          ! note
         527             :          !    v2nyy = voltonumblo_amode is proportional to dgnumlo**(-3),
         528             :          !            and produces the maximum allowed number for a given volume
         529             :          !    v2nxx = voltonumbhi_amode is proportional to dgnumhi**(-3),
         530             :          !            and produces the minimum allowed number for a given volume
         531             :          !    v2nxxrl and v2nyyrl are their "relaxed" equivalents.
         532             :          !            Setting frelaxadj=27=3**3 means that
         533             :          !            dgnumlo_relaxed = dgnumlo/3 and dgnumhi_relaxed = dgnumhi*3
         534             :          !
         535             :          ! if do_aitacc_transfer is .true., then
         536             :          !     for n=nacc, multiply v2nyy by 1.0e6 to effectively turn off the
         537             :          !         adjustment when number is too big (size is too small)
         538             :          !     for n=nait, divide   v2nxx by 1.0e6 to effectively turn off the
         539             :          !         adjustment when number is too small (size is too big)
         540             :          !OLD  however, do not change the v2nyyrl/v2nxxrl so that
         541             :          !OLD      the interstitial<-->activated adjustment is not changed
         542             :          !NEW  also change the v2nyyrl/v2nxxrl so that
         543             :          !NEW      the interstitial<-->activated adjustment is turned off
         544             :          !
         545             :       end if
         546             :       frelaxadj = 27.0_r8
         547             :       dumfac = exp(4.5_r8*alnsg_amode(n)**2)*pi/6.0_r8
         548             :       v2nxx = voltonumbhi_amode(n)
         549             :       v2nyy = voltonumblo_amode(n)
         550             :       v2nxxrl = v2nxx/frelaxadj
         551             :       v2nyyrl = v2nyy*frelaxadj
         552             :       dgnxx = dgnumhi_amode(n)
         553             :       dgnyy = dgnumlo_amode(n)
         554             :       if ( do_aitacc_transfer ) then
         555             :          if (n == nait) v2nxx = v2nxx/1.0e6_r8
         556             :          if (n == nacc) v2nyy = v2nyy*1.0e6_r8
         557             :          v2nxxrl = v2nxx/frelaxadj   ! NEW
         558             :          v2nyyrl = v2nyy*frelaxadj   ! NEW
         559             :       end if
         560             :
         561             :       if (do_adjust) then
         562             :          dotend(lna) = .true.
         563             :          dotendqqcw(lnc) = .true.
         564             :       end if
         565             :
         566             :       do  k = top_lev, pver
         567             :          do  i = 1, ncol
         568             :
         569             :             drv_a = dryvol_a(i,k)
         570             :             num_a0 = q(i,k,lna)
         571             :             num_a = max( 0.0_r8, num_a0 )
         572             :             drv_c = dryvol_c(i,k)
         573             :             num_c0 = fldcw(i,k)
         574             :             num_c = max( 0.0_r8, num_c0 )
         575             :
         576             :             if ( do_adjust) then
         577             :
         578             :                !
         579             :                ! do number adjustment for interstitial and activated particles
         580             :                !    adjustments that (1) make numbers non-negative or (2) make numbers
         581             :                !       zero when volume is zero are applied over time-scale deltat
         582             :                !    adjustments that bring numbers to within specified bounds are
         583             :                !       applied over time-scale tadj
         584             :                !
         585             :                if ((drv_a <= 0.0_r8) .and. (drv_c <= 0.0_r8)) then
         586             :                   ! both interstitial and activated volumes are zero
         587             :                   ! adjust both numbers to zero
         588             :                   num_a = 0.0_r8
         589             :                   dqdt(i,k,lna) = -num_a0*deltatinv
         590             :                   num_c = 0.0_r8
         591             :                   dqqcwdt(i,k,lnc) = -num_c0*deltatinv
         592             :                else if (drv_c <= 0.0_r8) then
         593             :                   ! activated volume is zero, so interstitial number/volume == total/combined
         594             :                   ! apply step 1 and 3, but skip the relaxed adjustment (step 2, see below)
         595             :                   num_c = 0.0_r8
         596             :                   dqqcwdt(i,k,lnc) = -num_c0*deltatinv
         597             :                   num_a1 = num_a
         598             :                   numbnd = max( drv_a*v2nxx, min( drv_a*v2nyy, num_a1 ) )
         599             :                   num_a  = num_a1 + (numbnd - num_a1)*fracadj
         600             :                   dqdt(i,k,lna) = (num_a - num_a0)*deltatinv
         601             :
         602             :                else if (drv_a <= 0.0_r8) then
         603             :                   ! interstitial volume is zero, treat similar to above
         604             :                   num_a = 0.0_r8
         605             :                   dqdt(i,k,lna) = -num_a0*deltatinv
         606             :                   num_c1 = num_c
         607             :                   numbnd = max( drv_c*v2nxx, min( drv_c*v2nyy, num_c1 ) )
         608             :                   num_c  = num_c1 + (numbnd - num_c1)*fracadj
         609             :                   dqqcwdt(i,k,lnc) = (num_c - num_c0)*deltatinv
         610             :                else
         611             :                   ! both volumes are positive
         612             :                   ! apply 3 adjustment steps
         613             :                   ! step1:  num_a,c0 --> num_a,c1 forces non-negative values
         614             :                   num_a1 = num_a
         615             :                   num_c1 = num_c
         616             :                   ! step2:  num_a,c1 --> num_a,c2 applies relaxed bounds to the interstitial
         617             :                   !    and activated number (individually)
         618             :                   !    if only only a or c changes, adjust the other in the opposite direction
         619             :                   !    as much as possible to conserve a+c
         620             :                   numbnd = max( drv_a*v2nxxrl, min( drv_a*v2nyyrl, num_a1 ) )
         621             :                   delnum_a2 = (numbnd - num_a1)*fracadj
         622             :                   num_a2 = num_a1 + delnum_a2
         623             :                   numbnd = max( drv_c*v2nxxrl, min( drv_c*v2nyyrl, num_c1 ) )
         624             :                   delnum_c2 = (numbnd - num_c1)*fracadj
         625             :                   num_c2 = num_c1 + delnum_c2
         626             :                   if ((delnum_a2 == 0.0_r8) .and. (delnum_c2 /= 0.0_r8)) then
         627             :                      num_a2 = max( drv_a*v2nxxrl, min( drv_a*v2nyyrl,   &
         628             :                         num_a1-delnum_c2 ) )
         629             :                   else if ((delnum_a2 /= 0.0_r8) .and. (delnum_c2 == 0.0_r8)) then
         630             :                      num_c2 = max( drv_c*v2nxxrl, min( drv_c*v2nyyrl,   &
         631             :                         num_c1-delnum_a2 ) )
         632             :                   end if
         633             :                   ! step3:  num_a,c2 --> num_a,c3 applies stricter bounds to the
         634             :                   !    combined/total number
         635             :                   drv_t = drv_a + drv_c
         636             :                   num_t2 = num_a2 + num_c2
         637             :                   delnum_a3 = 0.0_r8
         638             :                   delnum_c3 = 0.0_r8
         639             :                   if (num_t2 < drv_t*v2nxx) then
         640             :                      delnum_t3 = (drv_t*v2nxx - num_t2)*fracadj
         641             :                      ! if you are here then (num_a2 < drv_a*v2nxx) and/or
         642             :                      !                      (num_c2 < drv_c*v2nxx) must be true
         643             :                      if ((num_a2 < drv_a*v2nxx) .and. (num_c2 < drv_c*v2nxx)) then
         644             :                         delnum_a3 = delnum_t3*(num_a2/num_t2)
         645             :                         delnum_c3 = delnum_t3*(num_c2/num_t2)
         646             :                      else if (num_c2 < drv_c*v2nxx) then
         647             :                         delnum_c3 = delnum_t3
         648             :                      else if (num_a2 < drv_a*v2nxx) then
         649             :                         delnum_a3 = delnum_t3
         650             :                      end if
         651             :                   else if (num_t2 > drv_t*v2nyy) then
         652             :                      delnum_t3 = (drv_t*v2nyy - num_t2)*fracadj
         653             :                      ! if you are here then (num_a2 > drv_a*v2nyy) and/or
         654             :                      !                      (num_c2 > drv_c*v2nyy) must be true
         655             :                      if ((num_a2 > drv_a*v2nyy) .and. (num_c2 > drv_c*v2nyy)) then
         656             :                         delnum_a3 = delnum_t3*(num_a2/num_t2)
         657             :                         delnum_c3 = delnum_t3*(num_c2/num_t2)
         658             :                      else if (num_c2 > drv_c*v2nyy) then
         659             :                         delnum_c3 = delnum_t3
         660             :                      else if (num_a2 > drv_a*v2nyy) then
         661             :                         delnum_a3 = delnum_t3
         662             :                      end if
         663             :                   end if
         664             :                   num_a = num_a2 + delnum_a3
         665             :                   dqdt(i,k,lna) = (num_a - num_a0)*deltatinv
         666             :                   num_c = num_c2 + delnum_c3
         667             :                   dqqcwdt(i,k,lnc) = (num_c - num_c0)*deltatinv
         668             :                end if
         669             :
         670             :             end if ! do_adjust
         671             :
         672             :             !
         673             :             ! now compute current dgn and v2n
         674             :             !
         675             :             if (drv_a > 0.0_r8) then
         676             :                if (num_a <= drv_a*v2nxx) then
         677             :                   dgncur_a(i,k,n) = dgnxx
         678             :                   v2ncur_a(i,k,n) = v2nxx
         679             :                else if (num_a >= drv_a*v2nyy) then
         680             :                   dgncur_a(i,k,n) = dgnyy
         681             :                   v2ncur_a(i,k,n) = v2nyy
         682             :                else
         683             :                   dgncur_a(i,k,n) = (drv_a/(dumfac*num_a))**third
         684             :                   v2ncur_a(i,k,n) = num_a/drv_a
         685             :                end if
         686             :             end if
         687             :             pdel_fac = pdel(i,k)/gravit   ! = rho*dz
         688             :             jac = 1
         689             :             qsrflx(i,lna,1,jac) = qsrflx(i,lna,1,jac) + max(0.0_r8,dqdt(i,k,lna))*pdel_fac
         690             :             qsrflx(i,lna,2,jac) = qsrflx(i,lna,2,jac) + min(0.0_r8,dqdt(i,k,lna))*pdel_fac
         691             :
         692             :             if (drv_c > 0.0_r8) then
         693             :                if (num_c <= drv_c*v2nxx) then
         694             :                   dgncur_c(i,k,n) = dgnumhi_amode(n)
         695             :                   v2ncur_c(i,k,n) = v2nxx
         696             :                else if (num_c >= drv_c*v2nyy) then
         697             :                   dgncur_c(i,k,n) = dgnumlo_amode(n)
         698             :                   v2ncur_c(i,k,n) = v2nyy
         699             :                else
         700             :                   dgncur_c(i,k,n) = (drv_c/(dumfac*num_c))**third
         701             :                   v2ncur_c(i,k,n) = num_c/drv_c
         702             :                end if
         703             :             end if
         704             :             jac = 2
         705             :             qsrflx(i,lnc,1,jac) = qsrflx(i,lnc,1,jac) + max(0.0_r8,dqqcwdt(i,k,lnc))*pdel_fac
         706             :             qsrflx(i,lnc,2,jac) = qsrflx(i,lnc,2,jac) + min(0.0_r8,dqqcwdt(i,k,lnc))*pdel_fac
         707             :
         708             :
         709             :             ! save number and dryvol for aitken <--> accum renaming
         710             :             if ( do_aitacc_transfer ) then
         711             :                if (n == nait) then
         712             :                   drv_a_aitsv(i,k) = drv_a
         713             :                   num_a_aitsv(i,k) = num_a
         714             :                   drv_c_aitsv(i,k) = drv_c
         715             :                   num_c_aitsv(i,k) = num_c
         716             :                else if (n == nacc) then
         717             :                   drv_a_accsv(i,k) = drv_a
         718             :                   num_a_accsv(i,k) = num_a
         719             :                   drv_c_accsv(i,k) = drv_c
         720             :                   num_c_accsv(i,k) = num_c
         721             :                end if
         722             :             end if
         723             :             drv_a_sv(i,k,n) = drv_a
         724             :             num_a_sv(i,k,n) = num_a
         725             :             drv_c_sv(i,k,n) = drv_c
         726             :             num_c_sv(i,k,n) = num_c
         727             :
         728             :          end do
         729             :       end do
         730             :
         731             :
         732             :       !
         733             :       ! option 3 -- number and surface prognosed (variable dgnum and sigmag)
         734             :       !             this is not implemented
         735             :       !
         736             :    end do  ! do n = 1, ntot_amode
         737             :
         738             :
         739             :    !
         740             :    !
         741             :    ! the following section (from here to label 49000)
         742             :    !    does aitken <--> accum mode transfer
         743             :    !
         744             :    ! when the aitken mode mean size is too big, the largest
         745             :    !    aitken particles are transferred into the accum mode
         746             :    !    to reduce the aitken mode mean size
         747             :    ! when the accum mode mean size is too small, the smallest
         748             :    !    accum particles are transferred into the aitken mode
         749             :    !    to increase the accum mode mean size
         750             :    !
         751             :    !
         752             :    ixfer_ait2acc_sv(:,:) = 0
         753             :    ixfer_acc2ait_sv(:,:) = 0
         754             :    if ( do_aitacc_transfer ) then
         755             :
         756             :       ! old - on time first step, npair_renamexf will be <= 0,
         757             :       !       in which case need to do modal_aero_rename_init
         758             :       ! new - init is now done through chem_init and things below it
         759             :       if (npair_renamexf .le. 0) then
         760             :          npair_renamexf = 0
         761             :          !        call modal_aero_rename_init
         762             :          if (npair_renamexf .le. 0) then
         763             :             write( 6, '(//a//)' )   &
         764             :                '*** modal_aero_calcaersize_sub error -- npair_renamexf <= 0'
         765             :             call endrun( 'modal_aero_calcaersize_sub error' )
         766             :          end if
         767             :       end if
         768             :
         769             :       ! check that renaming ipair=1 is aitken-->accum
         770             :       ipair = 1
         771             :       if ((modefrm_renamexf(ipair) .ne. nait) .or.   &
         772             :          (modetoo_renamexf(ipair) .ne. nacc)) then
         773             :          write( 6, '(//2a//)' )   &
         774             :             '*** modal_aero_calcaersize_sub error -- ',   &
         775             :             'modefrm/too_renamexf(1) are wrong'
         776             :          call endrun( 'modal_aero_calcaersize_sub error' )
         777             :       end if
         778             :
         779             :       ! set dotend() for species that will be transferred
         780             :       do iq = 1, nspecfrm_renamexf(ipair)
         781             :          lsfrm = lspecfrma_renamexf(iq,ipair)
         782             :          lstoo = lspectooa_renamexf(iq,ipair)
         783             :          if ((lsfrm > 0) .and. (lstoo > 0)) then
         784             :             dotend(lsfrm) = .true.
         785             :             dotend(lstoo) = .true.
         786             :          end if
         787             :          lsfrm = lspecfrmc_renamexf(iq,ipair)
         788             :          lstoo = lspectooc_renamexf(iq,ipair)
         789             :          if ((lsfrm > 0) .and. (lstoo > 0)) then
         790             :             dotendqqcw(lsfrm) = .true.
         791             :             dotendqqcw(lstoo) = .true.
         792             :          end if
         793             :       end do
         794             :
         795             :       ! identify accum species cannot be transferred to aitken mode
         796             :       noxf_acc2ait(:) = .true.
         797             :       do l1 = 1, nspec_amode(nacc)
         798             :          la = lmassptr_amode(l1,nacc)
         799             :          do iq = 1, nspecfrm_renamexf(ipair)
         800             :             if (lspectooa_renamexf(iq,ipair) == la) then
         801             :                noxf_acc2ait(l1) = .false.
         802             :             end if
         803             :          end do
         804             :       end do
         805             :
         806             :       ! v2nzz is voltonumb at the "geometrically-defined" mid-point
         807             :       ! between the aitken and accum modes
         808             :       v2nzz = sqrt(voltonumb_amode(nait)*voltonumb_amode(nacc))
         809             :
         810             :       ! loop over columns and levels
         811             :       do  k = top_lev, pver
         812             :          do  i = 1, ncol
         813             :
         814             :             pdel_fac = pdel(i,k)/gravit   ! = rho*dz
         815             :             xfertend_num(:,:) = 0.0_r8
         816             :
         817             :             ! compute aitken --> accum transfer rates
         818             :             ixfer_ait2acc = 0
         819             :             xfercoef_num_ait2acc = 0.0_r8
         820             :             xfercoef_vol_ait2acc = 0.0_r8
         821             :
         822             :             drv_t = drv_a_aitsv(i,k) + drv_c_aitsv(i,k)
         823             :             num_t = num_a_aitsv(i,k) + num_c_aitsv(i,k)
         824             :             if (drv_t > 0.0_r8) then
         825             :                if (num_t < drv_t*v2nzz) then
         826             :                   ixfer_ait2acc = 1
         827             :                   if (num_t < drv_t*voltonumb_amode(nacc)) then
         828             :                      xferfrac_num_ait2acc = 1.0_r8
         829             :                      xferfrac_vol_ait2acc = 1.0_r8
         830             :                   else
         831             :                      xferfrac_vol_ait2acc = ((num_t/drv_t) - v2nzz)/   &
         832             :                         (voltonumb_amode(nacc) - v2nzz)
         833             :                      xferfrac_num_ait2acc = xferfrac_vol_ait2acc*   &
         834             :                         (drv_t*voltonumb_amode(nacc)/num_t)
         835             :                      if ((xferfrac_num_ait2acc <= 0.0_r8) .or.   &
         836             :                         (xferfrac_vol_ait2acc <= 0.0_r8)) then
         837             :                         xferfrac_num_ait2acc = 0.0_r8
         838             :                         xferfrac_vol_ait2acc = 0.0_r8
         839             :                      else if ((xferfrac_num_ait2acc >= 1.0_r8) .or.   &
         840             :                         (xferfrac_vol_ait2acc >= 1.0_r8)) then
         841             :                         xferfrac_num_ait2acc = 1.0_r8
         842             :                         xferfrac_vol_ait2acc = 1.0_r8
         843             :                      end if
         844             :                   end if
         845             :                   xfercoef_num_ait2acc = xferfrac_num_ait2acc*tadjinv
         846             :                   xfercoef_vol_ait2acc = xferfrac_vol_ait2acc*tadjinv
         847             :                   xfertend_num(1,1) = num_a_aitsv(i,k)*xfercoef_num_ait2acc
         848             :                   xfertend_num(1,2) = num_c_aitsv(i,k)*xfercoef_num_ait2acc
         849             :                end if
         850             :             end if
         851             :
         852             :             ! compute accum --> aitken transfer rates
         853             :             ! accum may have some species (seasalt, dust, poa, lll) that are
         854             :             !    not in aitken mode
         855             :             ! so first divide the accum drv & num into not-transferred (noxf) species
         856             :             !    and transferred species, and use the transferred-species
         857             :             !    portion in what follows
         858             :             ixfer_acc2ait = 0
         859             :             xfercoef_num_acc2ait = 0.0_r8
         860             :             xfercoef_vol_acc2ait = 0.0_r8
         861             :
         862             :             drv_t = drv_a_accsv(i,k) + drv_c_accsv(i,k)
         863             :             num_t = num_a_accsv(i,k) + num_c_accsv(i,k)
         864             :             drv_a_noxf = 0.0_r8
         865             :             drv_c_noxf = 0.0_r8
         866             :             if (drv_t > 0.0_r8) then
         867             :                if (num_t > drv_t*v2nzz) then
         868             :                   do l1 = 1, nspec_amode(nacc)
         869             :
         870             :                      if ( noxf_acc2ait(l1) ) then
         871             :                         ! need qmass*dummwdens = (kg/kg-air) * [1/(kg/m3)] = m3/kg-air
         872             :                         dummwdens = 1.0_r8 / specdens_amode(l1,nacc)
         873             :                         la = lmassptr_amode(l1,nacc)
         874             :                         drv_a_noxf = drv_a_noxf    &
         875             :                            + max(0.0_r8,q(i,k,la))*dummwdens
         876             :                         lc = lmassptrcw_amode(l1,nacc)
         877             :
         878             :                         fldcw => qqcw_get_field(pbuf,lmassptrcw_amode(l1,nacc),lchnk)
         879             :                         drv_c_noxf = drv_c_noxf    &
         880             :                            + max(0.0_r8,fldcw(i,k))*dummwdens
         881             :                      end if
         882             :                   end do
         883             :                   drv_t_noxf = drv_a_noxf + drv_c_noxf
         884             :                   num_t_noxf = drv_t_noxf*voltonumblo_amode(nacc)
         885             :                   num_t0 = num_t
         886             :                   drv_t0 = drv_t
         887             :                   num_t = max( 0.0_r8, num_t - num_t_noxf )
         888             :                   drv_t = max( 0.0_r8, drv_t - drv_t_noxf )
         889             :                end if
         890             :             end if
         891             :
         892             :             if (drv_t > 0.0_r8) then
         893             :                if (num_t > drv_t*v2nzz) then
         894             :                   ixfer_acc2ait = 1
         895             :                   if (num_t > drv_t*voltonumb_amode(nait)) then
         896             :                      xferfrac_num_acc2ait = 1.0_r8
         897             :                      xferfrac_vol_acc2ait = 1.0_r8
         898             :                   else
         899             :                      xferfrac_vol_acc2ait = ((num_t/drv_t) - v2nzz)/   &
         900             :                         (voltonumb_amode(nait) - v2nzz)
         901             :                      xferfrac_num_acc2ait = xferfrac_vol_acc2ait*   &
         902             :                         (drv_t*voltonumb_amode(nait)/num_t)
         903             :                      if ((xferfrac_num_acc2ait <= 0.0_r8) .or.   &
         904             :                         (xferfrac_vol_acc2ait <= 0.0_r8)) then
         905             :                         xferfrac_num_acc2ait = 0.0_r8
         906             :                         xferfrac_vol_acc2ait = 0.0_r8
         907             :                      else if ((xferfrac_num_acc2ait >= 1.0_r8) .or.   &
         908             :                         (xferfrac_vol_acc2ait >= 1.0_r8)) then
         909             :                         xferfrac_num_acc2ait = 1.0_r8
         910             :                         xferfrac_vol_acc2ait = 1.0_r8
         911             :                      end if
         912             :                   end if
         913             :                   duma = 1.0e-37_r8
         914             :                   xferfrac_num_acc2ait = xferfrac_num_acc2ait*   &
         915             :                      num_t/max( duma, num_t0 )
         916             :                   xfercoef_num_acc2ait = xferfrac_num_acc2ait*tadjinv
         917             :                   xfercoef_vol_acc2ait = xferfrac_vol_acc2ait*tadjinv
         918             :                   xfertend_num(2,1) = num_a_accsv(i,k)*xfercoef_num_acc2ait
         919             :                   xfertend_num(2,2) = num_c_accsv(i,k)*xfercoef_num_acc2ait
         920             :                end if
         921             :             end if
         922             :
         923             :             ! jump to end-of-loop if no transfer is needed at current i,k
         924             :             if (ixfer_ait2acc+ixfer_acc2ait > 0) then
         925             :                ixfer_ait2acc_sv(i,k) = ixfer_ait2acc
         926             :                ixfer_acc2ait_sv(i,k) = ixfer_acc2ait
         927             :
         928             :                !
         929             :                ! compute new dgncur & v2ncur for aitken & accum modes
         930             :                !
         931             :                ! currently inactive
         932             :                do n = nait, nacc, (nacc-nait)
         933             :                   if (n .eq. nait) then
         934             :                      duma = (xfertend_num(1,1) - xfertend_num(2,1))*deltat
         935             :                      num_a     = max( 0.0_r8, num_a_aitsv(i,k) - duma )
         936             :                      num_a_acc = max( 0.0_r8, num_a_accsv(i,k) + duma )
         937             :                      duma = (drv_a_aitsv(i,k)*xfercoef_vol_ait2acc -   &
         938             :                         (drv_a_accsv(i,k)-drv_a_noxf)*xfercoef_vol_acc2ait)*deltat
         939             :                      drv_a     = max( 0.0_r8, drv_a_aitsv(i,k) - duma )
         940             :                      drv_a_acc = max( 0.0_r8, drv_a_accsv(i,k) + duma )
         941             :                      duma = (xfertend_num(1,2) - xfertend_num(2,2))*deltat
         942             :                      num_c     = max( 0.0_r8, num_c_aitsv(i,k) - duma )
         943             :                      num_c_acc = max( 0.0_r8, num_c_accsv(i,k) + duma )
         944             :                      duma = (drv_c_aitsv(i,k)*xfercoef_vol_ait2acc -   &
         945             :                         (drv_c_accsv(i,k)-drv_c_noxf)*xfercoef_vol_acc2ait)*deltat
         946             :                      drv_c     = max( 0.0_r8, drv_c_aitsv(i,k) - duma )
         947             :                      drv_c_acc = max( 0.0_r8, drv_c_accsv(i,k) + duma )
         948             :                   else
         949             :                      num_a = num_a_acc
         950             :                      drv_a = drv_a_acc
         951             :                      num_c = num_c_acc
         952             :                      drv_c = drv_c_acc
         953             :                   end if
         954             :
         955             :                   if (drv_a > 0.0_r8) then
         956             :                      if (num_a <= drv_a*voltonumbhi_amode(n)) then
         957             :                         dgncur_a(i,k,n) = dgnumhi_amode(n)
         958             :                         v2ncur_a(i,k,n) = voltonumbhi_amode(n)
         959             :                      else if (num_a >= drv_a*voltonumblo_amode(n)) then
         960             :                         dgncur_a(i,k,n) = dgnumlo_amode(n)
         961             :                         v2ncur_a(i,k,n) = voltonumblo_amode(n)
         962             :                      else
         963             :                         dgncur_a(i,k,n) = (drv_a/(dumfac*num_a))**third
         964             :                         v2ncur_a(i,k,n) = num_a/drv_a
         965             :                      end if
         966             :                   else
         967             :                      dgncur_a(i,k,n) = dgnum_amode(n)
         968             :                      v2ncur_a(i,k,n) = voltonumb_amode(n)
         969             :                   end if
         970             :
         971             :                   if (drv_c > 0.0_r8) then
         972             :                      if (num_c <= drv_c*voltonumbhi_amode(n)) then
         973             :                         dgncur_c(i,k,n) = dgnumhi_amode(n)
         974             :                         v2ncur_c(i,k,n) = voltonumbhi_amode(n)
         975             :                      else if (num_c >= drv_c*voltonumblo_amode(n)) then
         976             :                         dgncur_c(i,k,n) = dgnumlo_amode(n)
         977             :                         v2ncur_c(i,k,n) = voltonumblo_amode(n)
         978             :                      else
         979             :                         dgncur_c(i,k,n) = (drv_c/(dumfac*num_c))**third
         980             :                         v2ncur_c(i,k,n) = num_c/drv_c
         981             :                      end if
         982             :                   else
         983             :                      dgncur_c(i,k,n) = dgnum_amode(n)
         984             :                      v2ncur_c(i,k,n) = voltonumb_amode(n)
         985             :                   end if
         986             :
         987             :                end do
         988             :
         989             :
         990             :                !
         991             :                ! compute tendency amounts for aitken <--> accum transfer
         992             :                !
         993             :
         994             :                if ( masterproc ) then
         995             :                   if (idiagaa > 0) then
         996             :                      do j = 1, 2
         997             :                         do iq = 1, nspecfrm_renamexf(ipair)
         998             :                            do jac = 1, 2
         999             :                               if (j .eq. 1) then
        1000             :                                  if (jac .eq. 1) then
        1001             :                                     lsfrm = lspecfrma_renamexf(iq,ipair)
        1002             :                                     lstoo = lspectooa_renamexf(iq,ipair)
        1003             :                                  else
        1004             :                                     lsfrm = lspecfrmc_renamexf(iq,ipair)
        1005             :                                     lstoo = lspectooc_renamexf(iq,ipair)
        1006             :                                  end if
        1007             :                               else
        1008             :                                  if (jac .eq. 1) then
        1009             :                                     lsfrm = lspectooa_renamexf(iq,ipair)
        1010             :                                     lstoo = lspecfrma_renamexf(iq,ipair)
        1011             :                                  else
        1012             :                                     lsfrm = lspectooc_renamexf(iq,ipair)
        1013             :                                     lstoo = lspecfrmc_renamexf(iq,ipair)
        1014             :                                  end if
        1015             :                               end if
        1016             :                               write( 6, '(a,3i3,2i4)' ) 'calcsize j,iq,jac, lsfrm,lstoo',   &
        1017             :                                  j,iq,jac, lsfrm,lstoo
        1018             :                            end do
        1019             :                         end do
        1020             :                      end do
        1021             :                   end if
        1022             :                end if
        1023             :                idiagaa = -1
        1024             :
        1025             :
        1026             :                ! j=1 does aitken-->accum; j=2 does accum-->aitken
        1027             :                do  j = 1, 2
        1028             :
        1029             :                   if ((j .eq. 1 .and. ixfer_ait2acc > 0) .or. &
        1030             :                      (j .eq. 2 .and. ixfer_acc2ait > 0)) then
        1031             :
        1032             :                      jsrflx = j+2
        1033             :                      if (j .eq. 1) then
        1034             :                         xfercoef = xfercoef_vol_ait2acc
        1035             :                      else
        1036             :                         xfercoef = xfercoef_vol_acc2ait
        1037             :                      end if
        1038             :
        1039             :                      do  iq = 1, nspecfrm_renamexf(ipair)
        1040             :
        1041             :                         ! jac=1 does interstitial ("_a"); jac=2 does activated ("_c");
        1042             :                         do  jac = 1, 2
        1043             :
        1044             :                            ! the lspecfrma_renamexf (and lspecfrmc_renamexf) are aitken species
        1045             :                            ! the lspectooa_renamexf (and lspectooc_renamexf) are accum  species
        1046             :                            ! for j=1, want lsfrm=aitken species, lstoo=accum  species
        1047             :                            ! for j=2, want lsfrm=accum  species,  lstoo=aitken species
        1048             :                            if (j .eq. 1) then
        1049             :                               if (jac .eq. 1) then
        1050             :                                  lsfrm = lspecfrma_renamexf(iq,ipair)
        1051             :                                  lstoo = lspectooa_renamexf(iq,ipair)
        1052             :                               else
        1053             :                                  lsfrm = lspecfrmc_renamexf(iq,ipair)
        1054             :                                  lstoo = lspectooc_renamexf(iq,ipair)
        1055             :                               end if
        1056             :                            else
        1057             :                               if (jac .eq. 1) then
        1058             :                                  lsfrm = lspectooa_renamexf(iq,ipair)
        1059             :                                  lstoo = lspecfrma_renamexf(iq,ipair)
        1060             :                               else
        1061             :                                  lsfrm = lspectooc_renamexf(iq,ipair)
        1062             :                                  lstoo = lspecfrmc_renamexf(iq,ipair)
        1063             :                               end if
        1064             :                            end if
        1065             :
        1066             :                            if ((lsfrm > 0) .and. (lstoo > 0)) then
        1067             :                               if (jac .eq. 1) then
        1068             :                                  if (iq .eq. 1) then
        1069             :                                     xfertend = xfertend_num(j,jac)
        1070             :                                  else
        1071             :                                     xfertend = max(0.0_r8,q(i,k,lsfrm))*xfercoef
        1072             :                                  end if
        1073             :                                  dqdt(i,k,lsfrm) = dqdt(i,k,lsfrm) - xfertend
        1074             :                                  dqdt(i,k,lstoo) = dqdt(i,k,lstoo) + xfertend
        1075             :                               else
        1076             :                                  if (iq .eq. 1) then
        1077             :                                     xfertend = xfertend_num(j,jac)
        1078             :                                  else
        1079             :                                     fldcw => qqcw_get_field(pbuf,lsfrm,lchnk)
        1080             :                                     xfertend = max(0.0_r8,fldcw(i,k))*xfercoef
        1081             :                                  end if
        1082             :                                  dqqcwdt(i,k,lsfrm) = dqqcwdt(i,k,lsfrm) - xfertend
        1083             :                                  dqqcwdt(i,k,lstoo) = dqqcwdt(i,k,lstoo) + xfertend
        1084             :                               end if
        1085             :                               qsrflx(i,lsfrm,jsrflx,jac) = qsrflx(i,lsfrm,jsrflx,jac) - xfertend*pdel_fac
        1086             :                               qsrflx(i,lstoo,jsrflx,jac) = qsrflx(i,lstoo,jsrflx,jac) + xfertend*pdel_fac
        1087             :                            end if
        1088             :
        1089             :                         end do
        1090             :                      end do
        1091             :                   end if
        1092             :                end do
        1093             :
        1094             :             end if
        1095             :          end do
        1096             :       end do
        1097             :
        1098             :
        1099             :    end if  !  do_aitacc_transfer
        1100             :    lsfrm = -123456789   ! executable statement for debugging
        1101             :
        1102             :
        1103             :    !
        1104             :    ! apply tendencies to cloud-borne species MRs
        1105             :    !
        1106             :    do l = 1, pcnst
        1107             :       lc = l
        1108             :       if ( lc>0 .and. dotendqqcw(lc) ) then
        1109             :          fldcw=> qqcw_get_field(pbuf,l,lchnk)
        1110             :          do k = top_lev, pver
        1111             :             do i = 1, ncol
        1112             :                fldcw(i,k) = max( 0.0_r8,   &
        1113             :                   (fldcw(i,k) + dqqcwdt(i,k,lc)*deltat) )
        1114             :             end do
        1115             :          end do
        1116             :       end if
        1117             :    end do
        1118             :
        1119             :    !
        1120             :    ! do outfld calls
        1121             :    !
        1122             :
        1123             :    ! history fields for number-adjust source-sink for all modes
        1124             :    if ( .not. do_adjust ) return
        1125             :
        1126             :    do n = 1, ntot_amode
        1127             :       if (mprognum_amode(n) <= 0) cycle
        1128             :
        1129             :       do jac = 1, 2
        1130             :          if (jac == 1) then
        1131             :             l = numptr_amode(n)
        1132             :             tmpnamea = cnst_name(l)
        1133             :          else
        1134             :             l = numptrcw_amode(n)
        1135             :             tmpnamea = cnst_name_cw(l)
        1136             :          end if
        1137             :          fieldname = trim(tmpnamea) // '_sfcsiz1'
        1138             :          call outfld( fieldname, qsrflx(:,l,1,jac), pcols, lchnk)
        1139             :
        1140             :          fieldname = trim(tmpnamea) // '_sfcsiz2'
        1141             :          call outfld( fieldname, qsrflx(:,l,2,jac), pcols, lchnk)
        1142             :       end do   ! jac = ...
        1143             :
        1144             :    end do   ! n = ...
        1145             :
        1146             :
        1147             :    ! history fields for aitken-accum transfer
        1148             :    if ( .not. do_aitacc_transfer ) return
        1149             :
        1150             :    do iq = 1, nspecfrm_renamexf(ipair)
        1151             :
        1152             :       ! jac=1 does interstitial ("_a"); jac=2 does activated ("_c");
        1153             :       do jac = 1, 2
        1154             :
        1155             :          ! the lspecfrma_renamexf (and lspecfrmc_renamexf) are aitken species
        1156             :          ! the lspectooa_renamexf (and lspectooc_renamexf) are accum  species
        1157             :          if (jac .eq. 1) then
        1158             :             lsfrm = lspecfrma_renamexf(iq,ipair)
        1159             :             lstoo = lspectooa_renamexf(iq,ipair)
        1160             :          else
        1161             :             lsfrm = lspecfrmc_renamexf(iq,ipair)
        1162             :             lstoo = lspectooc_renamexf(iq,ipair)
        1163             :          end if
        1164             :          if ((lsfrm <= 0) .or. (lstoo <= 0)) cycle
        1165             :
        1166             :          if (jac .eq. 1) then
        1167             :             tmpnamea = cnst_name(lsfrm)
        1168             :             tmpnameb = cnst_name(lstoo)
        1169             :          else
        1170             :             tmpnamea = cnst_name_cw(lsfrm)
        1171             :             tmpnameb = cnst_name_cw(lstoo)
        1172             :          end if
        1173             :          if ((lsfrm <= 0) .or. (lstoo <= 0)) cycle
        1174             :
        1175             :          fieldname = trim(tmpnamea) // '_sfcsiz3'
        1176             :          call outfld( fieldname, qsrflx(:,lsfrm,3,jac), pcols, lchnk)
        1177             :
        1178             :          fieldname = trim(tmpnameb) // '_sfcsiz3'
        1179             :          call outfld( fieldname, qsrflx(:,lstoo,3,jac), pcols, lchnk)
        1180             :
        1181             :          fieldname = trim(tmpnamea) // '_sfcsiz4'
        1182             :          call outfld( fieldname, qsrflx(:,lsfrm,4,jac), pcols, lchnk)
        1183             :
        1184             :          fieldname = trim(tmpnameb) // '_sfcsiz4'
        1185             :          call outfld( fieldname, qsrflx(:,lstoo,4,jac), pcols, lchnk)
        1186             :
        1187             :       end do   ! jac = ...
        1188             :    end do   ! iq = ...
        1189             :
        1190             :    call modal_aero_calcdry(state, pbuf)
        1191             :
        1192             : #endif
        1193             :
        1194           0 : end subroutine modal_aero_calcsize_sub
        1195             :
        1196             :
        1197             : !----------------------------------------------------------------------
        1198             :
        1199             :
        1200           0 : subroutine modal_aero_calcsize_diag(state, pbuf, list_idx_in, dgnum_m, &
        1201             :                                     hygro_m, dryvol_m, dryrad_m, drymass_m, so4dryvol_m, naer_m)
        1202             :
        1203             :    !-----------------------------------------------------------------------
        1204             :    !
        1205             :    ! Calculate aerosol size distribution parameters
        1206             :    !
        1207             :    ! ***N.B.*** DGNUM for the modes in the climate list are put directly into
        1208             :    !            the physics buffer.  For diagnostic list calculations use the
        1209             :    !            optional list_idx and dgnum args.
        1210             :    !-----------------------------------------------------------------------
        1211             :
        1212             :    ! arguments
        1213             :    type(physics_state), intent(in), target :: state   ! Physics state variables
        1214             :    type(physics_buffer_desc), pointer :: pbuf(:)      ! physics buffer
        1215             :
        1216             :    integer,  optional, intent(in)   :: list_idx_in    ! diagnostic list index
        1217             :    real(r8), optional, pointer      :: dgnum_m(:,:,:) ! interstital aerosol dry number mode radius (m)
        1218             :    real(r8), optional, pointer      :: hygro_m(:,:,:)
        1219             :    real(r8), optional, pointer      :: dryvol_m(:,:,:)
        1220             :    real(r8), optional, pointer      :: dryrad_m(:,:,:)
        1221             :    real(r8), optional, pointer      :: drymass_m(:,:,:)
        1222             :    real(r8), optional, pointer      :: so4dryvol_m(:,:,:)
        1223             :    real(r8), optional, pointer      :: naer_m(:,:,:)
        1224             :
        1225             :
        1226             :    ! local
        1227             :    integer  :: i, k, l1, n
        1228             :    integer  :: lchnk, ncol
        1229             :    integer  :: list_idx, stat
        1230             :    integer  :: nmodes
        1231             :    integer  :: nspec
        1232             :
        1233           0 :    real(r8), pointer :: dgncur_a(:,:) ! (pcols,pver)
        1234             :
        1235             :
        1236             :    real(r8), parameter :: third = 1.0_r8/3.0_r8
        1237             :
        1238           0 :    real(r8), pointer :: mode_num(:,:) ! mode number mixing ratio
        1239           0 :    real(r8), pointer :: specmmr(:,:)  ! specie mmr
        1240             :    real(r8)          :: specdens      ! specie density
        1241             :
        1242             :    real(r8) :: dryvol_a(pcols,pver)   ! interstital aerosol dry volume (cm^3/mol_air)
        1243             :
        1244             :    real(r8) :: dgnum, dgnumhi, dgnumlo
        1245             :    real(r8) :: dgnyy, dgnxx           ! dgnumlo/hi of current mode
        1246             :    real(r8) :: drv_a                  ! dry volume (cm3/mol_air)
        1247             :    real(r8) :: dumfac, dummwdens      ! work variables
        1248             :    real(r8) :: num_a0                 ! initial number (#/mol_air)
        1249             :    real(r8) :: num_a                  ! final number (#/mol_air)
        1250             :    real(r8) :: voltonumbhi, voltonumblo
        1251             :    real(r8) :: v2nyy, v2nxx           ! voltonumblo/hi of current mode
        1252             :    real(r8) :: sigmag, alnsg
        1253             :    !-----------------------------------------------------------------------
        1254             :
        1255           0 :    lchnk = state%lchnk
        1256           0 :    ncol  = state%ncol
        1257             :
        1258           0 :    list_idx = 0  ! climate list by default
        1259           0 :    if (present(list_idx_in)) list_idx = list_idx_in
        1260             :
        1261           0 :    call rad_cnst_get_info(list_idx, nmodes=nmodes)
        1262             :
        1263           0 :    if (list_idx /= 0) then
        1264           0 :       if (.not. present(dgnum_m)) then
        1265             :          call endrun('modal_aero_calcsize_diag called for'// &
        1266           0 :                      'diagnostic list but dgnum_m pointer not present')
        1267             :       end if
        1268           0 :       if (.not. associated(dgnum_m)) then
        1269             :          call endrun('modal_aero_calcsize_diag called for'// &
        1270           0 :             'diagnostic list but dgnum_m not associated')
        1271             :       end if
        1272             :
        1273           0 :       if (.not. present(hygro_m)) then
        1274             :          call endrun('modal_aero_calcsize_diag called for'// &
        1275           0 :                      'diagnostic list but hygro_m pointer not present')
        1276             :       end if
        1277           0 :       if (.not. associated(hygro_m)) then
        1278             :          call endrun('modal_aero_calcsize_diag called for'// &
        1279           0 :             'diagnostic list but hygro_m not associated')
        1280             :       end if
        1281             :
        1282           0 :       if (.not. present(dryvol_m)) then
        1283             :          call endrun('modal_aero_calcsize_diag called for'// &
        1284           0 :                      'diagnostic list but dryvol_m pointer not present')
        1285             :       end if
        1286           0 :       if (.not. associated(dryvol_m)) then
        1287             :          call endrun('modal_aero_calcsize_diag called for'// &
        1288           0 :             'diagnostic list but dryvol_m not associated')
        1289             :       end if
        1290             :
        1291           0 :       if (.not. present(dryrad_m)) then
        1292             :          call endrun('modal_aero_calcsize_diag called for'// &
        1293           0 :                      'diagnostic list but dryrad_m pointer not present')
        1294             :       end if
        1295           0 :       if (.not. associated(dryrad_m)) then
        1296             :          call endrun('modal_aero_calcsize_diag called for'// &
        1297           0 :             'diagnostic list but dryrad_m not associated')
        1298             :       end if
        1299             :
        1300           0 :       if (.not. present(drymass_m)) then
        1301             :          call endrun('modal_aero_calcsize_diag called for'// &
        1302           0 :                      'diagnostic list but drymass_m pointer not present')
        1303             :       end if
        1304           0 :       if (.not. associated(drymass_m)) then
        1305             :          call endrun('modal_aero_calcsize_diag called for'// &
        1306           0 :             'diagnostic list but drymass_m not associated')
        1307             :       end if
        1308             :
        1309           0 :       if (.not. present(so4dryvol_m)) then
        1310             :          call endrun('modal_aero_calcsize_diag called for'// &
        1311           0 :                      'diagnostic list but so4dryvol_m pointer not present')
        1312             :       end if
        1313           0 :       if (.not. associated(so4dryvol_m)) then
        1314             :          call endrun('modal_aero_calcsize_diag called for'// &
        1315           0 :             'diagnostic list but so4dryvol_m not associated')
        1316             :       end if
        1317             :
        1318           0 :       if (.not. present(naer_m)) then
        1319             :          call endrun('modal_aero_calcsize_diag called for'// &
        1320           0 :                      'diagnostic list but naer_m pointer not present')
        1321             :       end if
        1322           0 :       if (.not. associated(naer_m)) then
        1323             :          call endrun('modal_aero_calcsize_diag called for'// &
        1324           0 :             'diagnostic list but naer_m not associated')
        1325             :       end if
        1326             :
        1327             :    end if
        1328             :
        1329           0 :    do n = 1, nmodes
        1330             :
        1331           0 :       if (list_idx == 0) then
        1332           0 :          call pbuf_get_field(pbuf, dgnum_idx, dgncur_a, start=(/1,1,n/), kount=(/pcols,pver,1/))
        1333             :       else
        1334           0 :          dgncur_a => dgnum_m(:,:,n)
        1335             :       end if
        1336             :
        1337             :       ! get mode properties
        1338             :       call rad_cnst_get_mode_props(list_idx, n, dgnum=dgnum, dgnumhi=dgnumhi, dgnumlo=dgnumlo, &
        1339           0 :                                    sigmag=sigmag)
        1340             :
        1341             :       ! get mode number mixing ratio
        1342           0 :       call rad_cnst_get_mode_num(list_idx, n, 'a', state, pbuf, mode_num)
        1343             :
        1344           0 :       dgncur_a(:,:) = dgnum
        1345           0 :       dryvol_a(:,:) = 0.0_r8
        1346             :
        1347             :       ! compute dry volume mixrats =
        1348             :       !      sum_over_components{ component_mass mixrat / density }
        1349           0 :       call rad_cnst_get_info(list_idx, n, nspec=nspec)
        1350           0 :       do l1 = 1, nspec
        1351             :
        1352           0 :          call rad_cnst_get_aer_mmr(list_idx, n, l1, 'a', state, pbuf, specmmr)
        1353           0 :          call rad_cnst_get_aer_props(list_idx, n, l1, density_aer=specdens)
        1354             :
        1355             :          ! need qmass*dummwdens = (kg/kg-air) * [1/(kg/m3)] = m3/kg-air
        1356           0 :          dummwdens = 1.0_r8 / specdens
        1357             :
        1358           0 :          do k=top_lev,pver
        1359           0 :             do i=1,ncol
        1360           0 :                dryvol_a(i,k) = dryvol_a(i,k)    &
        1361           0 :                   + max(0.0_r8, specmmr(i,k))*dummwdens
        1362             :             end do
        1363             :          end do
        1364             :       end do
        1365             :
        1366           0 :       alnsg  = log( sigmag )
        1367           0 :       dumfac = exp(4.5_r8*alnsg**2)*pi/6.0_r8
        1368           0 :       voltonumblo = 1._r8 / ( (pi/6._r8)*(dgnumlo**3)*exp(4.5_r8*alnsg**2) )
        1369           0 :       voltonumbhi = 1._r8 / ( (pi/6._r8)*(dgnumhi**3)*exp(4.5_r8*alnsg**2) )
        1370           0 :       v2nxx = voltonumbhi
        1371           0 :       v2nyy = voltonumblo
        1372           0 :       dgnxx = dgnumhi
        1373           0 :       dgnyy = dgnumlo
        1374             :
        1375           0 :       do k = top_lev, pver
        1376           0 :          do i = 1, ncol
        1377             :
        1378           0 :             drv_a = dryvol_a(i,k)
        1379           0 :             num_a0 = mode_num(i,k)
        1380           0 :             num_a = max( 0.0_r8, num_a0 )
        1381             :
        1382           0 :             if (drv_a > 0.0_r8) then
        1383           0 :                if (num_a <= drv_a*v2nxx) then
        1384           0 :                   dgncur_a(i,k) = dgnxx
        1385           0 :                else if (num_a >= drv_a*v2nyy) then
        1386           0 :                   dgncur_a(i,k) = dgnyy
        1387             :                else
        1388           0 :                   dgncur_a(i,k) = (drv_a/(dumfac*num_a))**third
        1389             :                end if
        1390             :             end if
        1391             :
        1392             :          end do
        1393             :       end do
        1394             :
        1395             :    end do ! nmodes
        1396             :
        1397           0 :    call modal_aero_calcdry(state, pbuf, list_idx_in, dgnum_m, hygro_m, dryvol_m, dryrad_m, drymass_m, so4dryvol_m, naer_m)
        1398             :
        1399           0 : end subroutine modal_aero_calcsize_diag
        1400             :
        1401           0 : subroutine modal_aero_calcdry(state, pbuf, list_idx_in, dgnumdry_m, hygro_m, dryvol_m, dryrad_m, drymass_m, so4dryvol_m, naer_m)
        1402             :
        1403             :    type(physics_state), target, intent(in)    :: state       ! Physics state variables
        1404             :    type(physics_buffer_desc),   pointer       :: pbuf(:)     ! physics buffer
        1405             :    integer,  optional, intent(in)             :: list_idx_in ! diagnostic list index
        1406             :    real(r8), optional,          pointer       :: dgnumdry_m(:,:,:)
        1407             :    real(r8), optional,          pointer       :: hygro_m(:,:,:)
        1408             :    real(r8), optional,          pointer       :: dryvol_m(:,:,:)
        1409             :    real(r8), optional,          pointer       :: dryrad_m(:,:,:)
        1410             :    real(r8), optional,          pointer       :: drymass_m(:,:,:)
        1411             :    real(r8), optional,          pointer       :: so4dryvol_m(:,:,:)
        1412             :    real(r8), optional,          pointer       :: naer_m(:,:,:)
        1413             :
        1414             :    real(r8), parameter :: third = 1._r8/3._r8
        1415             :    real(r8), parameter :: pi43  = pi*4.0_r8/3.0_r8
        1416             :
        1417           0 :    real(r8), pointer :: maer(:,:)        ! aerosol wet mass MR (including water) (kg/kg-air)
        1418           0 :    real(r8), pointer :: hygro(:,:,:)     ! volume-weighted mean hygroscopicity (--)
        1419           0 :    real(r8), pointer :: dryvol(:,:,:)    ! single-particle-mean dry volume (m3)
        1420           0 :    real(r8), pointer :: dryrad(:,:,:)    ! dry volume mean radius of aerosol (m)
        1421           0 :    real(r8), pointer :: drymass(:,:,:)   ! single-particle-mean dry mass  (kg)
        1422           0 :    real(r8), pointer :: so4dryvol(:,:,:) ! single-particle-mean so4 dry volume (m3)
        1423           0 :    real(r8), pointer :: naer(:,:,:)      ! aerosol number MR (bounded!) (#/kg-air)
        1424             :
        1425           0 :    real(r8), pointer :: dgncur_a(:,:,:)
        1426           0 :    real(r8), pointer :: raer(:,:)   ! aerosol species MRs (kg/kg and #/kg)
        1427             :
        1428             :    real(r8), pointer :: sulfeq(:,:,:) ! H2SO4 equilibrium mixing ratios over particles (mol/mol)
        1429             :
        1430             :    real(r8) :: dryvolmr(pcols,pver)          ! volume MR for aerosol mode (m3/kg)
        1431             :    real(r8) :: so4dryvolmr(pcols,pver)       ! volume MR for sulfate aerosol in mode (m3/kg)
        1432             :
        1433             :    real(r8) :: specdens
        1434             :    real(r8) :: spechygro, spechygro_1
        1435             :    real(r8) :: sigmag
        1436             :    real(r8) :: duma, dumb
        1437             :    real(r8) :: alnsg
        1438             :
        1439             :    real(r8) :: v2ncur_a
        1440             :    real(r8) :: drydens               ! dry particle density  (kg/m^3)
        1441             :
        1442             :    character(len=fieldname_len+3) :: fieldname
        1443             :    character(len=32) :: spectype
        1444             :
        1445             :    integer :: nmodes, lchnk, ncol, list_idx, i, k, l, m
        1446             :    integer :: nspec
        1447             :
        1448             :
        1449           0 :    lchnk = state%lchnk
        1450           0 :    ncol = state%ncol
        1451             :
        1452           0 :    list_idx = 0
        1453           0 :    if (present(list_idx_in)) then
        1454           0 :       list_idx = list_idx_in
        1455             :
        1456             :       ! check that all optional args are present
        1457           0 :       if (.not. present(dgnumdry_m)) then
        1458             :          call endrun('modal_aero_calcdry called for'// &
        1459           0 :                      'diagnostic list but required args not present')
        1460             :       end if
        1461             :
        1462             :       ! arrays for diagnostic calculations must be associated
        1463           0 :      if (.not. associated(dgnumdry_m)) then
        1464             :          call endrun('modal_aero_calcdry called for'// &
        1465           0 :                      'diagnostic list but required args not associated')
        1466             :       end if
        1467             :    end if
        1468             :
        1469             :    ! loop over all aerosol modes
        1470           0 :    call rad_cnst_get_info(list_idx, nmodes=nmodes)
        1471             :
        1472           0 :    allocate( maer(pcols,pver))
        1473             :
        1474           0 :    if (list_idx == 0) then
        1475           0 :       call pbuf_get_field(pbuf, dgnum_idx,     dgncur_a )
        1476           0 :       call pbuf_get_field(pbuf, hygro_idx,     hygro)
        1477           0 :       call pbuf_get_field(pbuf, dryvol_idx,    dryvol)
        1478           0 :       call pbuf_get_field(pbuf, dryrad_idx,    dryrad)
        1479           0 :       call pbuf_get_field(pbuf, drymass_idx,   drymass)
        1480           0 :       call pbuf_get_field(pbuf, so4dryvol_idx, so4dryvol)
        1481           0 :       call pbuf_get_field(pbuf, naer_idx,      naer)
        1482             :    else
        1483           0 :       dgncur_a    => dgnumdry_m
        1484           0 :       hygro       => hygro_m
        1485           0 :       dryvol      => dryvol_m
        1486           0 :       dryrad      => dryrad_m
        1487           0 :       drymass     => drymass_m
        1488           0 :       so4dryvol   => so4dryvol_m
        1489           0 :       naer        => naer_m
        1490             :    end if
        1491             :
        1492           0 :    hygro(:,:,:)     = 0._r8
        1493           0 :    so4dryvol(:,:,:) = 0._r8
        1494             :
        1495           0 :    do m = 1, nmodes
        1496             :
        1497           0 :       maer(:,:)      = 0._r8
        1498           0 :       dryvolmr(:,:) = 0._r8
        1499           0 :       so4dryvolmr(:,:) = 0._r8
        1500             :
        1501             :       ! get mode properties
        1502           0 :       call rad_cnst_get_mode_props(list_idx, m, sigmag=sigmag)
        1503             :
        1504             :       ! get mode info
        1505           0 :       call rad_cnst_get_info(list_idx, m, nspec=nspec)
        1506             :
        1507           0 :       do l = 1, nspec
        1508             :
        1509             :          ! get species interstitial mixing ratio ('a')
        1510           0 :          call rad_cnst_get_aer_mmr(list_idx, m, l, 'a', state, pbuf, raer)
        1511             :          call rad_cnst_get_aer_props(list_idx, m, l, density_aer=specdens, &
        1512           0 :                                      hygro_aer=spechygro, spectype=spectype)
        1513             :
        1514           0 :          if (l == 1) then
        1515             :             ! save off these values to be used as defaults
        1516           0 :             spechygro_1    = spechygro
        1517             :          end if
        1518             :
        1519           0 :          do k = top_lev, pver
        1520           0 :             do i = 1, ncol
        1521           0 :                duma          = raer(i,k)     ! kg/kg air
        1522           0 :                maer(i,k)     = maer(i,k) + duma
        1523           0 :                dumb          = duma/specdens ! m3/kg air
        1524           0 :                dryvolmr(i,k) = dryvolmr(i,k) + dumb
        1525           0 :                if (modal_strat_sulfate .and. (trim(spectype).eq.'sulfate')) then
        1526           0 :                   so4dryvolmr(i,k) = so4dryvolmr(i,k) + dumb
        1527             :                end if
        1528           0 :                hygro(i,k,m)  = hygro(i,k,m) + dumb*spechygro
        1529             :             end do
        1530             :          end do
        1531             :       end do
        1532             :
        1533           0 :       alnsg = log(sigmag)
        1534             :
        1535           0 :       do k = top_lev, pver
        1536           0 :          do i = 1, ncol
        1537             :
        1538           0 :             if (dryvolmr(i,k) > 1.0e-30_r8) then
        1539           0 :                hygro(i,k,m) = hygro(i,k,m)/dryvolmr(i,k)
        1540             :             else
        1541           0 :                hygro(i,k,m) = spechygro_1
        1542             :             end if
        1543             :
        1544             :             ! dry aerosol properties
        1545             :
        1546           0 :             v2ncur_a = 1._r8 / ( (pi/6._r8)*(dgncur_a(i,k,m)**3._r8)*exp(4.5_r8*alnsg**2._r8) )
        1547             :             ! naer = aerosol number (#/kg)
        1548           0 :             naer(i,k,m) = dryvolmr(i,k)*v2ncur_a
        1549             :
        1550             :             ! compute mean (1 particle) dry volume and mass for each mode
        1551             :             ! old coding is replaced because the new (1/v2ncur_a) is equal to
        1552             :             ! the mean particle volume
        1553             :             ! also moletomass forces maer >= 1.0e-30, so (maer/dryvolmr)
        1554             :             ! should never cause problems (but check for maer < 1.0e-31 anyway)
        1555           0 :             if (maer(i,k) .gt. 1.0e-31_r8) then
        1556           0 :                drydens = maer(i,k)/dryvolmr(i,k)        ! kg/m3 aerosol
        1557             :             else
        1558             :                drydens = 1.0_r8
        1559             :             end if
        1560           0 :             dryvol(i,k,m)   = 1.0_r8/v2ncur_a             ! m3/particle
        1561           0 :             drymass(i,k,m)  = drydens*dryvol(i,k,m)       ! kg/particle
        1562           0 :             dryrad(i,k,m)   = (dryvol(i,k,m)/pi43)**third ! m
        1563             :          end do    ! i = 1, ncol
        1564             :       end do    ! k = top_lev, pver
        1565             :
        1566             :
        1567           0 :       if (modal_strat_sulfate) then
        1568           0 :          do k = top_lev, pver
        1569           0 :             do i = 1, ncol
        1570           0 :                if (so4dryvolmr(i,k) .gt. 1.0e-31_r8) then
        1571           0 :                   so4dryvol(i,k,m) = dryvol(i,k,m)*so4dryvolmr(i,k)/dryvolmr(i,k)
        1572             :                else
        1573           0 :                   so4dryvol(i,k,m) = 0.0_r8
        1574             :                end if
        1575             :
        1576             :             end do    ! i = 1, ncol
        1577             :          end do    ! k = top_lev, pver
        1578             :
        1579             :       end if
        1580             :
        1581             :    end do    ! m = 1, nmodes
        1582             :
        1583           0 :    deallocate( maer)
        1584             :
        1585             :
        1586           0 : end subroutine modal_aero_calcdry
        1587             : !----------------------------------------------------------------------
        1588             :
        1589             : end module modal_aero_calcsize

Generated by: LCOV version 1.14