LCOV - code coverage report
Current view: top level - physics/cam - vertical_diffusion.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 299 623 48.0 %
Date: 2025-03-13 18:42:46 Functions: 5 6 83.3 %

          Line data    Source code
       1             : module vertical_diffusion
       2             : 
       3             : !----------------------------------------------------------------------------------------------------- !
       4             : ! Module to compute vertical diffusion of momentum,  moisture, trace constituents                      !
       5             : ! and static energy. Separate modules compute                                                          !
       6             : !   1. stresses associated with turbulent flow over orography                                          !
       7             : !      ( turbulent mountain stress )                                                                   !
       8             : !   2. eddy diffusivities, including nonlocal tranport terms                                           !
       9             : !   3. molecular diffusivities                                                                         !
      10             : ! Lastly, a implicit diffusion solver is called, and tendencies retrieved by                           !
      11             : ! differencing the diffused and initial states.                                                        !
      12             : !                                                                                                      !
      13             : ! Calling sequence:                                                                                    !
      14             : !                                                                                                      !
      15             : !  vertical_diffusion_init      Initializes vertical diffustion constants and modules                  !
      16             : !        init_molec_diff        Initializes molecular diffusivity module                               !
      17             : !        init_eddy_diff         Initializes eddy diffusivity module (includes PBL)                     !
      18             : !        init_tms               Initializes turbulent mountain stress module                           !
      19             : !        init_vdiff             Initializes diffusion solver module                                    !
      20             : !  vertical_diffusion_ts_init   Time step initialization (only used for upper boundary condition)      !
      21             : !  vertical_diffusion_tend      Computes vertical diffusion tendencies                                 !
      22             : !        compute_tms            Computes turbulent mountain stresses                                   !
      23             : !        compute_eddy_diff      Computes eddy diffusivities and countergradient terms                  !
      24             : !        compute_vdiff          Solves vertical diffusion equations, including molecular diffusivities !
      25             : !                                                                                                      !
      26             : !----------------------------------------------------------------------------------------------------- !
      27             : ! Some notes on refactoring changes made in 2015, which were not quite finished.                       !
      28             : !                                                                                                      !
      29             : !      - eddy_diff_tend should really only have state, pbuf, and cam_in as inputs. The process of      !
      30             : !        removing these arguments, and referring to pbuf fields instead, is not complete.              !
      31             : !                                                                                                      !
      32             : !      - compute_vdiff was intended to be split up into three components:                              !
      33             : !                                                                                                      !
      34             : !         1. Diffusion of winds and heat ("U", "V", and "S" in the fieldlist object).                  !
      35             : !                                                                                                      !
      36             : !         2. Turbulent diffusion of a single constituent                                               !
      37             : !                                                                                                      !
      38             : !         3. Molecular diffusion of a single constituent                                               !
      39             : !                                                                                                      !
      40             : !        This reorganization would allow the three resulting functions to each use a simpler interface !
      41             : !        than the current combined version, and possibly also remove the need to use the fieldlist     !
      42             : !        object at all.                                                                                !
      43             : !                                                                                                      !
      44             : !      - The conditionals controlled by "do_pbl_diags" are somewhat scattered. It might be better to   !
      45             : !        pull out these diagnostic calculations and outfld calls into separate functions.              !
      46             : !                                                                                                      !
      47             : !---------------------------Code history-------------------------------------------------------------- !
      48             : ! J. Rosinski : Jun. 1992                                                                              !
      49             : ! J. McCaa    : Sep. 2004                                                                              !
      50             : ! S. Park     : Aug. 2006, Dec. 2008. Jan. 2010                                                        !
      51             : !----------------------------------------------------------------------------------------------------- !
      52             : 
      53             : use shr_kind_mod,     only : r8 => shr_kind_r8, i4=> shr_kind_i4
      54             : use ppgrid,           only : pcols, pver, pverp
      55             : use constituents,     only : pcnst
      56             : use diffusion_solver, only : vdiff_selector
      57             : use cam_abortutils,   only : endrun
      58             : use error_messages,   only : handle_errmsg
      59             : use physconst,        only :          &
      60             :      cpair  , &     ! Specific heat of dry air
      61             :      gravit , &     ! Acceleration due to gravity
      62             :      rair   , &     ! Gas constant for dry air
      63             :      zvir   , &     ! rh2o/rair - 1
      64             :      latvap , &     ! Latent heat of vaporization
      65             :      latice , &     ! Latent heat of fusion
      66             :      karman , &     ! von Karman constant
      67             :      mwdry  , &     ! Molecular weight of dry air
      68             :      avogad         ! Avogadro's number
      69             : use cam_history,      only : fieldname_len
      70             : use perf_mod
      71             : use cam_logfile,      only : iulog
      72             : use ref_pres,         only : do_molec_diff, nbot_molec
      73             : use phys_control,     only : phys_getopts
      74             : use time_manager,     only : is_first_step
      75             : implicit none
      76             : private
      77             : save
      78             : 
      79             : ! ----------------- !
      80             : ! Public interfaces !
      81             : ! ----------------- !
      82             : 
      83             : public vd_readnl
      84             : public vd_register                                   ! Register multi-time-level variables with physics buffer
      85             : public vertical_diffusion_init                       ! Initialization
      86             : public vertical_diffusion_ts_init                    ! Time step initialization (only used for upper boundary condition)
      87             : public vertical_diffusion_tend                       ! Full vertical diffusion routine
      88             : 
      89             : ! ------------ !
      90             : ! Private data !
      91             : ! ------------ !
      92             : 
      93             : character(len=16)    :: eddy_scheme                  ! Default set in phys_control.F90, use namelist to change
      94             : !     'HB'       = Holtslag and Boville (default)
      95             : !     'HBR'      = Holtslag and Boville and Rash
      96             : !     'diag_TKE' = Bretherton and Park ( UW Moist Turbulence Scheme )
      97             : logical, parameter   :: wstarent = .true.            ! Use wstar (.true.) or TKE (.false.) entrainment closure
      98             : ! ( when 'diag_TKE' scheme is selected )
      99             : logical              :: do_pseudocon_diff = .false.  ! If .true., do pseudo-conservative variables diffusion
     100             : 
     101             : character(len=16)    :: shallow_scheme               ! Shallow convection scheme
     102             : 
     103             : type(vdiff_selector) :: fieldlist_wet                ! Logical switches for moist mixing ratio diffusion
     104             : type(vdiff_selector) :: fieldlist_dry                ! Logical switches for dry mixing ratio diffusion
     105             : type(vdiff_selector) :: fieldlist_molec              ! Logical switches for molecular diffusion
     106             : integer              :: tke_idx, kvh_idx, kvm_idx    ! TKE and eddy diffusivity indices for fields in the physics buffer
     107             : integer              :: kvt_idx                      ! Index for kinematic molecular conductivity
     108             : integer              :: turbtype_idx, smaw_idx       ! Turbulence type and instability functions
     109             : integer              :: tauresx_idx, tauresy_idx     ! Redisual stress for implicit surface stress
     110             : 
     111             : character(len=fieldname_len) :: vdiffnam(pcnst)      ! Names of vertical diffusion tendencies
     112             : integer              :: ixcldice, ixcldliq           ! Constituent indices for cloud liquid and ice water
     113             : integer              :: ixnumice, ixnumliq
     114             : 
     115             : integer              :: pblh_idx, tpert_idx, qpert_idx
     116             : 
     117             : ! pbuf fields for unicon
     118             : integer              :: qtl_flx_idx  = -1            ! for use in cloud macrophysics when UNICON is on
     119             : integer              :: qti_flx_idx  = -1            ! for use in cloud macrophysics when UNICON is on
     120             : 
     121             : ! pbuf fields for tms
     122             : integer              :: ksrftms_idx  = -1
     123             : integer              :: tautmsx_idx  = -1
     124             : integer              :: tautmsy_idx  = -1
     125             : 
     126             : ! pbuf fields for blj (Beljaars)
     127             : integer              :: dragblj_idx  = -1
     128             : integer              :: taubljx_idx  = -1
     129             : integer              :: taubljy_idx  = -1
     130             : 
     131             : ! pbuf field for clubb top above which HB (Holtslag Boville) scheme may be enabled
     132             : integer              :: clubbtop_idx = -1
     133             : 
     134             : logical              :: diff_cnsrv_mass_check        ! do mass conservation check
     135             : logical              :: do_iss                       ! switch for implicit turbulent surface stress
     136             : logical              :: prog_modal_aero = .false.    ! set true if prognostic modal aerosols are present
     137             : integer              :: pmam_ncnst = 0               ! number of prognostic modal aerosol constituents
     138             : integer, allocatable :: pmam_cnst_idx(:)             ! constituent indices of prognostic modal aerosols
     139             : 
     140             : logical              :: do_pbl_diags = .false.
     141             : logical              :: waccmx_mode = .false.
     142             : logical              :: do_hb_above_clubb = .false.
     143             : 
     144             : real(r8),allocatable :: kvm_sponge(:)
     145             : 
     146             : contains
     147             : 
     148             :   ! =============================================================================== !
     149             :   !                                                                                 !
     150             :   ! =============================================================================== !
     151        1536 : subroutine vd_readnl(nlfile)
     152             : 
     153             :   use namelist_utils,  only: find_group_name
     154             :   use units,           only: getunit, freeunit
     155             :   use spmd_utils,      only: masterproc, masterprocid, mpi_logical, mpicom
     156             :   use shr_log_mod,     only: errMsg => shr_log_errMsg
     157             :   use trb_mtn_stress_cam, only: trb_mtn_stress_readnl
     158             :   use beljaars_drag_cam, only: beljaars_drag_readnl
     159             :   use eddy_diff_cam,   only: eddy_diff_readnl
     160             : 
     161             :   character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
     162             : 
     163             :   ! Local variables
     164             :   integer :: unitn, ierr
     165             :   character(len=*), parameter :: subname = 'vd_readnl'
     166             : 
     167             :   namelist /vert_diff_nl/ diff_cnsrv_mass_check, do_iss
     168             :   !-----------------------------------------------------------------------------
     169             : 
     170        1536 :   if (masterproc) then
     171           2 :      unitn = getunit()
     172           2 :      open( unitn, file=trim(nlfile), status='old' )
     173           2 :      call find_group_name(unitn, 'vert_diff_nl', status=ierr)
     174           2 :      if (ierr == 0) then
     175           2 :         read(unitn, vert_diff_nl, iostat=ierr)
     176           2 :         if (ierr /= 0) then
     177           0 :            call endrun(subname // ':: ERROR reading namelist')
     178             :         end if
     179             :      end if
     180           2 :      close(unitn)
     181           2 :      call freeunit(unitn)
     182             :   end if
     183             : 
     184        1536 :   call mpi_bcast(diff_cnsrv_mass_check, 1, mpi_logical, masterprocid, mpicom, ierr)
     185        1536 :   if (ierr /= 0) call endrun(errMsg(__FILE__, __LINE__)//" mpi_bcast error")
     186        1536 :   call mpi_bcast(do_iss,                1, mpi_logical, masterprocid, mpicom, ierr)
     187        1536 :   if (ierr /= 0) call endrun(errMsg(__FILE__, __LINE__)//" mpi_bcast error")
     188             : 
     189             :   ! Get eddy_scheme setting from phys_control.
     190             :   call phys_getopts( eddy_scheme_out          =          eddy_scheme, &
     191        1536 :        shallow_scheme_out       =       shallow_scheme )
     192             : 
     193             :   ! TMS reads its own namelist.
     194        1536 :   call trb_mtn_stress_readnl(nlfile)
     195             : 
     196             :   ! Beljaars reads its own namelist.
     197        1536 :   call beljaars_drag_readnl(nlfile)
     198             : 
     199        1536 :   if (eddy_scheme == 'diag_TKE' .or. eddy_scheme == 'SPCAM_m2005' ) call eddy_diff_readnl(nlfile)
     200             : 
     201        1536 : end subroutine vd_readnl
     202             : 
     203             : ! =============================================================================== !
     204             : !                                                                                 !
     205             : ! =============================================================================== !
     206             : 
     207        1536 : subroutine vd_register()
     208             : 
     209             :   !------------------------------------------------ !
     210             :   ! Register physics buffer fields and constituents !
     211             :   !------------------------------------------------ !
     212             : 
     213        1536 :   use physics_buffer,      only : pbuf_add_field, dtype_r8, dtype_i4
     214             :   use trb_mtn_stress_cam,  only : trb_mtn_stress_register
     215             :   use beljaars_drag_cam,   only : beljaars_drag_register
     216             :   use eddy_diff_cam,       only : eddy_diff_register
     217             : 
     218             :   ! Add fields to physics buffer
     219             : 
     220             :   ! kvt is used by gw_drag.  only needs physpkg scope.
     221        1536 :   call pbuf_add_field('kvt', 'physpkg', dtype_r8, (/pcols,pverp/), kvt_idx)
     222             : 
     223             : 
     224        1536 :   if (eddy_scheme /= 'CLUBB_SGS') then
     225           0 :      call pbuf_add_field('kvh',      'global', dtype_r8, (/pcols, pverp/), kvh_idx)
     226             :   end if
     227             : 
     228        1536 :   call pbuf_add_field('kvm',      'global', dtype_r8, (/pcols, pverp/), kvm_idx )
     229        1536 :   call pbuf_add_field('pblh',     'global', dtype_r8, (/pcols/),        pblh_idx)
     230        1536 :   call pbuf_add_field('tke',      'global', dtype_r8, (/pcols, pverp/), tke_idx)
     231        1536 :   call pbuf_add_field('turbtype', 'global', dtype_i4, (/pcols, pverp/), turbtype_idx)
     232        1536 :   call pbuf_add_field('smaw',     'global', dtype_r8, (/pcols, pverp/), smaw_idx)
     233             : 
     234        1536 :   call pbuf_add_field('tauresx',  'global', dtype_r8, (/pcols/),        tauresx_idx)
     235        1536 :   call pbuf_add_field('tauresy',  'global', dtype_r8, (/pcols/),        tauresy_idx)
     236             : 
     237        1536 :   call pbuf_add_field('tpert', 'global', dtype_r8, (/pcols/),                       tpert_idx)
     238        1536 :   call pbuf_add_field('qpert', 'global', dtype_r8, (/pcols,pcnst/),                 qpert_idx)
     239             : 
     240        1536 :   if (trim(shallow_scheme) == 'UNICON') then
     241           0 :      call pbuf_add_field('qtl_flx',  'global', dtype_r8, (/pcols, pverp/), qtl_flx_idx)
     242           0 :      call pbuf_add_field('qti_flx',  'global', dtype_r8, (/pcols, pverp/), qti_flx_idx)
     243             :   end if
     244             : 
     245             :   ! diag_TKE fields
     246        1536 :   if (eddy_scheme == 'diag_TKE' .or. eddy_scheme == 'SPCAM_m2005') then
     247           0 :      call eddy_diff_register()
     248             :   end if
     249             : 
     250             :   ! TMS fields
     251        1536 :   call trb_mtn_stress_register()
     252             : 
     253             :   ! Beljaars fields
     254        1536 :   call beljaars_drag_register()
     255             : 
     256        1536 : end subroutine vd_register
     257             : 
     258             : ! =============================================================================== !
     259             : !                                                                                 !
     260             : ! =============================================================================== !
     261             : 
     262        1536 : subroutine vertical_diffusion_init(pbuf2d)
     263             : 
     264             :   !------------------------------------------------------------------!
     265             :   ! Initialization of time independent fields for vertical diffusion !
     266             :   ! Calls initialization routines for subsidiary modules             !
     267             :   !----------------------------------------------------------------- !
     268             : 
     269        1536 :   use cam_history,       only : addfld, add_default, horiz_only
     270             :   use cam_history,       only : register_vector_field
     271             :   use eddy_diff_cam,     only : eddy_diff_init
     272             :   use hb_diff,           only : init_hb_diff
     273             :   use molec_diff,        only : init_molec_diff
     274             :   use diffusion_solver,  only : init_vdiff, new_fieldlist_vdiff, vdiff_select
     275             :   use constituents,      only : cnst_get_ind, cnst_get_type_byind, cnst_name, cnst_get_molec_byind
     276             :   use spmd_utils,        only : masterproc
     277             :   use ref_pres,          only : press_lim_idx, pref_mid
     278             :   use physics_buffer,    only : pbuf_set_field, pbuf_get_index, physics_buffer_desc
     279             :   use rad_constituents,  only : rad_cnst_get_info, rad_cnst_get_mode_num_idx, &
     280             :        rad_cnst_get_mam_mmr_idx
     281             :   use trb_mtn_stress_cam,only : trb_mtn_stress_init
     282             :   use beljaars_drag_cam, only : beljaars_drag_init
     283             :   use upper_bc,          only : ubc_init
     284             :   use phys_control,      only : waccmx_is, fv_am_correction
     285             :   use ref_pres,          only : ptop_ref
     286             : 
     287             :   type(physics_buffer_desc), pointer :: pbuf2d(:,:)
     288             :   character(128) :: errstring   ! Error status for init_vdiff
     289             :   integer        :: ntop_eddy   ! Top    interface level to which eddy vertical diffusion is applied ( = 1 )
     290             :   integer        :: nbot_eddy   ! Bottom interface level to which eddy vertical diffusion is applied ( = pver )
     291             :   integer        :: k           ! Vertical loop index
     292             : 
     293             :   real(r8), parameter :: ntop_eddy_pres = 1.e-7_r8 ! Pressure below which eddy diffusion is not done in WACCM-X. (Pa)
     294             : 
     295             :   integer :: im, l, m, nmodes, nspec, ierr
     296             : 
     297             :   logical :: history_amwg                 ! output the variables used by the AMWG diag package
     298             :   logical :: history_eddy                 ! output the eddy variables
     299             :   logical :: history_budget               ! Output tendencies and state variables for CAM4 T, qv, ql, qi
     300             :   integer :: history_budget_histfile_num  ! output history file number for budget fields
     301             :   logical :: history_waccm                ! output variables of interest for WACCM runs
     302             : 
     303             :   !
     304             :   ! add sponge layer vertical diffusion
     305             :   !
     306        1536 :   if (ptop_ref>1e-1_r8.and.ptop_ref<100.0_r8) then
     307             :      !
     308             :      ! CAM7 FMT (but not CAM6 top (~225 Pa) or CAM7 low top or lower)
     309             :      !
     310        1536 :      allocate(kvm_sponge(4), stat=ierr)
     311        1536 :      if( ierr /= 0 ) then
     312           0 :         write(iulog,*) 'vertical_diffusion_init:  kvm_sponge allocation error = ',ierr
     313           0 :         call endrun('vertical_diffusion_init: failed to allocate kvm_sponge array')
     314             :      end if
     315        1536 :      kvm_sponge(1) = 2E6_r8
     316        1536 :      kvm_sponge(2) = 2E6_r8
     317        1536 :      kvm_sponge(3) = 0.5E6_r8
     318        1536 :      kvm_sponge(4) = 0.1E6_r8
     319           0 :   else if (ptop_ref>1e-4_r8) then
     320             :      !
     321             :      ! WACCM and WACCM-x
     322             :      !
     323           0 :      allocate(kvm_sponge(6), stat=ierr)
     324           0 :      if( ierr /= 0 ) then
     325           0 :         write(iulog,*) 'vertical_diffusion_init:  kvm_sponge allocation error = ',ierr
     326           0 :         call endrun('vertical_diffusion_init: failed to allocate kvm_sponge array')
     327             :      end if
     328           0 :      kvm_sponge(1) = 2E6_r8
     329           0 :      kvm_sponge(2) = 2E6_r8
     330           0 :      kvm_sponge(3) = 1.5E6_r8
     331           0 :      kvm_sponge(4) = 1.0E6_r8
     332           0 :      kvm_sponge(5) = 0.5E6_r8
     333           0 :      kvm_sponge(6) = 0.1E6_r8
     334             :   end if
     335             : 
     336        1536 :   if (masterproc) then
     337           2 :      write(iulog,*)'Initializing vertical diffusion (vertical_diffusion_init)'
     338           2 :      if (allocated(kvm_sponge)) then
     339           2 :         write(iulog,*)'Artificial sponge layer vertical diffusion added:'
     340          10 :         do k=1,size(kvm_sponge(:),1)
     341           8 :            write(iulog,'(a44,i2,a17,e7.2,a8)') 'vertical diffusion coefficient at interface',k,' is increased by ', &
     342          18 :                                                 kvm_sponge(k),' m2 s-2'
     343             :         end do
     344             :      end if !allocated
     345             :   end if
     346             : 
     347             :   ! Check to see if WACCM-X is on (currently we don't care whether the
     348             :   ! ionosphere is on or not, since this neutral diffusion code is the
     349             :   ! same either way).
     350        1536 :   waccmx_mode = waccmx_is('ionosphere') .or. waccmx_is('neutral')
     351             : 
     352             :   ! ----------------------------------------------------------------- !
     353             :   ! Get indices of cloud liquid and ice within the constituents array !
     354             :   ! ----------------------------------------------------------------- !
     355             : 
     356        1536 :   call cnst_get_ind( 'CLDLIQ', ixcldliq )
     357        1536 :   call cnst_get_ind( 'CLDICE', ixcldice )
     358             :   ! These are optional; with the CAM4 microphysics, there are no number
     359             :   ! constituents.
     360        1536 :   call cnst_get_ind( 'NUMLIQ', ixnumliq, abort=.false. )
     361        1536 :   call cnst_get_ind( 'NUMICE', ixnumice, abort=.false. )
     362             : 
     363             :   ! prog_modal_aero determines whether prognostic modal aerosols are present in the run.
     364        1536 :   call phys_getopts(prog_modal_aero_out=prog_modal_aero)
     365        1536 :   if (prog_modal_aero) then
     366             : 
     367             :      ! Get the constituent indices of the number and mass mixing ratios of the modal
     368             :      ! aerosols.
     369             :      !
     370             :      ! N.B. - This implementation assumes that the prognostic modal aerosols are
     371             :      !        impacting the climate calculation (i.e., can get info from list 0).
     372             :      !
     373             : 
     374             :      ! First need total number of mam constituents
     375        1536 :      call rad_cnst_get_info(0, nmodes=nmodes)
     376        7680 :      do m = 1, nmodes
     377        6144 :         call rad_cnst_get_info(0, m, nspec=nspec)
     378        7680 :         pmam_ncnst = pmam_ncnst + 1 + nspec
     379             :      end do
     380             : 
     381        4608 :      allocate(pmam_cnst_idx(pmam_ncnst))
     382             : 
     383             :      ! Get the constituent indicies
     384        1536 :      im = 1
     385        7680 :      do m = 1, nmodes
     386        6144 :         call rad_cnst_get_mode_num_idx(m, pmam_cnst_idx(im))
     387        6144 :         im = im + 1
     388        6144 :         call rad_cnst_get_info(0, m, nspec=nspec)
     389       36864 :         do l = 1, nspec
     390       23040 :            call rad_cnst_get_mam_mmr_idx(m, l, pmam_cnst_idx(im))
     391       29184 :            im = im + 1
     392             :         end do
     393             :      end do
     394             :   end if
     395             : 
     396             :   ! Initialize upper boundary condition module
     397             : 
     398        1536 :   call ubc_init()
     399             : 
     400             :   ! ---------------------------------------------------------------------------------------- !
     401             :   ! Initialize molecular diffusivity module                                                  !
     402             :   ! Note that computing molecular diffusivities is a trivial expense, but constituent        !
     403             :   ! diffusivities depend on their molecular weights. Decomposing the diffusion matrix        !
     404             :   ! for each constituent is a needless expense unless the diffusivity is significant.        !
     405             :   ! ---------------------------------------------------------------------------------------- !
     406             : 
     407             :   !----------------------------------------------------------------------------------------
     408             :   ! Initialize molecular diffusion and get top and bottom molecular diffusion limits
     409             :   !----------------------------------------------------------------------------------------
     410             : 
     411        1536 :   if( do_molec_diff ) then
     412             :      call init_molec_diff( r8, pcnst, mwdry, avogad, &
     413           0 :           errstring)
     414             : 
     415           0 :      call handle_errmsg(errstring, subname="init_molec_diff")
     416             : 
     417           0 :      call addfld( 'TTPXMLC', horiz_only, 'A', 'K/S', 'Top interf. temp. flux: molec. viscosity' )
     418           0 :      if( masterproc ) write(iulog,fmt='(a,i3,5x,a,i3)') 'NBOT_MOLEC =', nbot_molec
     419             :   end if
     420             : 
     421             :   ! ---------------------------------- !
     422             :   ! Initialize eddy diffusivity module !
     423             :   ! ---------------------------------- !
     424             : 
     425             :   ! ntop_eddy must be 1 or <= nbot_molec
     426             :   ! Currently, it is always 1 except for WACCM-X.
     427        1536 :   if ( waccmx_mode ) then
     428           0 :      ntop_eddy  = press_lim_idx(ntop_eddy_pres, top=.true.)
     429             :   else
     430        1536 :      ntop_eddy = 1
     431             :   end if
     432        1536 :   nbot_eddy  = pver
     433             : 
     434        1536 :   if (masterproc) write(iulog, fmt='(a,i3,5x,a,i3)') 'NTOP_EDDY  =', ntop_eddy, 'NBOT_EDDY  =', nbot_eddy
     435             : 
     436        1536 :   call phys_getopts(do_hb_above_clubb_out=do_hb_above_clubb)
     437             : 
     438           0 :   select case ( eddy_scheme )
     439             :   case ( 'diag_TKE', 'SPCAM_m2005' )
     440           0 :      if( masterproc ) write(iulog,*) &
     441           0 :           'vertical_diffusion_init: eddy_diffusivity scheme: UW Moist Turbulence Scheme by Bretherton and Park'
     442           0 :      call eddy_diff_init(pbuf2d, ntop_eddy, nbot_eddy)
     443             :   case ( 'HB', 'HBR', 'SPCAM_sam1mom')
     444           0 :      if( masterproc ) write(iulog,*) 'vertical_diffusion_init: eddy_diffusivity scheme:  Holtslag and Boville'
     445             :      call init_hb_diff(gravit, cpair, ntop_eddy, nbot_eddy, pref_mid, &
     446           0 :           karman, eddy_scheme)
     447           0 :      call addfld('HB_ri',      (/ 'lev' /),  'A', 'no',  'Richardson Number (HB Scheme), I' )
     448             :   case ( 'CLUBB_SGS' )
     449        1536 :      do_pbl_diags = .true.
     450        1536 :      call init_hb_diff(gravit, cpair, ntop_eddy, nbot_eddy, pref_mid, karman, eddy_scheme)
     451             :      !
     452             :      ! run HB scheme where CLUBB is not active when running cam7 or cam6 physics
     453             :      ! else init_hb_diff is called just for diagnostic purposes
     454             :      !
     455        3072 :      if (do_hb_above_clubb) then
     456        1536 :        if( masterproc ) then
     457           2 :          write(iulog,*) 'vertical_diffusion_init: '
     458           2 :          write(iulog,*) 'eddy_diffusivity scheme where CLUBB is not active:  Holtslag and Boville'
     459             :        end if
     460        3072 :        call addfld('HB_ri',      (/ 'lev' /),  'A', 'no',  'Richardson Number (HB Scheme), I' )
     461             :      end if
     462             :   end select
     463             : 
     464             :   ! ------------------------------------------- !
     465             :   ! Initialize turbulent mountain stress module !
     466             :   ! ------------------------------------------- !
     467             : 
     468        1536 :   call trb_mtn_stress_init()
     469             : 
     470             :   ! ----------------------------------- !
     471             :   ! Initialize Beljaars SGO drag module !
     472             :   ! ----------------------------------- !
     473             : 
     474        1536 :   call beljaars_drag_init()
     475             : 
     476             :   ! ---------------------------------- !
     477             :   ! Initialize diffusion solver module !
     478             :   ! ---------------------------------- !
     479             : 
     480        1536 :   call init_vdiff(r8, iulog, rair, cpair, gravit, do_iss, fv_am_correction, errstring)
     481        1536 :   call handle_errmsg(errstring, subname="init_vdiff")
     482             : 
     483             :   ! Use fieldlist_wet to select the fields which will be diffused using moist mixing ratios ( all by default )
     484             :   ! Use fieldlist_dry to select the fields which will be diffused using dry   mixing ratios.
     485             : 
     486        1536 :   fieldlist_wet = new_fieldlist_vdiff( pcnst)
     487        1536 :   fieldlist_dry = new_fieldlist_vdiff( pcnst)
     488        1536 :   fieldlist_molec = new_fieldlist_vdiff( pcnst)
     489             : 
     490        1536 :   if( vdiff_select( fieldlist_wet, 'u' ) .ne. '' ) call endrun( vdiff_select( fieldlist_wet, 'u' ) )
     491        1536 :   if( vdiff_select( fieldlist_wet, 'v' ) .ne. '' ) call endrun( vdiff_select( fieldlist_wet, 'v' ) )
     492        1536 :   if( vdiff_select( fieldlist_wet, 's' ) .ne. '' ) call endrun( vdiff_select( fieldlist_wet, 's' ) )
     493             : 
     494       64512 :   constit_loop: do k = 1, pcnst
     495             : 
     496       62976 :      if (prog_modal_aero) then
     497             :         ! Do not diffuse droplet number - treated in dropmixnuc
     498       62976 :         if (k == ixnumliq) cycle constit_loop
     499             :         ! Don't diffuse modal aerosol - treated in dropmixnuc
     500      936960 :         do m = 1, pmam_ncnst
     501      936960 :            if (k == pmam_cnst_idx(m)) cycle constit_loop
     502             :         enddo
     503             :      end if
     504             : 
     505             :      ! Convert all constituents to wet before doing diffusion.
     506       32256 :      if( vdiff_select( fieldlist_wet, 'q', k ) .ne. '' ) call endrun( vdiff_select( fieldlist_wet, 'q', k ) )
     507             : 
     508             :      ! ----------------------------------------------- !
     509             :      ! Select constituents for molecular diffusion     !
     510             :      ! ----------------------------------------------- !
     511       33792 :      if ( cnst_get_molec_byind(k) .eq. 'minor' ) then
     512       95232 :         if( vdiff_select(fieldlist_molec,'q',k) .ne. '' ) call endrun( vdiff_select( fieldlist_molec,'q',k ) )
     513             :      endif
     514             : 
     515             :   end do constit_loop
     516             : 
     517             :   ! ------------------------ !
     518             :   ! Diagnostic output fields !
     519             :   ! ------------------------ !
     520             : 
     521       64512 :   do k = 1, pcnst
     522       62976 :      vdiffnam(k) = 'VD'//cnst_name(k)
     523       62976 :      if( k == 1 ) vdiffnam(k) = 'VD01'    !**** compatibility with old code ****
     524      127488 :      call addfld( vdiffnam(k), (/ 'lev' /), 'A', 'kg/kg/s', 'Vertical diffusion of '//cnst_name(k) )
     525             :   end do
     526             : 
     527        1536 :   if (.not. do_pbl_diags) then
     528           0 :      call addfld( 'PBLH'        , horiz_only    , 'A', 'm'      , 'PBL height'                                         )
     529           0 :      call addfld( 'QT'          , (/ 'lev' /)   , 'A', 'kg/kg'  , 'Total water mixing ratio'                           )
     530           0 :      call addfld( 'SL'          , (/ 'lev' /)   , 'A', 'J/kg'   , 'Liquid water static energy'                         )
     531           0 :      call addfld( 'SLV'         , (/ 'lev' /)   , 'A', 'J/kg'   , 'Liq wat virtual static energy'                      )
     532           0 :      call addfld( 'SLFLX'       , (/ 'ilev' /)  , 'A', 'W/m2'   , 'Liquid static energy flux'                          )
     533           0 :      call addfld( 'QTFLX'       , (/ 'ilev' /)  , 'A', 'W/m2'   , 'Total water flux'                                   )
     534           0 :      call addfld( 'TKE'         , (/ 'ilev' /)  , 'A', 'm2/s2'  , 'Turbulent Kinetic Energy'                           )
     535           0 :      call addfld( 'TPERT'       , horiz_only    , 'A', 'K'      , 'Perturbation temperature (eddies in PBL)'           )
     536           0 :      call addfld( 'QPERT'       , horiz_only    , 'A', 'kg/kg'  , 'Perturbation specific humidity (eddies in PBL)'     )
     537             : 
     538           0 :      call addfld( 'UFLX'        , (/ 'ilev' /)  , 'A', 'W/m2'   , 'Zonal momentum flux'                                )
     539           0 :      call addfld( 'VFLX'        , (/ 'ilev' /)  , 'A', 'W/m2'   , 'Meridional momentm flux'                            )
     540           0 :      call register_vector_field('UFLX', 'VFLX')
     541             :   end if
     542             : 
     543        1536 :   call addfld( 'USTAR'       , horiz_only    , 'A', 'm/s'    , 'Surface friction velocity'                          )
     544        3072 :   call addfld( 'KVH'         , (/ 'ilev' /)  , 'A', 'm2/s'   , 'Vertical diffusion diffusivities (heat/moisture)'   )
     545        3072 :   call addfld( 'KVM'         , (/ 'ilev' /)  , 'A', 'm2/s'   , 'Vertical diffusion diffusivities (momentum)'        )
     546        3072 :   call addfld( 'KVT'         , (/ 'ilev' /)  , 'A', 'm2/s'   , 'Vertical diffusion kinematic molecular conductivity')
     547        3072 :   call addfld( 'CGS'         , (/ 'ilev' /)  , 'A', 's/m2'   , 'Counter-gradient coeff on surface kinematic fluxes' )
     548        3072 :   call addfld( 'DTVKE'       , (/ 'lev' /)   , 'A', 'K/s'    , 'dT/dt vertical diffusion KE dissipation'            )
     549        3072 :   call addfld( 'DTV'         , (/ 'lev' /)   , 'A', 'K/s'    , 'T vertical diffusion'                               )
     550        3072 :   call addfld( 'DUV'         , (/ 'lev' /)   , 'A', 'm/s2'   , 'U vertical diffusion'                               )
     551        3072 :   call addfld( 'DVV'         , (/ 'lev' /)   , 'A', 'm/s2'   , 'V vertical diffusion'                               )
     552             : 
     553             :   ! ---------------------------------------------------------------------------- !
     554             :   ! Below ( with '_PBL') are for detailed analysis of UW Moist Turbulence Scheme !
     555             :   ! ---------------------------------------------------------------------------- !
     556             : 
     557        1536 :   if (.not. do_pbl_diags) then
     558             : 
     559           0 :      call addfld( 'qt_pre_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'qt_prePBL'          )
     560           0 :      call addfld( 'sl_pre_PBL',   (/ 'lev' /)   , 'A', 'J/kg'   , 'sl_prePBL'          )
     561           0 :      call addfld( 'slv_pre_PBL',  (/ 'lev' /)   , 'A', 'J/kg'   , 'slv_prePBL'         )
     562           0 :      call addfld( 'u_pre_PBL',    (/ 'lev' /)   , 'A', 'm/s'    , 'u_prePBL'           )
     563           0 :      call addfld( 'v_pre_PBL',    (/ 'lev' /)   , 'A', 'm/s'    , 'v_prePBL'           )
     564           0 :      call addfld( 'qv_pre_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'qv_prePBL'          )
     565           0 :      call addfld( 'ql_pre_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'ql_prePBL'          )
     566           0 :      call addfld( 'qi_pre_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'qi_prePBL'          )
     567           0 :      call addfld( 't_pre_PBL',    (/ 'lev' /)   , 'A', 'K'      , 't_prePBL'           )
     568           0 :      call addfld( 'rh_pre_PBL',   (/ 'lev' /)   , 'A', '%'      , 'rh_prePBL'          )
     569             : 
     570           0 :      call addfld( 'qt_aft_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'qt_afterPBL'        )
     571           0 :      call addfld( 'sl_aft_PBL',   (/ 'lev' /)   , 'A', 'J/kg'   , 'sl_afterPBL'        )
     572           0 :      call addfld( 'slv_aft_PBL',  (/ 'lev' /)   , 'A', 'J/kg'   , 'slv_afterPBL'       )
     573           0 :      call addfld( 'u_aft_PBL',    (/ 'lev' /)   , 'A', 'm/s'    , 'u_afterPBL'         )
     574           0 :      call addfld( 'v_aft_PBL',    (/ 'lev' /)   , 'A', 'm/s'    , 'v_afterPBL'         )
     575           0 :      call addfld( 'qv_aft_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'qv_afterPBL'        )
     576           0 :      call addfld( 'ql_aft_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'ql_afterPBL'        )
     577           0 :      call addfld( 'qi_aft_PBL',   (/ 'lev' /)   , 'A', 'kg/kg'  , 'qi_afterPBL'        )
     578           0 :      call addfld( 't_aft_PBL',    (/ 'lev' /)   , 'A', 'K'      , 't_afterPBL'         )
     579           0 :      call addfld( 'rh_aft_PBL',   (/ 'lev' /)   , 'A', '%'      , 'rh_afterPBL'        )
     580             : 
     581           0 :      call addfld( 'slflx_PBL',    (/ 'ilev' /)  , 'A', 'J/m2/s' , 'sl flux by PBL'     )
     582           0 :      call addfld( 'qtflx_PBL',    (/ 'ilev' /)  , 'A', 'kg/m2/s', 'qt flux by PBL'     )
     583           0 :      call addfld( 'uflx_PBL',     (/ 'ilev' /)  , 'A', 'kg/m/s2', 'u flux by PBL'      )
     584           0 :      call addfld( 'vflx_PBL',     (/ 'ilev' /)  , 'A', 'kg/m/s2', 'v flux by PBL'      )
     585             : 
     586           0 :      call addfld( 'slflx_cg_PBL', (/ 'ilev' /)  , 'A', 'J/m2/s' , 'sl_cg flux by PBL'  )
     587           0 :      call addfld( 'qtflx_cg_PBL', (/ 'ilev' /)  , 'A', 'kg/m2/s', 'qt_cg flux by PBL'  )
     588           0 :      call addfld( 'uflx_cg_PBL',  (/ 'ilev' /)  , 'A', 'kg/m/s2', 'u_cg flux by PBL'   )
     589           0 :      call addfld( 'vflx_cg_PBL',  (/ 'ilev' /)  , 'A', 'kg/m/s2', 'v_cg flux by PBL'   )
     590             : 
     591           0 :      call addfld( 'qtten_PBL',    (/ 'lev' /)   , 'A', 'kg/kg/s', 'qt tendency by PBL' )
     592           0 :      call addfld( 'slten_PBL',    (/ 'lev' /)   , 'A', 'J/kg/s' , 'sl tendency by PBL' )
     593           0 :      call addfld( 'uten_PBL',     (/ 'lev' /)   , 'A', 'm/s2'   , 'u tendency by PBL'  )
     594           0 :      call addfld( 'vten_PBL',     (/ 'lev' /)   , 'A', 'm/s2'   , 'v tendency by PBL'  )
     595           0 :      call addfld( 'qvten_PBL',    (/ 'lev' /)   , 'A', 'kg/kg/s', 'qv tendency by PBL' )
     596           0 :      call addfld( 'qlten_PBL',    (/ 'lev' /)   , 'A', 'kg/kg/s', 'ql tendency by PBL' )
     597           0 :      call addfld( 'qiten_PBL',    (/ 'lev' /)   , 'A', 'kg/kg/s', 'qi tendency by PBL' )
     598           0 :      call addfld( 'tten_PBL',     (/ 'lev' /)   , 'A', 'K/s'    , 'T tendency by PBL'  )
     599           0 :      call addfld( 'rhten_PBL',    (/ 'lev' /)   , 'A', '%/s'    , 'RH tendency by PBL' )
     600             : 
     601             :   end if
     602             : 
     603        1536 :   call addfld ('ustar',horiz_only, 'A',     ' ',' ')
     604        1536 :   call addfld ('obklen',horiz_only, 'A',    ' ',' ')
     605             : 
     606             :   ! ----------------------------
     607             :   ! determine default variables
     608             :   ! ----------------------------
     609             : 
     610             :   call phys_getopts( history_amwg_out = history_amwg, &
     611             :        history_eddy_out = history_eddy, &
     612             :        history_budget_out = history_budget, &
     613             :        history_budget_histfile_num_out = history_budget_histfile_num, &
     614        1536 :        history_waccm_out = history_waccm)
     615             : 
     616        1536 :   if (history_amwg) then
     617        1536 :      call add_default(  vdiffnam(1), 1, ' ' )
     618        1536 :      call add_default( 'DTV'       , 1, ' ' )
     619        1536 :      if (.not. do_pbl_diags) then
     620           0 :         call add_default( 'PBLH'      , 1, ' ' )
     621             :      end if
     622             :   endif
     623             : 
     624        1536 :   if (history_eddy) then
     625           0 :      call add_default( 'UFLX    ', 1, ' ' )
     626           0 :      call add_default( 'VFLX    ', 1, ' ' )
     627             :   endif
     628             : 
     629        1536 :   if( history_budget ) then
     630           0 :      call add_default( vdiffnam(ixcldliq), history_budget_histfile_num, ' ' )
     631           0 :      call add_default( vdiffnam(ixcldice), history_budget_histfile_num, ' ' )
     632           0 :      if( history_budget_histfile_num > 1 ) then
     633           0 :         call add_default(  vdiffnam(1), history_budget_histfile_num, ' ' )
     634           0 :         call add_default( 'DTV'       , history_budget_histfile_num, ' ' )
     635             :      end if
     636             :   end if
     637             : 
     638        1536 :   if ( history_waccm ) then
     639           0 :      if (do_molec_diff) then
     640           0 :         call add_default ( 'TTPXMLC', 1, ' ' )
     641             :      end if
     642           0 :      call add_default( 'DUV'     , 1, ' ' )
     643           0 :      call add_default( 'DVV'     , 1, ' ' )
     644             :   end if
     645             :   ! ----------------------------
     646             : 
     647             : 
     648        1536 :   ksrftms_idx = pbuf_get_index('ksrftms')
     649        1536 :   tautmsx_idx = pbuf_get_index('tautmsx')
     650        1536 :   tautmsy_idx = pbuf_get_index('tautmsy')
     651             : 
     652        1536 :   dragblj_idx = pbuf_get_index('dragblj')
     653        1536 :   taubljx_idx = pbuf_get_index('taubljx')
     654        1536 :   taubljy_idx = pbuf_get_index('taubljy')
     655             : 
     656        1536 :   if (eddy_scheme == 'CLUBB_SGS') then
     657        1536 :      kvh_idx = pbuf_get_index('kvh')
     658             :   end if
     659             : 
     660        1536 :   if (do_hb_above_clubb) then
     661             :      ! pbuf field denoting top of clubb
     662        1536 :      clubbtop_idx = pbuf_get_index('clubbtop')
     663             :   end if
     664             : 
     665             :   ! Initialization of some pbuf fields
     666        1536 :   if (is_first_step()) then
     667             :      ! Initialization of pbuf fields tke, kvh, kvm are done in phys_inidat
     668         768 :      call pbuf_set_field(pbuf2d, turbtype_idx, 0    )
     669         768 :      call pbuf_set_field(pbuf2d, smaw_idx,     0.0_r8)
     670         768 :      call pbuf_set_field(pbuf2d, tauresx_idx,  0.0_r8)
     671         768 :      call pbuf_set_field(pbuf2d, tauresy_idx,  0.0_r8)
     672         768 :      if (trim(shallow_scheme) == 'UNICON') then
     673           0 :         call pbuf_set_field(pbuf2d, qtl_flx_idx,  0.0_r8)
     674           0 :         call pbuf_set_field(pbuf2d, qti_flx_idx,  0.0_r8)
     675             :      end if
     676             :   end if
     677        1536 : end subroutine vertical_diffusion_init
     678             : 
     679             : ! =============================================================================== !
     680             : !                                                                                 !
     681             : ! =============================================================================== !
     682             : 
     683       32256 : subroutine vertical_diffusion_ts_init( pbuf2d, state )
     684             : 
     685             :   !-------------------------------------------------------------- !
     686             :   ! Timestep dependent setting,                                   !
     687             :   ! At present only invokes upper bc code                         !
     688             :   !-------------------------------------------------------------- !
     689        1536 :   use upper_bc,       only : ubc_timestep_init
     690             :   use physics_types , only : physics_state
     691             :   use ppgrid        , only : begchunk, endchunk
     692             : 
     693             :   use physics_buffer, only : physics_buffer_desc
     694             : 
     695             :   type(physics_state), intent(in) :: state(begchunk:endchunk)
     696             :   type(physics_buffer_desc), pointer :: pbuf2d(:,:)
     697             : 
     698       16128 :   call ubc_timestep_init( pbuf2d, state)
     699             : 
     700       16128 : end subroutine vertical_diffusion_ts_init
     701             : 
     702             : ! =============================================================================== !
     703             : !                                                                                 !
     704             : ! =============================================================================== !
     705             : 
     706     2470608 : subroutine vertical_diffusion_tend( &
     707             :      ztodt    , state    , cam_in,          &
     708             :      ustar    , obklen   , ptend    , &
     709             :      cldn     , pbuf)
     710             :   !---------------------------------------------------- !
     711             :   ! This is an interface routine for vertical diffusion !
     712             :   !---------------------------------------------------- !
     713       16128 :   use physics_buffer,     only : physics_buffer_desc, pbuf_get_field, pbuf_set_field
     714             :   use physics_types,      only : physics_state, physics_ptend, physics_ptend_init
     715             :   use physics_types,      only : set_dry_to_wet, set_wet_to_dry
     716             : 
     717             :   use camsrfexch,         only : cam_in_t
     718             :   use cam_history,        only : outfld
     719             : 
     720             :   use trb_mtn_stress_cam, only : trb_mtn_stress_tend
     721             :   use beljaars_drag_cam,  only : beljaars_drag_tend
     722             :   use eddy_diff_cam,      only : eddy_diff_tend
     723             :   use hb_diff,            only : compute_hb_diff, compute_hb_free_atm_diff
     724             :   use wv_saturation,      only : qsat
     725             :   use molec_diff,         only : compute_molec_diff, vd_lu_qdecomp
     726             :   use constituents,       only : qmincg, qmin, cnst_type
     727             :   use diffusion_solver,   only : compute_vdiff, any, operator(.not.)
     728             :   use air_composition,    only : cpairv, rairv !Needed for calculation of upward H flux
     729             :   use time_manager,       only : get_nstep
     730             :   use constituents,       only : cnst_get_type_byind, cnst_name, &
     731             :        cnst_mw, cnst_fixed_ubc, cnst_fixed_ubflx
     732             :   use physconst,          only : pi
     733             :   use pbl_utils,          only : virtem, calc_obklen, calc_ustar
     734             :   use upper_bc,           only : ubc_get_vals, ubc_fixed_temp
     735             :   use upper_bc,           only : ubc_get_flxs
     736             :   use coords_1d,          only : Coords1D
     737             :   use phys_control,       only : cam_physpkg_is
     738             :   use ref_pres,           only : ptop_ref
     739             : 
     740             :   ! --------------- !
     741             :   ! Input Arguments !
     742             :   ! --------------- !
     743             : 
     744             :   type(physics_state), intent(inout) :: state                     ! Physics state variables
     745             :   type(cam_in_t),      intent(in)    :: cam_in                    ! Surface inputs
     746             : 
     747             :   real(r8),            intent(in)    :: ztodt                     ! 2 delta-t [ s ]
     748             :   real(r8),            intent(in)    :: cldn(pcols,pver)          ! New stratus fraction [ fraction ]
     749             : 
     750             :   ! ---------------------- !
     751             :   ! Input-Output Arguments !
     752             :   ! ---------------------- !
     753             : 
     754             :   type(physics_ptend), intent(out) :: ptend                       ! Individual parameterization tendencies
     755             :   type(physics_buffer_desc), pointer :: pbuf(:)
     756             : 
     757             :   ! ---------------- !
     758             :   ! Output Arguments !
     759             :   ! ---------------- !
     760             : 
     761             :   real(r8),            intent(out)   :: ustar(pcols)              ! Surface friction velocity [ m/s ]
     762             :   real(r8),            intent(out)   :: obklen(pcols)             ! Obukhov length [ m ]
     763             : 
     764             :   ! --------------- !
     765             :   ! Local Variables !
     766             :   ! --------------- !
     767             : 
     768             :   character(128) :: errstring                                     ! Error status for compute_vdiff
     769             : 
     770             :   integer  :: lchnk                                               ! Chunk identifier
     771             :   integer  :: ncol                                                ! Number of atmospheric columns
     772             :   integer  :: i, k, l, m                                          ! column, level, constituent indices
     773             : 
     774             :   real(r8) :: dtk(pcols,pver)                                     ! T tendency from KE dissipation
     775       58824 :   real(r8), pointer   :: tke(:,:)                                 ! Turbulent kinetic energy [ m2/s2 ]
     776       58824 :   integer(i4),pointer :: turbtype(:,:)                            ! Turbulent interface types [ no unit ]
     777       58824 :   real(r8), pointer   :: smaw(:,:)                                ! Normalized Galperin instability function
     778             :   ! ( 0<= <=4.964 and 1 at neutral )
     779             : 
     780       58824 :   real(r8), pointer   :: qtl_flx(:,:)                             ! overbar(w'qtl') where qtl = qv + ql
     781       58824 :   real(r8), pointer   :: qti_flx(:,:)                             ! overbar(w'qti') where qti = qv + qi
     782             : 
     783             :   real(r8) :: cgs(pcols,pverp)                                    ! Counter-gradient star  [ cg/flux ]
     784             :   real(r8) :: cgh(pcols,pverp)                                    ! Counter-gradient term for heat
     785             :   real(r8) :: rztodt                                              ! 1./ztodt [ 1/s ]
     786       58824 :   real(r8), pointer :: ksrftms(:)                                 ! Turbulent mountain stress surface drag coefficient [ kg/s/m2 ]
     787       58824 :   real(r8), pointer :: tautmsx(:)                                 ! U component of turbulent mountain stress [ N/m2 ]
     788       58824 :   real(r8), pointer :: tautmsy(:)                                 ! V component of turbulent mountain stress [ N/m2 ]
     789             :   real(r8) :: tautotx(pcols)                                      ! U component of total surface stress [ N/m2 ]
     790             :   real(r8) :: tautoty(pcols)                                      ! V component of total surface stress [ N/m2 ]
     791             : 
     792       58824 :   real(r8), pointer :: dragblj(:,:)                               ! Beljaars SGO form drag profile [ 1/s ]
     793       58824 :   real(r8), pointer :: taubljx(:)                                 ! U component of turbulent mountain stress [ N/m2 ]
     794       58824 :   real(r8), pointer :: taubljy(:)                                 ! V component of turbulent mountain stress [ N/m2 ]
     795             : 
     796       58824 :   real(r8), pointer :: kvh_in(:,:)                                ! kvh from previous timestep [ m2/s ]
     797       58824 :   real(r8), pointer :: kvm_in(:,:)                                ! kvm from previous timestep [ m2/s ]
     798       58824 :   real(r8), pointer :: kvt(:,:)                                   ! Molecular kinematic conductivity for temperature [  ]
     799             :   real(r8) :: kvq(pcols,pverp)                                    ! Eddy diffusivity for constituents [ m2/s ]
     800             :   real(r8) :: kvh(pcols,pverp)                                    ! Eddy diffusivity for heat [ m2/s ]
     801             :   real(r8) :: kvm(pcols,pverp)                                    ! Eddy diffusivity for momentum [ m2/s ]
     802             :   real(r8) :: kvm_temp(pcols,pverp)                               ! Dummy eddy diffusivity for momentum (unused) [ m2/s ]
     803             :   real(r8) :: dtk_temp(pcols,pverp)                               ! Unused output from second compute_vdiff call
     804             :   real(r8) :: tautmsx_temp(pcols)                                 ! Unused output from second compute_vdiff call
     805             :   real(r8) :: tautmsy_temp(pcols)                                 ! Unused output from second compute_vdiff call
     806             :   real(r8) :: topflx_temp(pcols)                                  ! Unused output from second compute_vdiff call
     807             :   real(r8) :: sprod(pcols,pverp)                                  ! Shear production of tke [ m2/s3 ]
     808             :   real(r8) :: sfi(pcols,pverp)                                    ! Saturation fraction at interfaces [ fraction ]
     809             :   real(r8) :: sl(pcols,pver)
     810             :   real(r8) :: qt(pcols,pver)
     811             :   real(r8) :: slv(pcols,pver)
     812             :   real(r8) :: sl_prePBL(pcols,pver)
     813             :   real(r8) :: qt_prePBL(pcols,pver)
     814             :   real(r8) :: slv_prePBL(pcols,pver)
     815             :   real(r8) :: slten(pcols,pver)
     816             :   real(r8) :: qtten(pcols,pver)
     817             :   real(r8) :: slflx(pcols,pverp)
     818             :   real(r8) :: qtflx(pcols,pverp)
     819             :   real(r8) :: uflx(pcols,pverp)
     820             :   real(r8) :: vflx(pcols,pverp)
     821             :   real(r8) :: slflx_cg(pcols,pverp)
     822             :   real(r8) :: qtflx_cg(pcols,pverp)
     823             :   real(r8) :: uflx_cg(pcols,pverp)
     824             :   real(r8) :: vflx_cg(pcols,pverp)
     825             :   real(r8) :: th(pcols,pver)                                      ! Potential temperature
     826             :   real(r8) :: topflx(pcols)                                       ! Molecular heat flux at top interface
     827             :   real(r8) :: rhoair
     828             : 
     829             :   real(r8) :: ri(pcols,pver)                                      ! richardson number (HB output)
     830             : 
     831             :   ! for obklen calculation outside HB
     832             :   real(r8) :: thvs(pcols)                                         ! Virtual potential temperature at surface
     833             :   real(r8) :: rrho(pcols)                                         ! Reciprocal of density at surface
     834             :   real(r8) :: khfs(pcols)                                         ! sfc kinematic heat flux [mK/s]
     835             :   real(r8) :: kqfs(pcols)                                         ! sfc kinematic water vapor flux [m/s]
     836             :   real(r8) :: kbfs(pcols)                                         ! sfc kinematic buoyancy flux [m^2/s^3]
     837             : 
     838             :   real(r8) :: ftem(pcols,pver)                                    ! Saturation vapor pressure before PBL
     839             :   real(r8) :: ftem_prePBL(pcols,pver)                             ! Saturation vapor pressure before PBL
     840             :   real(r8) :: ftem_aftPBL(pcols,pver)                             ! Saturation vapor pressure after PBL
     841             :   real(r8) :: tem2(pcols,pver)                                    ! Saturation specific humidity and RH
     842             :   real(r8) :: t_aftPBL(pcols,pver)                                ! Temperature after PBL diffusion
     843             :   real(r8) :: tten(pcols,pver)                                    ! Temperature tendency by PBL diffusion
     844             :   real(r8) :: rhten(pcols,pver)                                   ! RH tendency by PBL diffusion
     845             :   real(r8) :: qv_aft_PBL(pcols,pver)                              ! qv after PBL diffusion
     846             :   real(r8) :: ql_aft_PBL(pcols,pver)                              ! ql after PBL diffusion
     847             :   real(r8) :: qi_aft_PBL(pcols,pver)                              ! qi after PBL diffusion
     848             :   real(r8) :: s_aft_PBL(pcols,pver)                               ! s after PBL diffusion
     849             :   real(r8) :: u_aft_PBL(pcols,pver)                               ! u after PBL diffusion
     850             :   real(r8) :: v_aft_PBL(pcols,pver)                               ! v after PBL diffusion
     851             :   real(r8) :: qv_pro(pcols,pver)
     852             :   real(r8) :: ql_pro(pcols,pver)
     853             :   real(r8) :: qi_pro(pcols,pver)
     854             :   real(r8) :: s_pro(pcols,pver)
     855             :   real(r8) :: t_pro(pcols,pver)
     856       58824 :   real(r8), pointer :: tauresx(:)                                      ! Residual stress to be added in vdiff to correct
     857       58824 :   real(r8), pointer :: tauresy(:)                                      ! for turb stress mismatch between sfc and atm accumulated.
     858             : 
     859             :   ! Interpolated interface values.
     860             :   real(r8) :: tint(pcols,pver+1)      ! Temperature [ K ]
     861             :   real(r8) :: rairi(pcols,pver+1)     ! Gas constant [ J/K/kg ]
     862             :   real(r8) :: rhoi(pcols,pver+1)      ! Density of air [ kg/m^3 ]
     863             :   real(r8) :: rhoi_dry(pcols,pver+1)  ! Density of air based on dry air pressure [ kg/m^3 ]
     864             : 
     865             :   ! Upper boundary conditions
     866             :   real(r8) :: ubc_t(pcols)            ! Temperature [ K ]
     867             :   real(r8) :: ubc_mmr(pcols,pcnst)    ! Mixing ratios [ kg/kg ]
     868             :   real(r8) :: ubc_flux(pcols,pcnst)   ! Constituent upper boundary flux (kg/s/m^2)
     869             : 
     870             :   ! Pressure coordinates used by the solver.
     871       58824 :   type(Coords1D) :: p
     872       58824 :   type(Coords1D) :: p_dry
     873             : 
     874       58824 :   real(r8), pointer :: tpert(:)
     875       58824 :   real(r8), pointer :: qpert(:)
     876       58824 :   real(r8), pointer :: pblh(:)
     877             : 
     878             :   real(r8) :: tmp1(pcols)                                         ! Temporary storage
     879             : 
     880             :   integer  :: nstep
     881             :   real(r8) :: sum1, sum2, sum3, pdelx
     882             :   real(r8) :: sflx
     883             : 
     884             :   ! Copy state so we can pass to intent(inout) routines that return
     885             :   ! new state instead of a tendency.
     886             :   real(r8) :: s_tmp(pcols,pver)
     887             :   real(r8) :: u_tmp(pcols,pver)
     888             :   real(r8) :: v_tmp(pcols,pver)
     889             :   real(r8) :: q_tmp(pcols,pver,pcnst)
     890             : 
     891             :   ! kq_fac*sqrt(T)*m_d/rho for molecular diffusivity
     892             :   real(r8) :: kq_scal(pcols,pver+1)
     893             :   ! composition dependent mw_fac on interface level
     894             :   real(r8) :: mw_fac(pcols,pver+1,pcnst)
     895             : 
     896             :   ! Dry static energy top boundary condition.
     897             :   real(r8) :: dse_top(pcols)
     898             : 
     899             :   ! Copies of flux arrays used to zero out any parts that are applied
     900             :   ! elsewhere (e.g. by CLUBB).
     901             :   real(r8) :: taux(pcols)
     902             :   real(r8) :: tauy(pcols)
     903             :   real(r8) :: shflux(pcols)
     904             :   real(r8) :: cflux(pcols,pcnst)
     905       58824 :   integer,  pointer :: clubbtop(:)   ! (pcols)
     906             : 
     907             :   logical  :: lq(pcnst)
     908             : 
     909             :   ! ----------------------- !
     910             :   ! Main Computation Begins !
     911             :   ! ----------------------- !
     912             : 
     913             :   ! Assume 'wet' mixing ratios in diffusion code.
     914       58824 :   call set_dry_to_wet(state)
     915             : 
     916       58824 :   rztodt = 1._r8 / ztodt
     917       58824 :   lchnk  = state%lchnk
     918       58824 :   ncol   = state%ncol
     919             : 
     920       58824 :   call pbuf_get_field(pbuf, tauresx_idx,  tauresx)
     921       58824 :   call pbuf_get_field(pbuf, tauresy_idx,  tauresy)
     922       58824 :   call pbuf_get_field(pbuf, tpert_idx,    tpert)
     923       58824 :   call pbuf_get_field(pbuf, qpert_idx,    qpert)
     924       58824 :   call pbuf_get_field(pbuf, pblh_idx,     pblh)
     925       58824 :   call pbuf_get_field(pbuf, turbtype_idx, turbtype)
     926             : 
     927             :   ! Interpolate temperature to interfaces.
     928     5470632 :   do k = 2, pver
     929    90423432 :      do i = 1, ncol
     930    90364608 :         tint(i,k)  = 0.5_r8 * ( state%t(i,k) + state%t(i,k-1) )
     931             :      end do
     932             :   end do
     933      982224 :   tint(:ncol,pver+1) = state%t(:ncol,pver)
     934             : 
     935             :   ! Get upper boundary values
     936       58824 :   call ubc_get_vals( state%lchnk, ncol, state%pint, state%zi, ubc_t, ubc_mmr )
     937             : 
     938       58824 :   if (waccmx_mode) then
     939           0 :      call ubc_get_flxs( state%lchnk, ncol, state%pint, state%zi, state%t, state%q, state%phis, ubc_flux )
     940             :      ! For WACCM-X, set ubc temperature to extrapolate from next two lower interface level temperatures
     941           0 :      tint(:ncol,1) = 1.5_r8*tint(:ncol,2)-.5_r8*tint(:ncol,3)
     942       58824 :   else if(ubc_fixed_temp) then
     943           0 :      tint(:ncol,1) = ubc_t(:ncol)
     944             :   else
     945      982224 :      tint(:ncol,1) = state%t(:ncol,1)
     946             :   end if
     947             : 
     948             :   ! Set up pressure coordinates for solver calls.
     949       58824 :   p = Coords1D(state%pint(:ncol,:))
     950       58824 :   p_dry = Coords1D(state%pintdry(:ncol,:))
     951             : 
     952             :   !------------------------------------------------------------------------
     953             :   !  Check to see if constituent dependent gas constant needed (WACCM-X)
     954             :   !------------------------------------------------------------------------
     955       58824 :   if (waccmx_mode) then
     956           0 :      rairi(:ncol,1) = rairv(:ncol,1,lchnk)
     957           0 :      do k = 2, pver
     958           0 :         do i = 1, ncol
     959           0 :            rairi(i,k) = 0.5_r8 * (rairv(i,k,lchnk)+rairv(i,k-1,lchnk))
     960             :         end do
     961             :      end do
     962           0 :      rairi(:ncol,pver+1) = rairv(:ncol,pver,lchnk)
     963             :   else
     964    92387880 :      rairi(:ncol,:pver+1) = rair
     965             :   endif
     966             : 
     967             :   ! Compute rho at interfaces.
     968     5588280 :   do k = 1, pver+1
     969    92387880 :      do i = 1, ncol
     970    92329056 :         rhoi(i,k)  = p%ifc(i,k) / (rairi(i,k)*tint(i,k))
     971             :      end do
     972             :   end do
     973             : 
     974             :   ! Compute rho_dry at interfaces.
     975     5588280 :   do k = 1, pver+1
     976    92387880 :      do i = 1, ncol
     977    92329056 :         rhoi_dry(i,k)  = p_dry%ifc(i,k) / (rairi(i,k)*tint(i,k))
     978             :      end do
     979             :   end do
     980             : 
     981             :   ! ---------------------------------------- !
     982             :   ! Computation of turbulent mountain stress !
     983             :   ! ---------------------------------------- !
     984             : 
     985             :   ! Consistent with the computation of 'normal' drag coefficient, we are using
     986             :   ! the raw input (u,v) to compute 'ksrftms', not the provisionally-marched 'u,v'
     987             :   ! within the iteration loop of the PBL scheme.
     988             : 
     989       58824 :   call trb_mtn_stress_tend(state, pbuf, cam_in)
     990             : 
     991       58824 :   call pbuf_get_field(pbuf, ksrftms_idx, ksrftms)
     992       58824 :   call pbuf_get_field(pbuf, tautmsx_idx, tautmsx)
     993       58824 :   call pbuf_get_field(pbuf, tautmsy_idx, tautmsy)
     994             : 
     995      982224 :   tautotx(:ncol) = cam_in%wsx(:ncol) + tautmsx(:ncol)
     996      982224 :   tautoty(:ncol) = cam_in%wsy(:ncol) + tautmsy(:ncol)
     997             : 
     998             :   ! ------------------------------------- !
     999             :   ! Computation of Beljaars SGO form drag !
    1000             :   ! ------------------------------------- !
    1001             : 
    1002       58824 :   call beljaars_drag_tend(state, pbuf, cam_in)
    1003             : 
    1004       58824 :   call pbuf_get_field(pbuf, dragblj_idx, dragblj)
    1005       58824 :   call pbuf_get_field(pbuf, taubljx_idx, taubljx)
    1006       58824 :   call pbuf_get_field(pbuf, taubljy_idx, taubljy)
    1007             : 
    1008             :   ! Add Beljaars integrated drag
    1009             : 
    1010      982224 :   tautotx(:ncol) = tautotx(:ncol) + taubljx(:ncol)
    1011      982224 :   tautoty(:ncol) = tautoty(:ncol) + taubljy(:ncol)
    1012             : 
    1013             :   !----------------------------------------------------------------------- !
    1014             :   !   Computation of eddy diffusivities - Select appropriate PBL scheme    !
    1015             :   !----------------------------------------------------------------------- !
    1016       58824 :   call pbuf_get_field(pbuf, kvm_idx,  kvm_in)
    1017       58824 :   call pbuf_get_field(pbuf, kvh_idx,  kvh_in)
    1018       58824 :   call pbuf_get_field(pbuf, smaw_idx, smaw)
    1019       58824 :   call pbuf_get_field(pbuf, tke_idx,  tke)
    1020             : 
    1021             :   ! Get potential temperature.
    1022    91405656 :   th(:ncol,:pver) = state%t(:ncol,:pver) * state%exner(:ncol,:pver)
    1023             : 
    1024           0 :   select case (eddy_scheme)
    1025             :   case ( 'diag_TKE', 'SPCAM_m2005' )
    1026             : 
    1027             :      call eddy_diff_tend(state, pbuf, cam_in, &
    1028             :           ztodt, p, tint, rhoi, cldn, wstarent, &
    1029             :           kvm_in, kvh_in, ksrftms, dragblj, tauresx, tauresy, &
    1030             :           rrho, ustar, pblh, kvm, kvh, kvq, cgh, cgs, tpert, qpert, &
    1031           0 :           tke, sprod, sfi, turbtype, smaw)
    1032             : 
    1033             :      ! The diag_TKE scheme does not calculate the Monin-Obukhov length, which is used in dry deposition calculations.
    1034             :      ! Use the routines from pbl_utils to accomplish this. Assumes ustar and rrho have been set.
    1035           0 :      call virtem(ncol, th(:ncol,pver),state%q(:ncol,pver,1), thvs(:ncol))
    1036           0 :      call calc_obklen(ncol, th(:ncol,pver), thvs(:ncol), cam_in%cflx(:ncol,1), &
    1037             :           cam_in%shf(:ncol), rrho(:ncol), ustar(:ncol), &
    1038           0 :           khfs(:ncol),    kqfs(:ncol), kbfs(:ncol),   obklen(:ncol))
    1039             : 
    1040             : 
    1041             :   case ( 'HB', 'HBR', 'SPCAM_sam1mom' )
    1042             : 
    1043             :      ! Modification : We may need to use 'taux' instead of 'tautotx' here, for
    1044             :      !                consistency with the previous HB scheme.
    1045             : 
    1046             : 
    1047             :      call compute_hb_diff(ncol                                    , &
    1048             :           th        , state%t  , state%q , state%zm , state%zi    , &
    1049             :           state%pmid, state%u  , state%v , tautotx  , tautoty     , &
    1050             :           cam_in%shf, cam_in%cflx(:,1), obklen  , ustar    , pblh , &
    1051             :           kvm       , kvh      , kvq     , cgh      , cgs         , &
    1052             :           tpert     , qpert    , cldn    , cam_in%ocnfrac  , tke  , &
    1053             :           ri        , &
    1054           0 :           eddy_scheme)
    1055             : 
    1056           0 :      call outfld( 'HB_ri',          ri,         pcols,   lchnk )
    1057             : 
    1058             :   case ( 'CLUBB_SGS' )
    1059             :     !
    1060             :     ! run HB scheme where CLUBB is not active when running cam7
    1061             :     !
    1062       58824 :     if (do_hb_above_clubb) then
    1063             :       call compute_hb_free_atm_diff( ncol          , &
    1064             :            th        , state%t  , state%q , state%zm           , &
    1065             :            state%pmid, state%u  , state%v , tautotx  , tautoty , &
    1066             :            cam_in%shf, cam_in%cflx(:,1), obklen  , ustar       , &
    1067             :            kvm       , kvh      , kvq     , cgh      , cgs     , &
    1068       58824 :            ri        )
    1069             : 
    1070       58824 :       call pbuf_get_field(pbuf, clubbtop_idx, clubbtop)
    1071             :       !
    1072             :       ! zero out HB where CLUBB is active
    1073             :       !
    1074      982224 :       do i=1,ncol
    1075    33310882 :         do k=clubbtop(i),pverp
    1076    32328658 :           kvm(i,k) = 0.0_r8
    1077    32328658 :           kvh(i,k) = 0.0_r8
    1078    32328658 :           kvq(i,k) = 0.0_r8
    1079    32328658 :           cgs(i,k) = 0.0_r8
    1080    33252058 :           cgh(i,k) = 0.0_r8
    1081             :         end do
    1082             :       end do
    1083             : 
    1084       58824 :       call outfld( 'HB_ri',          ri,         pcols,   lchnk )
    1085             :     else
    1086             :       ! CLUBB has only a bare-bones placeholder here. If using CLUBB, the
    1087             :       ! PBL diffusion will happen before coupling, so vertical_diffusion
    1088             :       ! is only handling other things, e.g. some boundary conditions, tms,
    1089             :       ! and molecular diffusion.
    1090             : 
    1091           0 :       call virtem(ncol, th(:ncol,pver),state%q(:ncol,pver,1), thvs(:ncol))
    1092             : 
    1093           0 :       call calc_ustar( ncol, state%t(:ncol,pver), state%pmid(:ncol,pver), &
    1094           0 :            cam_in%wsx(:ncol), cam_in%wsy(:ncol), rrho(:ncol), ustar(:ncol))
    1095             :       ! Use actual qflux, not lhf/latvap as was done previously
    1096           0 :       call calc_obklen( ncol, th(:ncol,pver), thvs(:ncol), cam_in%cflx(:ncol,1), &
    1097             :            cam_in%shf(:ncol), rrho(:ncol), ustar(:ncol),  &
    1098           0 :            khfs(:ncol), kqfs(:ncol), kbfs(:ncol), obklen(:ncol))
    1099             :       ! These tendencies all applied elsewhere.
    1100           0 :       kvm = 0._r8
    1101           0 :       kvh = 0._r8
    1102           0 :       kvq = 0._r8
    1103             :       ! Not defined since PBL is not actually running here.
    1104           0 :       cgh = 0._r8
    1105           0 :       cgs = 0._r8
    1106             :     end if
    1107             :   end select
    1108             : 
    1109       58824 :   call outfld( 'ustar',   ustar(:), pcols, lchnk )
    1110       58824 :   call outfld( 'obklen', obklen(:), pcols, lchnk )
    1111             :   !
    1112             :   ! add sponge layer vertical diffusion
    1113             :   !
    1114       58824 :   if (allocated(kvm_sponge)) then
    1115      294120 :      do k=1,size(kvm_sponge(:),1)
    1116     3987720 :         kvm(:ncol,1) = kvm(:ncol,1)+kvm_sponge(k)
    1117             :      end do
    1118             :   end if
    1119             : 
    1120             :   ! kvh (in pbuf) is used by other physics parameterizations, and as an initial guess in compute_eddy_diff
    1121             :   ! on the next timestep.  It is not updated by the compute_vdiff call below.
    1122       58824 :   call pbuf_set_field(pbuf, kvh_idx, kvh)
    1123             : 
    1124             :   ! kvm (in pbuf) is only used as an initial guess in compute_eddy_diff on the next timestep.
    1125             :   ! The contributions for molecular diffusion made to kvm by the call to compute_vdiff below
    1126             :   ! are not included in the pbuf as these are not needed in the initial guess by compute_eddy_diff.
    1127       58824 :   call pbuf_set_field(pbuf, kvm_idx, kvm)
    1128             : 
    1129             :   !------------------------------------ !
    1130             :   !    Application of diffusivities     !
    1131             :   !------------------------------------ !
    1132             : 
    1133             :   ! Set arrays from input state.
    1134  3747690720 :   q_tmp(:ncol,:,:) = state%q(:ncol,:,:)
    1135    91405656 :   s_tmp(:ncol,:) = state%s(:ncol,:)
    1136    91405656 :   u_tmp(:ncol,:) = state%u(:ncol,:)
    1137    91405656 :   v_tmp(:ncol,:) = state%v(:ncol,:)
    1138             : 
    1139             :   !------------------------------------------------------ !
    1140             :   ! Write profile output before applying diffusion scheme !
    1141             :   !------------------------------------------------------ !
    1142             : 
    1143       58824 :   if (.not. do_pbl_diags) then
    1144           0 :      sl_prePBL(:ncol,:pver)  = s_tmp(:ncol,:) -   latvap * q_tmp(:ncol,:,ixcldliq) &
    1145           0 :           - ( latvap + latice) * q_tmp(:ncol,:,ixcldice)
    1146             :      qt_prePBL(:ncol,:pver)  = q_tmp(:ncol,:,1) + q_tmp(:ncol,:,ixcldliq) &
    1147           0 :           + q_tmp(:ncol,:,ixcldice)
    1148           0 :      slv_prePBL(:ncol,:pver) = sl_prePBL(:ncol,:pver) * ( 1._r8 + zvir*qt_prePBL(:ncol,:pver) )
    1149             : 
    1150           0 :      do k = 1, pver
    1151           0 :         call qsat(state%t(1:ncol,k), state%pmid(1:ncol,k), tem2(1:ncol,k), ftem(1:ncol,k), ncol)
    1152             :      end do
    1153           0 :      ftem_prePBL(:ncol,:) = state%q(:ncol,:,1)/ftem(:ncol,:)*100._r8
    1154             : 
    1155           0 :      call outfld( 'qt_pre_PBL   ', qt_prePBL,                 pcols, lchnk )
    1156           0 :      call outfld( 'sl_pre_PBL   ', sl_prePBL,                 pcols, lchnk )
    1157           0 :      call outfld( 'slv_pre_PBL  ', slv_prePBL,                pcols, lchnk )
    1158           0 :      call outfld( 'u_pre_PBL    ', state%u,                   pcols, lchnk )
    1159           0 :      call outfld( 'v_pre_PBL    ', state%v,                   pcols, lchnk )
    1160           0 :      call outfld( 'qv_pre_PBL   ', state%q(:,:,1),            pcols, lchnk )
    1161           0 :      call outfld( 'ql_pre_PBL   ', state%q(:,:,ixcldliq),     pcols, lchnk )
    1162           0 :      call outfld( 'qi_pre_PBL   ', state%q(:,:,ixcldice),     pcols, lchnk )
    1163           0 :      call outfld( 't_pre_PBL    ', state%t,                   pcols, lchnk )
    1164           0 :      call outfld( 'rh_pre_PBL   ', ftem_prePBL,               pcols, lchnk )
    1165             : 
    1166             :   end if
    1167             : 
    1168             :   ! --------------------------------------------------------------------------------- !
    1169             :   ! Call the diffusivity solver and solve diffusion equation                          !
    1170             :   ! The final two arguments are optional function references to                       !
    1171             :   ! constituent-independent and constituent-dependent moleculuar diffusivity routines !
    1172             :   ! --------------------------------------------------------------------------------- !
    1173             : 
    1174             :   ! Modification : We may need to output 'tautotx_im,tautoty_im' from below 'compute_vdiff' and
    1175             :   !                separately print out as diagnostic output, because these are different from
    1176             :   !                the explicit 'tautotx, tautoty' computed above.
    1177             :   ! Note that the output 'tauresx,tauresy' from below subroutines are fully implicit ones.
    1178             : 
    1179       58824 :   call pbuf_get_field(pbuf, kvt_idx, kvt)
    1180             : 
    1181       58824 :   if (do_molec_diff .and. .not. waccmx_mode) then
    1182             :      ! Top boundary condition for dry static energy
    1183           0 :      dse_top(:ncol) = cpairv(:ncol,1,lchnk) * tint(:ncol,1) + &
    1184           0 :           gravit * state%zi(:ncol,1)
    1185             :   else
    1186      982224 :      dse_top(:ncol) = 0._r8
    1187             :   end if
    1188             : 
    1189       58824 :   select case (eddy_scheme)
    1190             :   case ('CLUBB_SGS')
    1191             :      ! CLUBB applies some fluxes itself, but we still want constituent
    1192             :      ! fluxes applied here (except water vapor).
    1193       58824 :      taux = 0._r8
    1194       58824 :      tauy = 0._r8
    1195       58824 :      shflux = 0._r8
    1196     1000008 :      cflux(:,1) = 0._r8
    1197       58824 :      if (cam_physpkg_is("cam7")) then
    1198             :        ! surface fluxes applied in clubb emissions module
    1199    40059144 :        cflux(:,2:) = 0._r8
    1200             :      else
    1201           0 :        cflux(:,2:) = cam_in%cflx(:,2:)
    1202             :      end if
    1203             :   case default
    1204           0 :      taux = cam_in%wsx
    1205           0 :      tauy = cam_in%wsy
    1206           0 :      shflux = cam_in%shf
    1207       58824 :      cflux = cam_in%cflx
    1208             :   end select
    1209             : 
    1210       58824 :   if( any(fieldlist_wet) ) then
    1211             : 
    1212       58824 :      if (do_molec_diff) then
    1213             :         call compute_molec_diff(state%lchnk, pcols, pver, pcnst, ncol, &
    1214             :              kvm, kvt, tint, rhoi, kq_scal, cnst_mw, &
    1215           0 :              mw_fac, nbot_molec)
    1216             :      end if
    1217             : 
    1218             :      call compute_vdiff( state%lchnk   ,                                                                     &
    1219             :           pcols         , pver               , pcnst        , ncol          , tint          , &
    1220             :           p    , state%t      , rhoi, ztodt         , taux          , &
    1221             :           tauy          , shflux             , cflux        , &
    1222             :           kvh           , kvm                , kvq          , cgs           , cgh           , &
    1223             :           state%zi      , ksrftms            , dragblj      , &
    1224             :           qmincg       , fieldlist_wet , fieldlist_molec,&
    1225             :           u_tmp         , v_tmp              , q_tmp        , s_tmp         ,                 &
    1226             :           tautmsx       , tautmsy            , dtk          , topflx        , errstring     , &
    1227             :           tauresx       , tauresy            , 1            , cpairv(:,:,state%lchnk), dse_top, &
    1228             :           do_molec_diff, waccmx_mode, &
    1229             :           vd_lu_qdecomp, &
    1230             :           ubc_mmr, ubc_flux, kvt, state%pmid, &
    1231             :           cnst_mw, cnst_fixed_ubc, cnst_fixed_ubflx, nbot_molec, &
    1232       58824 :           kq_scal, mw_fac)
    1233             : 
    1234             :      call handle_errmsg(errstring, subname="compute_vdiff", &
    1235       58824 :           extra_msg="Error in fieldlist_wet call from vertical_diffusion.")
    1236             : 
    1237             :   end if
    1238             : 
    1239       58824 :   if( any( fieldlist_dry ) ) then
    1240             : 
    1241           0 :      if( do_molec_diff ) then
    1242             :         ! kvm is unused in the output here (since it was assigned
    1243             :         ! above), so we use a temp kvm for the inout argument, and
    1244             :         ! ignore the value output by compute_molec_diff.
    1245           0 :         kvm_temp = kvm
    1246             :         call compute_molec_diff(state%lchnk, pcols, pver, pcnst, ncol, &
    1247             :              kvm_temp, kvt, tint, rhoi_dry, kq_scal, cnst_mw, &
    1248           0 :              mw_fac, nbot_molec)
    1249             :      end if
    1250             : 
    1251             :      call compute_vdiff( state%lchnk   ,                                                                     &
    1252             :           pcols         , pver               , pcnst        , ncol          , tint          , &
    1253             :           p_dry , state%t      , rhoi_dry,  ztodt         , taux          , &
    1254             :           tauy          , shflux             , cflux        , &
    1255             :           kvh           , kvm                , kvq          , cgs           , cgh           , &
    1256             :           state%zi      , ksrftms            , dragblj      , &
    1257             :           qmincg       , fieldlist_dry , fieldlist_molec,&
    1258             :           u_tmp         , v_tmp              , q_tmp        , s_tmp         ,                 &
    1259             :           tautmsx_temp  , tautmsy_temp       , dtk_temp     , topflx_temp   , errstring     , &
    1260             :           tauresx       , tauresy            , 1            , cpairv(:,:,state%lchnk), dse_top, &
    1261             :           do_molec_diff , waccmx_mode, &
    1262             :           vd_lu_qdecomp, &
    1263             :           ubc_mmr, ubc_flux, kvt, state%pmiddry, &
    1264             :           cnst_mw, cnst_fixed_ubc, cnst_fixed_ubflx, nbot_molec, &
    1265           0 :           kq_scal, mw_fac)
    1266             : 
    1267             :      call handle_errmsg(errstring, subname="compute_vdiff", &
    1268           0 :           extra_msg="Error in fieldlist_dry call from vertical_diffusion.")
    1269             : 
    1270             :   end if
    1271             : 
    1272       58824 :   if (prog_modal_aero) then
    1273             : 
    1274             :      ! Modal aerosol species not diffused, so just add the explicit surface fluxes to the
    1275             :      ! lowest layer.  **NOTE** This code assumes wet mmr.
    1276             : 
    1277      982224 :      tmp1(:ncol) = ztodt * gravit * state%rpdel(:ncol,pver)
    1278     1176480 :      do m = 1, pmam_ncnst
    1279     1117656 :         l = pmam_cnst_idx(m)
    1280    18721080 :         q_tmp(:ncol,pver,l) = q_tmp(:ncol,pver,l) + tmp1(:ncol) * cflux(:ncol,l)
    1281             :      enddo
    1282             :   end if
    1283             : 
    1284             :   ! -------------------------------------------------------- !
    1285             :   ! Diagnostics and output writing after applying PBL scheme !
    1286             :   ! -------------------------------------------------------- !
    1287             : 
    1288       58824 :   if (.not. do_pbl_diags) then
    1289             : 
    1290           0 :      sl(:ncol,:pver)  = s_tmp(:ncol,:) -   latvap           * q_tmp(:ncol,:,ixcldliq) &
    1291           0 :           - ( latvap + latice) * q_tmp(:ncol,:,ixcldice)
    1292             :      qt(:ncol,:pver)  = q_tmp(:ncol,:,1) + q_tmp(:ncol,:,ixcldliq) &
    1293           0 :           + q_tmp(:ncol,:,ixcldice)
    1294           0 :      slv(:ncol,:pver) = sl(:ncol,:pver) * ( 1._r8 + zvir*qt(:ncol,:pver) )
    1295             : 
    1296           0 :      slflx(:ncol,1) = 0._r8
    1297           0 :      qtflx(:ncol,1) = 0._r8
    1298           0 :      uflx(:ncol,1)  = 0._r8
    1299           0 :      vflx(:ncol,1)  = 0._r8
    1300             : 
    1301           0 :      slflx_cg(:ncol,1) = 0._r8
    1302           0 :      qtflx_cg(:ncol,1) = 0._r8
    1303           0 :      uflx_cg(:ncol,1)  = 0._r8
    1304           0 :      vflx_cg(:ncol,1)  = 0._r8
    1305             : 
    1306           0 :      do k = 2, pver
    1307           0 :         do i = 1, ncol
    1308           0 :            rhoair     = state%pint(i,k) / ( rair * ( ( 0.5_r8*(slv(i,k)+slv(i,k-1)) - gravit*state%zi(i,k))/cpair ) )
    1309           0 :            slflx(i,k) = kvh(i,k) * &
    1310           0 :                 ( - rhoair*(sl(i,k-1)-sl(i,k))/(state%zm(i,k-1)-state%zm(i,k)) &
    1311           0 :                 + cgh(i,k) )
    1312             :            qtflx(i,k) = kvh(i,k) * &
    1313           0 :                 ( - rhoair*(qt(i,k-1)-qt(i,k))/(state%zm(i,k-1)-state%zm(i,k)) &
    1314           0 :                 + rhoair*(cam_in%cflx(i,1)+cam_in%cflx(i,ixcldliq)+cam_in%cflx(i,ixcldice))*cgs(i,k) )
    1315             :            uflx(i,k)  = kvm(i,k) * &
    1316           0 :                 ( - rhoair*(u_tmp(i,k-1)-u_tmp(i,k))/(state%zm(i,k-1)-state%zm(i,k)))
    1317             :            vflx(i,k)  = kvm(i,k) * &
    1318           0 :                 ( - rhoair*(v_tmp(i,k-1)-v_tmp(i,k))/(state%zm(i,k-1)-state%zm(i,k)))
    1319           0 :            slflx_cg(i,k) = kvh(i,k) * cgh(i,k)
    1320             :            qtflx_cg(i,k) = kvh(i,k) * rhoair * ( cam_in%cflx(i,1) + &
    1321           0 :                 cam_in%cflx(i,ixcldliq) + cam_in%cflx(i,ixcldice) ) * cgs(i,k)
    1322           0 :            uflx_cg(i,k)  = 0._r8
    1323           0 :            vflx_cg(i,k)  = 0._r8
    1324             :         end do
    1325             :      end do
    1326             : 
    1327             :      ! Modification : I should check whether slflx(:ncol,pverp) is correctly computed.
    1328             :      !                Note also that 'tautotx' is explicit total stress, different from
    1329             :      !                the ones that have been actually added into the atmosphere.
    1330             : 
    1331           0 :      slflx(:ncol,pverp) = cam_in%shf(:ncol)
    1332           0 :      qtflx(:ncol,pverp) = cam_in%cflx(:ncol,1)
    1333           0 :      uflx(:ncol,pverp)  = tautotx(:ncol)
    1334           0 :      vflx(:ncol,pverp)  = tautoty(:ncol)
    1335             : 
    1336           0 :      slflx_cg(:ncol,pverp) = 0._r8
    1337           0 :      qtflx_cg(:ncol,pverp) = 0._r8
    1338           0 :      uflx_cg(:ncol,pverp)  = 0._r8
    1339           0 :      vflx_cg(:ncol,pverp)  = 0._r8
    1340             : 
    1341           0 :      if (trim(shallow_scheme) == 'UNICON') then
    1342           0 :         call pbuf_get_field(pbuf, qtl_flx_idx,  qtl_flx)
    1343           0 :         call pbuf_get_field(pbuf, qti_flx_idx,  qti_flx)
    1344           0 :         qtl_flx(:ncol,1) = 0._r8
    1345           0 :         qti_flx(:ncol,1) = 0._r8
    1346           0 :         do k = 2, pver
    1347           0 :            do i = 1, ncol
    1348             :               ! For use in the cloud macrophysics
    1349             :               ! Note that density is not added here. Also, only consider local transport term.
    1350           0 :               qtl_flx(i,k) = - kvh(i,k)*(q_tmp(i,k-1,1)-q_tmp(i,k,1)+q_tmp(i,k-1,ixcldliq)-q_tmp(i,k,ixcldliq))/&
    1351           0 :                    (state%zm(i,k-1)-state%zm(i,k))
    1352           0 :               qti_flx(i,k) = - kvh(i,k)*(q_tmp(i,k-1,1)-q_tmp(i,k,1)+q_tmp(i,k-1,ixcldice)-q_tmp(i,k,ixcldice))/&
    1353           0 :                    (state%zm(i,k-1)-state%zm(i,k))
    1354             :            end do
    1355             :         end do
    1356           0 :         do i = 1, ncol
    1357           0 :            rhoair = state%pint(i,pverp)/(rair*((slv(i,pver)-gravit*state%zi(i,pverp))/cpair))
    1358           0 :            qtl_flx(i,pverp) = cam_in%cflx(i,1)/rhoair
    1359           0 :            qti_flx(i,pverp) = cam_in%cflx(i,1)/rhoair
    1360             :         end do
    1361             :      end if
    1362             : 
    1363             :   end if
    1364             : 
    1365             :   ! --------------------------------------------------------------- !
    1366             :   ! Convert the new profiles into vertical diffusion tendencies.    !
    1367             :   ! Convert KE dissipative heat change into "temperature" tendency. !
    1368             :   ! --------------------------------------------------------------- !
    1369             :   ! All variables are modified by vertical diffusion
    1370             : 
    1371     2470608 :   lq(:) = .TRUE.
    1372             :   call physics_ptend_init(ptend,state%psetcols, "vertical diffusion", &
    1373       58824 :        ls=.true., lu=.true., lv=.true., lq=lq)
    1374             : 
    1375    91405656 :   ptend%s(:ncol,:)       = ( s_tmp(:ncol,:) - state%s(:ncol,:) ) * rztodt
    1376    91405656 :   ptend%u(:ncol,:)       = ( u_tmp(:ncol,:) - state%u(:ncol,:) ) * rztodt
    1377    91405656 :   ptend%v(:ncol,:)       = ( v_tmp(:ncol,:) - state%v(:ncol,:) ) * rztodt
    1378  3747690720 :   ptend%q(:ncol,:pver,:) = ( q_tmp(:ncol,:pver,:) - state%q(:ncol,:pver,:) ) * rztodt
    1379             : 
    1380             :   ! Convert tendencies of dry constituents to dry basis.
    1381     2470608 :   do m = 1,pcnst
    1382     2470608 :      if (cnst_type(m).eq.'dry') then
    1383  2742169680 :         ptend%q(:ncol,:pver,m) = ptend%q(:ncol,:pver,m)*state%pdel(:ncol,:pver)/state%pdeldry(:ncol,:pver)
    1384             :      endif
    1385             :   end do
    1386             :   ! convert wet mmr back to dry before conservation check
    1387       58824 :   call set_wet_to_dry(state)
    1388             : 
    1389       58824 :   if (.not. do_pbl_diags) then
    1390           0 :      slten(:ncol,:)         = ( sl(:ncol,:) - sl_prePBL(:ncol,:) ) * rztodt
    1391           0 :      qtten(:ncol,:)         = ( qt(:ncol,:) - qt_prePBL(:ncol,:) ) * rztodt
    1392             :   end if
    1393             : 
    1394             :   ! ------------------------------------------------------------ !
    1395             :   ! In order to perform 'pseudo-conservative variable diffusion' !
    1396             :   ! perform the following two stages:                            !
    1397             :   !                                                              !
    1398             :   ! I.  Re-set (1) 'qvten' by 'qtten', and 'qlten = qiten = 0'   !
    1399             :   !            (2) 'sten'  by 'slten', and                       !
    1400             :   !            (3) 'qlten = qiten = 0'                           !
    1401             :   !                                                              !
    1402             :   ! II. Apply 'positive_moisture'                                !
    1403             :   !                                                              !
    1404             :   ! ------------------------------------------------------------ !
    1405             : 
    1406       58824 :     if( (eddy_scheme .eq. 'diag_TKE' .or. eddy_scheme .eq. 'SPCAM_m2005') .and. do_pseudocon_diff ) then
    1407             : 
    1408           0 :      ptend%q(:ncol,:pver,1) = qtten(:ncol,:pver)
    1409           0 :      ptend%s(:ncol,:pver)   = slten(:ncol,:pver)
    1410           0 :      ptend%q(:ncol,:pver,ixcldliq) = 0._r8
    1411           0 :      ptend%q(:ncol,:pver,ixcldice) = 0._r8
    1412           0 :      if (ixnumliq > 0) ptend%q(:ncol,:pver,ixnumliq) = 0._r8
    1413           0 :      if (ixnumice > 0) ptend%q(:ncol,:pver,ixnumice) = 0._r8
    1414             : 
    1415           0 :      do i = 1, ncol
    1416           0 :         do k = 1, pver
    1417           0 :            qv_pro(i,k) = state%q(i,k,1)        + ptend%q(i,k,1)             * ztodt
    1418           0 :            ql_pro(i,k) = state%q(i,k,ixcldliq) + ptend%q(i,k,ixcldliq)      * ztodt
    1419           0 :            qi_pro(i,k) = state%q(i,k,ixcldice) + ptend%q(i,k,ixcldice)      * ztodt
    1420           0 :            s_pro(i,k)  = state%s(i,k)          + ptend%s(i,k)               * ztodt
    1421           0 :            t_pro(i,k)  = state%t(i,k)          + (1._r8/cpair)*ptend%s(i,k) * ztodt
    1422             :         end do
    1423             :      end do
    1424             : 
    1425           0 :      call positive_moisture( cpair, latvap, latvap+latice, ncol, pver, ztodt, qmin(1), qmin(ixcldliq), qmin(ixcldice),    &
    1426           0 :           state%pdel(:ncol,pver:1:-1), qv_pro(:ncol,pver:1:-1), ql_pro(:ncol,pver:1:-1), &
    1427           0 :           qi_pro(:ncol,pver:1:-1), t_pro(:ncol,pver:1:-1), s_pro(:ncol,pver:1:-1),       &
    1428           0 :           ptend%q(:ncol,pver:1:-1,1), ptend%q(:ncol,pver:1:-1,ixcldliq),                 &
    1429           0 :           ptend%q(:ncol,pver:1:-1,ixcldice), ptend%s(:ncol,pver:1:-1) )
    1430             : 
    1431             :   end if
    1432             : 
    1433             :   ! ----------------------------------------------------------------- !
    1434             :   ! Re-calculate diagnostic output variables after vertical diffusion !
    1435             :   ! ----------------------------------------------------------------- !
    1436             : 
    1437       58824 :   if (.not. do_pbl_diags) then
    1438             : 
    1439           0 :      qv_aft_PBL(:ncol,:pver)  =   state%q(:ncol,:pver,1)         + ptend%q(:ncol,:pver,1)        * ztodt
    1440           0 :      ql_aft_PBL(:ncol,:pver)  =   state%q(:ncol,:pver,ixcldliq)  + ptend%q(:ncol,:pver,ixcldliq) * ztodt
    1441           0 :      qi_aft_PBL(:ncol,:pver)  =   state%q(:ncol,:pver,ixcldice)  + ptend%q(:ncol,:pver,ixcldice) * ztodt
    1442           0 :      s_aft_PBL(:ncol,:pver)   =   state%s(:ncol,:pver)           + ptend%s(:ncol,:pver)          * ztodt
    1443           0 :      t_aftPBL(:ncol,:pver)    = ( s_aft_PBL(:ncol,:pver) - gravit*state%zm(:ncol,:pver) ) / cpair
    1444             : 
    1445           0 :      u_aft_PBL(:ncol,:pver)   =  state%u(:ncol,:pver)          + ptend%u(:ncol,:pver)            * ztodt
    1446           0 :      v_aft_PBL(:ncol,:pver)   =  state%v(:ncol,:pver)          + ptend%v(:ncol,:pver)            * ztodt
    1447             : 
    1448           0 :      do k = 1, pver
    1449           0 :         call qsat(t_aftPBL(1:ncol,k), state%pmid(1:ncol,k), tem2(1:ncol,k), ftem(1:ncol,k), ncol)
    1450             :      end do
    1451           0 :      ftem_aftPBL(:ncol,:pver) = qv_aft_PBL(:ncol,:pver) / ftem(:ncol,:pver) * 100._r8
    1452             : 
    1453           0 :      tten(:ncol,:pver)        = ( t_aftPBL(:ncol,:pver)    - state%t(:ncol,:pver) )              * rztodt
    1454           0 :      rhten(:ncol,:pver)       = ( ftem_aftPBL(:ncol,:pver) - ftem_prePBL(:ncol,:pver) )          * rztodt
    1455             : 
    1456             :   end if
    1457             : 
    1458             : 
    1459             :   ! -------------------------------------------------------------- !
    1460             :   ! mass conservation check.........
    1461             :   ! -------------------------------------------------------------- !
    1462       58824 :   if (diff_cnsrv_mass_check) then
    1463             : 
    1464             :      ! Conservation check
    1465           0 :      do m = 1, pcnst
    1466           0 :         fixed_ubc: if ((.not.cnst_fixed_ubc(m)).and.(.not.cnst_fixed_ubflx(m))) then
    1467           0 :            col_loop: do i = 1, ncol
    1468           0 :               sum1 = 0._r8
    1469           0 :               sum2 = 0._r8
    1470           0 :               sum3 = 0._r8
    1471           0 :               do k = 1, pver
    1472           0 :                  if(cnst_get_type_byind(m).eq.'wet') then
    1473           0 :                     pdelx = state%pdel(i,k)
    1474             :                  else
    1475           0 :                     pdelx = state%pdeldry(i,k)
    1476             :                  endif
    1477           0 :                  sum1 = sum1 + state%q(i,k,m)*pdelx/gravit                          ! total column
    1478           0 :                  sum2 = sum2 +(state%q(i,k,m)+ptend%q(i,k,m)*ztodt)*pdelx/ gravit   ! total column after tendancy is applied
    1479           0 :                  sum3 = sum3 +(               ptend%q(i,k,m)*ztodt)*pdelx/ gravit   ! rate of change in column
    1480             :               enddo
    1481           0 :               sum1 = sum1 + (cam_in%cflx(i,m) * ztodt) ! add in surface flux (kg/m2)
    1482           0 :               sflx = (cam_in%cflx(i,m) * ztodt)
    1483           0 :               if (sum1>1.e-36_r8) then
    1484           0 :                  if( abs((sum2-sum1)/sum1) .gt. 1.e-12_r8  ) then
    1485           0 :                     nstep = get_nstep()
    1486             :                     write(iulog,'(a,a8,a,I4,2f8.3,5e25.16)') &
    1487           0 :                          'MASSCHECK vert diff : nstep,lon,lat,mass1,mass2,sum3,sflx,rel-diff : ', &
    1488           0 :                          trim(cnst_name(m)), ' : ', nstep, state%lon(i)*180._r8/pi, state%lat(i)*180._r8/pi, &
    1489           0 :                          sum1, sum2, sum3, sflx, abs(sum2-sum1)/sum1
    1490             : !xxx                    call endrun('vertical_diffusion_tend : mass not conserved' )
    1491             :                  endif
    1492             :               endif
    1493             :            enddo col_loop
    1494             :         endif fixed_ubc
    1495             :      enddo
    1496             :   endif
    1497             : 
    1498             :   ! -------------------------------------------------------------- !
    1499             :   ! Writing state variables after PBL scheme for detailed analysis !
    1500             :   ! -------------------------------------------------------------- !
    1501             : 
    1502       58824 :   if (.not. do_pbl_diags) then
    1503             : 
    1504           0 :      call outfld( 'sl_aft_PBL'   , sl,                        pcols, lchnk )
    1505           0 :      call outfld( 'qt_aft_PBL'   , qt,                        pcols, lchnk )
    1506           0 :      call outfld( 'slv_aft_PBL'  , slv,                       pcols, lchnk )
    1507           0 :      call outfld( 'u_aft_PBL'    , u_aft_PBL,                 pcols, lchnk )
    1508           0 :      call outfld( 'v_aft_PBL'    , v_aft_PBL,                 pcols, lchnk )
    1509           0 :      call outfld( 'qv_aft_PBL'   , qv_aft_PBL,                pcols, lchnk )
    1510           0 :      call outfld( 'ql_aft_PBL'   , ql_aft_PBL,                pcols, lchnk )
    1511           0 :      call outfld( 'qi_aft_PBL'   , qi_aft_PBL,                pcols, lchnk )
    1512           0 :      call outfld( 't_aft_PBL '   , t_aftPBL,                  pcols, lchnk )
    1513           0 :      call outfld( 'rh_aft_PBL'   , ftem_aftPBL,               pcols, lchnk )
    1514           0 :      call outfld( 'slflx_PBL'    , slflx,                     pcols, lchnk )
    1515           0 :      call outfld( 'qtflx_PBL'    , qtflx,                     pcols, lchnk )
    1516           0 :      call outfld( 'uflx_PBL'     , uflx,                      pcols, lchnk )
    1517           0 :      call outfld( 'vflx_PBL'     , vflx,                      pcols, lchnk )
    1518           0 :      call outfld( 'slflx_cg_PBL' , slflx_cg,                  pcols, lchnk )
    1519           0 :      call outfld( 'qtflx_cg_PBL' , qtflx_cg,                  pcols, lchnk )
    1520           0 :      call outfld( 'uflx_cg_PBL'  , uflx_cg,                   pcols, lchnk )
    1521           0 :      call outfld( 'vflx_cg_PBL'  , vflx_cg,                   pcols, lchnk )
    1522           0 :      call outfld( 'slten_PBL'    , slten,                     pcols, lchnk )
    1523           0 :      call outfld( 'qtten_PBL'    , qtten,                     pcols, lchnk )
    1524           0 :      call outfld( 'uten_PBL'     , ptend%u,                   pcols, lchnk )
    1525           0 :      call outfld( 'vten_PBL'     , ptend%v,                   pcols, lchnk )
    1526           0 :      call outfld( 'qvten_PBL'    , ptend%q(:,:,1),            pcols, lchnk )
    1527           0 :      call outfld( 'qlten_PBL'    , ptend%q(:,:,ixcldliq),     pcols, lchnk )
    1528           0 :      call outfld( 'qiten_PBL'    , ptend%q(:,:,ixcldice),     pcols, lchnk )
    1529           0 :      call outfld( 'tten_PBL'     , tten,                      pcols, lchnk )
    1530           0 :      call outfld( 'rhten_PBL'    , rhten,                     pcols, lchnk )
    1531             : 
    1532             :   end if
    1533             : 
    1534             :   ! ------------------------------------------- !
    1535             :   ! Writing the other standard output variables !
    1536             :   ! ------------------------------------------- !
    1537             : 
    1538       58824 :   if (.not. do_pbl_diags) then
    1539           0 :      call outfld( 'QT'           , qt,                        pcols, lchnk )
    1540           0 :      call outfld( 'SL'           , sl,                        pcols, lchnk )
    1541           0 :      call outfld( 'SLV'          , slv,                       pcols, lchnk )
    1542           0 :      call outfld( 'SLFLX'        , slflx,                     pcols, lchnk )
    1543           0 :      call outfld( 'QTFLX'        , qtflx,                     pcols, lchnk )
    1544           0 :      call outfld( 'UFLX'         , uflx,                      pcols, lchnk )
    1545           0 :      call outfld( 'VFLX'         , vflx,                      pcols, lchnk )
    1546           0 :      call outfld( 'TKE'          , tke,                       pcols, lchnk )
    1547             : 
    1548           0 :      call outfld( 'PBLH'         , pblh,                      pcols, lchnk )
    1549           0 :      call outfld( 'TPERT'        , tpert,                     pcols, lchnk )
    1550           0 :      call outfld( 'QPERT'        , qpert,                     pcols, lchnk )
    1551             :   end if
    1552       58824 :   call outfld( 'USTAR'        , ustar,                     pcols, lchnk )
    1553       58824 :   call outfld( 'KVH'          , kvh,                       pcols, lchnk )
    1554       58824 :   call outfld( 'KVT'          , kvt,                       pcols, lchnk )
    1555       58824 :   call outfld( 'KVM'          , kvm,                       pcols, lchnk )
    1556       58824 :   call outfld( 'CGS'          , cgs,                       pcols, lchnk )
    1557    91405656 :   dtk(:ncol,:) = dtk(:ncol,:) / cpair / ztodt      ! Normalize heating for history
    1558       58824 :   call outfld( 'DTVKE'        , dtk,                       pcols, lchnk )
    1559    91405656 :   dtk(:ncol,:) = ptend%s(:ncol,:) / cpair          ! Normalize heating for history using dtk
    1560       58824 :   call outfld( 'DTV'          , dtk,                       pcols, lchnk )
    1561       58824 :   call outfld( 'DUV'          , ptend%u,                   pcols, lchnk )
    1562       58824 :   call outfld( 'DVV'          , ptend%v,                   pcols, lchnk )
    1563     2470608 :   do m = 1, pcnst
    1564     2470608 :      call outfld( vdiffnam(m) , ptend%q(1,1,m),            pcols, lchnk )
    1565             :   end do
    1566       58824 :   if( do_molec_diff ) then
    1567           0 :      call outfld( 'TTPXMLC'  , topflx,                    pcols, lchnk )
    1568             :   end if
    1569             : 
    1570       58824 :   call p%finalize()
    1571       58824 :   call p_dry%finalize()
    1572             : 
    1573      117648 : end subroutine vertical_diffusion_tend
    1574             : 
    1575             : ! =============================================================================== !
    1576             : !                                                                                 !
    1577             : ! =============================================================================== !
    1578             : 
    1579           0 : subroutine positive_moisture( cp, xlv, xls, ncol, mkx, dt, qvmin, qlmin, qimin, &
    1580           0 :      dp, qv, ql, qi, t, s, qvten, qlten, qiten, sten )
    1581             :   ! ------------------------------------------------------------------------------- !
    1582             :   ! If any 'ql < qlmin, qi < qimin, qv < qvmin' are developed in any layer,         !
    1583             :   ! force them to be larger than minimum value by (1) condensating water vapor      !
    1584             :   ! into liquid or ice, and (2) by transporting water vapor from the very lower     !
    1585             :   ! layer. '2._r8' is multiplied to the minimum values for safety.                  !
    1586             :   ! Update final state variables and tendencies associated with this correction.    !
    1587             :   ! If any condensation happens, update (s,t) too.                                  !
    1588             :   ! Note that (qv,ql,qi,t,s) are final state variables after applying corresponding !
    1589             :   ! input tendencies.                                                               !
    1590             :   ! Be careful the order of k : '1': near-surface layer, 'mkx' : top layer          !
    1591             :   ! ------------------------------------------------------------------------------- !
    1592             :   implicit none
    1593             :   integer,  intent(in)     :: ncol, mkx
    1594             :   real(r8), intent(in)     :: cp, xlv, xls
    1595             :   real(r8), intent(in)     :: dt, qvmin, qlmin, qimin
    1596             :   real(r8), intent(in)     :: dp(ncol,mkx)
    1597             :   real(r8), intent(inout)  :: qv(ncol,mkx), ql(ncol,mkx), qi(ncol,mkx), t(ncol,mkx), s(ncol,mkx)
    1598             :   real(r8), intent(inout)  :: qvten(ncol,mkx), qlten(ncol,mkx), qiten(ncol,mkx), sten(ncol,mkx)
    1599             :   integer   i, k
    1600             :   real(r8)  dql, dqi, dqv, sum, aa, dum
    1601             : 
    1602             :   ! Modification : I should check whether this is exactly same as the one used in
    1603             :   !                shallow convection and cloud macrophysics.
    1604             : 
    1605           0 :   do i = 1, ncol
    1606           0 :      do k = mkx, 1, -1    ! From the top to the 1st (lowest) layer from the surface
    1607           0 :         dql        = max(0._r8,1._r8*qlmin-ql(i,k))
    1608           0 :         dqi        = max(0._r8,1._r8*qimin-qi(i,k))
    1609           0 :         qlten(i,k) = qlten(i,k) +  dql/dt
    1610           0 :         qiten(i,k) = qiten(i,k) +  dqi/dt
    1611           0 :         qvten(i,k) = qvten(i,k) - (dql+dqi)/dt
    1612           0 :         sten(i,k)  = sten(i,k)  + xlv * (dql/dt) + xls * (dqi/dt)
    1613           0 :         ql(i,k)    = ql(i,k) +  dql
    1614           0 :         qi(i,k)    = qi(i,k) +  dqi
    1615           0 :         qv(i,k)    = qv(i,k) -  dql - dqi
    1616           0 :         s(i,k)     = s(i,k)  +  xlv * dql + xls * dqi
    1617           0 :         t(i,k)     = t(i,k)  + (xlv * dql + xls * dqi)/cp
    1618           0 :         dqv        = max(0._r8,1._r8*qvmin-qv(i,k))
    1619           0 :         qvten(i,k) = qvten(i,k) + dqv/dt
    1620           0 :         qv(i,k)    = qv(i,k)    + dqv
    1621           0 :         if( k .ne. 1 ) then
    1622           0 :            qv(i,k-1)    = qv(i,k-1)    - dqv*dp(i,k)/dp(i,k-1)
    1623           0 :            qvten(i,k-1) = qvten(i,k-1) - dqv*dp(i,k)/dp(i,k-1)/dt
    1624             :         endif
    1625           0 :         qv(i,k) = max(qv(i,k),qvmin)
    1626           0 :         ql(i,k) = max(ql(i,k),qlmin)
    1627           0 :         qi(i,k) = max(qi(i,k),qimin)
    1628             :      end do
    1629             :      ! Extra moisture used to satisfy 'qv(i,1)=qvmin' is proportionally
    1630             :      ! extracted from all the layers that has 'qv > 2*qvmin'. This fully
    1631             :      ! preserves column moisture.
    1632           0 :      if( dqv .gt. 1.e-20_r8 ) then
    1633             :         sum = 0._r8
    1634           0 :         do k = 1, mkx
    1635           0 :            if( qv(i,k) .gt. 2._r8*qvmin ) sum = sum + qv(i,k)*dp(i,k)
    1636             :         enddo
    1637           0 :         aa = dqv*dp(i,1)/max(1.e-20_r8,sum)
    1638           0 :         if( aa .lt. 0.5_r8 ) then
    1639           0 :            do k = 1, mkx
    1640           0 :               if( qv(i,k) .gt. 2._r8*qvmin ) then
    1641           0 :                  dum        = aa*qv(i,k)
    1642           0 :                  qv(i,k)    = qv(i,k) - dum
    1643           0 :                  qvten(i,k) = qvten(i,k) - dum/dt
    1644             :               endif
    1645             :            enddo
    1646             :         else
    1647           0 :            write(iulog,*) 'Full positive_moisture is impossible in vertical_diffusion'
    1648             :         endif
    1649             :      endif
    1650             :   end do
    1651           0 :   return
    1652             : 
    1653       58824 : end subroutine positive_moisture
    1654             : 
    1655             : end module vertical_diffusion

Generated by: LCOV version 1.14