#define MODAL_AERO
MODULE module_bl_camuwpbl_driver 2
!Note: Comments starting with "!!" are directly taken from CAM's interface routine for the UW PBL (vertical_diffusion.F90)
!This modules is based on vertical_diffusion.F90 of CAM5
!List of possible modifications in the future:
!_____________________________________________
!1. Constituents(per Kg of DRY air or "dry" constituents) are not diffused currently. The call which
! makes DRY constituents diffusion decision flag 'true' is commented out in camuwpblinit subroutine.
! Therefore the flag is ALWAYS false for DRY constituent diffusion.
!
! REASON: DRY constituents are Aerosols and other species (excepts for cloud mass mixing ratios and number concentrations).
! ------ In WRF, DRY constituents appear only when WRF_CHEM simulations are run. DRY constituents are vertically mixed(diffused)
! in dry_dep_driver of WRF_CHEM. Therefore, DRY constituents are not diffused in this PBL subroutine
!
!2. The liquid number concentrations is NOT diffused(or mixed) in PBL to mimic CAM5, which diffuses liquid number
! concentrations in dropmixnuc.
!3. Surface fluxes for ALL the constituents are ZERO except for the water vapours (1st constituent)
!4. Molecular diffusion is turned off for now
!5. Mountain stresses are not computed for now (all calls to Mountain stresses currently may hold undefined variables)
!6. *Formulas used for computing surface stresses is based on the formula given in CAM5's BareGround.F90.
! This formula may not work well for ocean surfaces (possible future modification)
!_____________________________________________
!!----------------------------------------------------------------------------------------------------- !
!! Module to compute vertical diffusion of momentum, moisture, trace constituents !
!! and static energy. Separate modules compute !
!! 1. stresses associated with turbulent flow over orography !
!! ( turbulent mountain stress ) !
!! 2. eddy diffusivities, including nonlocal tranport terms !
!! 3. molecular diffusivities !
!! 4. coming soon... gravity wave drag !
!! Lastly, a implicit diffusion solver is called, and tendencies retrieved by !
!! differencing the diffused and initial states. !
!! !
!! Calling sequence: !
!! !
!! vertical_diffusion_init Initializes vertical diffustion constants and modules !
!! init_molec_diff Initializes molecular diffusivity module !
!! init_eddy_diff Initializes eddy diffusivity module (includes PBL) !
!! init_tms Initializes turbulent mountain stress module !
!! init_vdiff Initializes diffusion solver module !
!! vertical_diffusion_ts_init Time step initialization (only used for upper boundary condition) !
!! vertical_diffusion_tend Computes vertical diffusion tendencies !
!! compute_tms Computes turbulent mountain stresses !
!! compute_eddy_diff Computes eddy diffusivities and countergradient terms !
!! compute_vdiff Solves vertical diffusion equations, including molecular diffusivities !
!! !
!!---------------------------Code history-------------------------------------------------------------- !
!! J. Rosinski : Jun. 1992 !
!! J. McCaa : Sep. 2004 !
!! S. Park : Aug. 2006, Dec. 2008. Jan. 2010 !
! B. Singh : Nov. 2010 (ported to WRF by balwinder.singh@pnl.gov)
!!----------------------------------------------------------------------------------------------------- !
use shr_kind_mod
, only : r8 => shr_kind_r8
use module_cam_support
, only : pcols, pver, pverp, endrun, iulog,fieldname_len,pcnst =>pcnst_runtime
use constituents
, only : qmin
use diffusion_solver
, only : vdiff_selector
use physconst
, only : &
cpair , & ! Specific heat of dry air
gravit , & ! Acceleration due to gravity
rair , & ! Gas constant for dry air
zvir , & ! rh2o/rair - 1
latvap , & ! Latent heat of vaporization
latice , & ! Latent heat of fusion
karman , & ! von Karman constant
mwdry , & ! Molecular weight of dry air
avogad , & ! Avogadro's number
boltz ! Boltzman's constant
implicit none
private
save
!! ----------------- !
!! Public interfaces !
!! ----------------- !
public camuwpblinit ! Initialization
public camuwpbl ! Driver for the PBL scheme
public vd_register ! Init routine for constituents
!! ------------ !
!! Private data !
!! ------------ !
character(len=16) :: eddy_scheme !! Default set in phys_control.F90, use namelist to change
!! 'HB' = Holtslag and Boville (default)
!! 'HBR' = Holtslag and Boville and Rash
!! 'diag_TKE' = Bretherton and Park ( UW Moist Turbulence Scheme )
integer, parameter :: nturb = 5 !! Number of iterations for solution ( when 'diag_TKE' scheme is selected )
logical, parameter :: wstarent = .true. !! Use wstar (.true.) or TKE (.false.) entrainment closure ( when 'diag_TKE' scheme is selected )
logical :: do_pseudocon_diff = .false. !! If .true., do pseudo-conservative variables diffusion
character(len=16) :: shallow_scheme !! For checking compatibility between eddy diffusion and shallow convection schemes
!! 'Hack' = Hack Shallow Convection Scheme
!! 'UW' = Park and Bretherton ( UW Shallow Convection Scheme )
character(len=16) :: microp_scheme !! Microphysics scheme
logical :: do_molec_diff = .false. !! Switch for molecular diffusion
logical :: do_tms !! Switch for turbulent mountain stress
real(r8) :: tms_orocnst !! Converts from standard deviation to height
real(r8) :: tms_z0fac ! Converts from standard deviation to height
type(vdiff_selector) :: fieldlist_wet !! Logical switches for moist mixing ratio diffusion
type(vdiff_selector) :: fieldlist_dry !! Logical switches for dry mixing ratio diffusion
integer :: ntop !! Top interface level to which vertical diffusion is applied ( = 1 ).
integer :: nbot !! Bottom interface level to which vertical diffusion is applied ( = pver ).
integer :: tke_idx, kvh_idx, kvm_idx !! TKE and eddy diffusivity indices for fields in the physics buffer
integer :: turbtype_idx, smaw_idx !! Turbulence type and instability functions
integer :: tauresx_idx, tauresy_idx !! Redisual stress for implicit surface stress
integer :: ixcldice, ixcldliq !! Constituent indices for cloud liquid and ice water
integer :: ixnumice, ixnumliq
#ifdef MODAL_AERO
integer :: ixndrop
#endif
integer :: wgustd_index
CONTAINS
subroutine camuwpbl(dt,u_phy,v_phy,th_phy,rho,qv_curr,hfx,qfx,ustar,p8w & 1,19
,p_phy,z,t_phy,qc_curr,qi_curr,z_at_w,cldfra_old_mp,cldfra,ht &
,rthratenlw,exner,is_CAMMGMP_used &
,itimestep,qnc_curr,qni_curr,wsedl3d &
,ids,ide, jds,jde, kds,kde &
,ims,ime, jms,jme, kms,kme &
,its,ite, jts,jte, kts,kte &
!Intent-inout
,tauresx2d,tauresy2d &
,rublten,rvblten,rthblten,rqiblten,rqniblten,rqvblten,rqcblten &
,kvm3d,kvh3d &
!Intent-out
,tpert2d,qpert2d,wpert2d,smaw3d,turbtype3d &
,tke_pbl,pblh2d,kpbl2d )
!!---------------------------------------------------- !
!! This is an interface routine for vertical diffusion !
! This subroutine is called by module_pbl_driver and !
! it calls: wrf_error_fatal,compute_tms, !
! compute_eddy_diff,aqsat,compute_vdiff and !
! positive_moisture.
!!---------------------------------------------------- !
use module_cam_support
, only : pcols
use trb_mtn_stress
, only : compute_tms
use eddy_diff
, only : compute_eddy_diff
use wv_saturation
, only : fqsatd, aqsat
use molec_diff
, only : compute_molec_diff, vd_lu_qdecomp
use constituents
, only : qmincg, qmin
use diffusion_solver
!!, only : compute_vdiff, any, operator(.not.)
#ifdef MODAL_AERO
use modal_aero_data
#endif
implicit none
!------------------------------------------------------------------------!
! Input !
!------------------------------------------------------------------------!
logical, intent(in) :: is_CAMMGMP_used
integer, intent(in) :: ids,ide, jds,jde, kds,kde
integer, intent(in) :: ims,ime, jms,jme, kms,kme
integer, intent(in) :: its,ite, jts,jte, kts,kte
integer, intent(in) :: itimestep
real, intent(in) :: dt ! Time step (s)
real, dimension( ims:ime,jms:jme ), intent(in) :: hfx !Sensible heat flux at surface (w/m2)
real, dimension( ims:ime,jms:jme ), intent(in) :: qfx !Moisture flux at surface (kg m-2 s-1)
real, dimension( ims:ime,jms:jme ), intent(in) :: ustar !Friction velocity (m/s)
real, dimension( ims:ime,jms:jme ), intent(in) :: ht !Terrain height (m)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: v_phy !Y-component of wind (m/s)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: u_phy !X-component of wind (m/s)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: th_phy !Potential temperature (K)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: rho !Air density (kg/m3)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: qv_curr !Water vapor mixing ratio - Moisture (kg/kg)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: qc_curr !Cloud water mixing ratio - Cloud liq (kg/kg)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: qi_curr !Ice mixing ratio - Cloud ice (kg/kg)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: qnc_curr !Liq # mixing ratio - Cloud liq # (#/kg)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: qni_curr !Ice # mixing ratio - Cloud ice # (#/kg)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: p_phy !Pressure at mid-level (Pa)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: p8w !Pressure at level interface (Pa)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: z !Height above sea level at mid-level (m)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: t_phy !Temperature (K)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: z_at_w !Height above sea level at layer interfaces (m)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: cldfra_old_mp !Cloud fraction [unitless]
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: cldfra !Cloud fraction [unitless]
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: exner !Dimensionless pressure [unitless]
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: rthratenlw !Tendency for LW ( K/s)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(in) :: wsedl3d !Sedimentation velocity of stratiform liquid cloud droplet (m/s)
!------------------------------------------------------------------------!
! Output !
!------------------------------------------------------------------------!
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rublten !Tendency for u_phy (Pa m s-2)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rvblten !Tendency for v_phy (Pa m s-2)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rthblten !Tendency for th_phy (Pa K s-1)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rqvblten !Tendency for qv_curr (Pa kg kg-1 s-1)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rqcblten !Tendency for qc_curr (Pa kg kg-1 s-1)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rqiblten !Tendency for qi_curr (Pa kg kg-1 s-1)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: rqniblten !Tendency for qni_curr(Pa # kg-1 s-1)
integer, dimension( ims:ime,jms:jme ), intent(out) :: kpbl2d !Layer index containing PBL top within or at the base interface
real, dimension( ims:ime,jms:jme ), intent(out) :: pblh2d !Planetary boundary layer height (m)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(out) :: tke_pbl !Turbulence kinetic energy at midpoints (m^2/s^2)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(out) :: turbtype3d !Turbulent interface types [ no unit ]
real, dimension( ims:ime, kms:kme, jms:jme ), intent(out) :: smaw3d !Normalized Galperin instability function for momentum ( 0<= <=4.964 and 1 at neutral ) [no units]
!---------------------------------------------------------------------------!
! Local, carried on from one timestep to the other (defined in registry)!
!---------------------------------------------------------------------------!
real, dimension( ims:ime, jms:jme ) , intent(inout ):: tauresx2d,tauresy2d !X AND Y-COMP OF RESIDUAL STRESSES(m^2/s^2)
real, dimension( ims:ime, jms:jme ) , intent(out) :: tpert2d ! Convective temperature excess (K)
real, dimension( ims:ime, jms:jme ) , intent(out) :: qpert2d ! Convective humidity excess (kg/kg)
real, dimension( ims:ime, jms:jme ) , intent(out) :: wpert2d ! Turbulent velocity excess (m/s)
real, dimension( ims:ime, kms:kme, jms:jme ), intent(inout) :: kvm3d,kvh3d !Eddy diffusivity for momentum and heat(m^2/s)
!---------------------------------------------------------------------------!
! Local !
!---------------------------------------------------------------------------!
character(128) :: errstring ! Error status for compute_vdiff
logical :: kvinit ! Tell compute_eddy_diff/ caleddy to initialize kvh, kvm (uses kvf)
logical :: is_first_step ! Flag to know if this a first time step
integer :: i,j,k,itsp1,itile_len,ktep1,kflip,ncol,ips,icnst,m,kp1
integer :: lchnk ! Chunk identifier
real(r8) :: tauFac, uMean, dp, multFrc
real(r8) :: ztodt ! 2*delta-t (s)
real(r8) :: rztodt ! 1./ztodt (1/s)
real(r8),parameter :: invalidVal = -999888777.0_r8
real(r8) :: topflx( pcols) ! Molecular heat flux at top interface
real(r8) :: wpert( pcols) ! Turbulent velocity excess (m/s)
real(r8) :: tauresx( pcols) ! [Residual stress to be added in vdiff to correct...
real(r8) :: tauresy( pcols) ! for turb stress mismatch between sfc and atm accumulated.] (N/m2)
real(r8) :: ipbl( pcols) ! If 1, PBL is CL, while if 0, PBL is STL.
real(r8) :: kpblh( pcols) ! Layer index containing PBL top within or at the base interface
real(r8) :: wstarPBL(pcols) ! Convective velocity within PBL (m/s)
real(r8) :: sgh( pcols) ! Standard deviation of orography (m)
real(r8) :: landfrac(pcols) ! Land fraction [unitless]
real(r8) :: taux( pcols) ! x surface stress (N/m2)
real(r8) :: tauy( pcols) ! y surface stress (N/m2)
real(r8) :: tautotx( pcols) ! U component of total surface stress (N/m2)
real(r8) :: tautoty( pcols) ! V component of total surface stress (N/m2)
real(r8) :: ksrftms( pcols) ! Turbulent mountain stress surface drag coefficient (kg/s/m2)
real(r8) :: tautmsx( pcols) ! U component of turbulent mountain stress (N/m2)
real(r8) :: tautmsy( pcols) ! V component of turbulent mountain stress (N/m2)
real(r8) :: ustar8( pcols) ! Surface friction velocity (m/s)
real(r8) :: pblh( pcols) ! Planetary boundary layer height (m)
real(r8) :: tpert( pcols) ! Convective temperature excess (K)
real(r8) :: qpert( pcols) ! Convective humidity excess (kg/kg)
real(r8) :: shflx( pcols) ! Surface sensible heat flux (w/m2)
real(r8) :: phis( pcols) ! Geopotential at terrain height (m2/s2)
real(r8) :: cldn8( pcols,kte) ! New stratus fraction (fraction)
real(r8) :: qrl8( pcols,kte) ! LW radiative cooling rate(W/kg*Pa)
real(r8) :: wsedl8( pcols,kte) ! Sedimentation velocity of stratiform liquid cloud droplet (m/s)
real(r8) :: dtk( pcols,kte) ! T tendency from KE dissipation
real(r8) :: qt( pcols,kte) !
real(r8) :: sl_prePBL( pcols,kte) !
real(r8) :: qt_prePBL( pcols,kte) !
real(r8) :: slten( pcols,kte) !
real(r8) :: qtten( pcols,kte) !
real(r8) :: sl( pcols,kte) !
real(r8) :: ftem( pcols,kte) ! Saturation vapor pressure before PBL
real(r8) :: ftem_prePBL(pcols,kte) ! Saturation vapor pressure before PBL
real(r8) :: ftem_aftPBL(pcols,kte) ! Saturation vapor pressure after PBL
real(r8) :: tem2( pcols,kte) ! Saturation specific humidity and RH
real(r8) :: t_aftPBL( pcols,kte) ! Temperature after PBL diffusion
real(r8) :: tten( pcols,kte) ! Temperature tendency by PBL diffusion
real(r8) :: rhten( pcols,kte) ! RH tendency by PBL diffusion
real(r8) :: qv_aft_PBL( pcols,kte) ! qv after PBL diffusion
real(r8) :: ql_aft_PBL( pcols,kte) ! ql after PBL diffusion
real(r8) :: qi_aft_PBL( pcols,kte) ! qi after PBL diffusion
real(r8) :: s_aft_PBL( pcols,kte) ! s after PBL diffusion
real(r8) :: u_aft_PBL( pcols,kte) ! u after PBL diffusion
real(r8) :: v_aft_PBL( pcols,kte) ! v after PBL diffusion
real(r8) :: qv_pro( pcols,kte) !
real(r8) :: ql_pro( pcols,kte) !
real(r8) :: qi_pro( pcols,kte) !
real(r8) :: s_pro( pcols,kte) !
real(r8) :: t_pro( pcols,kte) !
real(r8) :: u8( pcols,kte) ! x component of velocity in CAM's data structure (m/s)
real(r8) :: v8( pcols,kte) ! y component of velocity in CAM's data structure (m/s)
real(r8) :: t8( pcols,kte) !
real(r8) :: pmid8( pcols,kte) ! Pressure at the midpoints in CAM's data structure (Pa)
real(r8) :: pmiddry8( pcols,kte) ! Dry Pressure at the midpoints in CAM's data structure (Pa)
real(r8) :: zm8( pcols,kte) ! Height at the midpoints in CAM's data structure (m)
real(r8) :: exner8( pcols,kte) ! exner function in CAM's data structure
real(r8) :: s8( pcols,kte) ! Dry static energy (m2/s2)
real(r8) :: rpdel8( pcols,kte) ! Inverse of pressure difference (1/Pa)
real(r8) :: pdel8( pcols,kte) ! Pressure difference (Pa)
real(r8) :: rpdeldry8( pcols,kte) ! Inverse of dry pressure difference (1/Pa)
real(r8) :: pdeldry8( pcols,kte) ! dry pressure difference (1/Pa)
REAL(r8) :: stnd( pcols,kte) ! Heating rate (dry static energy tendency, W/kg)
real(r8) :: tke8( pcols,kte+1) ! Turbulent kinetic energy [ m2/s2 ]
real(r8) :: turbtype( pcols,kte+1) ! Turbulent interface types [ no unit ]
real(r8) :: smaw( pcols,kte+1) ! Normalized Galperin instability function for momentum ( 0<= <=4.964 and 1 at neutral ) [no units]
! This is 1 when neutral condition (Ri=0), 4.964 for maximum unstable case, and 0 when Ri > Ricrit=0.19.
real(r8) :: cgs( pcols,kte+1) ! Counter-gradient star [ cg/flux ]
real(r8) :: cgh( pcols,kte+1) ! Counter-gradient term for heat [ J/kg/m ]
real(r8) :: kvh( pcols,kte+1) ! Eddy diffusivity for heat [ m2/s ]
real(r8) :: kvm( pcols,kte+1) ! Eddy diffusivity for momentum [ m2/s ]
real(r8) :: kvq( pcols,kte+1) ! Eddy diffusivity for constituents [ m2/s ]
real(r8) :: kvh_in( pcols,kte+1) ! kvh from previous timestep [ m2/s ]
real(r8) :: kvm_in( pcols,kte+1) ! kvm from previous timestep [ m2/s ]
real(r8) :: bprod( pcols,kte+1) ! Buoyancy production of tke [ m2/s3 ]
real(r8) :: sprod( pcols,kte+1) ! Shear production of tke [ m2/s3 ]
real(r8) :: sfi( pcols,kte+1) ! Saturation fraction at interfaces [ fraction ]
real(r8) :: pint8( pcols,kte+1) ! Pressure at the interfaces in CAM's data structure (Pa)
real(r8) :: pintdry8( pcols,kte+1) ! Dry pressure at the interfaces in CAM's data structure (Pa)
real(r8) :: zi8( pcols,kte+1) ! Height at the interfacesin CAM's data structure (m)
real(r8) :: cloud( pcols,kte,pcnst) ! Holder for cloud water and ice (q in cam)
real(r8) :: cloudtnd( pcols,kte,pcnst) ! Holder for cloud tendencies (ptend_loc%q in cam)
real(r8) :: wind_tends(pcols,kte,2) ! Wind component tendencies (m/s2)
real(r8) :: cflx(pcols,pcnst) ! Surface constituent flux [ kg/m2/s ]
#ifdef MODAL_AERO
real(r8) :: tmp1(pcols) ! Temporary storage
integer :: l, lspec
#endif
!! ----------------------- !
!! Main Computation Begins !
!! ----------------------- !
do icnst = 1 , pcnst
!Setting curface fluxes for all constituents to be zero. Later, cflx(:,1) is populated by the water vapour surface flux
cflx(:pcols,icnst) = 0.0_r8
enddo
is_first_step = .false.
if(itimestep == 1) then
is_first_step = .true.
endif
ncol = pcols
ztodt = DT
rztodt = 1.0_r8 / ztodt
!Few definitions in this subroutine require that ncol==1
if(ncol .NE. 1) then
call wrf_error_fatal
('Number of CAM Columns (NCOL) in CAMUWPBL scheme must be 1')
endif
!Initialize errstring
errstring = ''
!-------------------------------------------------------------------------------------!
!Map CAM variables to the corresponding WRF variables !
!Loop over the points in the tile and treat them each as a CAM Chunk !
!-------------------------------------------------------------------------------------!
itsp1 = its - 1
itile_len = ite - itsp1
do j = jts , jte
do i = its , ite
lchnk = (j - jts) * itile_len + (i - itsp1) !1-D index location from a 2-D tile
phis(1) = ht(i,j) * gravit !Used for computing dry static energy
!Flip vertically quantities computed at the mid points
ktep1 = kte + 1
do k = kts,kte
kflip = ktep1 - k
!Loop is used as vector assignment may take more computational time
do icnst = 1 , pcnst
!Setting cloud and cloudtnd to values (obtained from module_cam_support) which should produce errors if used
!1st,2nd,3rd and 5th constituents are used (see the assignments below) and diffused presently in this scheme
cloud(1,kflip,icnst) = invalidVal
cloudtnd(1,kflip,icnst) = invalidVal
enddo
u8( 1,kflip) = u_phy(i,k,j) ! X-component of velocity at the mid-points (m/s) [state%u in CAM]
v8( 1,kflip) = v_phy(i,k,j) ! Y-component of velocity at the mid-points (m/s) [state%v in CAM]
pmid8( 1,kflip) = p_phy(i,k,j) ! Pressure at the mid-points (Pa) [state%pmid in CAM]
dp = p8w(i,k,j) - p8w(i,k+1,j) !Change in pressure (Pa)
pdel8( 1,kflip) = dp
rpdel8( 1,kflip) = 1.0_r8/dp ! Reciprocal of pressure difference (1/Pa) [state%rpdel in CAM]
zm8( 1,kflip) = z(i,k,j)-ht(i,j) ! Height above the ground at the midpoints (m) [state%zm in CAM]
t8( 1,kflip) = t_phy(i,k,j) ! Temprature at the mid points (K) [state%t in CAM]
s8( 1,kflip) = cpair *t8(1,kflip) + gravit*zm8(1,kflip) + phis(1) ! Dry static energy (m2/s2) [state%s in CAM]-Formula tested in vertical_diffusion.F90 of CAM
qrl8( 1,kflip) = rthratenlw(i,k,j)* cpair * dp ! Long Wave heating rate (W/kg*Pa)- Formula obtained from definition of qrlw(pcols,pver) in eddy_diff.F90 in CAM
wsedl8( 1,kflip) = wsedl3d(i,k,j) ! Sedimentation velocity of stratiform liquid cloud droplet (m/s)
!Following three formulas are obtained from ported CAM's ZM cumulus scheme
!Values of 0 cause a crash in entropy
multFrc = 1._r8/(1._r8 + qv_curr(i,k,j))
cloud( 1,kflip,1) = max( qv_curr(i,k,j) * multFrc, 1.0e-30_r8 ) !Specific humidity [state%q(:,:,1) in CAM]
cloud( 1,kflip,ixcldliq) = qc_curr(i,k,j) * multFrc !Convert to moist mix ratio-cloud liquid [state%q(:,:,2) in CAM]
cloud( 1,kflip,ixcldice) = qi_curr(i,k,j) * multFrc !cloud ice [state%q(:,:,3) in CAM]
cloud( 1,kflip,ixnumliq) = qnc_curr(i,k,j) * multFrc
cloud( 1,kflip,ixnumice) = qni_curr(i,k,j) * multFrc
exner8(1,kflip) = exner(i,k,j) !Exner function (no units)
if(is_CAMMGMP_used) then
cldn8( 1,kflip) = cldfra_old_mp(i,k,j) !Cloud fraction (no unit)
else
cldn8( 1,kflip) = cldfra(i,k,j) !Cloud fraction (no unit)
endif
!Following formula is obtained from physics_types.F90 of CAM (CESM101)
pdeldry8(1,kflip) = pdel8(1,kflip)*(1._r8-cloud(1,kflip,1))
rpdeldry8(1,kflip) = 1._r8/pdeldry8(1,kflip)
enddo
do k = kts,kte+1
kflip = kte - k + 2
pint8( 1,kflip) = p8w( i,k,j) ! Pressure at interfaces [state%pint in CAM]
zi8( 1,kflip) = z_at_w(i,k,j) -ht(i,j) ! Height at interfaces [state%zi in CAM]
!Initialize Variables to zero, these are outputs from the "compute_eddy_diff"
kvq(1,kflip) = 0.0_r8 ! Eddy diffusivity for constituents (m2/s)
cgh(1,kflip) = 0.0_r8 ! Counter-gradient term for heat
cgs(1,kflip) = 0.0_r8 ! Counter-gradient star (cg/flux)
if( is_first_step ) then
kvm3d(i,k,j) = 0.0_r8 ! Eddy diffusivity for heat (m2/s)
kvh3d(i,k,j) = 0.0_r8 ! Eddy diffusivity for momentum (m2/s)
endif
kvh(1,kflip) = kvh3d(i,k,j)
kvm(1,kflip) = kvm3d(i,k,j)
end do
!Compute pintdry8 and pmiddry8
!Following formula is obtained from physics_types.F90 of CAM (CESM101)
pintdry8(1,1) = pint8(1,1)
do k = 1, pver
pintdry8(1,k+1) = pintdry8(1,k) + pdeldry8(1,k)
pmiddry8(1,k) = (pintdry8(1,k+1)+ pintdry8(1,k))*0.5_r8
end do
shflx( ncol) = hfx(i,j) ! Surface sensible heat flux (w/m2)
!SGH and LANDFRAC are inputs for the compute_tms subroutine. Presently set to zero as do_tms is always false for now
sgh( ncol) = 0.0_r8 ! Standard deviation of orography (m)
landfrac(ncol) = 0.0_r8 ! Fraction (unitless)
uMean = sqrt( u_phy(i,kts,j) * u_phy(i,kts,j) + v_phy(i,kts,j) * v_phy(i,kts,j) ) ! Mean velocity
tauFac = rho(i,kts,j) * ustar(i,j) *ustar(i,j)/uMean
taux(ncol) = -tauFac * u_phy(i,kts,j) ! x surface stress (N/m2) [Formulation obtained from CAM's BareGround.F90]
tauy(ncol) = -tauFac * v_phy(i,kts,j) ! y surface stress (N/m2)
!! Retrieve 'tauresx, tauresy' from from the last timestep
if( is_first_step ) then
tauresx2d(i,j) = 0._r8
tauresy2d(i,j) = 0._r8
endif
tauresx(:ncol) = tauresx2d(i,j)
tauresy(:ncol) = tauresy2d(i,j)
!! All variables are modified by vertical diffusion
!!------------------------------------------!
!! Computation of turbulent mountain stress !
!!------------------------------------------!
!! Consistent with the computation of 'normal' drag coefficient, we are using
!! the raw input (u,v) to compute 'ksrftms', not the provisionally-marched 'u,v'
!! within the iteration loop of the PBL scheme.
if( do_tms ) then
call compute_tms
( pcols , pver , ncol , &
u8 , v8 , t8 , pmid8 , &
exner8 , zm8 , sgh , ksrftms , &
tautmsx , tautmsy , landfrac )
!! Here, both 'taux, tautmsx' are explicit surface stresses.
!! Note that this 'tautotx, tautoty' are different from the total stress
!! that has been actually added into the atmosphere. This is because both
!! taux and tautmsx are fully implicitly treated within compute_vdiff.
!! However, 'tautotx, tautoty' are not used in the actual numerical
!! computation in this module.
tautotx(:ncol) = taux(:ncol) + tautmsx(:ncol)
tautoty(:ncol) = tauy(:ncol) + tautmsy(:ncol)
else
ksrftms(:ncol) = 0.0_r8
tautotx(:ncol) = taux(:ncol)
tautoty(:ncol) = tauy(:ncol)
endif
!-------------------------------------------------------------------------------------!
!We are currenly using just water vapour flux at the surface, rest are set to zero
!-------------------------------------------------------------------------------------!
cflx(:pcols,1) = qfx(i,j) ! Surface constituent flux (kg/m2/s)
!Following variables are initialized to zero, they are the output from the "compute_eddy_diff" call
ustar8( :pcols) = 0.0_r8 ! Surface friction velocity (m/s)
pblh( :pcols) = 0.0_r8 ! Planetary boundary layer height (m )
ipbl( :pcols) = 0.0_r8 ! If 1, PBL is CL, while if 0, PBL is STL.
kpblh( :pcols) = 0.0_r8 ! Layer index containing PBL top within or at the base interface
wstarPBL(:pcols) = 0.0_r8 ! Convective velocity within PBL (m/s)
!!----------------------------------------------------------------------- !
!! Computation of eddy diffusivities - Select appropriate PBL scheme !
!!----------------------------------------------------------------------- !
select case (eddy_scheme)
case ( 'diag_TKE' )
!! ---------------------------------------------------------------- !
!! At first time step, have eddy_diff.F90:caleddy() use kvh=kvm=kvf !
!! This has to be done in compute_eddy_diff after kvf is calculated !
!! ---------------------------------------------------------------- !
kvinit = .false.
if(is_first_step) then
kvinit = .true.
endif
!! ---------------------------------------------- !
!! Get LW radiative heating out of physics buffer !
!! ---------------------------------------------- !
!! Retrieve eddy diffusivities for heat and momentum from physics buffer
!! from last timestep ( if first timestep, has been initialized by inidat.F90 )
kvm_in(:ncol,:) = kvm(:ncol,:)
kvh_in(:ncol,:) = kvh(:ncol,:)
call compute_eddy_diff
( lchnk , pcols , pver , ncol , t8 , cloud(:,:,1) , ztodt , &
cloud(:,:,2), cloud(:,:,3), s8 , rpdel8 , cldn8 , qrl8 , wsedl8 , zm8 , zi8 , &
pmid8 , pint8 , u8 , v8 , taux , tauy , shflx , cflx(:,1), wstarent, &
nturb , ustar8 , pblh , kvm_in , kvh_in , kvm , kvh , kvq , cgh , &
cgs , tpert , qpert , wpert , tke8 , bprod , sprod , sfi , fqsatd , &
kvinit , tauresx , tauresy, ksrftms, ipbl(:), kpblh(:), wstarPBL(:) , turbtype , smaw )
!! ----------------------------------------------- !
!! Store TKE in pbuf for use by shallow convection !
!! ----------------------------------------------- !
!! Store updated kvh, kvm in pbuf to use here on the next timestep
do k = kts,kte+1
kflip = kte - k + 2
kvh3d(i,k,j) = kvh(1,kflip)
kvm3d(i,k,j) = kvm(1,kflip)
end do
end select
!!------------------------------------ !
!! Application of diffusivities !
!!------------------------------------ !
cloudtnd( :ncol,:,:) = cloud(:ncol,:,:)
stnd( :ncol,: ) = s8( :ncol,: )
wind_tends(:ncol,:,1) = u8( :ncol,: )
wind_tends(:ncol,:,2) = v8( :ncol,: )
!!------------------------------------------------------ !
!! Write profile output before applying diffusion scheme !
!!------------------------------------------------------ !
sl_prePBL(:ncol,:pver) = stnd(:ncol,:pver) - latvap * cloudtnd(:ncol,:pver,ixcldliq) &
- ( latvap + latice) * cloudtnd(:ncol,:pver,ixcldice)
qt_prePBL(:ncol,:pver) = cloudtnd(:ncol,:pver,1) + cloudtnd(:ncol,:pver,ixcldliq) &
+ cloudtnd(:ncol,:pver,ixcldice)
call aqsat
( t8, pmid8, tem2, ftem, pcols, ncol, pver, 1, pver )
ftem_prePBL(:ncol,:) = cloud(:ncol,:,1)/ftem(:ncol,:)*100._r8
!! --------------------------------------------------------------------------------- !
!! Call the diffusivity solver and solve diffusion equation !
!! The final two arguments are optional function references to !
!! constituent-independent and constituent-dependent moleculuar diffusivity routines !
!! --------------------------------------------------------------------------------- !
!! Modification : We may need to output 'tautotx_im,tautoty_im' from below 'compute_vdiff' and
!! separately print out as diagnostic output, because these are different from
!! the explicit 'tautotx, tautoty' computed above.
!! Note that the output 'tauresx,tauresy' from below subroutines are fully implicit ones.
if( any(fieldlist_wet) ) then
call compute_vdiff
( lchnk, pcols, pver, pcnst, ncol, pmid8, pint8, rpdel8, t8, ztodt, &
taux, tauy, shflx, cflx, ntop, nbot, kvh, kvm, kvq, cgs, cgh, zi8, ksrftms, qmincg, &
fieldlist_wet, wind_tends(:,:,1), wind_tends(:,:,2), cloudtnd, stnd, tautmsx, &
tautmsy, dtk, topflx, errstring, tauresx, tauresy, 1, do_molec_diff, &
compute_molec_diff, vd_lu_qdecomp)
end if
if( errstring .ne. '' ) then
call wrf_error_fatal
(errstring)
endif
if( any( fieldlist_dry ) ) then
if( do_molec_diff ) then
errstring = "Design flaw: dry vdiff not currently supported with molecular diffusion"
call wrf_error_fatal
(errstring)
end if
call compute_vdiff
( lchnk, pcols, pver, pcnst, ncol, pmiddry8, pintdry8, rpdeldry8, t8, &
ztodt, taux, tauy, shflx, cflx, ntop, nbot, kvh, kvm, kvq, cgs, cgh, zi8, ksrftms, &
qmincg, fieldlist_dry, wind_tends(:,:,1), wind_tends(:,:,2), cloudtnd, stnd, tautmsx, &
tautmsy, dtk, topflx, errstring, tauresx, tauresy, 1, do_molec_diff, &
compute_molec_diff, vd_lu_qdecomp)
if( errstring .ne. '' ) call wrf_error_fatal
(errstring)
end if
!! Store updated tauresx, tauresy to use here on the next timestep
tauresx2d(i,j) = tauresx(ncol)
tauresy2d(i,j) = tauresy(ncol)
#ifdef MODAL_AERO
!! Add the explicit surface fluxes to the lowest layer
!! Modification : I should check whether this explicit adding is consistent with
!! the treatment of other tracers.
!The following code is commented out as the diffusion for the Aerosols and other species is handled by CAMMGMP and WRF_CHEM's dry_dep_driver subroutines
!tmp1(:ncol) = ztodt * gravit * rpdel8(:ncol,pver)
!do m = 1, ntot_amode
! l = numptr_amode(m)
! cloudtnd(:ncol,pver,l) = cloudtnd(:ncol,pver,l) + tmp1(:ncol) * cflx(:ncol,l)
! do lspec = 1, nspec_amode(m)
! l = lmassptr_amode(lspec,m)
! cloudtnd(:ncol,pver,l) = cloudtnd(:ncol,pver,l) + tmp1(:ncol) * cflx(:ncol,l)
! enddo
!enddo
#endif
!! -------------------------------------------------------- !
!! Diagnostics and output writing after applying PBL scheme !
!! -------------------------------------------------------- !
sl(:ncol,:pver) = stnd(:ncol,:pver) - latvap * cloudtnd(:ncol,:pver,ixcldliq) &
- ( latvap + latice) * cloudtnd(:ncol,:pver,ixcldice)
qt(:ncol,:pver) = cloudtnd(:ncol,:pver,1) + cloudtnd(:ncol,:pver,ixcldliq) &
+ cloudtnd(:ncol,:pver,ixcldice)
!! --------------------------------------------------------------- !
!! Convert the new profiles into vertical diffusion tendencies. !
!! Convert KE dissipative heat change into "temperature" tendency. !
!! --------------------------------------------------------------- !
slten(:ncol,:) = ( sl(:ncol,:) - sl_prePBL(:ncol,:) ) * rztodt
qtten(:ncol,:) = ( qt(:ncol,:) - qt_prePBL(:ncol,:) ) * rztodt
stnd(:ncol,:) = ( stnd(:ncol,:) - s8(:ncol,:) ) * rztodt
wind_tends(:ncol,:,1) = ( wind_tends(:ncol,:,1) - u8(:ncol,:) ) * rztodt
wind_tends(:ncol,:,2) = ( wind_tends(:ncol,:,2) - v8(:ncol,:) ) * rztodt
cloudtnd(:ncol,:pver,:) = ( cloudtnd(:ncol,:pver,:) - cloud(:ncol,:pver,:) ) * rztodt
!! ----------------------------------------------------------- !
!! In order to perform 'pseudo-conservative varible diffusion' !
!! perform the following two stages: !
!! !
!! I. Re-set (1) 'qvten' by 'qtten', and 'qlten = qiten = 0' !
!! (2) 'sten' by 'slten', and !
!! (3) 'qlten = qiten = 0' !
!! !
!! II. Apply 'positive_moisture' !
!! !
!! ----------------------------------------------------------- !
if( eddy_scheme .eq. 'diag_TKE' .and. do_pseudocon_diff ) then
cloudtnd(:ncol,:pver,1) = qtten(:ncol,:pver)
stnd(:ncol,:pver) = slten(:ncol,:pver)
cloudtnd(:ncol,:pver,ixcldliq) = 0._r8
cloudtnd(:ncol,:pver,ixcldice) = 0._r8
cloudtnd(:ncol,:pver,ixnumliq) = 0._r8
cloudtnd(:ncol,:pver,ixnumice) = 0._r8
do ips = 1, ncol
do k = 1, pver
qv_pro(ips,k) = cloud(ips,k,1) + cloudtnd(ips,k,1) * ztodt
ql_pro(ips,k) = cloud(ips,k,ixcldliq) + cloudtnd(ips,k,ixcldliq) * ztodt
qi_pro(ips,k) = cloud(ips,k,ixcldice) + cloudtnd(ips,k,ixcldice) * ztodt
s_pro(ips,k) = s8(ips,k) + stnd(ips,k) * ztodt
t_pro(ips,k) = t8(ips,k) + (1._r8/cpair)*stnd(ips,k) * ztodt
end do
end do
call positive_moisture
( cpair, latvap, latvap+latice, ncol, pver, ztodt, qmin(1), qmin(2), qmin(3), &
pdel8(:ncol,pver:1:-1), qv_pro(:ncol,pver:1:-1), ql_pro(:ncol,pver:1:-1), &
qi_pro(:ncol,pver:1:-1), t_pro(:ncol,pver:1:-1), s_pro(:ncol,pver:1:-1), &
cloudtnd(:ncol,pver:1:-1,1), cloudtnd(:ncol,pver:1:-1,ixcldliq), &
cloudtnd(:ncol,pver:1:-1,ixcldice), stnd(:ncol,pver:1:-1) )
end if
!! ----------------------------------------------------------------- !
!! Re-calculate diagnostic output variables after vertical diffusion !
!! ----------------------------------------------------------------- !
qv_aft_PBL(:ncol,:pver) = cloud(:ncol,:pver,1) + cloudtnd(:ncol,:pver,1) * ztodt
ql_aft_PBL(:ncol,:pver) = cloud(:ncol,:pver,ixcldliq) + cloudtnd(:ncol,:pver,ixcldliq) * ztodt
qi_aft_PBL(:ncol,:pver) = cloud(:ncol,:pver,ixcldice) + cloudtnd(:ncol,:pver,ixcldice) * ztodt
s_aft_PBL(:ncol,:pver) = s8(:ncol,:pver) + stnd(:ncol,:pver) * ztodt
t_aftPBL(:ncol,:pver) = ( s_aft_PBL(:ncol,:pver) - gravit*zm8(:ncol,:pver) ) / cpair
u_aft_PBL(:ncol,:pver) = u8(:ncol,:pver) + wind_tends(:ncol,:pver,1) * ztodt
v_aft_PBL(:ncol,:pver) = v8(:ncol,:pver) + wind_tends(:ncol,:pver,2) * ztodt
call aqsat
( t_aftPBL, pmid8, tem2, ftem, pcols, ncol, pver, 1, pver )
ftem_aftPBL(:ncol,:pver) = qv_aft_PBL(:ncol,:pver) / ftem(:ncol,:pver) * 100._r8
tten(:ncol,:pver) = ( t_aftPBL(:ncol,:pver) - t8(:ncol,:pver) ) * rztodt
rhten(:ncol,:pver) = ( ftem_aftPBL(:ncol,:pver) - ftem_prePBL(:ncol,:pver) ) * rztodt
!Post processing of the output from CAM's parameterization
do k=kts,kte
kflip = kte-k+1
rublten(i,k,j) = wind_tends(1,kflip,1)
rvblten(i,k,j) = wind_tends(1,kflip,2)
rthblten(i,k,j) = stnd(1,kflip)/cpair/exner8(1,kflip)
multFrc = 1._r8/(1._r8 - qv_curr(i,k,j))
rqvblten(i,k,j) = cloudtnd(1,kflip,1 ) * multFrc
rqcblten(i,k,j) = cloudtnd(1,kflip,ixcldliq) * multFrc
rqiblten(i,k,j) = cloudtnd(1,kflip,ixcldice) * multFrc
!*Important* : ixnumliq is mixed in the dropmixnuc, therefore ixnumliq is NOT mixed here (ONLY if CAMMGMP is used for mp_physics)
rqniblten(i,k,j) = cloudtnd(1,kflip,ixnumice) * multFrc
!Diffusivity coefficients at the midpoints
kp1 = k + 1
end do
do k = kts,kte+1
kflip = kte - k + 2
tke_pbl(i,k,j) = tke8(1,kflip) !TKE at the interfaces
turbtype3d(i,k,j) = turbtype(1,kflip)
smaw3d(i,k,j) = smaw(1,kflip)
end do
kpbl2d(i,j) = kte - int(kpblh(1)) + 1 !int(kpblh(1))
pblh2d(i,j) = pblh( 1)
tpert2d(i,j) = tpert(1)
qpert2d(i,j) = qpert(1)
wpert2d(i,j) = wpert(1)
!End Post processing of the output from CAM
enddo !loop of i
enddo !loop of j
return
end subroutine camuwpbl
!-----------------------------------------------------------------------------------------
subroutine positive_moisture( cp, xlv, xls, ncol, mkx, dt, qvmin, qlmin, qimin, & 1,1
dp, qv, ql, qi, t, s, qvten, qlten, qiten, sten )
!! ------------------------------------------------------------------------------- !
!! If any 'ql < qlmin, qi < qimin, qv < qvmin' are developed in any layer, !
!! force them to be larger than minimum value by (1) condensating water vapor !
!! into liquid or ice, and (2) by transporting water vapor from the very lower !
!! layer. '2._r8' is multiplied to the minimum values for safety. !
!! Update final state variables and tendencies associated with this correction. !
!! If any condensation happens, update (s,t) too. !
!! Note that (qv,ql,qi,t,s) are final state variables after applying corresponding !
!! input tendencies. !
!! Be careful the order of k : '1': near-surface layer, 'mkx' : top layer !
!! ------------------------------------------------------------------------------- !
!-----------------------------------------------------------------------------------------
implicit none
integer, intent(in) :: ncol, mkx
real(r8), intent(in) :: cp, xlv, xls
real(r8), intent(in) :: dt, qvmin, qlmin, qimin
real(r8), intent(in) :: dp(ncol,mkx)
real(r8), intent(inout) :: qv(ncol,mkx), ql(ncol,mkx), qi(ncol,mkx), t(ncol,mkx), s(ncol,mkx)
real(r8), intent(inout) :: qvten(ncol,mkx), qlten(ncol,mkx), qiten(ncol,mkx), sten(ncol,mkx)
integer i, k
real(r8) dql, dqi, dqv, sum, aa, dum
!! Modification : I should check whether this is exactly same as the one used in
!! shallow convection and cloud macrophysics.
do i = 1, ncol
do k = mkx, 1, -1 ! From the top to the 1st (lowest) layer from the surface
dql = max(0._r8,1._r8*qlmin-ql(i,k))
dqi = max(0._r8,1._r8*qimin-qi(i,k))
qlten(i,k) = qlten(i,k) + dql/dt
qiten(i,k) = qiten(i,k) + dqi/dt
qvten(i,k) = qvten(i,k) - (dql+dqi)/dt
sten(i,k) = sten(i,k) + xlv * (dql/dt) + xls * (dqi/dt)
ql(i,k) = ql(i,k) + dql
qi(i,k) = qi(i,k) + dqi
qv(i,k) = qv(i,k) - dql - dqi
s(i,k) = s(i,k) + xlv * dql + xls * dqi
t(i,k) = t(i,k) + (xlv * dql + xls * dqi)/cp
dqv = max(0._r8,1._r8*qvmin-qv(i,k))
qvten(i,k) = qvten(i,k) + dqv/dt
qv(i,k) = qv(i,k) + dqv
if( k .ne. 1 ) then
qv(i,k-1) = qv(i,k-1) - dqv*dp(i,k)/dp(i,k-1)
qvten(i,k-1) = qvten(i,k-1) - dqv*dp(i,k)/dp(i,k-1)/dt
endif
qv(i,k) = max(qv(i,k),qvmin)
ql(i,k) = max(ql(i,k),qlmin)
qi(i,k) = max(qi(i,k),qimin)
end do
!! Extra moisture used to satisfy 'qv(i,1)=qvmin' is proportionally
!! extracted from all the layers that has 'qv > 2*qvmin'. This fully
!! preserves column moisture.
if( dqv .gt. 1.e-20_r8 ) then
sum = 0._r8
do k = 1, mkx
if( qv(i,k) .gt. 2._r8*qvmin ) sum = sum + qv(i,k)*dp(i,k)
enddo
aa = dqv*dp(i,1)/max(1.e-20_r8,sum)
if( aa .lt. 0.5_r8 ) then
do k = 1, mkx
if( qv(i,k) .gt. 2._r8*qvmin ) then
dum = aa*qv(i,k)
qv(i,k) = qv(i,k) - dum
qvten(i,k) = qvten(i,k) - dum/dt
endif
enddo
else
write(iulog,*) 'Full positive_moisture is impossible in vertical_diffusion'
call wrf_message
(iulog)
endif
endif
end do
return
end subroutine positive_moisture
!-----------------------------------------------------------------------------------------
subroutine camuwpblinit(rublten,rvblten,rthblten,rqvblten, & 1,31
restart,tke_pbl,is_CAMMGMP_used, &
ids,ide,jds,jde,kds,kde, &
ims,ime,jms,jme,kms,kme, &
its,ite,jts,jte,kts,kte)
!!------------------------------------------------------------------!
!! Initialization of time independent fields for vertical diffusion !
!! Calls initialization routines for subsidiary modules !
!!----------------------------------------------------------------- !
!This subroutine is based on vertical_diffusion_init of CAM. This subroutine
!initializes variables for vertical diffusion subroutine calls. The layout
!is kept similar to the original CAM subroutine to facillitate future adaptations.
!Called by : physics_init.F
!Calls: vd_register, cnst_get_ind, wrf_error_fatal,init_eddy_diff,init_tms,init_vdiff
!-----------------------------------------------------------------------------------------
use eddy_diff
, only : init_eddy_diff
use molec_diff
, only : init_molec_diff
use trb_mtn_stress
, only : init_tms
use diffusion_solver
, only : init_vdiff, vdiff_select
use constituents
, only : cnst_get_ind, cnst_get_type_byind, cnst_name
use module_cam_support
, only : masterproc
use module_model_constants
, only : epsq2
#ifdef MODAL_AERO
use modal_aero_data
#endif
implicit none
!-------------------------------------------------------------------------------------!
!Input and output variables !
!-------------------------------------------------------------------------------------!
logical,intent(in) :: restart,is_CAMMGMP_used
integer,intent(in) :: ids,ide,jds,jde,kds,kde
integer,intent(in) :: ims,ime,jms,jme,kms,kme
integer,intent(in) :: its,ite,jts,jte,kts,kte
real,dimension(ims:ime,kms:kme,jms:jme),intent(inout) :: &
rublten, rvblten, rthblten, rqvblten
real,dimension(ims:ime,kms:kme,jms:jme),intent(out) :: TKE_PBL
!-------------------------------------------------------------------------------------!
!Local Variables !
!-------------------------------------------------------------------------------------!
integer :: i,j,k,itf,jtf,ktf
integer :: ntop_eddy !! Top interface level to which eddy vertical diffusion is applied ( = 1 )
integer :: nbot_eddy !! Bottom interface level to which eddy vertical diffusion is applied ( = pver )
integer :: ntop_molec !! Top interface level to which molecular vertical diffusion is applied ( = 1 )
integer :: nbot_molec !! Bottom interface level to which molecular vertical diffusion is applied
character(128) :: errstring !! Error status for init_vdiff
real(r8) :: hypm(kte) !! reference state midpoint pressures
#ifdef MODAL_AERO
integer :: m, l
#endif
jtf = min(jte,jde-1)
ktf = min(kte,kde-1)
itf = min(ite,ide-1)
!Map CAM veritcal level variables
pver = ktf - kts + 1
pverp = pver + 1
!Initialize flags and add constituents
call vd_register
()
!! ----------------------------------------------------------------- !
!! Get indices of cloud liquid and ice within the constituents array !
!! ----------------------------------------------------------------- !
call cnst_get_ind
( 'CLDLIQ', ixcldliq )
call cnst_get_ind
( 'CLDICE', ixcldice )
if( microp_scheme .eq. 'MG' ) then
call cnst_get_ind
( 'NUMLIQ', ixnumliq )
call cnst_get_ind
( 'NUMICE', ixnumice )
endif
if (masterproc) then
write(iulog,*)'Initializing vertical diffusion (vertical_diffusion_init)'
call wrf_debug
(1,iulog)
end if
!! ---------------------------------------------------------------------------------------- !
!! Initialize molecular diffusivity module !
!! Molecular diffusion turned on above ~60 km (50 Pa) if model top is above ~90 km (.1 Pa). !
!! Note that computing molecular diffusivities is a trivial expense, but constituent !
!! diffusivities depend on their molecular weights. Decomposing the diffusion matric !
!! for each constituent is a needless expense unless the diffusivity is significant. !
!! ---------------------------------------------------------------------------------------- !
ntop_molec = 1 !! Should always be 1
nbot_molec = 0 !! Should be set below about 70 km
!! ---------------------------------- !
!! Initialize eddy diffusivity module !
!! ---------------------------------- !
ntop_eddy = 1 !! No reason not to make this 1, if > 1, must be <= nbot_molec
nbot_eddy = pver !! Should always be pver
if( masterproc ) write(iulog,fmt='(a,i3,5x,a,i3)') 'NTOP_EDDY =', ntop_eddy, 'NBOT_EDDY =', nbot_eddy
call wrf_debug
(1,iulog)
select case ( eddy_scheme )
case ( 'diag_TKE' )
if( masterproc ) write(iulog,*) 'vertical_diffusion_init: eddy_diffusivity scheme: UW Moist Turbulence Scheme by Bretherton and Park'
call wrf_debug
(1,iulog)
!! Check compatibility of eddy and shallow scheme
if( shallow_scheme .ne. 'UW' ) then
write(iulog,*) 'ERROR: shallow convection scheme ', shallow_scheme,' is incompatible with eddy scheme ', eddy_scheme
call wrf_message
(iulog)
call wrf_error_fatal
( 'convect_shallow_init: shallow_scheme and eddy_scheme are incompatible' )
endif
call init_eddy_diff
( r8, pver, gravit, cpair, rair, zvir, latvap, latice, &
ntop_eddy, nbot_eddy, hypm, karman )
if( masterproc ) write(iulog,*) 'vertical_diffusion: nturb, ntop_eddy, nbot_eddy ', nturb, ntop_eddy, nbot_eddy
call wrf_debug
(1,iulog)
end select
!!-------------------------------------------------------------------------------------!
!! The vertical diffusion solver must operate !
!! over the full range of molecular and eddy diffusion !
!!-------------------------------------------------------------------------------------!
ntop = min(ntop_molec,ntop_eddy)
nbot = max(nbot_molec,nbot_eddy)
!! ------------------------------------------- !
!! Initialize turbulent mountain stress module !
!! ------------------------------------------- !
if( do_tms ) then
call init_tms
( r8, tms_orocnst, tms_z0fac, karman, gravit, rair )
if (masterproc) then
write(iulog,*)'Using turbulent mountain stress module'
call wrf_message
(iulog)
write(iulog,*)' tms_orocnst = ',tms_orocnst
call wrf_message
(iulog)
end if
endif
!! ---------------------------------- !
!! Initialize diffusion solver module !
!! ---------------------------------- !
call init_vdiff
( r8, pcnst, rair, gravit, fieldlist_wet, fieldlist_dry, errstring )
if( errstring .ne. '' ) call wrf_error_fatal
( errstring )
!!-------------------------------------------------------------------------------------
!! Use fieldlist_wet to select the fields which will be diffused using moist mixing ratios ( all by default )
!! Use fieldlist_dry to select the fields which will be diffused using dry mixing ratios.
!!-------------------------------------------------------------------------------------
if( vdiff_select( fieldlist_wet, 'u' ) .ne. '' ) call wrf_error_fatal
( vdiff_select( fieldlist_wet, 'u' ) )
if( vdiff_select( fieldlist_wet, 'v' ) .ne. '' ) call wrf_error_fatal
( vdiff_select( fieldlist_wet, 'v' ) )
if( vdiff_select( fieldlist_wet, 's' ) .ne. '' ) call wrf_error_fatal
( vdiff_select( fieldlist_wet, 's' ) )
#ifdef MODAL_AERO
!Get index for the liquid number concentration (#/kg)
call cnst_get_ind
( 'NUMLIQ', ixndrop )
#endif
do k = 1, pcnst
#ifdef MODAL_AERO
!! Do not diffuse droplet number - treated in dropmixnuc
!BSINGH:01/31/2013: The following if condition is modified from its original form[which is:if( k == ixndrop ) cycle]
!to allow the PBL scheme to mix liquid number when CAMMGMP scheme is not being used
if(is_CAMMGMP_used) then!BSINGH:01/31/2013: Modified this if cond. see comment above
if( k == ixndrop ) cycle
endif
!BSINGH-08/31/2012: In WRF, Physics init is called before chem init therefore
!aerosol species are not yet added. Following condition, skip all other constituents
!(which will be added in chem init) except first five (vapor, cld liq, cld ice, liq num and ice num)
if( k > 5 ) cycle
!The Following do-loop is commented out as Aerosols and other species are diffused in CAMMGMP and WRF_CHEM's dry_dep_driver subroutines
!! Don't diffuse aerosol - treated in dropmixnuc
!do m = 1, ntot_amode
! if( k == numptr_amode(m) ) cycle
!! if( k == numptrcw_amode(m) ) go to 20
! do l = 1, nspec_amode(m)
! if( k == lmassptr_amode(l,m) )cycle
!! if( k == lmassptrcw_amode(l,m) ) go to 20
! enddo
!! if( k == lwaterptr_amode(m) ) go to 20
!enddo
#endif
!endif
if( cnst_get_type_byind(k) .eq. 'wet' ) then
if( vdiff_select( fieldlist_wet, 'q', k ) .ne. '' ) call wrf_error_fatal
( vdiff_select( fieldlist_wet, 'q', k ) )
else
!The DRY constituents are not diffused currently in PBL, they are diffused in WRF_CHEM's dry_dep_driver subroutine. Therefore the following line is commented out
!if( vdiff_select( fieldlist_dry, 'q', k ) .ne. '' ) call wrf_error_fatal
( vdiff_select( fieldlist_dry, 'q', k ) )
endif
enddo
!Initialize the tendencies
jtf=min0(jte,jde-1)
ktf=min0(kte,kde-1)
itf=min0(ite,ide-1)
if(.not.restart)then
do j = jts , jtf
do k = kts , ktf
do i = its , itf
tke_pbl(i,k,j) = epsq2
rublten(i,k,j) = 0.
rvblten(i,k,j) = 0.
rthblten(i,k,j) = 0.
rqvblten(i,k,j) = 0.
enddo
enddo
enddo
endif
end subroutine camuwpblinit
!-----------------------------------------------------------------------------------------
subroutine vd_register() 1
!
!This subroutine is based on the vd_register subroutine of CAM.
!-----------------------------------------------------------------------------------------
!Set flags for the PBL scheme (these flags are obtained using phys_getopts in CAM)
microp_scheme = 'MG' !Used for adding constituents
eddy_scheme = 'diag_TKE' !Used for calling eddy scheme
!The following flag is deliberately set to UW for now.
shallow_scheme = 'UW' !Eddy scheme is ONLY compaticle with 'UW' shallow scheme;
do_tms = .false. !To include stresses due to orography
tms_orocnst = 1._r8 !Orography constant
end subroutine vd_register
end module module_bl_camuwpbl_driver