LCOV - code coverage report
Current view: top level - physics/cam - ndrop.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 448 604 74.2 %
Date: 2025-03-14 01:21:06 Functions: 5 5 100.0 %

          Line data    Source code
       1             : module ndrop
       2             : 
       3             : !---------------------------------------------------------------------------------
       4             : ! Purpose:
       5             : !   CAM Interface for droplet activation by modal aerosols
       6             : !
       7             : ! ***N.B.*** This module is currently hardcoded to recognize only the modes that
       8             : !            affect the climate calculation.  This is implemented by using list
       9             : !            index 0 in all the calls to rad_constituent interfaces.
      10             : !---------------------------------------------------------------------------------
      11             : 
      12             : use shr_kind_mod,     only: r8 => shr_kind_r8, shr_kind_cs
      13             : use ppgrid,           only: pcols, pver
      14             : use physconst,        only: pi, rhoh2o, mwh2o, r_universal, rh2o, &
      15             :                             gravit, latvap, cpair, rair
      16             : use constituents,     only: pcnst, cnst_get_ind, cnst_name, cnst_spec_class_gas, cnst_species_class
      17             : use physics_types,    only: physics_state, physics_ptend, physics_ptend_init
      18             : use physics_buffer,   only: physics_buffer_desc, pbuf_get_index, pbuf_get_field
      19             : 
      20             : use wv_saturation,    only: qsat
      21             : use phys_control,     only: phys_getopts
      22             : use ref_pres,         only: top_lev => trop_cloud_top_lev
      23             : use shr_spfn_mod,     only: erf => shr_spfn_erf
      24             : use cam_history,      only: addfld, add_default, horiz_only, fieldname_len, outfld
      25             : use cam_abortutils,   only: endrun
      26             : use cam_logfile,      only: iulog
      27             : 
      28             : use aerosol_properties_mod, only: aerosol_properties
      29             : use aerosol_state_mod, only: aerosol_state, ptr2d_t
      30             : 
      31             : implicit none
      32             : private
      33             : save
      34             : 
      35             : public ndrop_init, dropmixnuc, activate_aerosol
      36             : 
      37             : ! mathematical constants
      38             : real(r8), parameter :: zero     = 0._r8
      39             : real(r8), parameter :: third    = 1._r8/3._r8
      40             : real(r8), parameter :: twothird = 2._r8*third
      41             : real(r8), parameter :: sixth    = 1._r8/6._r8
      42             : real(r8), parameter :: sq2      = sqrt(2._r8)
      43             : real(r8), parameter :: sq2pi    = sqrt(2._r8*pi)
      44             : real(r8), parameter :: sqpi     = sqrt(pi)
      45             : real(r8), parameter :: surften  = 0.076_r8
      46             : real(r8), parameter :: tmelt    = 273._r8
      47             : 
      48             : real(r8) :: aten
      49             : 
      50             : ! CCN diagnostic fields
      51             : integer,  parameter :: psat=6    ! number of supersaturations to calc ccn concentration
      52             : real(r8), parameter :: supersat(psat)= & ! supersaturation (%) to determine ccn concentration
      53             :                        (/ 0.02_r8, 0.05_r8, 0.1_r8, 0.2_r8, 0.5_r8, 1.0_r8 /)
      54             : character(len=8) :: ccn_name(psat)= &
      55             :                     (/'CCN1','CCN2','CCN3','CCN4','CCN5','CCN6'/)
      56             : 
      57             : ! indices in state and pbuf structures
      58             : integer :: numliq_idx = -1
      59             : integer :: kvh_idx    = -1
      60             : 
      61             : logical :: history_aerosol      ! Output the aerosol tendencies
      62             : character(len=fieldname_len), allocatable :: fieldname(:)    ! names for drop nuc tendency output fields
      63             : character(len=fieldname_len), allocatable :: fieldname_cw(:) ! names for drop nuc tendency output fields
      64             : 
      65             : ! Indices for aerosol species in the ptend%q array.
      66             : integer, allocatable :: aer_cnst_idx(:,:)
      67             : 
      68             : logical :: lq(pcnst) = .false. ! set flags true for constituents with non-zero tendencies
      69             :                                ! in the ptend object
      70             : 
      71             : !===============================================================================
      72             : contains
      73             : !===============================================================================
      74             : 
      75        1536 : subroutine ndrop_init(aero_props)
      76             : 
      77             :    class(aerosol_properties), intent(in) :: aero_props
      78             : 
      79             :    integer :: l, m, mm
      80             :    integer :: idxtmp = -1
      81             :    character(len=32)   :: tmpname
      82             :    character(len=32)   :: tmpname_cw
      83             :    character(len=128)  :: long_name
      84             :    character(len=8)    :: unit
      85             :    logical :: history_amwg         ! output the variables used by the AMWG diag package
      86             : 
      87             :    !-------------------------------------------------------------------------------
      88             : 
      89             :    ! get indices into state%q and pbuf structures
      90        1536 :    call cnst_get_ind('NUMLIQ', numliq_idx)
      91             : 
      92        1536 :    kvh_idx = pbuf_get_index('kvh')
      93             : 
      94        1536 :    aten = 2._r8*mwh2o*surften/(r_universal*tmelt*rhoh2o)
      95             : 
      96             :    allocate( &
      97           0 :       aer_cnst_idx(aero_props%nbins(),0:maxval(aero_props%nmasses())), &
      98           0 :       fieldname(aero_props%ncnst_tot()),                 &
      99       21504 :       fieldname_cw(aero_props%ncnst_tot())               )
     100             : 
     101             :    ! Add dropmixnuc tendencies for all modal aerosol species
     102             : 
     103             :    call phys_getopts(history_amwg_out = history_amwg, &
     104        1536 :                      history_aerosol_out = history_aerosol)
     105             : 
     106             : 
     107        9216 :    do m = 1, aero_props%nbins()
     108       87552 :       do l = 0, aero_props%nmasses(m)
     109             : 
     110       78336 :          mm = aero_props%indexer(m,l)
     111             : 
     112       78336 :          unit = 'kg/m2/s'
     113       78336 :          if (l == 0) then   ! number
     114        7680 :             unit = '#/m2/s'
     115             :          end if
     116             : 
     117       78336 :          if (l == 0) then   ! number
     118        7680 :             call aero_props%num_names( m, tmpname, tmpname_cw)
     119             :          else
     120       70656 :             call aero_props%mmr_names( m,l, tmpname, tmpname_cw)
     121             :          end if
     122             : 
     123       78336 :          fieldname(mm)    = trim(tmpname) // '_mixnuc1'
     124       78336 :          fieldname_cw(mm) = trim(tmpname_cw) // '_mixnuc1'
     125             : 
     126             :          ! To set tendencies in the ptend object need to get the constituent indices
     127             :          ! for the prognostic species
     128             : 
     129       78336 :          call cnst_get_ind(tmpname, idxtmp, abort=.false.)
     130       78336 :          aer_cnst_idx(m,l) = idxtmp
     131             : 
     132       78336 :          if (idxtmp>0) then
     133       78336 :             lq(idxtmp) = .true.
     134             :          end if
     135             : 
     136             :          ! Add tendency fields to the history only when prognostic MAM is enabled.
     137       78336 :          long_name = trim(tmpname) // ' dropmixnuc mixnuc column tendency'
     138       78336 :          call addfld(fieldname(mm),    horiz_only, 'A', unit, long_name, sampled_on_subcycle=.true.)
     139             : 
     140       78336 :          long_name = trim(tmpname_cw) // ' dropmixnuc mixnuc column tendency'
     141       78336 :          call addfld(fieldname_cw(mm), horiz_only, 'A', unit, long_name, sampled_on_subcycle=.true.)
     142             : 
     143       86016 :          if (history_aerosol) then
     144           0 :             call add_default(fieldname(mm), 1, ' ')
     145           0 :             call add_default(fieldname_cw(mm), 1, ' ')
     146             :          end if
     147             : 
     148             :       end do
     149             :    end do
     150             : 
     151        3072 :    call addfld('CCN1',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.02%', sampled_on_subcycle=.true.)
     152        3072 :    call addfld('CCN2',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.05%', sampled_on_subcycle=.true.)
     153        3072 :    call addfld('CCN3',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.1%',  sampled_on_subcycle=.true.)
     154        3072 :    call addfld('CCN4',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.2%',  sampled_on_subcycle=.true.)
     155        3072 :    call addfld('CCN5',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=0.5%',  sampled_on_subcycle=.true.)
     156        3072 :    call addfld('CCN6',(/ 'lev' /), 'A','#/cm3','CCN concentration at S=1.0%',  sampled_on_subcycle=.true.)
     157             : 
     158             : 
     159        3072 :    call addfld('WTKE',     (/ 'lev' /), 'A', 'm/s', 'Standard deviation of updraft velocity', sampled_on_subcycle=.true.)
     160        3072 :    call addfld('NDROPMIX', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number mixing', sampled_on_subcycle=.true.)
     161        3072 :    call addfld('NDROPSRC', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number source', sampled_on_subcycle=.true.)
     162        3072 :    call addfld('NDROPSNK', (/ 'lev' /), 'A', '#/kg/s', 'Droplet number loss by microphysics', sampled_on_subcycle=.true.)
     163        1536 :    call addfld('NDROPCOL', horiz_only,  'A', '#/m2', 'Column droplet number', sampled_on_subcycle=.true.)
     164             : 
     165             :    ! set the add_default fields
     166        1536 :    if (history_amwg) then
     167        1536 :       call add_default('CCN3', 1, ' ')
     168             :    endif
     169             : 
     170        3072 : end subroutine ndrop_init
     171             : 
     172             : !===============================================================================
     173             : 
     174    58302720 : subroutine dropmixnuc( aero_props, aero_state, &
     175             :    state, ptend, dtmicro, pbuf, wsub, wmixmin, &
     176      241920 :    cldn, cldo, cldliqf, tendnd, factnum)
     177             : 
     178             :    ! vertical diffusion and nucleation of cloud droplets
     179             :    ! assume cloud presence controlled by cloud fraction
     180             :    ! doesn't distinguish between warm, cold clouds
     181             : 
     182             :    ! arguments
     183             :    type(physics_state), target, intent(in)    :: state
     184             :    type(physics_ptend),         intent(out)   :: ptend
     185             :    real(r8),                    intent(in)    :: dtmicro     ! time step for microphysics (s)
     186             :    real(r8),                    intent(in)    :: wmixmin     ! minimum turbulence vertical velocity (m/s)
     187             : 
     188             :    type(physics_buffer_desc), pointer :: pbuf(:)
     189             : 
     190             :    class(aerosol_properties), intent(in) :: aero_props
     191             :    class(aerosol_state), intent(in) :: aero_state
     192             : 
     193             :    ! arguments
     194             :    real(r8), intent(in) :: wsub(pcols,pver)    ! subgrid vertical velocity
     195             :    real(r8), intent(in) :: cldn(pcols,pver)    ! cloud fraction
     196             :    real(r8), intent(in) :: cldo(pcols,pver)    ! cloud fraction on previous time step
     197             :    real(r8), intent(in) :: cldliqf(pcols,pver) ! liquid cloud fraction (liquid / (liquid + ice))
     198             : 
     199             :    ! output arguments
     200             :    real(r8), intent(out) :: tendnd(pcols,pver) ! change in droplet number concentration (#/kg/s)
     201             :    real(r8), intent(out) :: factnum(:,:,:)     ! activation fraction for aerosol number
     202             :    !--------------------Local storage-------------------------------------
     203             : 
     204             :    integer  :: lchnk               ! chunk identifier
     205             :    integer  :: ncol                ! number of columns
     206             :    integer  :: nbin                ! number of modes/bins
     207             :    integer  :: nele_tot            ! total number of aerosol elements
     208             : 
     209      241920 :    real(r8), pointer :: ncldwtr(:,:) ! droplet number concentration (#/kg)
     210      241920 :    real(r8), pointer :: temp(:,:)    ! temperature (K)
     211      241920 :    real(r8), pointer :: pmid(:,:)    ! mid-level pressure (Pa)
     212      241920 :    real(r8), pointer :: pint(:,:)    ! pressure at layer interfaces (Pa)
     213      241920 :    real(r8), pointer :: pdel(:,:)    ! pressure thickess of layer (Pa)
     214      241920 :    real(r8), pointer :: rpdel(:,:)   ! inverse of pressure thickess of layer (/Pa)
     215      241920 :    real(r8), pointer :: zm(:,:)      ! geopotential height of level (m)
     216             : 
     217      241920 :    real(r8), pointer :: kvh(:,:)     ! vertical diffusivity (m2/s)
     218             : 
     219      241920 :    type(ptr2d_t), allocatable :: raer(:)     ! aerosol mass, number mixing ratios
     220      241920 :    type(ptr2d_t), allocatable :: qqcw(:)
     221             :    real(r8) :: raertend(pver)  ! tendency of aerosol mass, number mixing ratios
     222             :    real(r8) :: qqcwtend(pver)  ! tendency of cloudborne aerosol mass, number mixing ratios
     223             : 
     224             :    real(r8), parameter :: zkmin = 0.01_r8, zkmax = 100._r8
     225             :    integer  :: i, k, l, m, mm, n
     226             :    integer  :: km1, kp1
     227             :    integer  :: nnew, nsav, ntemp
     228             :    integer  :: lptr
     229             :    integer  :: nsubmix, nsubmix_bnd
     230             :    integer, save :: count_submix(100)
     231             :    integer  :: phase ! phase of aerosol
     232             : 
     233             :    real(r8) :: arg
     234             :    real(r8) :: dtinv
     235             :    real(r8) :: dtmin, tinv, dtt
     236             :    real(r8) :: lcldn(pcols,pver)
     237             :    real(r8) :: lcldo(pcols,pver)
     238             : 
     239             :    real(r8) :: zs(pver) ! inverse of distance between levels (m)
     240             :    real(r8) :: qcld(pver) ! cloud droplet number mixing ratio (#/kg)
     241             :    real(r8) :: qncld(pver)     ! droplet number nucleated on cloud boundaries
     242             :    real(r8) :: srcn(pver)       ! droplet source rate (/s)
     243             :    real(r8) :: cs(pcols,pver)      ! air density (kg/m3)
     244             :    real(r8) :: csbot(pver)       ! air density at bottom (interface) of layer (kg/m3)
     245             :    real(r8) :: csbot_cscen(pver) ! csbot(i)/cs(i,k)
     246             :    real(r8) :: dz(pcols,pver)      ! geometric thickness of layers (m)
     247             : 
     248             :    real(r8) :: wtke(pcols,pver)     ! turbulent vertical velocity at base of layer k (m/s)
     249             :    real(r8) :: wtke_cen(pcols,pver) ! turbulent vertical velocity at center of layer k (m/s)
     250             :    real(r8) :: wbar, wmix, wmin, wmax
     251             : 
     252             :    real(r8) :: zn(pver)   ! g/pdel (m2/g) for layer
     253             :    real(r8) :: flxconv    ! convergence of flux into lowest layer
     254             : 
     255             :    real(r8) :: wdiab           ! diabatic vertical velocity
     256             :    real(r8) :: ekd(pver)       ! diffusivity for droplets (m2/s)
     257             :    real(r8) :: ekk(0:pver)     ! density*diffusivity for droplets (kg/m3 m2/s)
     258             :    real(r8) :: ekkp(pver)      ! zn*zs*density*diffusivity
     259             :    real(r8) :: ekkm(pver)      ! zn*zs*density*diffusivity
     260             : 
     261             :    real(r8) :: dum, dumc
     262             :    real(r8) :: tmpa
     263             :    real(r8) :: dact
     264             :    real(r8) :: fluxntot         ! (#/cm2/s)
     265             :    real(r8) :: dtmix
     266             :    real(r8) :: alogarg
     267             :    real(r8) :: overlapp(pver), overlapm(pver) ! cloud overlap
     268             : 
     269             :    real(r8) :: nsource(pcols,pver)            ! droplet number source (#/kg/s)
     270             :    real(r8) :: ndropmix(pcols,pver)           ! droplet number mixing (#/kg/s)
     271             :    real(r8) :: ndropcol(pcols)               ! column droplet number (#/m2)
     272             :    real(r8) :: cldo_tmp, cldn_tmp
     273             :    real(r8) :: tau_cld_regenerate
     274             :    real(r8) :: taumix_internal_pver_inv ! 1/(internal mixing time scale for k=pver) (1/s)
     275             : 
     276             : 
     277      241920 :    real(r8), allocatable :: nact(:,:)  ! fractional aero. number  activation rate (/s)
     278      241920 :    real(r8), allocatable :: mact(:,:)  ! fractional aero. mass    activation rate (/s)
     279             : 
     280      241920 :    real(r8), allocatable :: raercol(:,:,:)    ! single column of aerosol mass, number mixing ratios
     281      241920 :    real(r8), allocatable :: raercol_cw(:,:,:) ! same as raercol but for cloud-borne phase
     282             : 
     283             : 
     284             :    real(r8) :: na(pcols), va(pcols), hy(pcols)
     285      241920 :    real(r8), allocatable :: naermod(:)  ! (1/m3)
     286      241920 :    real(r8), allocatable :: hygro(:)    ! hygroscopicity of aerosol mode
     287      241920 :    real(r8), allocatable :: vaerosol(:) ! interstit+activated aerosol volume conc (cm3/cm3)
     288             : 
     289             :    real(r8) :: source(pver)
     290             : 
     291      241920 :    real(r8), allocatable :: fn(:)              ! activation fraction for aerosol number
     292      241920 :    real(r8), allocatable :: fm(:)              ! activation fraction for aerosol mass
     293             : 
     294      241920 :    real(r8), allocatable :: fluxn(:)           ! number  activation fraction flux (cm/s)
     295      241920 :    real(r8), allocatable :: fluxm(:)           ! mass    activation fraction flux (cm/s)
     296             :    real(r8)              :: flux_fullact(pver) ! 100%    activation fraction flux (cm/s)
     297             :    !     note:  activation fraction fluxes are defined as
     298             :    !     fluxn = [flux of activated aero. number into cloud (#/cm2/s)]
     299             :    !           / [aero. number conc. in updraft, just below cloudbase (#/cm3)]
     300             : 
     301             : 
     302      241920 :    real(r8), allocatable :: coltend(:,:)       ! column tendency for diagnostic output
     303      241920 :    real(r8), allocatable :: coltend_cw(:,:)    ! column tendency
     304             :    real(r8) :: ccn(pcols,pver,psat)    ! number conc of aerosols activated at supersat
     305             : 
     306             :    !for gas species turbulent mixing
     307             :    real(r8), pointer :: rgas(:, :, :)
     308             :    real(r8), allocatable :: rgascol(:, :, :)
     309             :    real(r8), allocatable :: coltendgas(:)
     310             :    real(r8) :: zerogas(pver)
     311             :    character*200 fieldnamegas
     312             : 
     313             :    integer :: errnum
     314             :    character(len=shr_kind_cs) :: errstr
     315             :    !-------------------------------------------------------------------------------
     316             : 
     317      241920 :    lchnk = state%lchnk
     318      241920 :    ncol  = state%ncol
     319      241920 :    nbin  = aero_props%nbins()
     320      241920 :    nele_tot  = aero_props%ncnst_tot()
     321             : 
     322      241920 :    ncldwtr  => state%q(:,:,numliq_idx)
     323      241920 :    temp     => state%t
     324      241920 :    pmid     => state%pmid
     325      241920 :    pint     => state%pint
     326      241920 :    pdel     => state%pdel
     327      241920 :    rpdel    => state%rpdel
     328      241920 :    zm       => state%zm
     329             : 
     330      241920 :    call pbuf_get_field(pbuf, kvh_idx, kvh)
     331             : 
     332             :    ! Create the liquid weighted cloud fractions that were passsed in
     333             :    ! before. This doesn't seem like the best variable, since the cloud could
     334             :    ! have liquid condensate, but the part of it that is changing could be the
     335             :    ! ice portion; however, this is what was done before.
     336   119460096 :    lcldo(:ncol,:)  = cldo(:ncol,:)  * cldliqf(:ncol,:)
     337   119460096 :    lcldn(:ncol,:) = cldn(:ncol,:) * cldliqf(:ncol,:)
     338             : 
     339             : 
     340      241920 :    arg = 1.0_r8
     341      241920 :    if (abs(0.8427_r8 - erf(arg))/0.8427_r8 > 0.001_r8) then
     342           0 :       write(iulog,*) 'erf(1.0) = ',ERF(arg)
     343           0 :       call endrun('dropmixnuc: Error function error')
     344             :    endif
     345      241920 :    arg = 0.0_r8
     346      241920 :    if (erf(arg) /= 0.0_r8) then
     347           0 :       write(iulog,*) 'erf(0.0) = ',erf(arg)
     348           0 :       write(iulog,*) 'dropmixnuc: Error function error'
     349           0 :       call endrun('dropmixnuc: Error function error')
     350             :    endif
     351             : 
     352      241920 :    dtinv = 1._r8/dtmicro
     353             : 
     354             :    allocate( &
     355             :       nact(pver,nbin),             &
     356             :       mact(pver,nbin),             &
     357           0 :       raer(nele_tot),              &
     358           0 :       qqcw(nele_tot),              &
     359             :       raercol(pver,nele_tot,2),    &
     360             :       raercol_cw(pver,nele_tot,2), &
     361             :       coltend(pcols,nele_tot),     &
     362             :       coltend_cw(pcols,nele_tot),  &
     363           0 :       naermod(nbin),               &
     364           0 :       hygro(nbin),                 &
     365           0 :       vaerosol(nbin),              &
     366           0 :       fn(nbin),                    &
     367           0 :       fm(nbin),                    &
     368           0 :       fluxn(nbin),                 &
     369     5322240 :       fluxm(nbin)               )
     370             : 
     371             :    ! Init pointers to mode number and specie mass mixing ratios in
     372             :    ! intersitial and cloud borne phases.
     373      241920 :    call aero_state%get_states( aero_props, raer, qqcw )
     374             : 
     375   659473920 :    factnum = 0._r8
     376      241920 :    wtke = 0._r8
     377      241920 :    nsource = 0._r8
     378      241920 :    ndropmix = 0._r8
     379      241920 :    ndropcol = 0._r8
     380      241920 :    tendnd = 0._r8
     381             : 
     382             :    ! initialize aerosol tendencies
     383      241920 :    call physics_ptend_init(ptend, state%psetcols, 'ndrop', lq=lq)
     384             : 
     385             :    ! overall_main_i_loop
     386     3725568 :    do i = 1, ncol
     387             : 
     388   111476736 :       do k = top_lev, pver-1
     389   111476736 :          zs(k) = 1._r8/(zm(i,k) - zm(i,k+1))
     390             :       end do
     391     3483648 :       zs(pver) = zs(pver-1)
     392             : 
     393             :       ! load number nucleated into qcld on cloud boundaries
     394             : 
     395   114960384 :       do k = top_lev, pver
     396             : 
     397   111476736 :          qcld(k)  = ncldwtr(i,k)
     398   111476736 :          qncld(k) = 0._r8
     399   111476736 :          srcn(k)  = 0._r8
     400   111476736 :          cs(i,k)  = pmid(i,k)/(rair*temp(i,k))        ! air density (kg/m3)
     401   111476736 :          dz(i,k)  = 1._r8/(cs(i,k)*gravit*rpdel(i,k)) ! layer thickness in m
     402             : 
     403   668860416 :          do m = 1, nbin
     404   557383680 :             nact(k,m) = 0._r8
     405   668860416 :             mact(k,m) = 0._r8
     406             :          end do
     407             : 
     408   111476736 :          zn(k) = gravit*rpdel(i,k)
     409             : 
     410   111476736 :          if (k < pver) then
     411   107993088 :             ekd(k)   = kvh(i,k+1)
     412   107993088 :             ekd(k)   = max(ekd(k), zkmin)
     413   107993088 :             ekd(k)   = min(ekd(k), zkmax)
     414   107993088 :             csbot(k) = 2.0_r8*pint(i,k+1)/(rair*(temp(i,k) + temp(i,k+1)))
     415   107993088 :             csbot_cscen(k) = csbot(k)/cs(i,k)
     416             :          else
     417     3483648 :             ekd(k)   = 0._r8
     418     3483648 :             csbot(k) = cs(i,k)
     419     3483648 :             csbot_cscen(k) = 1.0_r8
     420             :          end if
     421             : 
     422             :          ! rce-comment - define wtke at layer centers for new-cloud activation
     423             :          !    and at layer boundaries for old-cloud activation
     424   111476736 :          wtke_cen(i,k) = wsub(i,k)
     425   111476736 :          wtke(i,k)     = wsub(i,k)
     426   111476736 :          wtke_cen(i,k) = max(wtke_cen(i,k), wmixmin)
     427   111476736 :          wtke(i,k)     = max(wtke(i,k), wmixmin)
     428             : 
     429   114960384 :          nsource(i,k) = 0._r8
     430             : 
     431             :       end do
     432             : 
     433   181149696 :       nsav = 1
     434   181149696 :       nnew = 2
     435             : 
     436   181149696 :       do mm = 1,nele_tot
     437  5862979584 :          raercol_cw(:,mm,nsav) = 0.0_r8
     438  5862979584 :          raercol(:,mm,nsav)    = 0.0_r8
     439  5862979584 :          raercol_cw(top_lev:pver,mm,nsav) = qqcw(mm)%fld(i,top_lev:pver)
     440  5866463232 :          raercol(top_lev:pver,mm,nsav)    = raer(mm)%fld(i,top_lev:pver)
     441             :       end do
     442             : 
     443             :       ! droplet nucleation/aerosol activation
     444             : 
     445             :       ! tau_cld_regenerate = time scale for regeneration of cloudy air
     446             :       !    by (horizontal) exchange with clear air
     447     3483648 :       tau_cld_regenerate = 3600.0_r8 * 3.0_r8
     448             : 
     449             :       ! k-loop for growing/shrinking cloud calcs .............................
     450             :       ! grow_shrink_main_k_loop: &
     451   114960384 :       do k = top_lev, pver
     452             : 
     453             :          ! This code was designed for liquid clouds, but the cloudbourne
     454             :          ! aerosol can be either from liquid or ice clouds. For the ice clouds,
     455             :          ! we do not do regeneration, but as cloud fraction decreases the
     456             :          ! aerosols should be returned interstitial. The lack of a liquid cloud
     457             :          ! should not mean that all of the aerosol is realease. Therefor a
     458             :          ! section has been added for shrinking ice clouds and checks were added
     459             :          ! to protect ice cloudbourne aerosols from being released when no
     460             :          ! liquid cloud is present.
     461             : 
     462             :          ! shrinking ice cloud ......................................................
     463   111476736 :          cldo_tmp = cldo(i,k) * (1._r8 - cldliqf(i,k))
     464   111476736 :          cldn_tmp = cldn(i,k) * (1._r8 - cldliqf(i,k))
     465             : 
     466   111476736 :          if (cldn_tmp < cldo_tmp) then
     467             : 
     468             :             ! convert activated aerosol to interstitial in decaying cloud
     469             : 
     470    10256574 :             dumc = (cldn_tmp - cldo_tmp)/cldo_tmp * (1._r8 - cldliqf(i,k))
     471   533341848 :             do mm = 1,nele_tot
     472   523085274 :                dact   = raercol_cw(k,mm,nsav)*dumc
     473   523085274 :                raercol_cw(k,mm,nsav) = raercol_cw(k,mm,nsav) + dact   ! cloud-borne aerosol
     474   533341848 :                raercol(k,mm,nsav)    = raercol(k,mm,nsav) - dact
     475             :             end do
     476             : 
     477             :          end if
     478             : 
     479             :          ! shrinking liquid cloud ......................................................
     480             :          !    treat the reduction of cloud fraction from when cldn(i,k) < cldo(i,k)
     481             :          !    and also dissipate the portion of the cloud that will be regenerated
     482   111476736 :          cldo_tmp = lcldo(i,k)
     483   111476736 :          cldn_tmp = lcldn(i,k) * exp( -dtmicro/tau_cld_regenerate )
     484             :          !    alternate formulation
     485             :          !    cldn_tmp = cldn(i,k) * max( 0.0_r8, (1.0_r8-dtmicro/tau_cld_regenerate) )
     486             : 
     487             :          ! fraction is also provided.
     488   111476736 :          if (cldn_tmp < cldo_tmp) then
     489             :             !  droplet loss in decaying cloud
     490             :             !++ sungsup
     491    13775976 :             nsource(i,k) = nsource(i,k) + qcld(k)*(cldn_tmp - cldo_tmp)/cldo_tmp*cldliqf(i,k)*dtinv
     492    13775976 :             qcld(k)      = qcld(k)*(1._r8 + (cldn_tmp - cldo_tmp)/cldo_tmp)
     493             :             !-- sungsup
     494             : 
     495             :             ! convert activated aerosol to interstitial in decaying cloud
     496             : 
     497    13775976 :             dumc = (cldn_tmp - cldo_tmp)/cldo_tmp * cldliqf(i,k)
     498   716350752 :             do mm = 1,nele_tot
     499   702574776 :                dact   = raercol_cw(k,mm,nsav)*dumc
     500   702574776 :                raercol_cw(k,mm,nsav) = raercol_cw(k,mm,nsav) + dact   ! cloud-borne aerosol
     501   716350752 :                raercol(k,mm,nsav)    = raercol(k,mm,nsav) - dact
     502             :             end do
     503             : 
     504             :          end if
     505             : 
     506             :          ! growing liquid cloud ......................................................
     507             :          !    treat the increase of cloud fraction from when cldn(i,k) > cldo(i,k)
     508             :          !    and also regenerate part of the cloud
     509   111476736 :          cldo_tmp = cldn_tmp
     510   111476736 :          cldn_tmp = lcldn(i,k)
     511             : 
     512   114960384 :          if (cldn_tmp-cldo_tmp > 0.01_r8) then
     513             : 
     514             :             ! rce-comment - use wtke at layer centers for new-cloud activation
     515     7507451 :             wbar  = wtke_cen(i,k)
     516     7507451 :             wmix  = 0._r8
     517     7507451 :             wmin  = 0._r8
     518     7507451 :             wmax  = 10._r8
     519     7507451 :             wdiab = 0._r8
     520             : 
     521             :             ! load aerosol properties, assuming external mixtures
     522             : 
     523     7507451 :             phase = 1 ! interstitial
     524    45044706 :             do m = 1, nbin
     525             :                call aero_state%loadaer( aero_props, &
     526             :                   i, i, k, &
     527             :                   m, cs, phase, na, va, &
     528    37537255 :                   hy, errnum, errstr)
     529    37537255 :                if (errnum/=0) then
     530           0 :                   call endrun('dropmixnuc : '//trim(errstr))
     531             :                end if
     532    37537255 :                naermod(m)  = na(i)
     533    37537255 :                vaerosol(m) = va(i)
     534    45044706 :                hygro(m)    = hy(i)
     535             :             end do
     536             : 
     537             :             call activate_aerosol( &
     538             :                wbar, wmix, wdiab, wmin, wmax,                       &
     539     7507451 :                temp(i,k), cs(i,k), naermod, nbin,             &
     540             :                vaerosol, hygro, aero_props, fn, fm, fluxn,     &
     541    15014902 :                fluxm,flux_fullact(k))
     542             : 
     543    45044706 :             factnum(i,k,:) = fn
     544             : 
     545     7507451 :             dumc = (cldn_tmp - cldo_tmp)
     546             : 
     547    45044706 :             do m = 1, nbin
     548    37537255 :                mm = aero_props%indexer(m,0)
     549    37537255 :                dact   = dumc*fn(m)*raer(mm)%fld(i,k) ! interstitial only
     550    37537255 :                qcld(k) = qcld(k) + dact
     551    37537255 :                nsource(i,k) = nsource(i,k) + dact*dtinv
     552    37537255 :                raercol_cw(k,mm,nsav) = raercol_cw(k,mm,nsav) + dact  ! cloud-borne aerosol
     553    37537255 :                raercol(k,mm,nsav)    = raercol(k,mm,nsav) - dact
     554    37537255 :                dum = dumc*fm(m)
     555   390387452 :                do l = 1,aero_props%nmasses(m)
     556   345342746 :                   mm = aero_props%indexer(m,l)
     557   345342746 :                   dact    = dum*raer(mm)%fld(i,k) ! interstitial only
     558   345342746 :                   raercol_cw(k,mm,nsav) = raercol_cw(k,mm,nsav) + dact  ! cloud-borne aerosol
     559   382880001 :                   raercol(k,mm,nsav)    = raercol(k,mm,nsav) - dact
     560             :                enddo
     561             :             enddo
     562             : 
     563             :          endif
     564             : 
     565             :       enddo  ! grow_shrink_main_k_loop
     566             :       ! end of k-loop for growing/shrinking cloud calcs ......................
     567             : 
     568             :       ! ......................................................................
     569             :       ! start of k-loop for calc of old cloud activation tendencies ..........
     570             :       !
     571             :       ! rce-comment
     572             :       !    changed this part of code to use current cloud fraction (cldn) exclusively
     573             :       !    consider case of cldo(:)=0, cldn(k)=1, cldn(k+1)=0
     574             :       !    previous code (which used cldo below here) would have no cloud-base activation
     575             :       !       into layer k.  however, activated particles in k mix out to k+1,
     576             :       !       so they are incorrectly depleted with no replacement
     577             : 
     578             :       ! old_cloud_main_k_loop
     579   114960384 :       do k = top_lev, pver
     580   111476736 :          kp1 = min0(k+1, pver)
     581   111476736 :          taumix_internal_pver_inv = 0.0_r8
     582             : 
     583   114960384 :          if (lcldn(i,k) > 0.01_r8) then
     584             : 
     585    10024290 :             wdiab = 0._r8
     586    10024290 :             wmix  = 0._r8                       ! single updraft
     587    10024290 :             wbar  = wtke(i,k)                   ! single updraft
     588    10024290 :             if (k == pver) wbar = wtke_cen(i,k) ! single updraft
     589    10024290 :             wmax  = 10._r8
     590    10024290 :             wmin  = 0._r8
     591             : 
     592    10024290 :             if (lcldn(i,k) - lcldn(i,kp1) > 0.01_r8 .or. k == pver) then
     593             : 
     594             :                ! cloud base
     595             : 
     596             :                ! ekd(k) = wtke(i,k)*dz(i,k)/sq2pi
     597             :                ! rce-comments
     598             :                !   first, should probably have 1/zs(k) here rather than dz(i,k) because
     599             :                !      the turbulent flux is proportional to ekd(k)*zs(k),
     600             :                !      while the dz(i,k) is used to get flux divergences
     601             :                !      and mixing ratio tendency/change
     602             :                !   second and more importantly, using a single updraft velocity here
     603             :                !      means having monodisperse turbulent updraft and downdrafts.
     604             :                !      The sq2pi factor assumes a normal draft spectrum.
     605             :                !      The fluxn/fluxm from activate must be consistent with the
     606             :                !      fluxes calculated in explmix.
     607     4998466 :                ekd(k) = wbar/zs(k)
     608             : 
     609     4998466 :                alogarg = max(1.e-20_r8, 1._r8/lcldn(i,k) - 1._r8)
     610     4998466 :                wmin    = wbar + wmix*0.25_r8*sq2pi*log(alogarg)
     611     4998466 :                phase   = 1   ! interstitial
     612             : 
     613    29990796 :                do m = 1, nbin
     614             :                   ! rce-comment - use kp1 here as old-cloud activation involves
     615             :                   !   aerosol from layer below
     616             :                   call aero_state%loadaer( aero_props, &
     617             :                      i, i, kp1,  &
     618             :                      m, cs, phase, na, va,   &
     619    24992330 :                      hy, errnum, errstr)
     620    24992330 :                   if (errnum/=0) then
     621           0 :                      call endrun('dropmixnuc : '//trim(errstr))
     622             :                   end if
     623    24992330 :                   naermod(m)  = na(i)
     624    24992330 :                   vaerosol(m) = va(i)
     625    29990796 :                   hygro(m)    = hy(i)
     626             :                end do
     627             : 
     628             :                call activate_aerosol( &
     629             :                   wbar, wmix, wdiab, wmin, wmax,                       &
     630     4998466 :                   temp(i,k), cs(i,k), naermod, nbin,             &
     631             :                   vaerosol, hygro, aero_props, fn, fm, fluxn,     &
     632     9996932 :                   fluxm, flux_fullact(k))
     633             : 
     634    29990796 :                factnum(i,k,:) = fn
     635             : 
     636     4998466 :                if (k < pver) then
     637     4502329 :                   dumc = lcldn(i,k) - lcldn(i,kp1)
     638             :                else
     639      496137 :                   dumc = lcldn(i,k)
     640             :                endif
     641             : 
     642     4998466 :                fluxntot = 0
     643             : 
     644             :                ! rce-comment 1
     645             :                !    flux of activated mass into layer k (in kg/m2/s)
     646             :                !       = "actmassflux" = dumc*fluxm*raercol(kp1,lmass)*csbot(k)
     647             :                !    source of activated mass (in kg/kg/s) = flux divergence
     648             :                !       = actmassflux/(cs(i,k)*dz(i,k))
     649             :                !    so need factor of csbot_cscen = csbot(k)/cs(i,k)
     650             :                !                   dum=1./(dz(i,k))
     651     4998466 :                dum=csbot_cscen(k)/(dz(i,k))
     652             : 
     653             :                ! rce-comment 2
     654             :                !    code for k=pver was changed to use the following conceptual model
     655             :                !    in k=pver, there can be no cloud-base activation unless one considers
     656             :                !       a scenario such as the layer being partially cloudy,
     657             :                !       with clear air at bottom and cloudy air at top
     658             :                !    assume this scenario, and that the clear/cloudy portions mix with
     659             :                !       a timescale taumix_internal = dz(i,pver)/wtke_cen(i,pver)
     660             :                !    in the absence of other sources/sinks, qact (the activated particle
     661             :                !       mixratio) attains a steady state value given by
     662             :                !          qact_ss = fcloud*fact*qtot
     663             :                !       where fcloud is cloud fraction, fact is activation fraction,
     664             :                !       qtot=qact+qint, qint is interstitial particle mixratio
     665             :                !    the activation rate (from mixing within the layer) can now be
     666             :                !       written as
     667             :                !          d(qact)/dt = (qact_ss - qact)/taumix_internal
     668             :                !                     = qtot*(fcloud*fact*wtke/dz) - qact*(wtke/dz)
     669             :                !    note that (fcloud*fact*wtke/dz) is equal to the nact/mact
     670             :                !    also, d(qact)/dt can be negative.  in the code below
     671             :                !       it is forced to be >= 0
     672             :                !
     673             :                ! steve --
     674             :                !    you will likely want to change this.  i did not really understand
     675             :                !       what was previously being done in k=pver
     676             :                !    in the cam3_5_3 code, wtke(i,pver) appears to be equal to the
     677             :                !       droplet deposition velocity which is quite small
     678             :                !    in the cam3_5_37 version, wtke is done differently and is much
     679             :                !       larger in k=pver, so the activation is stronger there
     680             :                !
     681     4998466 :                if (k == pver) then
     682      496137 :                   taumix_internal_pver_inv = flux_fullact(k)/dz(i,k)
     683             :                end if
     684             : 
     685    29990796 :                do m = 1, nbin
     686    24992330 :                   mm = aero_props%indexer(m,0)
     687    24992330 :                   fluxn(m) = fluxn(m)*dumc
     688    24992330 :                   fluxm(m) = fluxm(m)*dumc
     689    24992330 :                   nact(k,m) = nact(k,m) + fluxn(m)*dum
     690    24992330 :                   mact(k,m) = mact(k,m) + fluxm(m)*dum
     691    29990796 :                   if (k < pver) then
     692             :                      ! note that kp1 is used here
     693             :                      fluxntot = fluxntot &
     694    22511645 :                         + fluxn(m)*raercol(kp1,mm,nsav)*cs(i,k)
     695             :                   else
     696     4961370 :                      tmpa = raercol(kp1,mm,nsav)*fluxn(m) &
     697             :                           + raercol_cw(kp1,mm,nsav)*(fluxn(m) &
     698     7442055 :                           - taumix_internal_pver_inv*dz(i,k))
     699     2480685 :                      fluxntot = fluxntot + max(0.0_r8, tmpa)*cs(i,k)
     700             :                   end if
     701             :                end do
     702     4998466 :                srcn(k)      = srcn(k) + fluxntot/(cs(i,k)*dz(i,k))
     703     4998466 :                nsource(i,k) = nsource(i,k) + fluxntot/(cs(i,k)*dz(i,k))
     704             : 
     705             :             endif  ! (cldn(i,k) - cldn(i,kp1) > 0.01 .or. k == pver)
     706             : 
     707             :          else
     708             : 
     709             :             ! no liquid cloud
     710   101452446 :             nsource(i,k) = nsource(i,k) - qcld(k)*dtinv
     711   101452446 :             qcld(k)      = 0
     712             : 
     713   101452446 :             if (cldn(i,k) < 0.01_r8) then
     714             :                ! no ice cloud either
     715             : 
     716             :                ! convert activated aerosol to interstitial in decaying cloud
     717             : 
     718  4675332792 :                do mm = 1,nele_tot
     719  4585422546 :                   raercol(k,mm,nsav)    = raercol(k,mm,nsav) + raercol_cw(k,mm,nsav)  ! cloud-borne aerosol
     720  4675332792 :                   raercol_cw(k,mm,nsav) = 0._r8
     721             :                end do
     722             : 
     723             :             end if
     724             :          end if
     725             : 
     726             :       end do  ! old_cloud_main_k_loop
     727             : 
     728             :       ! switch nsav, nnew so that nnew is the updated aerosol
     729     3483648 :       ntemp = nsav
     730     3483648 :       nsav  = nnew
     731     3483648 :       nnew  = ntemp
     732             : 
     733             :       ! load new droplets in layers above, below clouds
     734             : 
     735     3483648 :       dtmin     = dtmicro
     736     3483648 :       ekk(top_lev-1)    = 0.0_r8
     737     3483648 :       ekk(pver) = 0.0_r8
     738   111476736 :       do k = top_lev, pver-1
     739             :          ! rce-comment -- ekd(k) is eddy-diffusivity at k/k+1 interface
     740             :          !   want ekk(k) = ekd(k) * (density at k/k+1 interface)
     741             :          !   so use pint(i,k+1) as pint is 1:pverp
     742             :          !           ekk(k)=ekd(k)*2.*pint(i,k)/(rair*(temp(i,k)+temp(i,k+1)))
     743             :          !           ekk(k)=ekd(k)*2.*pint(i,k+1)/(rair*(temp(i,k)+temp(i,k+1)))
     744   111476736 :          ekk(k) = ekd(k)*csbot(k)
     745             :       end do
     746             : 
     747   114960384 :       do k = top_lev, pver
     748   111476736 :          km1     = max0(k-1, top_lev)
     749   111476736 :          ekkp(k) = zn(k)*ekk(k)*zs(k)
     750   111476736 :          ekkm(k) = zn(k)*ekk(k-1)*zs(km1)
     751   111476736 :          tinv    = ekkp(k) + ekkm(k)
     752             : 
     753             :          ! rce-comment -- tinv is the sum of all first-order-loss-rates
     754             :          !    for the layer.  for most layers, the activation loss rate
     755             :          !    (for interstitial particles) is accounted for by the loss by
     756             :          !    turb-transfer to the layer above.
     757             :          !    k=pver is special, and the loss rate for activation within
     758             :          !    the layer must be added to tinv.  if not, the time step
     759             :          !    can be too big, and explmix can produce negative values.
     760             :          !    the negative values are reset to zero, resulting in an
     761             :          !    artificial source.
     762   111476736 :          if (k == pver) tinv = tinv + taumix_internal_pver_inv
     763             : 
     764   114960384 :          if (tinv .gt. 1.e-6_r8) then
     765    26201922 :             dtt   = 1._r8/tinv
     766    26201922 :             dtmin = min(dtmin, dtt)
     767             :          end if
     768             :       end do
     769             : 
     770     3483648 :       dtmix   = 0.9_r8*dtmin
     771     3483648 :       nsubmix = int(dtmicro/dtmix) + 1
     772     3483648 :       if (nsubmix > 100) then
     773             :          nsubmix_bnd = 100
     774             :       else
     775             :          nsubmix_bnd = nsubmix
     776             :       end if
     777     3483648 :       count_submix(nsubmix_bnd) = count_submix(nsubmix_bnd) + 1
     778     3483648 :       dtmix = dtmicro/nsubmix
     779             : 
     780   114960384 :       do k = top_lev, pver
     781   111476736 :          kp1 = min(k+1, pver)
     782   111476736 :          km1 = max(k-1, top_lev)
     783             :          ! maximum overlap assumption
     784   111476736 :          if (cldn(i,kp1) > 1.e-10_r8) then
     785    37085337 :             overlapp(k) = min(cldn(i,k)/cldn(i,kp1), 1._r8)
     786             :          else
     787    74391399 :             overlapp(k) = 1._r8
     788             :          end if
     789   114960384 :          if (cldn(i,km1) > 1.e-10_r8) then
     790    34280979 :             overlapm(k) = min(cldn(i,k)/cldn(i,km1), 1._r8)
     791             :          else
     792    77195757 :             overlapm(k) = 1._r8
     793             :          end if
     794             :       end do
     795             : 
     796             : 
     797             :       ! rce-comment
     798             :       !    the activation source(k) = mact(k,m)*raercol(kp1,lmass)
     799             :       !       should not exceed the rate of transfer of unactivated particles
     800             :       !       from kp1 to k which = ekkp(k)*raercol(kp1,lmass)
     801             :       !    however it might if things are not "just right" in subr activate
     802             :       !    the following is a safety measure to avoid negatives in explmix
     803   111476736 :       do k = top_lev, pver-1
     804   651442176 :          do m = 1, nbin
     805   539965440 :             nact(k,m) = min( nact(k,m), ekkp(k) )
     806   647958528 :             mact(k,m) = min( mact(k,m), ekkp(k) )
     807             :          end do
     808             :       end do
     809             : 
     810             : 
     811             :       ! old_cloud_nsubmix_loop
     812    12903360 :       do n = 1, nsubmix
     813     9419712 :          qncld(:) = qcld(:)
     814             :          ! switch nsav, nnew so that nsav is the updated aerosol
     815     9419712 :          ntemp   = nsav
     816     9419712 :          nsav    = nnew
     817     9419712 :          nnew    = ntemp
     818     9419712 :          srcn(:) = 0.0_r8
     819             : 
     820    56518272 :          do m = 1, nbin
     821    47098560 :             mm = aero_props%indexer(m,0)
     822             : 
     823             :             ! update droplet source
     824             :             ! rce-comment- activation source in layer k involves particles from k+1
     825             :             !          srcn(:)=srcn(:)+nact(:,m)*(raercol(:,mm,nsav))
     826  1507153920 :             srcn(top_lev:pver-1) = srcn(top_lev:pver-1) + nact(top_lev:pver-1,m)*(raercol(top_lev+1:pver,mm,nsav))
     827             : 
     828             :             ! rce-comment- new formulation for k=pver
     829             :             !              srcn(  pver  )=srcn(  pver  )+nact(  pver  ,m)*(raercol(  pver,mm,nsav))
     830             :             tmpa = raercol(pver,mm,nsav)*nact(pver,m) &
     831    47098560 :                  + raercol_cw(pver,mm,nsav)*(nact(pver,m) - taumix_internal_pver_inv)
     832    56518272 :             srcn(pver) = srcn(pver) + max(0.0_r8,tmpa)
     833             :          end do
     834             :          call explmix(  &
     835             :             qcld, srcn, ekkp, ekkm, overlapp,  &
     836             :             overlapm, qncld, zero, zero, pver, &
     837     9419712 :             dtmix, .false.)
     838             : 
     839             :          ! rce-comment
     840             :          !    the interstitial particle mixratio is different in clear/cloudy portions
     841             :          !    of a layer, and generally higher in the clear portion.  (we have/had
     842             :          !    a method for diagnosing the the clear/cloudy mixratios.)  the activation
     843             :          !    source terms involve clear air (from below) moving into cloudy air (above).
     844             :          !    in theory, the clear-portion mixratio should be used when calculating
     845             :          !    source terms
     846    60001920 :          do m = 1, nbin
     847    47098560 :             mm = aero_props%indexer(m,0)
     848             :             ! rce-comment -   activation source in layer k involves particles from k+1
     849             :             !                 source(:)= nact(:,m)*(raercol(:,mm,nsav))
     850  1507153920 :             source(top_lev:pver-1) = nact(top_lev:pver-1,m)*(raercol(top_lev+1:pver,mm,nsav))
     851             :             ! rce-comment - new formulation for k=pver
     852             :             !               source(  pver  )= nact(  pver,  m)*(raercol(  pver,mm,nsav))
     853             :             tmpa = raercol(pver,mm,nsav)*nact(pver,m) &
     854    47098560 :                  + raercol_cw(pver,mm,nsav)*(nact(pver,m) - taumix_internal_pver_inv)
     855    47098560 :             source(pver) = max(0.0_r8, tmpa)
     856    47098560 :             flxconv = 0._r8
     857             : 
     858             :             call explmix( &
     859             :                  raercol_cw(:,mm,nnew), source, ekkp, ekkm, overlapp, &
     860             :                  overlapm, raercol_cw(:,mm,nsav), zero, zero, pver,   &
     861    47098560 :                  dtmix, .false.)
     862             : 
     863             :             call explmix( &
     864             :                  raercol(:,mm,nnew), source, ekkp, ekkm, overlapp,  &
     865             :                  overlapm, raercol(:,mm,nsav), zero, flxconv, pver, &
     866    47098560 :                  dtmix, .true., raercol_cw(:,mm,nsav))
     867             : 
     868   489825024 :             do l = 1,aero_props%nmasses(m)
     869   433306752 :                mm = aero_props%indexer(m,l)
     870             :                ! rce-comment -   activation source in layer k involves particles from k+1
     871             :                !                  source(:)= mact(:,m)*(raercol(:,mm,nsav))
     872 13865816064 :                source(top_lev:pver-1) = mact(top_lev:pver-1,m)*(raercol(top_lev+1:pver,mm,nsav))
     873             :                ! rce-comment- new formulation for k=pver
     874             :                !                 source(  pver  )= mact(  pver  ,m)*(raercol(  pver,mm,nsav))
     875             :                tmpa = raercol(pver,mm,nsav)*mact(pver,m) &
     876   433306752 :                     + raercol_cw(pver,mm,nsav)*(mact(pver,m) - taumix_internal_pver_inv)
     877   433306752 :                source(pver) = max(0.0_r8, tmpa)
     878   433306752 :                flxconv = 0._r8
     879             : 
     880             :                call explmix( &
     881             :                     raercol_cw(:,mm,nnew), source, ekkp, ekkm, overlapp, &
     882             :                     overlapm, raercol_cw(:,mm,nsav), zero, zero, pver,   &
     883   433306752 :                     dtmix, .false.)
     884             : 
     885             :                call explmix( &
     886             :                     raercol(:,mm,nnew), source, ekkp, ekkm, overlapp,  &
     887             :                     overlapm, raercol(:,mm,nsav), zero, flxconv, pver, &
     888   480405312 :                     dtmix, .true., raercol_cw(:,mm,nsav))
     889             : 
     890             :             end do
     891             :          end do
     892             : 
     893             :       end do ! old_cloud_nsubmix_loop
     894             : 
     895             :       ! evaporate particles again if no cloud (either ice or liquid)
     896             : 
     897   114960384 :       do k = top_lev, pver
     898   114960384 :          if (cldn(i,k) == 0._r8) then
     899             :             ! no ice or liquid cloud
     900    75793578 :             qcld(k)=0._r8
     901             : 
     902             :             ! convert activated aerosol to interstitial in decaying cloud
     903  3941266056 :             do mm = 1,nele_tot
     904  3865472478 :                raercol(k,mm,nnew)    = raercol(k,mm,nnew) + raercol_cw(k,mm,nnew)
     905  3941266056 :                raercol_cw(k,mm,nnew) = 0._r8
     906             :             end do
     907             : 
     908             :          end if
     909             :       end do
     910             : 
     911             :       ! droplet number
     912             : 
     913     3483648 :       ndropcol(i) = 0._r8
     914   114960384 :       do k = top_lev, pver
     915   111476736 :          ndropmix(i,k) = (qcld(k) - ncldwtr(i,k))*dtinv - nsource(i,k)
     916   111476736 :          tendnd(i,k)   = (max(qcld(k), 1.e-6_r8) - ncldwtr(i,k))*dtinv
     917   114960384 :          ndropcol(i)   = ndropcol(i) + ncldwtr(i,k)*pdel(i,k)
     918             :       end do
     919     3483648 :       ndropcol(i) = ndropcol(i)/gravit
     920             : 
     921     3483648 :       raertend = 0._r8
     922     3483648 :       qqcwtend = 0._r8
     923             : 
     924    21143808 :       do m = 1, nbin
     925   198567936 :          do l = 0, aero_props%nmasses(m)
     926             : 
     927   177666048 :             mm = aero_props%indexer(m,l)
     928   177666048 :             lptr = aer_cnst_idx(m,l)
     929             : 
     930  5862979584 :             raertend(top_lev:pver) = (raercol(top_lev:pver,mm,nnew) - raer(mm)%fld(i,top_lev:pver))*dtinv
     931  5862979584 :             qqcwtend(top_lev:pver) = (raercol_cw(top_lev:pver,mm,nnew) - qqcw(mm)%fld(i,top_lev:pver))*dtinv
     932             : 
     933  5862979584 :             coltend(i,mm)    = sum( pdel(i,:)*raertend )/gravit
     934  5862979584 :             coltend_cw(i,mm) = sum( pdel(i,:)*qqcwtend )/gravit
     935             : 
     936             :             ! check for advected aerosol constituents
     937   177666048 :             if (lptr>0) then ! advected aerosol parts
     938  5862979584 :                ptend%q(i,:,lptr) = 0.0_r8
     939  5862979584 :                ptend%q(i,top_lev:pver,lptr) = raertend(top_lev:pver)         ! set tendencies for interstitial aerosol
     940             :             else
     941           0 :                raer(mm)%fld(i,:) = 0.0_r8
     942           0 :                raer(mm)%fld(i,top_lev:pver)  = raercol(top_lev:pver,mm,nnew) ! update non-advected interstitial aerosol (pbuf)
     943             :             end if
     944             : 
     945  5862979584 :             qqcw(mm)%fld(i,:) = 0.0_r8
     946  5880397824 :             qqcw(mm)%fld(i,top_lev:pver) = raercol_cw(top_lev:pver,mm,nnew)  ! update cloud-borne aerosol
     947             : 
     948             :          end do
     949             :       end do
     950             : 
     951             :    end do  ! overall_main_i_loop
     952             :    ! end of main loop over i/longitude ....................................
     953             : 
     954      241920 :    call outfld('NDROPCOL', ndropcol, pcols, lchnk)
     955      241920 :    call outfld('NDROPSRC', nsource,  pcols, lchnk)
     956      241920 :    call outfld('NDROPMIX', ndropmix, pcols, lchnk)
     957      241920 :    call outfld('WTKE    ', wtke,     pcols, lchnk)
     958             : 
     959      241920 :    call ccncalc(aero_state, aero_props, state, cs, ccn)
     960     1693440 :    do l = 1, psat
     961     1693440 :       call outfld(ccn_name(l), ccn(1,1,l), pcols, lchnk)
     962             :    enddo
     963             : 
     964             :    ! do column tendencies
     965     1451520 :    do m = 1, nbin
     966    13789440 :       do l = 0,aero_props%nmasses(m)
     967    12337920 :          mm = aero_props%indexer(m,l)
     968    12337920 :          call outfld(fieldname(mm),    coltend(:,mm),    pcols, lchnk)
     969    13547520 :          call outfld(fieldname_cw(mm), coltend_cw(:,mm), pcols, lchnk)
     970             :       end do
     971             :    end do
     972             : 
     973           0 :    deallocate( &
     974             :       nact,       &
     975           0 :       mact,       &
     976           0 :       raer,       &
     977           0 :       qqcw,       &
     978           0 :       raercol,    &
     979           0 :       raercol_cw, &
     980           0 :       coltend,    &
     981           0 :       coltend_cw, &
     982           0 :       naermod,    &
     983           0 :       hygro,      &
     984           0 :       vaerosol,   &
     985           0 :       fn,         &
     986           0 :       fm,         &
     987           0 :       fluxn,      &
     988      241920 :       fluxm       )
     989             : 
     990      483840 : end subroutine dropmixnuc
     991             : 
     992             : !===============================================================================
     993             : 
     994  1940460672 : subroutine explmix( q, src, ekkp, ekkm, overlapp, overlapm, &
     995   480405312 :    qold, surfrate, flxconv, pver, dt, is_unact, qactold )
     996             : 
     997             :    !  explicit integration of droplet/aerosol mixing
     998             :    !     with source due to activation/nucleation
     999             : 
    1000             : 
    1001             :    integer, intent(in) :: pver ! number of levels
    1002             :    real(r8), intent(out) :: q(pver) ! mixing ratio to be updated
    1003             :    real(r8), intent(in) :: qold(pver) ! mixing ratio from previous time step
    1004             :    real(r8), intent(in) :: src(pver) ! source due to activation/nucleation (/s)
    1005             :    real(r8), intent(in) :: ekkp(pver) ! zn*zs*density*diffusivity (kg/m3 m2/s) at interface
    1006             :    ! below layer k  (k,k+1 interface)
    1007             :    real(r8), intent(in) :: ekkm(pver) ! zn*zs*density*diffusivity (kg/m3 m2/s) at interface
    1008             :    ! above layer k  (k,k+1 interface)
    1009             :    real(r8), intent(in) :: overlapp(pver) ! cloud overlap below
    1010             :    real(r8), intent(in) :: overlapm(pver) ! cloud overlap above
    1011             :    real(r8), intent(in) :: surfrate ! surface exchange rate (/s)
    1012             :    real(r8), intent(in) :: flxconv ! convergence of flux from surface
    1013             :    real(r8), intent(in) :: dt ! time step (s)
    1014             :    logical, intent(in) :: is_unact ! true if this is an unactivated species
    1015             :    real(r8), intent(in),optional :: qactold(pver)
    1016             :    ! mixing ratio of ACTIVATED species from previous step
    1017             :    ! *** this should only be present
    1018             :    !     if the current species is unactivated number/sfc/mass
    1019             : 
    1020             :    integer k,kp1,km1
    1021             : 
    1022   970230336 :    if ( is_unact ) then
    1023             :       !     the qactold*(1-overlap) terms are resuspension of activated material
    1024 15853375296 :       do k=top_lev,pver
    1025 15372969984 :          kp1=min(k+1,pver)
    1026 15372969984 :          km1=max(k-1,top_lev)
    1027 30745939968 :          q(k) = qold(k) + dt*( - src(k) + ekkp(k)*(qold(kp1) - qold(k) +       &
    1028 15372969984 :             qactold(kp1)*(1.0_r8-overlapp(k)))               &
    1029 15372969984 :             + ekkm(k)*(qold(km1) - qold(k) +     &
    1030 61491879936 :             qactold(km1)*(1.0_r8-overlapm(k))) )
    1031             :          !        force to non-negative
    1032             :          !        if(q(k)<-1.e-30)then
    1033             :          !           write(iulog,*)'q=',q(k),' in explmix'
    1034 15853375296 :          q(k)=max(q(k),0._r8)
    1035             :          !        endif
    1036             :       end do
    1037             : 
    1038             :       !     diffusion loss at base of lowest layer
    1039   480405312 :       q(pver)=q(pver)-surfrate*qold(pver)*dt+flxconv*dt
    1040             :       !        force to non-negative
    1041             :       !        if(q(pver)<-1.e-30)then
    1042             :       !           write(iulog,*)'q=',q(pver),' in explmix'
    1043   480405312 :       q(pver)=max(q(pver),0._r8)
    1044             :       !        endif
    1045             :    else
    1046 16164225792 :       do k=top_lev,pver
    1047 15674400768 :          kp1=min(k+1,pver)
    1048 15674400768 :          km1=max(k-1,top_lev)
    1049 31348801536 :          q(k) = qold(k) + dt*(src(k) + ekkp(k)*(overlapp(k)*qold(kp1)-qold(k)) +      &
    1050 47023202304 :             ekkm(k)*(overlapm(k)*qold(km1)-qold(k)) )
    1051             :          !        force to non-negative
    1052             :          !        if(q(k)<-1.e-30)then
    1053             :          !           write(iulog,*)'q=',q(k),' in explmix'
    1054 16164225792 :          q(k)=max(q(k),0._r8)
    1055             :          !        endif
    1056             :       end do
    1057             :       !     diffusion loss at base of lowest layer
    1058   489825024 :       q(pver)=q(pver)-surfrate*qold(pver)*dt+flxconv*dt
    1059             :       !        force to non-negative
    1060             :       !        if(q(pver)<-1.e-30)then
    1061             :       !           write(iulog,*)'q=',q(pver),' in explmix'
    1062   489825024 :       q(pver)=max(q(pver),0._r8)
    1063             : 
    1064             :    end if
    1065             : 
    1066   970230336 : end subroutine explmix
    1067             : 
    1068             : !===============================================================================
    1069             : 
    1070    14062087 : subroutine activate_aerosol(wbar, sigw, wdiab, wminf, wmaxf, tair, rhoair,  &
    1071    14062087 :    na, nbins, volume, hygro, aero_props, &
    1072    14062087 :    fn, fm, fluxn, fluxm, flux_fullact, smax_prescribed, in_cloud_in, smax_f)
    1073             : 
    1074             :    !      calculates number, surface, and mass fraction of aerosols activated as CCN
    1075             :    !      calculates flux of cloud droplets, surface area, and aerosol mass into cloud
    1076             :    !      assumes an internal mixture within each of up to nbin multiple aerosol bins
    1077             :    !      a gaussiam spectrum of updrafts can be treated.
    1078             : 
    1079             :    !      mks units
    1080             : 
    1081             :    !      Abdul-Razzak and Ghan, A parameterization of aerosol activation.
    1082             :    !      2. Multiple aerosol types. J. Geophys. Res., 105, 6837-6844.
    1083             : 
    1084             :    !      input
    1085             : 
    1086             :    real(r8), intent(in) :: wbar          ! grid cell mean vertical velocity (m/s)
    1087             :    real(r8), intent(in) :: sigw          ! subgrid standard deviation of vertical vel (m/s)
    1088             :    real(r8), intent(in) :: wdiab         ! diabatic vertical velocity (0 if adiabatic)
    1089             :    real(r8), intent(in) :: wminf         ! minimum updraft velocity for integration (m/s)
    1090             :    real(r8), intent(in) :: wmaxf         ! maximum updraft velocity for integration (m/s)
    1091             :    real(r8), intent(in) :: tair          ! air temperature (K)
    1092             :    real(r8), intent(in) :: rhoair        ! air density (kg/m3)
    1093             :    real(r8), intent(in) :: na(:)      ! aerosol number concentration (/m3)
    1094             :    integer,  intent(in) :: nbins      ! number of aerosol bins
    1095             :    real(r8), intent(in) :: volume(:)  ! aerosol volume concentration (m3/m3)
    1096             :    real(r8), intent(in) :: hygro(:)   ! hygroscopicity of aerosol mode
    1097             : 
    1098             :    class(aerosol_properties), intent(in) :: aero_props
    1099             : 
    1100             :    !      output
    1101             : 
    1102             :    real(r8), intent(out) :: fn(:)      ! number fraction of aerosols activated
    1103             :    real(r8), intent(out) :: fm(:)      ! mass fraction of aerosols activated
    1104             :    real(r8), intent(out) :: fluxn(:)   ! flux of activated aerosol number fraction into cloud (cm/s)
    1105             :    real(r8), intent(out) :: fluxm(:)   ! flux of activated aerosol mass fraction into cloud (cm/s)
    1106             :    real(r8), intent(out) :: flux_fullact   ! flux of activated aerosol fraction assuming 100% activation (cm/s)
    1107             :    !    rce-comment
    1108             :    !    used for consistency check -- this should match (ekd(k)*zs(k))
    1109             :    !    also, fluxm/flux_fullact gives fraction of aerosol mass flux
    1110             :    !       that is activated
    1111             : 
    1112             :    !      optional
    1113             :    real(r8), optional, intent(in) :: smax_prescribed  ! prescribed max. supersaturation for secondary activation
    1114             :    logical,  optional, intent(in) :: in_cloud_in      ! switch to modify calculations when above cloud base
    1115             :    real(r8), optional, intent(in) :: smax_f           ! droplet and rain size distr factor in the smax calculation
    1116             :                                                       ! used when in_cloud=.true.
    1117             : 
    1118             :    !      local
    1119             : 
    1120             :    integer, parameter:: nx=200
    1121             :    real(r8) integ,integf
    1122             :    real(r8), parameter :: p0 = 1013.25e2_r8    ! reference pressure (Pa)
    1123             :    real(r8) pres ! pressure (Pa)
    1124             :    real(r8) diff0,conduct0
    1125             :    real(r8) es ! saturation vapor pressure
    1126             :    real(r8) qs ! water vapor saturation mixing ratio
    1127             :    real(r8) dqsdt ! change in qs with temperature
    1128             :    real(r8) g ! thermodynamic function (m2/s)
    1129    28124174 :    real(r8) zeta(nbins), eta(nbins)
    1130             :    real(r8) alpha
    1131             :    real(r8) gamma
    1132             :    real(r8) beta
    1133             :    real(r8) sqrtg
    1134    28124174 :    real(r8) :: amcube(nbins) ! cube of dry bin radius (m)
    1135    28124174 :    real(r8) smc(nbins) ! critical supersaturation for number bin radius
    1136             :    real(r8) sumflx_fullact
    1137    28124174 :    real(r8) sumflxn(nbins)
    1138    28124174 :    real(r8) sumflxm(nbins)
    1139    28124174 :    real(r8) sumfn(nbins)
    1140    28124174 :    real(r8) sumfm(nbins)
    1141    28124174 :    real(r8) fnold(nbins)   ! number fraction activated
    1142    28124174 :    real(r8) fmold(nbins)   ! mass fraction activated
    1143             :    real(r8) wold,gold
    1144             :    real(r8) wmin,wmax,w,dw,dwmax,dwmin,wnuc,dwnew,wb
    1145             :    real(r8) dfmin,dfmax,fnew,fold,fnmin,fnbar,fmbar
    1146             :    real(r8) alw,sqrtalw
    1147             :    real(r8) smax
    1148             :    real(r8) z,z1,z2,wf1,wf2,zf1,zf2,gf1,gf2,gf
    1149    14062087 :    real(r8) etafactor1,etafactor2(nbins),etafactor2max
    1150             :    real(r8) grow
    1151             :    character(len=*), parameter :: subname='activate_aerosol'
    1152             : 
    1153             :    logical :: in_cloud
    1154             :    integer m,n
    1155             :    !      numerical integration parameters
    1156             :    real(r8), parameter :: eps=0.3_r8,fmax=0.99_r8,sds=3._r8
    1157             : 
    1158             :    real(r8), parameter :: namin=1.e6_r8   ! minimum aerosol number concentration (/m3)
    1159             : 
    1160             :    integer ndist(nx)  ! accumulates frequency distribution of integration bins required
    1161             :    data ndist/nx*0/
    1162             :    save ndist
    1163             : 
    1164    14062087 :    if (present(in_cloud_in)) then
    1165           0 :       if (.not. present(smax_f)) call endrun(subname//' error: smax_f must be supplied when in_cloud is used')
    1166           0 :       in_cloud = in_cloud_in
    1167             :    else
    1168             :       in_cloud = .false.
    1169             :    end if
    1170             : 
    1171    84372522 :    fn(:)=0._r8
    1172    84372522 :    fm(:)=0._r8
    1173    84372522 :    fluxn(:)=0._r8
    1174    84372522 :    fluxm(:)=0._r8
    1175    14062087 :    flux_fullact=0._r8
    1176             : 
    1177    14062087 :    if(nbins.eq.1.and.na(1).lt.1.e-20_r8)return
    1178             : 
    1179    14062087 :    if(sigw.le.1.e-5_r8.and.wbar.le.0._r8)return
    1180             : 
    1181    14062087 :    if ( present( smax_prescribed ) ) then
    1182     1299743 :       if (smax_prescribed <= 0.0_r8) return
    1183             :    end if
    1184             : 
    1185    14062087 :    pres=rair*rhoair*tair
    1186    14062087 :    diff0=0.211e-4_r8*(p0/pres)*(tair/tmelt)**1.94_r8
    1187    14062087 :    conduct0=(5.69_r8+0.017_r8*(tair-tmelt))*4.186e2_r8*1.e-5_r8 ! convert to J/m/s/deg
    1188    14062087 :    call qsat(tair, pres, es, qs)
    1189    14062087 :    dqsdt=latvap/(rh2o*tair*tair)*qs
    1190    14062087 :    alpha=gravit*(latvap/(cpair*rh2o*tair*tair)-1._r8/(rair*tair))
    1191    14062087 :    gamma=(1.0_r8+latvap/cpair*dqsdt)/(rhoair*qs)
    1192    14062087 :    etafactor2max=1.e10_r8/(alpha*wmaxf)**1.5_r8 ! this should make eta big if na is very small.
    1193             : 
    1194             :    grow  = 1._r8/(rhoh2o/(diff0*rhoair*qs)  &
    1195    14062087 :            + latvap*rhoh2o/(conduct0*tair)*(latvap/(rh2o*tair) - 1._r8))
    1196    14062087 :    sqrtg = sqrt(grow)
    1197    14062087 :    beta  = 2._r8*pi*rhoh2o*grow*gamma
    1198             : 
    1199    84372522 :    do m=1,nbins
    1200             : 
    1201    84372522 :       if(volume(m).gt.1.e-39_r8.and.na(m).gt.1.e-39_r8)then
    1202             :          ! number mode radius (m)
    1203    69654993 :          amcube(m)=aero_props%amcube(m, volume(m),na(m))
    1204             :          ! growth coefficent Abdul-Razzak & Ghan 1998 eqn 16
    1205             :          ! should depend on mean radius of mode to account for gas kinetic effects
    1206             :          ! see Fountoukis and Nenes, JGR2005 and Meskhidze et al., JGR2006
    1207             :          ! for approriate size to use for effective diffusivity.
    1208    69654993 :          etafactor2(m)=1._r8/(na(m)*beta*sqrtg)
    1209    69654993 :          if(hygro(m).gt.1.e-10_r8)then
    1210    69654993 :             smc(m)=2._r8*aten*sqrt(aten/(27._r8*hygro(m)*amcube(m))) ! only if variable size dist
    1211             :          else
    1212           0 :             smc(m)=100._r8
    1213             :          endif
    1214             :       else
    1215      655442 :          smc(m)=1._r8
    1216      655442 :          etafactor2(m)=etafactor2max ! this should make eta big if na is very small.
    1217             :       endif
    1218             : 
    1219             :    enddo
    1220             : 
    1221    14062087 :    if(sigw.gt.1.e-5_r8)then ! spectrum of updrafts
    1222             : 
    1223           0 :       wmax=min(wmaxf,wbar+sds*sigw)
    1224           0 :       wmin=max(wminf,-wdiab)
    1225           0 :       wmin=max(wmin,wbar-sds*sigw)
    1226           0 :       w=wmin
    1227           0 :       dwmax=eps*sigw
    1228           0 :       dw=dwmax
    1229           0 :       dfmax=0.2_r8
    1230           0 :       dfmin=0.1_r8
    1231           0 :       if (wmax <= w) return
    1232           0 :       do m=1,nbins
    1233           0 :          sumflxn(m)=0._r8
    1234           0 :          sumfn(m)=0._r8
    1235           0 :          fnold(m)=0._r8
    1236           0 :          sumflxm(m)=0._r8
    1237           0 :          sumfm(m)=0._r8
    1238           0 :          fmold(m)=0._r8
    1239             :       enddo
    1240           0 :       sumflx_fullact=0._r8
    1241             : 
    1242           0 :       fold=0._r8
    1243           0 :       wold=0._r8
    1244           0 :       gold=0._r8
    1245             : 
    1246           0 :       dwmin = min( dwmax, 0.01_r8 )
    1247           0 :       do n = 1, nx
    1248             : 
    1249           0 : 100      wnuc=w+wdiab
    1250             :          !           write(iulog,*)'wnuc=',wnuc
    1251           0 :          alw=alpha*wnuc
    1252           0 :          sqrtalw=sqrt(alw)
    1253           0 :          etafactor1=alw*sqrtalw
    1254             : 
    1255           0 :          do m=1,nbins
    1256           0 :             eta(m)=etafactor1*etafactor2(m)
    1257           0 :             zeta(m)=twothird*sqrtalw*aten/sqrtg
    1258             :          enddo
    1259             : 
    1260           0 :          if ( present( smax_prescribed ) ) then
    1261           0 :             smax = smax_prescribed
    1262             :          else
    1263           0 :             smax = aero_props%maxsat(zeta,eta,smc)
    1264             :          endif
    1265             : 
    1266           0 :          call aero_props%actfracs( nbins, smc(nbins), smax, fnew, fm(nbins) )
    1267             : 
    1268           0 :          dwnew = dw
    1269           0 :          if(fnew-fold.gt.dfmax.and.n.gt.1)then
    1270             :             !              reduce updraft increment for greater accuracy in integration
    1271           0 :             if (dw .gt. 1.01_r8*dwmin) then
    1272           0 :                dw=0.7_r8*dw
    1273           0 :                dw=max(dw,dwmin)
    1274           0 :                w=wold+dw
    1275           0 :                go to 100
    1276             :             else
    1277             :                dwnew = dwmin
    1278             :             endif
    1279             :          endif
    1280             : 
    1281           0 :          if(fnew-fold.lt.dfmin)then
    1282             :             !              increase updraft increment to accelerate integration
    1283           0 :             dwnew=min(1.5_r8*dw,dwmax)
    1284             :          endif
    1285           0 :          fold=fnew
    1286             : 
    1287           0 :          z=(w-wbar)/(sigw*sq2)
    1288           0 :          g=exp(-z*z)
    1289           0 :          fnmin=1._r8
    1290             : 
    1291           0 :          do m=1,nbins
    1292             :             !              modal
    1293           0 :             call aero_props%actfracs( m, smc(m), smax, fn(m), fm(m) )
    1294           0 :             fnmin=min(fn(m),fnmin)
    1295             :             !               integration is second order accurate
    1296             :             !               assumes linear variation of f*g with w
    1297           0 :             fnbar=(fn(m)*g+fnold(m)*gold)
    1298           0 :             fmbar=(fm(m)*g+fmold(m)*gold)
    1299           0 :             wb=(w+wold)
    1300           0 :             if(w.gt.0._r8)then
    1301             :                sumflxn(m)=sumflxn(m)+sixth*(wb*fnbar           &
    1302           0 :                   +(fn(m)*g*w+fnold(m)*gold*wold))*dw
    1303             :                sumflxm(m)=sumflxm(m)+sixth*(wb*fmbar           &
    1304           0 :                   +(fm(m)*g*w+fmold(m)*gold*wold))*dw
    1305             :             endif
    1306           0 :             sumfn(m)=sumfn(m)+0.5_r8*fnbar*dw
    1307           0 :             fnold(m)=fn(m)
    1308           0 :             sumfm(m)=sumfm(m)+0.5_r8*fmbar*dw
    1309           0 :             fmold(m)=fm(m)
    1310             :          enddo
    1311             :          !           same form as sumflxm but replace the fm with 1.0
    1312             :          sumflx_fullact = sumflx_fullact &
    1313           0 :             + sixth*(wb*(g+gold) + (g*w+gold*wold))*dw
    1314           0 :          gold=g
    1315           0 :          wold=w
    1316           0 :          dw=dwnew
    1317           0 :          if (n > 1 .and. (w > wmax .or. fnmin > fmax)) exit
    1318           0 :          w=w+dw
    1319           0 :          if (n == nx) then
    1320           0 :             write(iulog,*)'do loop is too short in activate'
    1321           0 :             write(iulog,*)'wmin=',wmin,' w=',w,' wmax=',wmax,' dw=',dw
    1322           0 :             write(iulog,*)'wbar=',wbar,' sigw=',sigw,' wdiab=',wdiab
    1323           0 :             write(iulog,*)'wnuc=',wnuc
    1324           0 :             write(iulog,*)'na=',(na(m),m=1,nbins)
    1325           0 :             write(iulog,*)'fn=',(fn(m),m=1,nbins)
    1326             :             !   dump all subr parameters to allow testing with standalone code
    1327             :             !   (build a driver that will read input and call activate)
    1328           0 :             write(iulog,*)'wbar,sigw,wdiab,tair,rhoair,nbins='
    1329           0 :             write(iulog,*) wbar,sigw,wdiab,tair,rhoair,nbins
    1330           0 :             write(iulog,*)'na=',na
    1331           0 :             write(iulog,*)'volume=', (volume(m),m=1,nbins)
    1332           0 :             write(iulog,*)'hygro='
    1333           0 :             write(iulog,*) hygro
    1334           0 :             call endrun(subname)
    1335             :          end if
    1336             : 
    1337             :       enddo
    1338             : 
    1339           0 :       ndist(n)=ndist(n)+1
    1340           0 :       if(w.lt.wmaxf)then
    1341             : 
    1342             :          !            contribution from all updrafts stronger than wmax
    1343             :          !            assuming constant f (close to fmax)
    1344           0 :          wnuc=w+wdiab
    1345             : 
    1346           0 :          z1=(w-wbar)/(sigw*sq2)
    1347           0 :          z2=(wmaxf-wbar)/(sigw*sq2)
    1348           0 :          g=exp(-z1*z1)
    1349           0 :          integ=sigw*0.5_r8*sq2*sqpi*(erf(z2)-erf(z1))
    1350             :          !            consider only upward flow into cloud base when estimating flux
    1351           0 :          wf1=max(w,zero)
    1352           0 :          zf1=(wf1-wbar)/(sigw*sq2)
    1353           0 :          gf1=exp(-zf1*zf1)
    1354           0 :          wf2=max(wmaxf,zero)
    1355           0 :          zf2=(wf2-wbar)/(sigw*sq2)
    1356           0 :          gf2=exp(-zf2*zf2)
    1357           0 :          gf=(gf1-gf2)
    1358           0 :          integf=wbar*sigw*0.5_r8*sq2*sqpi*(erf(zf2)-erf(zf1))+sigw*sigw*gf
    1359             : 
    1360           0 :          do m=1,nbins
    1361           0 :             sumflxn(m)=sumflxn(m)+integf*fn(m)
    1362           0 :             sumfn(m)=sumfn(m)+fn(m)*integ
    1363           0 :             sumflxm(m)=sumflxm(m)+integf*fm(m)
    1364           0 :             sumfm(m)=sumfm(m)+fm(m)*integ
    1365             :          enddo
    1366             :          !           same form as sumflxm but replace the fm with 1.0
    1367           0 :          sumflx_fullact = sumflx_fullact + integf
    1368             :          !            sumg=sumg+integ
    1369             :       endif
    1370             : 
    1371             : 
    1372           0 :       do m=1,nbins
    1373           0 :          fn(m)=sumfn(m)/(sq2*sqpi*sigw)
    1374             :          !            fn(m)=sumfn(m)/(sumg)
    1375           0 :          if(fn(m).gt.1.01_r8)then
    1376           0 :             write(iulog,*)'fn=',fn(m),' > 1 in activate'
    1377           0 :             write(iulog,*)'w,m,na,amcube=',w,m,na(m),amcube(m)
    1378           0 :             write(iulog,*)'integ,sumfn,sigw=',integ,sumfn(m),sigw
    1379           0 :             call endrun('activate')
    1380             :          endif
    1381           0 :          fluxn(m)=sumflxn(m)/(sq2*sqpi*sigw)
    1382           0 :          fm(m)=sumfm(m)/(sq2*sqpi*sigw)
    1383             :          !            fm(m)=sumfm(m)/(sumg)
    1384           0 :          if(fm(m).gt.1.01_r8)then
    1385           0 :             write(iulog,*)'fm=',fm(m),' > 1 in activate'
    1386             :          endif
    1387           0 :          fluxm(m)=sumflxm(m)/(sq2*sqpi*sigw)
    1388             :       enddo
    1389             :       !        same form as fluxm
    1390           0 :       flux_fullact = sumflx_fullact/(sq2*sqpi*sigw)
    1391             : 
    1392             :    else
    1393             : 
    1394             :       !        single updraft
    1395    14062087 :       wnuc=wbar+wdiab
    1396             : 
    1397    14062087 :       if(wnuc.gt.0._r8)then
    1398             : 
    1399    14062087 :          w=wbar
    1400             : 
    1401    14062087 :          if(in_cloud) then
    1402             : 
    1403           0 :             if (smax_f > 0._r8) then
    1404           0 :                smax = alpha*w/(2.0_r8*pi*rhoh2o*grow*gamma*smax_f)
    1405             :             else
    1406           0 :                smax = 1.e-20_r8
    1407             :             end if
    1408             : 
    1409             :          else ! at cloud base
    1410    14062087 :             alw        = alpha*wnuc
    1411    14062087 :             sqrtalw    = sqrt(alw)
    1412    14062087 :             etafactor1 = alw*sqrtalw
    1413             : 
    1414    84372522 :             do m = 1, nbins
    1415    70310435 :                eta(m)  = etafactor1*etafactor2(m)
    1416    84372522 :                zeta(m) = twothird*sqrtalw*aten/sqrtg
    1417             :             end do
    1418    14062087 :             if ( present(smax_prescribed) ) then
    1419     1299743 :                smax = smax_prescribed
    1420             :             else
    1421    12762344 :                smax = aero_props%maxsat(zeta,eta,smc)
    1422             :             end if
    1423             :          end if
    1424             : 
    1425    84372522 :          do m=1,nbins
    1426             : 
    1427    70310435 :             call aero_props%actfracs( m, smc(m), smax, fn(m), fm(m) )
    1428             : 
    1429    84372522 :             if(wbar.gt.0._r8)then
    1430    70310435 :                fluxn(m)=fn(m)*w
    1431    70310435 :                fluxm(m)=fm(m)*w
    1432             :             endif
    1433             :          enddo
    1434    14062087 :          flux_fullact = w
    1435             :       endif
    1436             : 
    1437             :    endif
    1438             : 
    1439             : end subroutine activate_aerosol
    1440             : 
    1441             : !===============================================================================
    1442             : 
    1443      241920 : subroutine ccncalc(aero_state, aero_props, state, cs, ccn)
    1444             : 
    1445             :    ! calculates number concentration of aerosols activated as CCN at
    1446             :    ! supersaturation supersat.
    1447             :    ! assumes an internal mixture of a multiple externally-mixed aerosol modes
    1448             :    ! cgs units
    1449             : 
    1450             :    ! Ghan et al., Atmos. Res., 1993, 198-221.
    1451             : 
    1452             :    ! arguments
    1453             :    class(aerosol_state), intent(in) :: aero_state
    1454             :    class(aerosol_properties), intent(in) :: aero_props
    1455             : 
    1456             :    type(physics_state), target, intent(in)    :: state
    1457             : 
    1458             :    real(r8), intent(in)  :: cs(pcols,pver)       ! air density (kg/m3)
    1459             :    real(r8), intent(out) :: ccn(pcols,pver,psat) ! number conc of aerosols activated at supersat (#/m3)
    1460             : 
    1461             :    ! local
    1462             : 
    1463             :    integer :: ncol  ! number of columns
    1464             :    integer :: nbin  ! number of bins
    1465      241920 :    real(r8), pointer :: tair(:,:)     ! air temperature (K)
    1466             : 
    1467             :    real(r8) naerosol(pcols) ! interstit+activated aerosol number conc (/m3)
    1468             :    real(r8) vaerosol(pcols) ! interstit+activated aerosol volume conc (m3/m3)
    1469             : 
    1470             :    real(r8) amcube(pcols)
    1471      241920 :    real(r8), allocatable :: argfactor(:)
    1472             :    real(r8) surften_coef
    1473             :    real(r8) a(pcols) ! surface tension parameter
    1474             :    real(r8) hygro(pcols)  ! aerosol hygroscopicity
    1475             :    real(r8) sm(pcols)  ! critical supersaturation at mode radius
    1476             :    real(r8) arg(pcols)
    1477             :    integer l,m,i,k, astat
    1478             :    real(r8) smcoef(pcols)
    1479             :    integer phase ! phase of aerosol
    1480             : 
    1481             :    integer :: errnum
    1482             :    character(len=shr_kind_cs) :: errstr
    1483             : 
    1484             :    !     mathematical constants
    1485             :    real(r8), parameter :: super(psat) = supersat(:psat)*0.01_r8
    1486             :    real(r8), parameter :: smcoefcoef  = 2._r8/sqrt(27._r8)
    1487             : 
    1488             :    !-------------------------------------------------------------------------------
    1489             : 
    1490      483840 :    nbin  = aero_props%nbins()
    1491      241920 :    ncol  = state%ncol
    1492      241920 :    tair  => state%t
    1493             : 
    1494      725760 :    allocate( argfactor(nbin), stat=astat )
    1495      241920 :    if (astat/=0) then
    1496           0 :       call endrun('ndrop::ccncalc : not able to allocate argfactor')
    1497             :    end if
    1498             : 
    1499      241920 :    surften_coef=2._r8*mwh2o*surften/(r_universal*rhoh2o)
    1500             : 
    1501     1451520 :    do m=1,nbin
    1502     1451520 :       argfactor(m)=twothird/(sq2*aero_props%alogsig(m))
    1503             :    end do
    1504             : 
    1505      241920 :    ccn = 0._r8
    1506     7983360 :    do k=top_lev,pver
    1507             : 
    1508   119218176 :       do i=1,ncol
    1509   111476736 :          a(i)=surften_coef/tair(i,k)
    1510   119218176 :          smcoef(i)=smcoefcoef*a(i)*sqrt(a(i))
    1511             :       end do
    1512             : 
    1513    46690560 :       do m=1,nbin
    1514             : 
    1515    38707200 :          phase=3 ! interstitial+cloudborne
    1516             : 
    1517             :          call aero_state%loadaer( aero_props, &
    1518             :             1, ncol, k, &
    1519             :             m, cs, phase, naerosol, vaerosol, &
    1520    38707200 :             hygro, errnum, errstr)
    1521    38707200 :          if (errnum/=0) then
    1522           0 :             call endrun('ccncalc : '//trim(errstr))
    1523             :          end if
    1524             : 
    1525  2903040000 :          where(naerosol(:ncol)>1.e-3_r8 .and. hygro(:ncol)>1.e-10_r8)
    1526    38707200 :             amcube(:ncol)=aero_props%amcube(m, vaerosol(:ncol), naerosol(:ncol) )
    1527    38707200 :             sm(:ncol)=smcoef(:ncol)/sqrt(hygro(:ncol)*amcube(:ncol)) ! critical supersaturation
    1528             :          elsewhere
    1529             :             sm(:ncol)=1._r8 ! value shouldn't matter much since naerosol is small
    1530             :          endwhere
    1531   278691840 :          do l=1,psat
    1532  3615252480 :             do i=1,ncol
    1533  3344302080 :                arg(i)=argfactor(m)*log(sm(i)/super(l))
    1534  3576545280 :                ccn(i,k,l)=ccn(i,k,l)+naerosol(i)*0.5_r8*(1._r8-erf(arg(i)))
    1535             :             enddo
    1536             :          enddo
    1537             :       enddo
    1538             :    enddo
    1539   717002496 :    ccn(:ncol,:,:)=ccn(:ncol,:,:)*1.e-6_r8 ! convert from #/m3 to #/cm3
    1540             : 
    1541      241920 :    deallocate( argfactor )
    1542             : 
    1543      241920 : end subroutine ccncalc
    1544             : 
    1545             : !===============================================================================
    1546             : end module ndrop

Generated by: LCOV version 1.14