! +-======-+
! Copyright (c) 2003-2018 United States Government as represented by
! the Admistrator of the National Aeronautics and Space Administration.
! All Rights Reserved.
!
! THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE,
! REPRODUCTION, DISTRIBUTION, MODIFICATION AND REDISTRIBUTION OF CERTAIN
! COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE UNITED STATES GOVERNMENT AS
! REPRESENTED BY THE GOVERNMENT AGENCY LISTED BELOW ("GOVERNMENT AGENCY").
! THE UNITED STATES GOVERNMENT, AS REPRESENTED BY GOVERNMENT AGENCY, IS AN
! INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT DISTRIBUTIONS OR
! REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES,
! DISTRIBUTES, MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED
! HEREIN, OR ANY PART THEREOF, IS, BY THAT ACTION, ACCEPTING IN FULL THE
! RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT.
!
! Government Agency: National Aeronautics and Space Administration
! Government Agency Original Software Designation: GSC-15354-1
! Government Agency Original Software Title: GEOS-5 GCM Modeling Software
! User Registration Requested. Please Visit http://opensource.gsfc.nasa.gov
! Government Agency Point of Contact for Original Software:
! Dale Hithon, SRA Assistant, (301) 286-2691
!
! +-======-+
module LockEntrain
!
!
! K-PROFILE BOUNDARY LAYER SCHEME WITH CLOUD TOP ENTRAINMENT
! Adapted from code provided by Stephen A. Klein at GFDL
!
! This routine calculates diffusivity coefficients for vertical
! diffusion using a K-profile approach. This scheme is modelled
! after:
!
! Lock, A.P., A.R. Brown, M.R. Bush, G.M. Martin, and R.N.B. Smith,
! 2000: A new boundary layer mixing scheme. Part I: Scheme
! description and single-column modeling tests. Mon. Wea. Rev.,
! 128, 3187-3199.
!
!
!
!
!
! The key part is the parameterization of entrainment at the top
! convective layers. For an entrainment interface from surface
! driven mixing, the entrainment rate, we, is parameterized as:
!
!
! we, surf = A / B
!
! where A = ( beta_surf * (V_surf**3 + V_shear**3) / zsml )
! and B = ( delta_b + ((V_surf**3 + V_shear**3)**(2/3))/zsml )
!
!
! In this formula,
!
! zsml = depth of surface mixed layer
!
! V_surf = surface driven scaling velocity
! = (u_star*b_star*zsml)**(1/3)
!
! V_shear = surface driven shear velocity,
! = (Ashear**(1/3))*u_star
!
! delta_b = buoyancy jump at the entrainment interface(m/s2)
! = grav * delta_slv / slv
!
! If an entrainment interface is associated only with cloud top
! radiative cooling, the entrainment rate is parameterized as:
!
!
!
! we, rad = ( A / B)
!
! where A = beta_rad * V_rad**3 / zradml
! and B = delta_b + V_rad**2 / zradml
!
! where
!
! zradml = depth of radiatively driven layer
!
! V_rad = radiatively driven scaling velocity
! = (grav*delta-F*zradml/(rho*cp_air*T)) **(1/3)
!
!
! Note that the source of entrainment from cloud top buoyancy
! reversal has been omitted in this implementation.
!
! If the entrainment interface for surface driven mixing coincides
! with that for cloud top radiatively driven convection then the
! following full entrainment rate:
!
!
! we, full = A / B
!
! where A = V_full**3 / zsml
! and B = delta_b+((V_surf**3+V_shear**3+V_rad**3)**(2/3))/zsml
! and V_full**3 = beta_surf*(V_surf**3+V_shear**3) + beta_rad*V_rad**3
!
!
!
!-----------------------------------------------------------------------
!
! outside modules used
!
#ifndef _CUDA
use GEOS_UtilsMod, only: DQSAT=>GEOS_DQSAT
#else
use cudafor
! NOTE: GPUs use the QSAT and DQSAT at the end of this module
#endif
use MAPL_ConstantsMod, only: MAPL_GRAV, MAPL_KARMAN, MAPL_CP, &
MAPL_RGAS, MAPL_RVAP, MAPL_ALHL, &
MAPL_ALHS, MAPL_TICE, MAPL_VIREPS, &
MAPL_P00, MAPL_KAPPA, MAPL_H2OMW, &
MAPL_AIRMW, MAPL_R4, MAPL_R8
use MAPL_Mod, only: MAPL_UNDEF
implicit none
#ifndef _CUDA
private
!-----------------------------------------------------------------------
!
! public interfaces
PUBLIC ENTRAIN
#endif
#ifdef _CUDA
! Inputs
! ------
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: TDTLW_IN_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: U_STAR_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: B_STAR_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: FRLAND_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: T_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: QV_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: QLLS_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: QILS_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: U_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: V_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: ZFULL_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: PFULL_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: ZHALF_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: PHALF_dev
! Inoutputs
! ---------
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: DIFF_M_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: DIFF_T_dev
! Outputs
! -------
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: K_M_ENTR_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: K_T_ENTR_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: K_SFC_dev
REAL, ALLOCATABLE, DIMENSION(:,:,:), DEVICE :: K_RAD_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: ZCLOUD_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: ZRADML_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: ZRADBASE_dev
REAL, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: ZSML_dev
! Diagnostics
! -----------
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: ZCLDTOP_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: WENTR_SFC_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: WENTR_RAD_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: DEL_BUOY_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: VSFC_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: VRAD_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: KENTRAD_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: VBRV_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: WENTR_BRV_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: DSIEMS_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: CHIS_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: DELSINV_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: SLMIXTURE_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: CLDRADF_DIAG_dev
REAL, TARGET, ALLOCATABLE, DIMENSION(:,: ), DEVICE :: RADRCODE_DIAG_dev
REAL, POINTER, DIMENSION(:,: ), DEVICE :: ZCLDTOP_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: WENTR_SFC_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: WENTR_RAD_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: DEL_BUOY_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: VSFC_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: VRAD_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: KENTRAD_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: VBRV_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: WENTR_BRV_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: DSIEMS_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: CHIS_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: DELSINV_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: SLMIXTURE_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: CLDRADF_DIAG_dev_ptr
REAL, POINTER, DIMENSION(:,: ), DEVICE :: RADRCODE_DIAG_dev_ptr
! Parameters for Internal DQSAT
! -----------------------------
REAL, PARAMETER :: ESFAC = MAPL_H2OMW/MAPL_AIRMW
REAL, PARAMETER :: MAX_MIXING_RATIO = 1.
REAL, PARAMETER :: ZEROC = MAPL_TICE
REAL, PARAMETER :: TMINTBL = 150.0
REAL, PARAMETER :: TMAXTBL = 333.0
REAL, PARAMETER :: DEGSUBS = 100
REAL, PARAMETER :: ERFAC = (DEGSUBS/ESFAC)
REAL, PARAMETER :: DELTA_T = 1.0 / DEGSUBS
REAL, PARAMETER :: TABLESIZE = NINT(TMAXTBL-TMINTBL)*DEGSUBS + 1
REAL, PARAMETER :: TMIX = -20.
REAL, PARAMETER :: TMINSTR = -95.
REAL, PARAMETER :: TSTARR1 = -75.
REAL, PARAMETER :: TSTARR2 = -65.
REAL, PARAMETER :: TSTARR3 = -50.
REAL, PARAMETER :: TSTARR4 = -40.
REAL, PARAMETER :: TMAXSTR = +60.
REAL(KIND=MAPL_R8), PARAMETER :: B6 = 6.136820929E-11*100.0
REAL(KIND=MAPL_R8), PARAMETER :: B5 = 2.034080948E-8 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: B4 = 3.031240396E-6 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: B3 = 2.650648471E-4 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: B2 = 1.428945805E-2 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: B1 = 4.436518521E-1 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: B0 = 6.107799961E+0 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI6= 1.838826904E-10*100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI5= 4.838803174E-8 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI4= 5.824720280E-6 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI3= 4.176223716E-4 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI2= 1.886013408E-2 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI1= 5.034698970E-1 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: BI0= 6.109177956E+0 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S16= 0.516000335E-11*100.0
REAL(KIND=MAPL_R8), PARAMETER :: S15= 0.276961083E-8 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S14= 0.623439266E-6 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S13= 0.754129933E-4 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S12= 0.517609116E-2 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S11= 0.191372282E+0 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S10= 0.298152339E+1 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S26= 0.314296723E-10*100.0
REAL(KIND=MAPL_R8), PARAMETER :: S25= 0.132243858E-7 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S24= 0.236279781E-5 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S23= 0.230325039E-3 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S22= 0.129690326E-1 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S21= 0.401390832E+0 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: S20= 0.535098336E+1 *100.0
REAL(KIND=MAPL_R8), PARAMETER :: DI(0:3) = (/ 57518.5606E08, 2.01889049, 3.56654, 20.947031 /)
REAL(KIND=MAPL_R8), PARAMETER :: CI(0:3) = (/ 9.550426, -5723.265, 3.53068, -.00728332 /)
REAL(KIND=MAPL_R8), PARAMETER :: DL(1:6) = (/ -7.902980, 5.02808, -1.3816, 11.344, 8.1328, -3.49149 /)
REAL(KIND=MAPL_R8), PARAMETER :: LOGPS = 3.005714898 ! LOG10(1013.246)
REAL(KIND=MAPL_R8), PARAMETER :: TS = 373.16
REAL(KIND=MAPL_R8), PARAMETER :: CL(0:9) = (/54.842763, -6763.22, -4.21000, .000367, &
.0415, 218.8, 53.878000, -1331.22, -9.44523, .014025 /)
REAL, PARAMETER :: TMINLQU = MAPL_TICE - 40.0
REAL, PARAMETER :: TMINICE = MAPL_TICE + -95.
#endif
!-----------------------------------------------------------------------
!
! set default values to some instance independent parameters
!
real, parameter :: akmax = 1.e4 ! maximum value for a diffusion coefficient
! (m2/s)
real, parameter :: zcldtopmax = 3.e3 ! maximum altitude for cloud top of
! radiatively driven convection (m)
real, parameter :: ramp = 20.
!-----------------------------------------------------------------------
!
! declare version number
!
character(len=128) :: Version = '$Id$'
character(len=128) :: Tagname = '$Name$'
!-----------------------------------------------------------------------
!
! Subroutines include:
!
! entrain main driver program of the module
!
! mpbl_depth routine to calculate the depth of surface driven
! mixed layer
!
! radml_depth subroutine to calculate the depth of the cloud
! topped radiatively driven mixed layer
!
! diffusivity_pbl2 subroutine to calculate diffusivity coefficients
! for surface driven mixed layer
contains
!=======================================================================
#ifdef _CUDA
attributes(global) &
#endif
subroutine entrain( &
! Integer Inputs
icol, &
jcol, &
nlev, &
! Inputs
tdtlw_in, &
u_star, &
b_star, &
frland, &
t, &
qv, &
qlls, &
qils, &
u, &
v, &
zfull, &
pfull, &
zhalf, &
phalf, &
! Inoutputs
diff_m, &
diff_t, &
! Outputs
k_m_entr, &
k_t_entr, &
k_sfc, &
k_rad, &
zcloud, &
zradml, &
zradbase, &
zsml, &
! Diagnostics
zcldtop_diag, &
wentr_sfc_diag, &
wentr_rad_diag, &
del_buoy_diag, &
vsfc_diag, &
vrad_diag, &
kentrad_diag, &
vbrv_diag, &
wentr_brv_diag, &
dsiems_diag, &
chis_diag, &
delsinv_diag, &
slmixture_diag, &
cldradf_diag, &
radrcode_diag, &
! Constants
prandtlsfc, &
prandtlrad, &
beta_surf, &
beta_rad, &
tpfac_sfc, &
entrate_sfc, &
pceff_sfc, &
khradfac, &
khsfcfac )
!-----------------------------------------------------------------------
!
! variables
!
! -----
! input
! -----
!
! ncol,nlev sizes of i,j,k dimensions
!
! convect is surface based moist convection occurring in this
! grid box?
! u_star friction velocity (m/s)
! b_star buoyancy scale (m/s**2)
!
! three dimensional fields on model full levels, reals dimensioned
! (:,:,pressure), third index running from top of atmosphere to
! bottom
!
! t temperature (K)
! qv water vapor specific humidity (kg vapor/kg air)
! ql liquid water specific humidity (kg cond/kg air)
! qi ice water specific humidity (kg cond/kg air)
! zfull height of full levels (m)
! pfull pressure (Pa)
! u zonal wind (m/s)
! v meridional wind (m/s)
!
! the following two fields are on the model half levels, with
! size(zhalf,3) = size(t,3) +1, zhalf(:,:,size(zhalf,3))
! must be height of surface (if you are not using eta-model)
!
! zhalf height at half levels (m)
! phalf pressure at half levels (Pa)
!
! ------------
! input/output
! ------------
!
! the following variables are defined at half levels and are
! dimensions 1:nlev
!
! diff_t input and output heat diffusivity (m2/sec)
! diff_m input and output momentum diffusivity (m2/sec)
!
! The diffusivity coefficient output from the routine includes
! the modifications to use the internally calculated diffusivity
! coefficients.
!
! ------
! output
! ------
!
! The following variables are defined at half levels and are
! dimensions 1:nlev.
!
! k_t_entr heat diffusivity coefficient (m**2/s)
! k_m_entr momentum diffusivity coefficient (m**2/s)
! zsml height of surface driven mixed layer (m)
!
! --------
! internal
! --------
!
!
! General variables
! -----------------
!
! slv virtual static energy (J/kg)
! density air density (kg/m3)
! hleff effective latent heat of vaporization/sublimation
! (J/kg)
!
!
!
! Variables related to surface driven convective layers
! -----------------------------------------------------
!
! vsurf surface driven buoyancy velocity scale (m/s)
! vshear surface driven shear velocity scale (m/s)
! wentr_pbl surface driven entrainment rate (m/s)
! convpbl 1 is surface driven convective layer present
! 0 otherwise
! pblfq 1 if the half level is part of a surface driven
! layer, 0 otherwise
! k_m_troen momentum diffusion coefficient (m2/s) !Why are there two
! k_t_troen heat diffusion coefficient (m2/s) !of these. They are equal?
!
!
! Variables related to cloud top driven radiatively driven layers
! ---------------------------------------------------------------
!
! zradbase height of base of radiatively driven mixed layer (m)
! zradtop height of top of radiatively driven mixed layer (m)
! zradml depth of radiatively driven mixed layer (m)
! vrad radiatively driven velocity scale (m/s)
! radf longwave jump at cloud top (W/m2) -- the radiative
! forcing for cloud top driven mixing.
! wentr_rad cloud top driven entrainment (m/s)
! svpcp cloud top value of liquid water virtual static energy
! divided by cp (K)
! radpbl 1 if cloud top radiatively driven layer is present
! 0 otherwise
! radfq 1 if the half level is part of a radiatively driven
! layer, 0 otherwise
! k_rad radiatively driven diffusion coefficient (m2/s)
!
!-----------------------------------------------------------------------
implicit none
#ifdef _CUDA
integer, value, intent(in) :: icol,jcol,nlev
real, value, intent(in) :: prandtlsfc,prandtlrad,beta_surf,beta_rad
real, value, intent(in) :: khradfac,tpfac_sfc,entrate_sfc
real, value, intent(in) :: pceff_sfc,khsfcfac
real, device, intent(in), dimension(icol,jcol,nlev) :: tdtlw_in
real, device, intent(in), dimension(icol,jcol) :: u_star,b_star,frland
real, device, intent(in), dimension(icol,jcol,nlev) :: t,qv,qlls,qils
real, device, intent(in), dimension(icol,jcol,nlev) :: u,v,zfull,pfull
real, device, intent(in), dimension(icol,jcol,1:nlev+1) :: zhalf, phalf ! 0:72 in GC, 1:73 here.
real, device, intent(inout), dimension(icol,jcol,1:nlev+1) :: diff_m,diff_t
real, device, intent(out), dimension(icol,jcol,1:nlev+1) :: k_m_entr,k_t_entr
real, device, intent(out), dimension(icol,jcol,1:nlev+1) :: k_rad,k_sfc
real, device, intent(out), dimension(icol,jcol) :: zsml,zradml,zcloud,zradbase
real, device, pointer, dimension(:,:) :: wentr_rad_diag, wentr_sfc_diag ,del_buoy_diag
real, device, pointer, dimension(:,:) :: vrad_diag, kentrad_diag,vbrv_diag,wentr_brv_diag
real, device, pointer, dimension(:,:) :: dsiems_diag, chis_diag,zcldtop_diag
real, device, pointer, dimension(:,:) :: delsinv_diag, slmixture_diag,cldradf_diag
real, device, pointer, dimension(:,:) :: vsfc_diag,radrcode_diag
#else
integer, intent(in) :: icol,jcol,nlev
real, intent(in), dimension(icol,jcol,nlev) :: tdtlw_in
real, intent(in), dimension(icol,jcol) :: u_star,b_star,frland
real, intent(in), dimension(icol,jcol,nlev) :: t,qv,qlls,qils
real, intent(in), dimension(icol,jcol,nlev) :: u,v,zfull,pfull
real, intent(in), dimension(icol,jcol,1:nlev+1) :: zhalf, phalf ! 0:72 in GC, 1:73 here.
real, intent(inout), dimension(icol,jcol,1:nlev+1) :: diff_m,diff_t
real, intent(out), dimension(icol,jcol,1:nlev+1) :: k_m_entr,k_t_entr
real, intent(out), dimension(icol,jcol,1:nlev+1) :: k_rad,k_sfc
real, intent(out), dimension(icol,jcol) :: zsml,zradml,zcloud,zradbase
real, intent(in) :: prandtlsfc,prandtlrad,beta_surf,beta_rad
real, intent(in) :: khradfac,tpfac_sfc,entrate_sfc
real, intent(in) :: pceff_sfc,khsfcfac
real, pointer, dimension(:,:) :: wentr_rad_diag, wentr_sfc_diag ,del_buoy_diag
real, pointer, dimension(:,:) :: vrad_diag, kentrad_diag,vbrv_diag,wentr_brv_diag
real, pointer, dimension(:,:) :: dsiems_diag, chis_diag,zcldtop_diag
real, pointer, dimension(:,:) :: delsinv_diag, slmixture_diag,cldradf_diag
real, pointer, dimension(:,:) :: vsfc_diag,radrcode_diag
#endif
! GPU The GPUs need to know how big local arrays are during compile-time
! as the GPUs cannot allocate memory themselves. This command resets
! this a priori size to nlev for the CPU.
#ifndef GPU_MAXLEVS
#define GPU_MAXLEVS nlev
#endif
integer :: i,j,k,ibot
integer :: ipbl
integer :: kmax,kcldtop,kcldbot,kcldtop2
logical :: do_jump_exit
real :: maxradf,stab
real :: wentrmax
real :: qlcrit,ql00,qlm1,Abuoy,Ashear
real :: wentr_tmp,hlf,vbulkshr,vbulk_scale
real :: k_entr_tmp,tmpjump,critjump,radperturb,buoypert
real :: tmp1, tmp2, slmixture
real :: vsurf3, vshear3,vrad3, vbr3,dsiems
real :: ztmp
real :: zradtop
real :: vrad,radf,svpcp,chis,vbrv
real :: vsurf
real :: wentr_rad,wentr_pbl,wentr_brv
real :: convpbl, radpbl
real, dimension(GPU_MAXLEVS) :: slv, density,qc, slvcp
!real, dimension(GPU_MAXLEVS) :: rh ! Not used in current code
real, dimension(GPU_MAXLEVS) :: hleff
real, dimension(GPU_MAXLEVS) :: radfq,pblfq
real, dimension(GPU_MAXLEVS) :: k_m_troen,k_t_troen
real, dimension(GPU_MAXLEVS) :: k_rad_col
real, dimension(GPU_MAXLEVS) :: dqs
!real, dimension(GPU_MAXLEVS) :: qs ! Not used in current code
real :: qs_dummy
!-----------------------------------------------------------------------
!
! initialize variables
!-----------------------------------------------------------------------
!
! Sizes
!
qlcrit = 1.0e-6
Abuoy = 0.23
Ashear = 25.0
wentrmax = 0.05
ibot = nlev
#ifdef _CUDA
i = (blockidx%x - 1) * blockdim%x + threadidx%x
j = (blockidx%y - 1) * blockdim%y + threadidx%y
I_LOOP: if ( i <= icol ) then
J_LOOP: if ( j <= jcol ) then
#else
I_LOOP: do i = 1, icol
J_LOOP: do j = 1, jcol
#endif
zradml(i,j) = 0.0
zcloud(i,j) = 0.0
zradbase(i,j) = 0.0
zsml(i,j) = 0.0 ! note that this must be zero as this is
! indicates stable surface layer and this
! value is output for use in gravity
! wave drag scheme
zradtop = 0.0
convpbl = 0.0
wentr_pbl = 0.0
vsurf = 0.0
radpbl = 0.0
svpcp = 0.0
vrad = 0.0
radf = 0.0
wentr_rad = 0.0
K_LOOP_0: do k = 1, nlev
pblfq(k) = 0.0
k_t_troen(k) = 0.0
k_m_troen(k) = 0.0
radfq(k) = 0.0
k_rad_col(k) = 0.0
k_t_entr(i,j,k) = 0.0
k_m_entr(i,j,k) = 0.0
k_sfc(i,j,k) = 0.0
k_rad(i,j,k) = 0.0
end do K_LOOP_0
! For GPU we must zero out even the LM+1'th position
k_t_entr(i,j,nlev+1) = 0.0
k_m_entr(i,j,nlev+1) = 0.0
k_sfc(i,j,nlev+1) = 0.0
k_rad(i,j,nlev+1) = 0.0
!--------------------------------------------------------------------------
! Initialize optional outputs
if(associated(wentr_sfc_diag)) wentr_sfc_diag(i,j) = MAPL_UNDEF
if(associated(wentr_rad_diag)) wentr_rad_diag(i,j) = MAPL_UNDEF
if(associated(del_buoy_diag)) del_buoy_diag(i,j) = MAPL_UNDEF
if(associated(vrad_diag)) vrad_diag(i,j) = MAPL_UNDEF
if(associated(vsfc_diag)) vsfc_diag(i,j) = MAPL_UNDEF
if(associated(kentrad_diag)) kentrad_diag(i,j) = MAPL_UNDEF
if(associated(chis_diag)) chis_diag(i,j) = MAPL_UNDEF
if(associated(vbrv_diag)) vbrv_diag(i,j) = MAPL_UNDEF
if(associated(dsiems_diag)) dsiems_diag(i,j) = MAPL_UNDEF
if(associated(wentr_brv_diag)) wentr_brv_diag(i,j) = MAPL_UNDEF
if(associated(zcldtop_diag)) zcldtop_diag(i,j) = MAPL_UNDEF
if(associated(slmixture_diag)) slmixture_diag(i,j) = MAPL_UNDEF
if(associated(delsinv_diag)) delsinv_diag(i,j) = MAPL_UNDEF
if(associated(cldradf_diag)) cldradf_diag(i,j) = MAPL_UNDEF
if(associated(radrcode_diag)) radrcode_diag(i,j) = MAPL_UNDEF
!-----------------------------------------------------------------------
!
! set up specific humidities and static energies
! compute airdensity
!
do k = 1, nlev
if ( t(i,j,k) <= MAPL_TICE-ramp ) then
HLEFF(k) = MAPL_ALHS
else if ( (t(i,j,k) > MAPL_TICE-ramp) .and. (t(i,j,k) < MAPL_TICE) ) then
HLEFF(k) = ( (t(i,j,k)-MAPL_TICE+ramp)*MAPL_ALHL + &
(MAPL_TICE -t(i,j,k) )*MAPL_ALHS ) / ramp
else
HLEFF(k) = MAPL_ALHL
end if
!--------------------------------------------------------------------------
! Compute:
! qs saturation specific humidity (kg/kg)
! dqs derivative of qs w/ respect to temp
! Note. The array QS is never needed in the current code. So we
! use a dummy. QS can be restored if needed.
!dqs(k) = dqsat(t(i,j,k), pfull(i,j,k), qsat=qs(k), pascals=.true. )
dqs(k) = dqsat(t(i,j,k), pfull(i,j,k), qsat=qs_dummy, pascals=.true. )
!--------------------------------------------------------------------------
! Compute total cloud condensate - qc. These are grid box mean values.
qc(k) = (qlls(i,j,k) + qils(i,j,k))
!--------------------------------------------------------------------------
! Compute relative humidity
! rh is not used in the current code. Commented out below.
!rh(k) = qv(i,j,k) / qs(k)
!--------------------------------------------------------------------------
! Compute liquid static energy.
slv(k) = MAPL_CP*t(i,j,k)*(1+MAPL_VIREPS*qv(i,j,k)-qc(k)) + &
MAPL_GRAV*zfull(i,j,k) - hleff(k)*qc(k)
!! slv(k) = MAPL_CP*t(i,j,k) + MAPL_GRAV*zfull(i,j,k) - hleff(k)*qc(k)
!! slv(k) = slv(k)*(1+MAPL_VIREPS*(qv(i,j,k)+qc(k)))
density(k) = pfull(i,j,k)/(MAPL_RGAS*(t(i,j,k) *(1.+MAPL_VIREPS*qv(i,j,k)-qc(k))))
end do
!--------------------------
!
! big loop over points
!
!---------------
! reset indices
ipbl = -1
kcldtop = -1
!-----------------------------------------------------------
!
! SURFACE DRIVEN CONVECTIVE LAYERS
!
! Note this part is done only if b_star > 0., that is,
! upward surface buoyancy flux
IF_BSTAR_GT_0: if (b_star(i,j) .gt. 0.) then
!------------------------------------------------------
! Find depth of surface driven mixing by raising a
! parcel from the surface with some excess buoyancy
! to its level of neutral buoyancy. Note the use
! slv as the density variable permits one to goes
! through phase changes to find parcel top
call mpbl_depth(i,j,icol,jcol,nlev,&
tpfac_sfc, &
entrate_sfc, &
pceff_sfc, &
t, &
qv, &
u, &
v, &
zfull, &
pfull, &
b_star, &
u_star, &
ipbl,zsml )
!------------------------------------------------------
! Define velocity scales vsurf and vshear
!
! vsurf = (u_star*b_star*zsml)**(1/3)
! vshear = (Ashear**(1/3))*u_star
vsurf3 = u_star(i,j)*b_star(i,j)*zsml(i,j)
vshear3 = Ashear*u_star(i,j)*u_star(i,j)*u_star(i,j)
vsurf = vsurf3**(1./3.)
if(associated(vsfc_diag)) vsfc_diag(i,j) = vsurf
!------------------------------------------------------
! Define velocity scale vbulkshr
!
vbulkshr = sqrt ( ( u(i,j,ipbl) - u(i,j,ibot) )**2 &
+ ( v(i,j,ipbl) - v(i,j,ibot) )**2 ) &
/ zsml(i,j)
vbulk_scale = 3.0 / 1000. ! Non-local (PBL-deep) shear scale
!------------------------------------------------------
! Following Lock et al. 2000, limit height of surface
! well mixed layer if interior stable interface is
! found. An interior stable interface is diagnosed if
! the slope between 2 full levels is greater than critjump
critjump = 2.0
if (ipbl .lt. ibot) then
do k = ibot, ipbl+1, -1
tmpjump =(slv(k-1)-slv(k))/MAPL_CP
if (tmpjump .gt. critjump) then
ipbl = k
zsml(i,j) = zhalf(i,j,ipbl)
exit
end if
enddo
end if
!-------------------------------------
! compute entrainment rate
!
tmp1 = MAPL_GRAV*max(0.1,(slv(ipbl-1)-slv(ipbl))/ &
MAPL_CP)/(slv(ipbl)/MAPL_CP)
tmp2 = ((vsurf3+vshear3)**(2./3.)) / zsml(i,j)
wentr_tmp= min( wentrmax, max(0., (beta_surf * &
(vsurf3 + vshear3)/zsml(i,j))/ &
(tmp1+tmp2) ) )
!----------------------------------------
! fudgey adjustment of entrainment to reduce it
! for shallow boundary layers, and increase for
! deep ones
if ( zsml(i,j) .lt. 1600. ) then
wentr_tmp = wentr_tmp * ( zsml(i,j) / 800. )
else
wentr_tmp = 2.*wentr_tmp
endif
!-----------------------------------------
!!AMM106 !----------------------------------------
!!AMM106 ! More fudgey adjustment of entrainment.
!!AMM106 ! Zeroes entr if bulk shear in PBL > vbulk_scale
!!AMM106 if ( vbulkshr .gt. vbulk_scale ) wentr_tmp = 0.0
!!AMM106 if ( ( vbulkshr .gt. 0.5*vbulk_scale ) &
!!AMM106 .and. ( vbulkshr .le. vbulk_scale ) ) then
!!AMM106 wentr_tmp = wentr_tmp * ( vbulk_scale - vbulkshr ) *2 &
!!AMM106 / vbulk_scale
!!AMM106 endif
k_entr_tmp = wentr_tmp*(zfull(i,j,ipbl-1)-zfull(i,j,ipbl))
k_entr_tmp = min ( k_entr_tmp, akmax )
do k = ipbl, ibot
pblfq(k) = 1.
end do
convpbl = 1.
wentr_pbl = wentr_tmp
k_t_troen(ipbl) = k_entr_tmp
k_m_troen(ipbl) = k_entr_tmp
k_t_entr(i,j,ipbl) = k_t_entr(i,j,ipbl) + k_entr_tmp
k_m_entr(i,j,ipbl) = k_m_entr(i,j,ipbl) + k_entr_tmp
if(associated(wentr_sfc_diag)) wentr_sfc_diag(i,j) = wentr_tmp
!------------------------------------------------------
! compute diffusion coefficients in the interior of
! the PBL
if (ipbl .lt. ibot) then
call diffusivity_pbl2(i,j,icol,jcol,nlev, &
zsml, &
khsfcfac, k_entr_tmp, &
vsurf,frland, &
zhalf, &
k_m_troen, &
k_t_troen )
do k = ipbl+1, ibot
k_t_entr(i,j,k) = &
k_t_entr(i,j,k) + &
k_t_troen(k)
k_m_entr(i,j,k) = &
k_m_entr(i,j,k) + &
k_m_troen(k)*prandtlsfc
end do
end if
end if IF_BSTAR_GT_0
!-----------------------------------------------------------
!
! NEGATIVELY BUOYANT PLUMES DRIVEN BY
! LW RADIATIVE COOLING AND/OR BUOYANCY REVERSAL
!
! This part is done only if a level kcldtop can be
! found with:
!
! qc(kcldtop)>=qlcrit.and.qc(kcldtop-1)= 0.0 ) then
chis = 0.
else
chis = chis / ( tmp2 - tmp1 )
endif
if ( chis .gt. 1.0 ) chis=1.0
slmixture = ( 1.0-chis )* ( slv(kcldtop) - hlf*qc(kcldtop) ) &
+ chis * ( slv(kcldtop-1) - hlf*qc(kcldtop-1) )
!-----------------------------------------------------------
! compute temperature of parcel at cloud top, svpcp.
svpcp = slmixture /MAPL_CP
buoypert = ( slmixture - slv(kcldtop) )/MAPL_CP
!-----------------------------------------------------------
! calculate my best guess at the LCs' D parameter attributed
! to Siems et al.
stab = slv(kcldtop-1) - slv(kcldtop)
if (stab .eq. 0.) then
dsiems = ( slv(kcldtop) - slmixture ) ! / 1.0 ! arbitrary, needs to be re-thought
else
dsiems = ( slv(kcldtop) - slmixture ) / stab
endif
dsiems = min( dsiems, 10. )
dsiems = max( dsiems, 0. )
radf = maxradf
zradtop = zhalf(i,j,kcldtop)
!-----------------------------------------------------------
! find depth of radiatively driven convection
!-----------------------------------------------------------
! Expose radperturb and other funny business outside of radml_depth
radperturb = min( maxradf/100. , 0.3 ) ! dim. argument based on 100m deep cloud over 1000s
do_jump_exit = .true.
critjump = 0.3
svpcp = svpcp - radperturb
slvcp = slv/MAPL_CP
if (kcldtop .lt. ibot) then
call radml_depth( &
i,j,icol,jcol, &
nlev,kcldtop,ibot, &
svpcp,zradtop, &
critjump, do_jump_exit, &
slvcp, &
zfull, &
zhalf,zradbase, &
zradml )
else
zradbase(i,j) = 0.0
zradml(i,j) = zradtop
end if
zcloud(i,j) = zhalf(i,j,kcldtop) - zhalf(i,j,kcldbot)
if (zradml(i,j) .le. 0.0 ) then
if(associated(radrcode_diag)) radrcode_diag(i,j)=3.
go to 55 ! break out here if zradml<=0.0
endif
!-----------------------------------------------------------
! compute radiation driven scale
!
! Vrad**3 = g*zradml*radf/density/slv
vrad3 = MAPL_GRAV*zradml(i,j)*maxradf/density(kcldtop)/slv(kcldtop)
!-----------------------------------------------------------
! compute entrainment rate
!
!-----------------------------------------------------------
! tmp1 here should be the buoyancy jump at cloud top
! SAK has it w/ resp to parcel property - svpcp. Im not
! sure about that.
tmp1 = MAPL_GRAV*max(0.1,((slv(kcldtop-1)/MAPL_CP)-svpcp))/(slv(kcldtop)/MAPL_CP)
!-----------------------------------------------------------
! Straightforward buoyancy jump across cloud top
tmp1 = MAPL_GRAV*max( 0.1, ( slv(kcldtop-1)-slv(kcldtop) )/MAPL_CP ) &
/ ( slv(kcldtop) /MAPL_CP )
!-----------------------------------------------------------
! compute buoy rev driven scale
vbr3 = ( max( tmp1*zcloud(i,j), 0.)**3 )
vbr3 = Abuoy*(chis**2)*max(dsiems,0.)*SQRT( vbr3 )
!----------------------------------------
! adjust velocity scales to prevent jumps
! near zradtop=zcldtopmax
if ( zradtop .gt. zcldtopmax-500. ) then
vrad3 = vrad3*(zcldtopmax - zradtop)/500.
vbr3 = vbr3 *(zcldtopmax - zradtop)/500.
endif
vrad3=max( vrad3, 0. ) ! these really should not be needed
vbr3 =max( vbr3, 0. )
!-----------------------------------------
vrad = vrad3 ** (1./3.)
vbrv = vbr3 ** (1./3.)
tmp2 = ( vrad**2 + vbrv**2 ) / zradml(i,j)
wentr_rad = min(wentrmax,beta_rad*(vrad3+vbr3)/zradml(i,j)/(tmp1+tmp2))
wentr_brv = beta_rad*vbr3/zradml(i,j)/(tmp1+tmp2)
!----------------------------------------
! fudgey adjustment of entrainment to reduce it
! for shallow boundary layers, and increase for
! deep ones
!!AMM107
if ( zradtop .lt. 500. ) then
wentr_rad = 0.00
endif
if (( zradtop .gt. 500.) .and. (zradtop .le. 800. )) then
wentr_rad = wentr_rad * ( zradtop-500.) / 300.
endif
if ( zradtop .lt. 2400. ) then
wentr_rad = wentr_rad * ( zradtop / 800. )
else
wentr_rad = 3.*wentr_rad
endif
!-----------------------------------------
k_entr_tmp = min ( akmax, wentr_rad*(zfull(i,j,kcldtop-1)-zfull(i,j,kcldtop)) )
radfq(kcldtop) = 1.
radpbl = 1.
k_rad_col(kcldtop) = k_entr_tmp
k_t_entr(i,j,kcldtop) = k_t_entr(i,j,kcldtop) + k_entr_tmp
k_m_entr(i,j,kcldtop) = k_m_entr(i,j,kcldtop) + k_entr_tmp
if(associated(del_buoy_diag)) del_buoy_diag(i,j) = tmp1
if(associated(vrad_diag)) vrad_diag(i,j) = vrad
if(associated(kentrad_diag)) kentrad_diag(i,j) = k_entr_tmp
if(associated(chis_diag)) chis_diag(i,j) = chis
if(associated(vbrv_diag)) vbrv_diag(i,j) = vbrv
if(associated(dsiems_diag)) dsiems_diag(i,j) = dsiems
if(associated(wentr_brv_diag)) wentr_brv_diag(i,j) = wentr_brv
if(associated(wentr_rad_diag)) wentr_rad_diag(i,j) = wentr_rad
if(associated(zcldtop_diag)) zcldtop_diag(i,j) = zhalf(i,j,kcldtop)
if(associated(slmixture_diag)) slmixture_diag(i,j) = buoypert
if(associated(delsinv_diag)) delsinv_diag(i,j) = ( slv(kcldtop-1) - slv(kcldtop) )/MAPL_CP
if(associated(cldradf_diag)) cldradf_diag(i,j) = radf
!-----------------------------------------------------------
! handle case of radiatively driven top being the same top
! as surface driven top
if (ipbl .eq. kcldtop .and. ipbl .gt. 0) then
tmp2 = ((vbr3+vrad3+vsurf3+vshear3)**(2./3.)) / zradml(i,j)
wentr_rad = min( wentrmax, max(0., &
((beta_surf *(vsurf3 + vshear3)+beta_rad*(vrad3+vbr3) )/ &
zradml(i,j))/(tmp1+tmp2) ) )
wentr_pbl = wentr_rad
k_entr_tmp = min ( akmax, wentr_rad*(zfull(i,j,kcldtop-1)-zfull(i,j,kcldtop)) )
pblfq(ipbl) = 1.
radfq(kcldtop) = 1.
radpbl = 1.
k_rad_col(kcldtop) = k_entr_tmp
k_t_troen(ipbl) = k_entr_tmp
k_m_troen(ipbl) = k_entr_tmp
k_t_entr(i,j,kcldtop) = k_entr_tmp
k_m_entr(i,j,kcldtop) = k_entr_tmp
end if
!-----------------------------------------------------------
! if there are any interior layers to calculate diffusivity
if ( kcldtop .lt. ibot ) then
do k = kcldtop+1,ibot
ztmp = max(0.,(zhalf(i,j,k)-zradbase(i,j))/zradml(i,j) )
if (ztmp.gt.0.) then
radfq(k) = 1.
k_entr_tmp = khradfac*MAPL_KARMAN*( vrad+vbrv )*ztmp* &
zradml(i,j)*ztmp*((1.-ztmp)**0.5)
k_entr_tmp = min ( k_entr_tmp, akmax )
k_rad_col(k) = k_entr_tmp
k_t_entr(i,j,k) = k_t_entr(i,j,k) + k_entr_tmp
k_m_entr(i,j,k) = k_m_entr(i,j,k) + k_entr_tmp*prandtlrad
end if
enddo
end if
!-----------------------------------------------------------
! handle special case of zradbase < zsml
!
! in this case there should be no entrainment from the
! surface.
if (zradbase(i,j) .lt. zsml(i,j) .and. convpbl .eq. 1. .and. ipbl .gt. kcldtop) then
wentr_pbl = 0.
pblfq(ipbl) = 0.
k_t_entr(i,j,ipbl) = k_t_entr(i,j,ipbl) - k_t_troen(ipbl)
k_m_entr(i,j,ipbl) = k_m_entr(i,j,ipbl) - k_m_troen(ipbl)
k_t_troen(ipbl) = 0.
k_m_troen(ipbl) = 0.
end if
55 continue
!-----------------------------------------------------------
!
! Modify diffusivity coefficients using MAX( A , B )
do k = 2, ibot
diff_t(i,j,k) = max( k_t_entr(i,j,k), diff_t(i,j,k) )
diff_m(i,j,k) = max( k_m_entr(i,j,k), diff_m(i,j,k) )
k_t_entr(i,j,k) = max( k_t_entr(i,j,k), 0.0 )
k_m_entr(i,j,k) = max( k_m_entr(i,j,k), 0.0 )
enddo
do k = 1, nlev
k_sfc(i,j,k) = k_t_troen(k)
k_rad(i,j,k) = k_rad_col(k)
end do
#ifndef _CUDA
end do J_LOOP
end do I_LOOP
#else
end if J_LOOP
end if I_LOOP
#endif
!-----------------------------------------------------------------------
!
! subroutine end
!
end subroutine entrain
!=======================================================================
!
! Subroutine to calculate pbl depth
!
#ifdef _CUDA
attributes(device) &
#endif
subroutine mpbl_depth(i,j,icol,jcol,nlev,tpfac, entrate, pceff, t, q, u, v, z, p, b_star, u_star , ipbl, ztop )
!
! -----
! INPUT
! -----
!
! i column number
! j column number
! icol total number of columns
! jcol total number of columns
! nlev number of levels
! t temperature (K)
! q specific humidity (g/g)
! u zonal wind (m/s)
! v meridional wind (m/s)
! b_star buoyancy scale (m s-2)
! u_star surface velocity scale (m/s)
!
! ------
! OUTPUT
! ------
!
! ipbl half level containing pbl height
! ztop pbl height (m)
integer, intent(in ) :: i, j, nlev, icol, jcol
real, intent(in ), dimension(icol,jcol,nlev) :: t, z, q, p, u, v
real, intent(in ), dimension(icol,jcol) :: b_star, u_star
real, intent(in ) :: tpfac, entrate, pceff
integer, intent( out) :: ipbl
real, intent( out),dimension(icol,jcol) :: ztop
real :: tep,z1,z2,t1,t2,qp,pp,qsp,dqp,dqsp,u1,v1,u2,v2,du
real :: entfr,entrate_x,vscale
integer :: k
!real, dimension(nlev) :: qst ! Not used in this code?
!calculate surface parcel properties
tep = t(i,j,nlev)
qp = q(i,j,nlev)
!--------------------------------------------
! wind dependence of plume character.
!
! actual_entrainment_rate_at_z ~ entrate * [ 1.0 + |U(z)-U(0)| / vscale ]
!
! entrate: tunable param from rc file
! vscale: tunable param hardwired here.
!!Old Shear vscale = 5.0 ! m s-1
vscale = 0.25 / 100. ! change of .25 m s-1 in 100 m
!!vscale = 0.10 / 100. ! change of .10 m s-1 in 100 m
!---------------------------------------------
! tpfac scales up bstar by inv. ratio of
! heat-bubble area to stagnant area
tep = tep * (1.+ tpfac * b_star(i,j)/MAPL_GRAV)
!! tep = tep * (1.+ tpfac * b_star(i,j)*u_star(i,j)/MAPL_GRAV)
!search for level where this is exceeded
t1 = t(i,j,nlev)
v1 = v(i,j,nlev)
u1 = u(i,j,nlev)
z1 = z(i,j,nlev)
ztop(i,j) = z1
do k = nlev-1 , 2, -1
z2 = z(i,j,k)
t2 = t(i,j,k)
u2 = u(i,j,k)
v2 = v(i,j,k)
pp = p(i,j,k)
!!Old Shear du = sqrt ( ( u(i,j,k) - u1 )**2 + ( v(i,j,k) - v1 )**2 )
du = sqrt ( ( u2 - u1 )**2 + ( v2 - v1 )**2 ) / (z2-z1)
du = min(du,1.0e-8)
entrate_x = entrate * ( 1.0 + du / vscale )
entfr = min( entrate_x*(z2-z1), 0.99 )
qp = qp + entfr*(q(i,j,k)-qp)
! dry adiabatic ascent through one layer.
! Static energy conserved.
tep = tep - MAPL_GRAV*( z2-z1 )/MAPL_CP
! Environmental air entrained
tep = tep + entfr*(t(i,j,k)-tep)
dqsp = dqsat(tep , pp , qsat=qsp, pascals=.true. )
dqp = max( qp - qsp, 0. )/(1.+(MAPL_ALHL/MAPL_CP)*dqsp )
qp = qp - dqp
tep = tep + pceff * MAPL_ALHL * dqp/MAPL_CP ! "Precipitation efficiency" basically means fraction
! of condensation heating that gets applied to parcel
! If parcel temperature (tep) colder than env (t2)
! OR if entrainment too big, declare this the PBL top
if ( (t2 .ge. tep) .or. ( entfr .ge. 0.9899 ) ) then
!!a0082 Make the parcel a little less buoyant (liquid water loading)-
!!a0082 translates here into subtracting from tep
!!a0082 if ( (t2 .ge. (tep-0.2) ) .or. ( entfr .ge. 0.9899 ) ) then
ztop(i,j) = 0.5*(z2+z1)
ipbl = k+1
exit
end if
z1 = z2
t1 = t2
u1 = u2
v1 = v2
enddo
return
end subroutine mpbl_depth
!=======================================================================
!=======================================================================
!
! Subroutine to calculate bottom and depth of radiatively driven mixed
! layer
!
!
#ifdef _CUDA
attributes(device) &
#endif
subroutine radml_depth(i, j, icol, jcol, nlev, toplev, botlev, &
svp, zt, critjump, do_jump_exit, t, zf, zh, zb, zml)
!
! -----
! INPUT
! -----
!
! i column number
! j column number
! icol total number of columns
! jcol total number of columns
! toplev top level of calculation
! botlev bottom level of calculation
! nlev number of levels
! svp cloud top liquid water virtual static energy divided by cp (K)
! zt top of radiatively driven layer (m)
! t liquid water virtual static energy divided by cp (K)
! zf full level height above ground (m)
! zh half level height above ground (m)
!
! ------
! OUTPUT
! ------
!
! zb base height of radiatively driven mixed layer (m)
! zml depth of radiatively driven mixed layer (m)
integer, intent(in ) :: i, j, toplev, botlev, icol, jcol, nlev
real, intent(in ) :: svp, zt, critjump
real, intent(in ), dimension(nlev) :: t
real, intent(in ), dimension(icol,jcol,nlev) :: zf
real, intent(in ), dimension(icol,jcol,nlev+1) :: zh
real, intent( out), dimension(icol,jcol) :: zb, zml
logical, intent(in ) :: do_jump_exit
real :: svpar,h1,h2,t1,t2,entrate,entfr
integer :: k
!initialize zml
zml(i,j) = 0.
!calculate cloud top parcel properties
svpar = svp
h1 = zf(i,j,toplev)
t1 = t(toplev)
entrate = 0.2/200.
!search for level where parcel is warmer than env
! first cut out if parcel is already warmer than
! cloudtop.
if (t1.lt.svpar) then
zb(i,j) = h1
zml(i,j) = 0.00
return
endif
! If above is false keep looking
do k = 1,botlev
if (k > toplev) then
h2 = zf(i,j,k)
t2 = t(k)
if (t2.lt.svpar) then
if ( abs(t1 - t2 ) .gt. 0.2 ) then
zb(i,j) = h2 + (h1 - h2)*(svpar - t2)/(t1 - t2)
zb(i,j) = MAX( zb(i,j) , 0. ) ! final protection against interp problems
else
zb(i,j) = h2
endif
zml(i,j) = zt - zb(i,j)
return
end if
if (do_jump_exit .and. (t1-t2) .gt. critjump .and. k .gt. toplev+1) then
zb(i,j) = zh(i,j,k)
zml(i,j) = zt - zb(i,j)
return
end if
entfr = min( entrate*(h1-h2), 1.0 )
svpar = svpar + entfr*(t2-svpar)
h1 = h2
t1 = t2
end if
enddo
zb(i,j) = 0.
zml(i,j) = zt
return
end subroutine radml_depth
!=======================================================================
!========================================================================
! Subroutine to return the vertical K-profile of diffusion
! coefficients for the surface driven convective mixed layer.
! This code returns to form used Lock et al.. Does not match
! to surface layer.
!
! call diffusivity_pbl2(i, j, lm, h, k_ent, vsurf, zm, k_m, k_t)
!
! i: Column number
! j: Column number
! icol: Total number of columns
! jcol: Total number of columns
! lm: Number of levels (one less than total in half-level zm)
! h: Depth of surface driven mixed layer (m)
! k_ent: PBL top entrainment diffusivity (m+2 s-1)
! vsurf: PBL top entrainment velocity scale (m s-1)
! zm: Half level heights relative to the ground (m), DIM[1:lm+1]
! k_m: Momentum diffusion coefficient (m+2 s-1), DIM[1:lm] (edges)
! k_t: Heat and tracer diffusion coefficient (m+2 s-1) DIM[1:lm] (edges)
#ifdef _CUDA
attributes(device) &
#endif
subroutine diffusivity_pbl2(i, j, icol, jcol, lm, h, kfac, k_ent, vsurf, frland, zm, k_m, k_t)
integer, intent(in ) :: i, j, lm, icol, jcol
real, intent(in ), dimension(icol,jcol) :: h, frland
real, intent(in ) :: k_ent, vsurf, kfac
real, intent(in ), dimension(icol,jcol,1:lm+1) :: zm
real, intent( out), dimension(lm) :: k_m, k_t
real :: EE, hin, kfacx
integer :: k
! Kluge. Raise KHs over land
!---------------------------
if ( frland(i,j) < 0.5 ) then
kfacx = kfac
else
kfacx = kfac*2.0
endif
hin = 0.0 ! 200. ! "Organization" scale for plume (m).
do k = 1, lm
k_m(k) = 0.0
k_t(k) = 0.0
end do
!! factor = (zm(i,j,k)/hinner)* (1.0 -(zm(i,j,k)-hinner)/(h(i,j)-hinner))**2
if ( vsurf*h(i,j) .gt. 0. ) then
EE = 1.0 - sqrt( k_ent / ( kfacx * MAPL_KARMAN * vsurf * h(i,j) ) )
EE = max( EE , 0.7 ) ! If EE is too small, then punt, as LCs
do k = 1, lm
if ( ( zm(i,j,k) .le. h(i,j) ) .and. ( zm(i,j,k) .gt. hin ) ) then
k_t(k) = kfacx * MAPL_KARMAN * vsurf * ( zm(i,j,k)-hin ) * ( 1. - EE*( (zm(i,j,k)-hin)/(h(i,j)-hin) ))**2
end if
end do
endif
do k = 1, lm
k_m(k) = k_t(k)
end do
return
end subroutine diffusivity_pbl2
!
!=======================================================================
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#ifdef _CUDA
attributes(device) function QSAT(TL,PL,PASCALS)
real, intent(IN) :: TL, PL
logical, optional, intent(IN) :: PASCALS
real :: QSAT
real :: URAMP, DD, QQ, TI, DQ, PP
integer :: IT
URAMP = TMIX
if (present(PASCALS)) then
if (PASCALS) then
PP = PL
else
PP = PL*100.
end if
else
PP = PL*100.
end if
TI = TL - ZEROC
if (TI <= URAMP) then
QSAT = QSATICE0(TL,PP,DQ)
elseif(TI >= 0.0 ) then
QSAT = QSATLQU0(TL,PP,DQ)
else
QSAT = QSATICE0(TL,PP,DQ)
QQ = QSATLQU0(TL,PP,DQ)
TI = TI/URAMP
QSAT = TI*(QSAT - QQ) + QQ
end if
end function QSAT
attributes(device) function DQSAT(TL,PL,QSAT,PASCALS)
real, intent(IN) :: TL, PL
real, intent(OUT):: QSAT
logical, optional, intent(IN ):: PASCALS
real :: DQSAT
real :: URAMP, TT, WW, DD, DQQ, QQ, TI, DQI, QI, PP, DQ
integer :: IT
URAMP = TMIX
if (present(PASCALS)) then
if (PASCALS) then
PP = PL
else
PP = PL*100.
end if
else
PP = PL*100.
end if
TI = TL - ZEROC
if (TI <= URAMP) then
QQ = QSATICE0(TL,PP,DQ)
QSAT = QQ
DQSAT = DQ
elseif(TI >= 0.0 ) then
QQ = QSATLQU0(TL,PP,DQ)
QSAT = QQ
DQSAT = DQ
else
QQ = QSATLQU0(TL,PP,DQQ)
QI = QSATICE0(TL,PP,DQI)
TI = TI/URAMP
DQSAT = TI*(DQI - DQQ) + DQQ
QSAT = TI*(QI - QQ) + QQ
end if
end function DQSAT
attributes(device) function QSATLQU0(TL,PL,DQ) result(QS)
real, intent(IN) :: TL
real, intent(IN) :: PL
real, intent(OUT):: DQ
real :: QS
real :: TI,W
real :: DD
real :: TT
real :: DDQ
integer :: IT
integer, parameter :: TYPE = 1
#define TX TL
#define PX PL
#define EX QS
#define DX DQ
if (TXTMAXTBL) then
TI = TMAXTBL
else
TI = TX
end if
#include "esatlqu.code"
if (TXTMAXTBL) then
DDQ = 0.0
else
if(PX>EX) then
DD = EX
TI = TX + DELTA_T
#include "esatlqu.code"
DDQ = EX-DD
EX = DD
endif
end if
if(PX > EX) then
DD = ESFAC/(PX - (1.0-ESFAC)*EX)
EX = EX*DD
DX = DDQ*ERFAC*PX*DD*DD
else
EX = MAX_MIXING_RATIO
DX = 0.0
end if
#undef DX
#undef TX
#undef EX
#undef PX
return
end function QSATLQU0
attributes(device) function QSATICE0(TL,PL,DQ) result(QS)
real, intent(IN) :: TL
real, intent(IN) :: PL
real, intent(OUT):: DQ
real :: QS
real :: TI,W
real :: DD
real :: TT
real :: DDQ
integer :: IT
integer, parameter :: TYPE = 1
#define TX TL
#define PX PL
#define EX QS
#define DX DQ
if (TXZEROC ) then
TI = ZEROC
else
TI = TX
end if
#include "esatice.code"
if (TXZEROC ) then
DDQ = 0.0
else
if(PX>EX) then
DD = EX
TI = TX + DELTA_T
#include "esatice.code"
DDQ = EX-DD
EX = DD
endif
end if
if(PX > EX) then
DD = ESFAC/(PX - (1.0-ESFAC)*EX)
EX = EX*DD
DX = DDQ*ERFAC*PX*DD*DD
else
EX = MAX_MIXING_RATIO
DX = 0.0
end if
#undef DX
#undef TX
#undef EX
#undef PX
return
end function QSATICE0
#endif
!*********************************************************************
end module LockEntrain