Line data Source code
1 : ! Copyright (C) 2024-2025 National Science Foundation-National Center for Atmospheric Research
2 : ! SPDX-License-Identifier: Apache-2.0
3 : !
4 : ! Hack shallow convective scheme.
5 : ! The main subroutine was formerly named "cmfmca", and its initialization "mfinti".
6 : !
7 : ! Original Author: J. Hack
8 : ! CCPPized: Haipeng Lin, October 2024
9 : module hack_convect_shallow
10 : use ccpp_kinds, only: kind_phys
11 : implicit none
12 : private
13 : save
14 :
15 : ! public CCPP-compliant subroutines
16 : public :: hack_convect_shallow_init
17 : public :: hack_convect_shallow_run
18 :
19 : ! namelist variables for tuning of hack shallow convective scheme
20 : real(kind_phys) :: cmftau ! characteristic adjustment time scale [s]
21 : real(kind_phys) :: c0 ! rain water autoconversion coefficient [m-1]
22 :
23 : ! host-model physical constants and shorthands
24 : real(kind_phys) :: cp ! specific heat of dry air [J K-1 kg-1]
25 : real(kind_phys) :: rgas ! gas constant for dry air [J K-1 kg-1]
26 : real(kind_phys) :: grav ! gravitational constant [m s-2]
27 : real(kind_phys) :: hlat ! latent heat of vaporization [J kg-1]
28 : real(kind_phys) :: rhoh2o ! density of liquid water at STP [kg m-3]
29 :
30 : real(kind_phys) :: rcp ! reciprocal of cp
31 : real(kind_phys) :: rgrav ! reciprocal of grav
32 : real(kind_phys) :: rhlat ! reciprocal of hlat
33 :
34 : integer :: limcnv ! top vertical interface level limit for convection [index]
35 : ! derived from reference pressures to below 40 mb
36 :
37 : ! internal parameters
38 : real(kind_phys) :: betamn = 0.10_kind_phys ! minimum overshoot parameter [???]
39 : real(kind_phys) :: dzmin = 0.0_kind_phys ! minimum convective depth for precipitation [m]
40 : logical :: rlxclm = .true. ! control for relaxing column versus cloud triplet (default: true)
41 : ! true: relaxation timescale should be applied to column as opposed to triplets individually
42 : real(kind_phys) :: ssfac = 1.001_kind_phys ! detrained air supersaturation bound [???]
43 :
44 : ! internal parameters for tolerance
45 : real(kind_phys) :: tiny = 1.0e-36_kind_phys ! arbitrary small num in scalar transport estimates
46 : real(kind_phys) :: eps = 1.0e-13_kind_phys ! machine dependent convergence criteria
47 : real(kind_phys) :: tpmax = 1.50_kind_phys ! maximum acceptable T perturbation [K]
48 : real(kind_phys) :: shpmax = 1.50e-3_kind_phys ! maximum acceptable Q perturbation [g g-1]
49 :
50 : ! diagnostic only
51 : logical :: debug_verbose = .false. ! control for debug messages
52 :
53 :
54 : contains
55 : ! Initialization of moist convective mass procedure including namelist read.
56 : !> \section arg_table_hack_convect_shallow_init Argument Table
57 : !! \htmlinclude hack_convect_shallow_init.html
58 0 : subroutine hack_convect_shallow_init( &
59 : pver, &
60 : amIRoot, iulog, &
61 : cmftau_in, c0_in, &
62 : rair, cpair, gravit, latvap, rhoh2o_in, &
63 0 : pref_edge, &
64 0 : use_shfrc, shfrc, &
65 : top_lev, &
66 0 : errmsg, errflg)
67 :
68 : integer, intent(in) :: pver ! number of vertical levels
69 : logical, intent(in) :: amIRoot
70 : integer, intent(in) :: iulog ! log output unit
71 : real(kind_phys), intent(in) :: cmftau_in ! characteristic adjustment time scale [s]
72 : real(kind_phys), intent(in) :: c0_in ! rain water autoconversion coefficient [m-1]
73 : real(kind_phys), intent(in) :: rair ! gas constant for dry air [J K-1 kg-1]
74 : real(kind_phys), intent(in) :: cpair ! specific heat of dry air [J K-1 kg-1]
75 : real(kind_phys), intent(in) :: gravit ! gravitational constant [m s-2]
76 : real(kind_phys), intent(in) :: latvap ! latent heat of vaporization [J kg-1]
77 : real(kind_phys), intent(in) :: rhoh2o_in ! density of liquid water [kg m-3]
78 : real(kind_phys), intent(in) :: pref_edge(:) ! reference pressures at interface [Pa]
79 :
80 : logical, intent(out) :: use_shfrc ! this shallow scheme provides convective cloud fractions? [flag]
81 : real(kind_phys), intent(out) :: shfrc(:,:) ! (dummy) shallow convective cloud fractions calculated in-scheme [fraction]
82 :
83 : integer, intent(out) :: top_lev ! top level for cloud fraction [index]
84 :
85 : character(len=512), intent(out) :: errmsg
86 : integer, intent(out) :: errflg
87 :
88 : ! local variables
89 : integer :: k
90 :
91 0 : errmsg = ''
92 0 : errflg = 0
93 :
94 : ! namelist variables
95 0 : cmftau = cmftau_in
96 0 : c0 = c0_in
97 :
98 0 : if(amIRoot) then
99 0 : write(iulog,*) 'tuning parameters hack_convect_shallow: cmftau',cmftau
100 0 : write(iulog,*) 'tuning parameters hack_convect_shallow: c0',c0
101 : endif
102 :
103 : ! host model physical constants
104 0 : cp = cpair
105 0 : rcp = 1.0_kind_phys/cp
106 0 : hlat = latvap
107 0 : rhlat = 1.0_kind_phys/hlat
108 0 : grav = gravit
109 0 : rgrav = 1.0_kind_phys/gravit
110 0 : rgas = rair
111 0 : rhoh2o = rhoh2o_in
112 :
113 : ! determine limit of shallow convection: regions below 40 mb
114 : ! logic ported from convect_shallow_init with note that this calculation is repeated in the deep
115 : ! convection interface.
116 0 : if(pref_edge(1) >= 4.e3_kind_phys) then
117 0 : limcnv = 1
118 : else
119 0 : limcnv = pver + 1
120 0 : do k = 1, pver
121 0 : if(pref_edge(k) < 4.e3_kind_phys .and. pref_edge(k+1) >= 4.e3_kind_phys) then
122 0 : limcnv = k
123 : endif
124 : enddo
125 : endif
126 :
127 0 : if(amIRoot) then
128 0 : write(iulog,*) "hack_convect_shallow_init: convection will be capped at interface ", limcnv, &
129 0 : "which is ", pref_edge(limcnv), " pascals"
130 : endif
131 :
132 : ! flags for whether this shallow convection scheme
133 : ! calculates and provides convective cloud fractions
134 : ! to convective cloud cover scheme.
135 : !
136 : ! the Hack scheme does not provide this.
137 : ! a dummy shfrc is provided and is never used.
138 0 : use_shfrc = .false.
139 0 : shfrc(:,:) = 0._kind_phys
140 :
141 : ! for Hack shallow convection (CAM4 physics), do not limit cloud fraction
142 : ! (extend all the way to model top)
143 0 : top_lev = 1
144 0 : end subroutine hack_convect_shallow_init
145 :
146 : ! Moist convective mass flux procedure.
147 : !
148 : ! If stratification is unstable to nonentraining parcel ascent,
149 : ! complete an adjustment making successive use of a simple cloud model
150 : ! consisting of three layers (sometimes referred to as a triplet)
151 : !
152 : ! Code generalized to allow specification of parcel ("updraft")
153 : ! properties, as well as convective transport of an arbitrary
154 : ! number of passive constituents (see q array). The code
155 : ! is written so the water vapor field is passed independently
156 : ! in the calling list from the block of other transported
157 : ! constituents, even though as currently designed, it is the
158 : ! first component in the constituents field.
159 : !
160 : ! Reports tendencies in cmfdt and dq instead of updating profiles.
161 : !
162 : ! Original author: J. Hack, BAB
163 : !> \section arg_table_hack_convect_shallow_run Argument Table
164 : !! \htmlinclude hack_convect_shallow_run.html
165 0 : subroutine hack_convect_shallow_run( &
166 : ncol, pver, pcnst, &
167 : iulog, &
168 0 : const_props, &
169 : ztodt, &
170 0 : pmid, pmiddry, &
171 0 : pdel, pdeldry, rpdel, rpdeldry, &
172 0 : zm, &
173 0 : qpert_in, &
174 0 : phis, &
175 0 : pblh, &
176 0 : t, &
177 0 : q, & ! ... below are output arguments:
178 0 : dq, &
179 0 : qc_sh, &
180 0 : cmfdt, &
181 0 : cmfmc_sh, &
182 0 : cmfdqr, &
183 0 : cmfsl, &
184 0 : cmflq, &
185 0 : precc, &
186 0 : cnt_sh, &
187 0 : cnb_sh, &
188 0 : icwmr, &
189 0 : rliq_sh, &
190 0 : scheme_name, &
191 0 : flx_cnd, &
192 0 : errmsg, errflg &
193 : )
194 : ! framework dependency for const_props
195 : use ccpp_constituent_prop_mod, only: ccpp_constituent_prop_ptr_t
196 :
197 : ! dependency to get constituent index
198 : use ccpp_const_utils, only: ccpp_const_get_idx
199 :
200 : ! to_be_ccppized
201 : use wv_saturation, only: qsat
202 :
203 : ! Input arguments
204 : integer, intent(in) :: ncol ! number of atmospheric columns
205 : integer, intent(in) :: pver ! number of vertical levels
206 : integer, intent(in) :: pcnst ! number of ccpp constituents
207 : integer, intent(in) :: iulog ! log output unit
208 : type(ccpp_constituent_prop_ptr_t), &
209 : intent(in) :: const_props(:) ! ccpp constituent properties pointer
210 : real(kind_phys), intent(in) :: ztodt ! physics timestep [s]
211 :
212 : real(kind_phys), intent(in) :: pmid(:,:) ! midpoint pressures [Pa]
213 : real(kind_phys), intent(in) :: pmiddry(:,:) ! dry pressure at midpoints [Pa]
214 : real(kind_phys), intent(in) :: pdel(:,:) ! layer thickness (delta-p) [Pa]
215 : real(kind_phys), intent(in) :: pdeldry(:,:) ! dry layer thickness [Pa]
216 : real(kind_phys), intent(in) :: rpdel(:,:) ! 1.0 / pdel
217 : real(kind_phys), intent(in) :: rpdeldry(:,:) ! 1.0 / pdeldry
218 :
219 : real(kind_phys), intent(in) :: zm(:,:) ! geopotential height at midpoints [m]
220 : real(kind_phys), intent(in) :: qpert_in(:) ! PBL perturbation specific humidity (convective humidity excess) [kg kg-1]
221 : real(kind_phys), intent(in) :: phis(:) ! surface geopotential [m2 s-2]
222 : real(kind_phys), intent(in) :: pblh(:) ! PBL height [m]
223 : real(kind_phys), intent(in) :: t(:,:) ! temperature [K]
224 : real(kind_phys), intent(in) :: q(:,:,:) ! constituents [kg kg-1]
225 :
226 : ! Output arguments
227 : real(kind_phys), intent(out) :: dq(:,:,:) ! constituent tendencies [kg kg-1 s-1]
228 : real(kind_phys), intent(out) :: qc_sh(:,:) ! dq/dt due to export of cloud water / shallow reserved cloud condensate [kg kg-1 s-1]
229 : real(kind_phys), intent(out) :: cmfdt(:,:) ! heating rate (to ptend%s) [J kg-1 s-1]
230 : real(kind_phys), intent(out) :: cmfmc_sh(:,:) ! convective updraft mass flux, shallow [kg s-1 m-2]
231 : real(kind_phys), intent(out) :: cmfdqr(:,:) ! q tendency due to shallow convective rainout [kg kg-1 s-1]
232 : real(kind_phys), intent(out) :: cmfsl(:,:) ! moist shallow convection liquid water static energy flux [W m-2]
233 : real(kind_phys), intent(out) :: cmflq(:,:) ! moist shallow convection total water flux [W m-2]
234 : real(kind_phys), intent(out) :: precc(:) ! shallow convective precipitation rate [m s-1]
235 : integer, intent(out) :: cnt_sh(:) ! top level of shallow convective activity [index]
236 : integer, intent(out) :: cnb_sh(:) ! bottom level of shallow convective activity [index]
237 : real(kind_phys), intent(out) :: icwmr(:,:) ! shallow convection in-cloud water mixing ratio [kg kg-1]
238 : real(kind_phys), intent(out) :: rliq_sh(:) ! vertically-integrated shallow reserved cloud condensate [m s-1]
239 :
240 : character(len=64), intent(out) :: scheme_name ! scheme name
241 : real(kind_phys), intent(out) :: flx_cnd(:) ! net_liquid_and_lwe_ice_fluxes_through_top_and_bottom_of_atmosphere_column [m s-1] for check_energy_chng
242 :
243 : character(len=512), intent(out) :: errmsg
244 : integer, intent(out) :: errflg
245 :
246 : ! Local variables
247 0 : real(kind_phys) :: tpert(ncol) ! PBL perturbation temperature (convective temperature excess) [K]
248 :
249 : character(len=256) :: const_standard_name ! temp: constituent standard name
250 : logical :: const_is_dry ! temp: constituent is dry flag
251 : integer :: const_wv_idx ! temp: index of water vapor
252 :
253 0 : real(kind_phys) :: pm(ncol,pver) ! pressure [Pa]
254 0 : real(kind_phys) :: pd(ncol,pver) ! delta-p [Pa]
255 0 : real(kind_phys) :: rpd(ncol,pver) ! 1./pdel [Pa-1]
256 0 : real(kind_phys) :: cmfdq(ncol,pver) ! dq(wv)/dt due to moist convection (later copied to dq(:,:,const_wv_idx)) [kg kg-1 s-1]
257 0 : real(kind_phys) :: gam(ncol,pver) ! 1/cp (d(qsat)/dT) change in saturation mixing ratio with temp
258 0 : real(kind_phys) :: sb(ncol,pver) ! dry static energy (s bar) [J kg-1]
259 0 : real(kind_phys) :: hb(ncol,pver) ! moist static energy (h bar) [J kg-1]
260 0 : real(kind_phys) :: shbs(ncol,pver) ! sat. specific humidity (sh bar star)
261 0 : real(kind_phys) :: hbs(ncol,pver) ! sat. moist static energy (h bar star)
262 0 : real(kind_phys) :: shbh(ncol,pver+1) ! specific humidity on interfaces
263 0 : real(kind_phys) :: sbh(ncol,pver+1) ! s bar on interfaces
264 0 : real(kind_phys) :: hbh(ncol,pver+1) ! h bar on interfaces
265 0 : real(kind_phys) :: cmrh(ncol,pver+1) ! interface constituent mixing ratio
266 0 : real(kind_phys) :: prec(ncol) ! instantaneous total precipitation
267 0 : real(kind_phys) :: dzcld(ncol) ! depth of convective layer (m)
268 0 : real(kind_phys) :: beta(ncol) ! overshoot parameter (fraction)
269 0 : real(kind_phys) :: betamx(ncol) ! local maximum on overshoot
270 0 : real(kind_phys) :: eta(ncol) ! convective mass flux (kg/m^2 s)
271 0 : real(kind_phys) :: etagdt(ncol) ! eta*grav*dt
272 0 : real(kind_phys) :: cldwtr(ncol) ! cloud water (mass)
273 0 : real(kind_phys) :: rnwtr(ncol) ! rain water (mass)
274 0 : real(kind_phys) :: totcond(ncol) ! total condensate; mix of precip and cloud water (mass)
275 0 : real(kind_phys) :: sc (ncol) ! dry static energy ("in-cloud")
276 0 : real(kind_phys) :: shc (ncol) ! specific humidity ("in-cloud")
277 0 : real(kind_phys) :: hc (ncol) ! moist static energy ("in-cloud")
278 0 : real(kind_phys) :: cmrc(ncol) ! constituent mix rat ("in-cloud")
279 0 : real(kind_phys) :: dq1(ncol) ! shb convective change (lower lvl)
280 0 : real(kind_phys) :: dq2(ncol) ! shb convective change (mid level)
281 0 : real(kind_phys) :: dq3(ncol) ! shb convective change (upper lvl)
282 0 : real(kind_phys) :: ds1(ncol) ! sb convective change (lower lvl)
283 0 : real(kind_phys) :: ds2(ncol) ! sb convective change (mid level)
284 0 : real(kind_phys) :: ds3(ncol) ! sb convective change (upper lvl)
285 0 : real(kind_phys) :: dcmr1(ncol) ! q convective change (lower lvl)
286 0 : real(kind_phys) :: dcmr2(ncol) ! q convective change (mid level)
287 0 : real(kind_phys) :: dcmr3(ncol) ! q convective change (upper lvl)
288 0 : real(kind_phys) :: estemp(ncol,pver) ! saturation vapor pressure (scratch)
289 0 : real(kind_phys) :: vtemp1(2*ncol) ! intermediate scratch vector
290 0 : real(kind_phys) :: vtemp2(2*ncol) ! intermediate scratch vector
291 0 : real(kind_phys) :: vtemp3(2*ncol) ! intermediate scratch vector
292 0 : real(kind_phys) :: vtemp4(2*ncol) ! intermediate scratch vector
293 0 : real(kind_phys) :: vtemp5(2*ncol) ! intermediate scratch vector
294 0 : integer :: indx1(ncol) ! longitude indices for condition true
295 : logical :: etagt0 ! true if eta > 0.0
296 : real(kind_phys) :: cats ! modified characteristic adj. time
297 : real(kind_phys) :: rtdt ! 1./ztodt
298 : real(kind_phys) :: qprime ! modified specific humidity pert.
299 : real(kind_phys) :: tprime ! modified thermal perturbation
300 : real(kind_phys) :: pblhgt ! bounded pbl height (max[pblh,1m])
301 : real(kind_phys) :: fac1 ! intermediate scratch variable
302 : real(kind_phys) :: shprme ! intermediate specific humidity pert.
303 : real(kind_phys) :: qsattp ! sat mix rat for thermally pert PBL parcels
304 : real(kind_phys) :: dz ! local layer depth
305 : real(kind_phys) :: temp1 ! intermediate scratch variable
306 : real(kind_phys) :: b1 ! bouyancy measure in detrainment lvl
307 : real(kind_phys) :: b2 ! bouyancy measure in condensation lvl
308 : real(kind_phys) :: temp2 ! intermediate scratch variable
309 : real(kind_phys) :: temp3 ! intermediate scratch variable
310 : real(kind_phys) :: g ! bounded vertical gradient of hb
311 : real(kind_phys) :: tmass ! total mass available for convective exch
312 : real(kind_phys) :: denom ! intermediate scratch variable
313 : real(kind_phys) :: qtest1 ! used in negative q test (middle lvl)
314 : real(kind_phys) :: qtest2 ! used in negative q test (lower lvl)
315 : real(kind_phys) :: fslkp ! flux lw static energy (bot interface)
316 : real(kind_phys) :: fslkm ! flux lw static energy (top interface)
317 : real(kind_phys) :: fqlkp ! flux total water (bottom interface)
318 : real(kind_phys) :: fqlkm ! flux total water (top interface)
319 : real(kind_phys) :: botflx ! bottom constituent mixing ratio flux
320 : real(kind_phys) :: topflx ! top constituent mixing ratio flux
321 : real(kind_phys) :: efac1 ! ratio q to convectively induced chg (btm lvl)
322 : real(kind_phys) :: efac2 ! ratio q to convectively induced chg (mid lvl)
323 : real(kind_phys) :: efac3 ! ratio q to convectively induced chg (top lvl)
324 0 : real(kind_phys) :: tb(ncol,pver) ! working storage for temp (t bar)
325 0 : real(kind_phys) :: shb(ncol,pver) ! working storage for spec hum (sh bar)
326 : real(kind_phys) :: adjfac ! adjustment factor (relaxation related)
327 : integer :: i,k ! longitude, level indices
328 : integer :: ii ! index on "gathered" vectors
329 : integer :: len1 ! vector length of "gathered" vectors
330 : integer :: m ! constituent index
331 : integer :: ktp ! tmp indx used to track top of convective layer
332 :
333 : ! debug use quantities
334 : real(kind_phys) :: rh ! relative humidity
335 : real(kind_phys) :: es ! sat vapor pressure
336 : real(kind_phys) :: hsum1 ! moist static energy integral
337 : real(kind_phys) :: qsum1 ! total water integral
338 : real(kind_phys) :: hsum2 ! final moist static energy integral
339 : real(kind_phys) :: qsum2 ! final total water integral
340 : real(kind_phys) :: fac ! intermediate scratch variable
341 : integer :: n ! vertical index (diagnostics)
342 : integer :: kp ! vertical index (diagnostics)
343 : integer :: kpp ! index offset, kp+1 (diagnostics)
344 : integer :: kpm1 ! index offset, kp-1 (diagnostics)
345 :
346 0 : errmsg = ''
347 0 : errflg = 0
348 :
349 0 : scheme_name = 'hack_convect_shallow'
350 :
351 : !---------------------------------------------------
352 : ! Initialize output tendencies
353 : !---------------------------------------------------
354 0 : cmfdt (:ncol,:) = 0._kind_phys
355 0 : cmfdq (:ncol,:) = 0._kind_phys
356 0 : cmfmc_sh(:ncol,:) = 0._kind_phys
357 0 : cmfdqr (:ncol,:) = 0._kind_phys
358 0 : cmfsl (:ncol,:) = 0._kind_phys
359 0 : cmflq (:ncol,:) = 0._kind_phys
360 0 : qc_sh (:ncol,:) = 0._kind_phys
361 0 : rliq_sh (:ncol) = 0._kind_phys
362 :
363 : ! Check constituents list and locate water vapor index
364 : ! (not assumed to be 1)
365 : call ccpp_const_get_idx(const_props, &
366 : 'water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water', &
367 0 : const_wv_idx, errmsg, errflg)
368 :
369 : !---------------------------------------------------
370 : ! copy q to dq for passive tracer transport.
371 : ! this is NOT an initialization. the dq at this point
372 : ! is not physical (used as temporary here) only at the end
373 : ! dq is updated to be an actual tendency.
374 : !---------------------------------------------------
375 0 : if(pcnst > 1) then
376 : ! set dq for passive tracer transport from q as temporary...
377 0 : dq(:ncol,:,:) = q(:ncol,:,:)
378 :
379 : ! except for water vapor
380 0 : dq(:ncol,:,const_wv_idx) = 0._kind_phys
381 : endif
382 :
383 : !---------------------------------------------------
384 : ! Quantity preparations from convect_shallow.F90.
385 : !---------------------------------------------------
386 :
387 : ! convect_shallow.F90 is not linked to pbuf tpert and always sets to zero.
388 : ! "This field probably should reference the pbuf tpert field but it doesnt"
389 0 : tpert(:ncol) = 0.0_kind_phys
390 :
391 : !---------------------------------------------------
392 : ! Preparation of working arrays
393 : !---------------------------------------------------
394 : ! Ensure that characteristic adjustment time scale (cmftau) assumed
395 : ! in estimate of eta isn't smaller than model time scale (ztodt)
396 : ! The time over which the convection is assumed to act (the adjustment
397 : ! time scale) can be applied with each application of the three-level
398 : ! cloud model, or applied to the column tendencies after a "hard"
399 : ! adjustment (i.e., on a 2-delta t time scale) is evaluated
400 0 : if (rlxclm) then
401 0 : cats = ztodt ! relaxation applied to column
402 0 : adjfac = ztodt/(max(ztodt,cmftau))
403 : else
404 0 : cats = max(ztodt,cmftau) ! relaxation applied to triplet
405 0 : adjfac = 1.0_kind_phys
406 : endif
407 0 : rtdt = 1.0_kind_phys/ztodt
408 :
409 : ! Move temperature and moisture into working storage
410 0 : do k=limcnv,pver
411 0 : do i=1,ncol
412 0 : tb (i,k) = t(i,k)
413 0 : shb(i,k) = q(i,k,const_wv_idx)
414 : end do
415 : end do
416 0 : do k=1,pver
417 0 : do i=1,ncol
418 0 : icwmr(i,k) = 0._kind_phys
419 : end do
420 : end do
421 :
422 : ! Compute sb,hb,shbs,hbs
423 0 : do k = limcnv,pver
424 0 : call qsat(tb(1:ncol,k), pmid(1:ncol,k), &
425 : estemp(1:ncol,k), shbs(1:ncol,k), ncol, &
426 0 : gam=gam(1:ncol,k))
427 : end do
428 :
429 0 : do k=limcnv,pver
430 0 : do i=1,ncol
431 0 : sb (i,k) = cp*tb(i,k) + zm(i,k)*grav + phis(i)
432 0 : hb (i,k) = sb(i,k) + hlat*shb(i,k)
433 0 : hbs(i,k) = sb(i,k) + hlat*shbs(i,k)
434 : end do
435 : end do
436 :
437 : ! Compute sbh, shbh
438 0 : do k=limcnv+1,pver
439 0 : do i=1,ncol
440 0 : sbh (i,k) = 0.5_kind_phys*(sb(i,k-1) + sb(i,k))
441 0 : shbh(i,k) = qhalf(shb(i,k-1),shb(i,k),shbs(i,k-1),shbs(i,k))
442 0 : hbh (i,k) = sbh(i,k) + hlat*shbh(i,k)
443 : end do
444 : end do
445 :
446 : ! Specify properties at top of model (not used, but filling anyway)
447 0 : do i=1,ncol
448 0 : sbh (i,limcnv) = sb(i,limcnv)
449 0 : shbh(i,limcnv) = shb(i,limcnv)
450 0 : hbh (i,limcnv) = hb(i,limcnv)
451 : end do
452 :
453 : ! Zero vertically independent control, tendency & diagnostic arrays
454 0 : do i=1,ncol
455 0 : prec(i) = 0.0_kind_phys
456 0 : dzcld(i) = 0.0_kind_phys
457 0 : cnb_sh(i)= 0
458 0 : cnt_sh(i)= pver+1
459 : end do
460 :
461 0 : if(debug_verbose) then
462 : ! DEBUG DIAGNOSTICS - Output initial thermodynamic profile
463 0 : do i=1,ncol
464 0 : if(i == 1) then
465 : ! Approximate vertical integral of moist static energy
466 : ! and total precipitable water
467 0 : hsum1 = 0.0_kind_phys
468 0 : qsum1 = 0.0_kind_phys
469 0 : do k=limcnv,pver
470 0 : hsum1 = hsum1 + pdel(i,k)*rgrav*hb(i,k)
471 0 : qsum1 = qsum1 + pdel(i,k)*rgrav*shb(i,k)
472 : end do
473 :
474 0 : write(iulog,8010)
475 0 : fac = grav*864._kind_phys
476 0 : do k=limcnv,pver
477 0 : rh = shb(i,k)/shbs(i,k)
478 0 : write(iulog,8020) shbh(i,k),sbh(i,k),hbh(i,k),fac*cmfmc_sh(i,k),cmfsl(i,k), cmflq(i,k)
479 0 : write(iulog,8040) tb(i,k),shb(i,k),rh,sb(i,k),hb(i,k),hbs(i,k),ztodt*cmfdt(i,k), &
480 0 : ztodt*cmfdq(i,k),ztodt*cmfdqr(i,k)
481 : end do
482 0 : write(iulog, 8000) prec(i)
483 : end if
484 : end do
485 : endif
486 :
487 : !---------------------------------------------------
488 : ! Begin moist convective mass flux adjustment procedure.
489 : ! Formalism ensures that negative cloud liquid water can never occur
490 : !---------------------------------------------------
491 0 : kloop: do k = pver-1,limcnv+1,-1
492 0 : do i = 1, ncol
493 0 : etagdt(i) = 0.0_kind_phys
494 0 : eta (i) = 0.0_kind_phys
495 0 : beta (i) = 0.0_kind_phys
496 0 : ds1 (i) = 0.0_kind_phys
497 0 : ds2 (i) = 0.0_kind_phys
498 0 : ds3 (i) = 0.0_kind_phys
499 0 : dq1 (i) = 0.0_kind_phys
500 0 : dq2 (i) = 0.0_kind_phys
501 0 : dq3 (i) = 0.0_kind_phys
502 : ! Specification of "cloud base" conditions
503 0 : qprime = 0.0_kind_phys
504 0 : tprime = 0.0_kind_phys
505 :
506 : ! Assign tprime within the PBL to be proportional to the quantity
507 : ! tpert (which will be bounded by tpmax), passed to this routine by
508 : ! the PBL routine. Don't allow perturbation to produce a dry
509 : ! adiabatically unstable parcel. Assign qprime within the PBL to be
510 : ! an appropriately modified value of the quantity qpert (which will be
511 : ! bounded by shpmax) passed to this routine by the PBL routine. The
512 : ! quantity qprime should be less than the local saturation value
513 : ! (qsattp=qsat[t+tprime,p]). In both cases, tpert and qpert are
514 : ! linearly reduced toward zero as the PBL top is approached.
515 0 : pblhgt = max(pblh(i),1.0_kind_phys)
516 0 : if ( (zm(i,k+1) <= pblhgt) .and. dzcld(i) == 0.0_kind_phys ) then
517 0 : fac1 = max(0.0_kind_phys,1.0_kind_phys-zm(i,k+1)/pblhgt)
518 0 : tprime = min(tpert(i),tpmax)*fac1
519 0 : qsattp = shbs(i,k+1) + cp*rhlat*gam(i,k+1)*tprime
520 0 : shprme = min(min(qpert_in(i),shpmax)*fac1,max(qsattp-shb(i,k+1),0.0_kind_phys))
521 0 : qprime = max(qprime,shprme)
522 : else
523 : tprime = 0.0_kind_phys
524 : qprime = 0.0_kind_phys
525 : end if
526 :
527 : ! Specify "updraft" (in-cloud) thermodynamic properties
528 0 : sc (i) = sb (i,k+1) + cp*tprime
529 0 : shc(i) = shb(i,k+1) + qprime
530 0 : hc (i) = sc (i ) + hlat*shc(i)
531 0 : vtemp4(i) = hc(i) - hbs(i,k)
532 0 : dz = pdel(i,k)*rgas*tb(i,k)*rgrav/pmid(i,k)
533 0 : if (vtemp4(i) > 0.0_kind_phys) then
534 0 : dzcld(i) = dzcld(i) + dz
535 : else
536 0 : dzcld(i) = 0.0_kind_phys
537 : end if
538 : enddo
539 :
540 0 : if(debug_verbose) then
541 : ! DEBUG DIAGNOSTICS - output thermodynamic perturbation information
542 0 : do i=1,ncol
543 0 : if(i == 1) then
544 0 : write(iulog,8090) k+1,sc(i),shc(i),hc(i)
545 : end if
546 : enddo
547 : endif
548 :
549 :
550 : ! Check on moist convective instability
551 : ! Build index vector of points where instability exists
552 : len1 = 0
553 0 : do i=1,ncol
554 0 : if (vtemp4(i) > 0.0_kind_phys) then
555 0 : len1 = len1 + 1
556 0 : indx1(len1) = i
557 : end if
558 : end do
559 :
560 0 : if (len1 <= 0) cycle kloop
561 :
562 : ! Current level just below top level => no overshoot
563 0 : if (k <= limcnv+1) then
564 0 : do ii=1,len1
565 0 : i = indx1(ii)
566 0 : temp1 = vtemp4(i)/(1.0_kind_phys + gam(i,k))
567 0 : cldwtr(i) = max(0.0_kind_phys,(sb(i,k) - sc(i) + temp1))
568 0 : beta(i) = 0.0_kind_phys
569 0 : vtemp3(i) = (1.0_kind_phys + gam(i,k))*(sc(i) - sbh(i,k))
570 : end do
571 : else
572 : ! First guess at overshoot parameter using crude buoyancy closure
573 : ! 10% overshoot assumed as a minimum and 1-c0*dz maximum to start
574 : ! If pre-existing supersaturation in detrainment layer, beta=0
575 : ! cldwtr is temporarily equal to hlat*l (l=> liquid water)
576 0 : do ii=1,len1
577 0 : i = indx1(ii)
578 0 : temp1 = vtemp4(i)/(1.0_kind_phys + gam(i,k))
579 0 : cldwtr(i) = max(0.0_kind_phys,(sb(i,k)-sc(i)+temp1))
580 0 : betamx(i) = 1.0_kind_phys - c0*max(0.0_kind_phys,(dzcld(i)-dzmin))
581 0 : b1 = (hc(i) - hbs(i,k-1))*pdel(i,k-1)
582 0 : b2 = (hc(i) - hbs(i,k ))*pdel(i,k )
583 0 : beta(i) = max(betamn,min(betamx(i), 1.0_kind_phys + b1/b2))
584 0 : if (hbs(i,k-1) <= hb(i,k-1)) beta(i) = 0.0_kind_phys
585 :
586 : ! Bound maximum beta to ensure physically realistic solutions
587 : !
588 : ! First check constrains beta so that eta remains positive
589 : ! (assuming that eta is already positive for beta equal zero)
590 0 : vtemp1(i) = -(hbh(i,k+1) - hc(i))*pdel(i,k)*rpdel(i,k+1)+ &
591 0 : (1.0_kind_phys + gam(i,k))*(sc(i) - sbh(i,k+1) + cldwtr(i))
592 0 : vtemp2(i) = (1.0_kind_phys + gam(i,k))*(sc(i) - sbh(i,k))
593 0 : vtemp3(i) = vtemp2(i)
594 0 : if ((beta(i)*vtemp2(i) - vtemp1(i)) > 0._kind_phys) then
595 0 : betamx(i) = 0.99_kind_phys*(vtemp1(i)/vtemp2(i))
596 0 : beta(i) = max(0.0_kind_phys,min(betamx(i),beta(i)))
597 : end if
598 : end do
599 :
600 : ! Second check involves supersaturation of "detrainment layer"
601 : ! small amount of supersaturation acceptable (by ssfac factor)
602 0 : do ii=1,len1
603 0 : i = indx1(ii)
604 0 : if (hb(i,k-1) < hbs(i,k-1)) then
605 0 : vtemp1(i) = vtemp1(i)*rpdel(i,k)
606 0 : temp2 = gam(i,k-1)*(sbh(i,k) - sc(i) + cldwtr(i)) - &
607 0 : hbh(i,k) + hc(i) - sc(i) + sbh(i,k)
608 0 : temp3 = vtemp3(i)*rpdel(i,k)
609 0 : vtemp2(i) = (ztodt/cats)*(hc(i) - hbs(i,k))*temp2/ &
610 0 : (pdel(i,k-1)*(hbs(i,k-1) - hb(i,k-1))) + temp3
611 0 : if ((beta(i)*vtemp2(i) - vtemp1(i)) > 0._kind_phys) then
612 0 : betamx(i) = ssfac*(vtemp1(i)/vtemp2(i))
613 0 : beta(i) = max(0.0_kind_phys,min(betamx(i),beta(i)))
614 : end if
615 : else
616 0 : beta(i) = 0.0_kind_phys
617 : end if
618 : end do
619 :
620 : ! Third check to avoid introducing 2 delta x thermodynamic
621 : ! noise in the vertical ... constrain adjusted h (or theta e)
622 : ! so that the adjustment doesn't contribute to "kinks" in h
623 0 : do ii=1,len1
624 0 : i = indx1(ii)
625 0 : g = min(0.0_kind_phys,hb(i,k) - hb(i,k-1))
626 0 : temp1 = (hb(i,k) - hb(i,k-1) - g)*(cats/ztodt)/(hc(i) - hbs(i,k))
627 0 : vtemp1(i) = temp1*vtemp1(i) + (hc(i) - hbh(i,k+1))*rpdel(i,k)
628 0 : vtemp2(i) = temp1*vtemp3(i)*rpdel(i,k) + (hc(i) - hbh(i,k) - cldwtr(i))* &
629 0 : (rpdel(i,k) + rpdel(i,k+1))
630 0 : if ((beta(i)*vtemp2(i) - vtemp1(i)) > 0._kind_phys) then
631 0 : if (vtemp2(i) /= 0.0_kind_phys) then
632 0 : betamx(i) = vtemp1(i)/vtemp2(i)
633 : else
634 0 : betamx(i) = 0.0_kind_phys
635 : end if
636 0 : beta(i) = max(0.0_kind_phys,min(betamx(i),beta(i)))
637 : end if
638 : end do
639 : end if ! (k <= limcnv+1) Current level just below top level => no overshoot
640 :
641 :
642 : ! Calculate mass flux required for stabilization.
643 : !
644 : ! Ensure that the convective mass flux, eta, is positive by
645 : ! setting negative values of eta to zero..
646 : ! Ensure that estimated mass flux cannot move more than the
647 : ! minimum of total mass contained in either layer k or layer k+1.
648 : ! Also test for other pathological cases that result in non-
649 : ! physical states and adjust eta accordingly.
650 0 : do ii=1,len1
651 0 : i = indx1(ii)
652 0 : beta(i) = max(0.0_kind_phys,beta(i))
653 0 : temp1 = hc(i) - hbs(i,k)
654 0 : temp2 = ((1.0_kind_phys + gam(i,k))*(sc(i) - sbh(i,k+1) + cldwtr(i)) - &
655 0 : beta(i)*vtemp3(i))*rpdel(i,k) - (hbh(i,k+1) - hc(i))*rpdel(i,k+1)
656 0 : eta(i) = temp1/(temp2*grav*cats)
657 0 : tmass = min(pdel(i,k),pdel(i,k+1))*rgrav
658 0 : if (eta(i) > tmass*rtdt .or. eta(i) <= 0.0_kind_phys) eta(i) = 0.0_kind_phys
659 :
660 : ! Check on negative q in top layer (bound beta)
661 0 : if (shc(i)-shbh(i,k) < 0.0_kind_phys .and. beta(i)*eta(i) /= 0.0_kind_phys) then
662 0 : denom = eta(i)*grav*ztodt*(shc(i) - shbh(i,k))*rpdel(i,k-1)
663 0 : beta(i) = max(0.0_kind_phys,min(-0.999_kind_phys*shb(i,k-1)/denom,beta(i)))
664 : end if
665 :
666 : ! Check on negative q in middle layer (zero eta)
667 : qtest1 = shb(i,k) + eta(i)*grav*ztodt*((shc(i) - shbh(i,k+1)) - &
668 : (1.0_kind_phys - beta(i))*cldwtr(i)*rhlat - beta(i)*(shc(i) - shbh(i,k)))* &
669 0 : rpdel(i,k)
670 0 : if (qtest1 <= 0.0_kind_phys) eta(i) = 0.0_kind_phys
671 :
672 : ! Check on negative q in lower layer (bound eta)
673 0 : fac1 = -(shbh(i,k+1) - shc(i))*rpdel(i,k+1)
674 0 : qtest2 = shb(i,k+1) - eta(i)*grav*ztodt*fac1
675 0 : if (qtest2 < 0.0_kind_phys) then
676 0 : eta(i) = 0.99_kind_phys*shb(i,k+1)/(grav*ztodt*fac1)
677 : end if
678 0 : etagdt(i) = eta(i)*grav*ztodt
679 : end do
680 :
681 0 : if(debug_verbose) then
682 0 : do i=1,ncol
683 0 : if (i == 1) then
684 0 : write(iulog,8080) beta(i), eta(i)
685 : endif
686 : enddo
687 : endif
688 :
689 : ! Calculate cloud water, rain water, and thermodynamic changes
690 0 : do ii=1,len1
691 0 : i = indx1(ii)
692 0 : icwmr(i,k) = cldwtr(i)*rhlat
693 0 : cldwtr(i) = etagdt(i)*cldwtr(i)*rhlat*rgrav
694 :
695 : ! JJH changes to facilitate export of cloud liquid water --------------------------------
696 0 : totcond(i) = (1.0_kind_phys - beta(i))*cldwtr(i)
697 0 : rnwtr(i) = min(totcond(i),c0*(dzcld(i)-dzmin)*cldwtr(i))
698 0 : ds1(i) = etagdt(i)*(sbh(i,k+1) - sc(i))*rpdel(i,k+1)
699 0 : dq1(i) = etagdt(i)*(shbh(i,k+1) - shc(i))*rpdel(i,k+1)
700 : ds2(i) = (etagdt(i)*(sc(i) - sbh(i,k+1)) + &
701 0 : hlat*grav*cldwtr(i) - beta(i)*etagdt(i)*(sc(i) - sbh(i,k)))*rpdel(i,k)
702 :
703 : ! JJH change for export of cloud liquid water; must use total condensate
704 : ! since rainwater no longer represents total condensate
705 : dq2(i) = (etagdt(i)*(shc(i) - shbh(i,k+1)) - grav*totcond(i) - beta(i)* &
706 0 : etagdt(i)*(shc(i) - shbh(i,k)))*rpdel(i,k)
707 : ds3(i) = beta(i)*(etagdt(i)*(sc(i) - sbh(i,k)) - hlat*grav*cldwtr(i))* &
708 0 : rpdel(i,k-1)
709 0 : dq3(i) = beta(i)*etagdt(i)*(shc(i) - shbh(i,k))*rpdel(i,k-1)
710 :
711 : ! Isolate convective fluxes for later diagnostics
712 0 : fslkp = eta(i)*(sc(i) - sbh(i,k+1))
713 0 : fslkm = beta(i)*(eta(i)*(sc(i) - sbh(i,k)) - hlat*cldwtr(i)*rtdt)
714 0 : fqlkp = eta(i)*(shc(i) - shbh(i,k+1))
715 0 : fqlkm = beta(i)*eta(i)*(shc(i) - shbh(i,k))
716 :
717 : ! Update thermodynamic profile (update sb, hb, & hbs later)
718 0 : tb (i,k+1) = tb(i,k+1) + ds1(i)*rcp
719 0 : tb (i,k ) = tb(i,k ) + ds2(i)*rcp
720 0 : tb (i,k-1) = tb(i,k-1) + ds3(i)*rcp
721 0 : shb(i,k+1) = shb(i,k+1) + dq1(i)
722 0 : shb(i,k ) = shb(i,k ) + dq2(i)
723 0 : shb(i,k-1) = shb(i,k-1) + dq3(i)
724 :
725 : ! ** Update diagnostic information for final budget **
726 : ! Tracking precipitation, temperature & specific humidity tendencies,
727 : ! rainout term, convective mass flux, convective liquid
728 : ! water static energy flux, and convective total water flux
729 : ! The variable afac makes the necessary adjustment to the
730 : ! diagnostic fluxes to account for adjustment time scale based on
731 : ! how relaxation time scale is to be applied (column vs. triplet)
732 0 : prec(i) = prec(i) + (rnwtr(i)/rhoh2o)*adjfac
733 :
734 : ! The following variables have units of "units"/second
735 0 : cmfdt (i,k+1) = cmfdt (i,k+1) + ds1(i)*rtdt*adjfac
736 0 : cmfdt (i,k ) = cmfdt (i,k ) + ds2(i)*rtdt*adjfac
737 0 : cmfdt (i,k-1) = cmfdt (i,k-1) + ds3(i)*rtdt*adjfac
738 0 : cmfdq (i,k+1) = cmfdq (i,k+1) + dq1(i)*rtdt*adjfac
739 0 : cmfdq (i,k ) = cmfdq (i,k ) + dq2(i)*rtdt*adjfac
740 0 : cmfdq (i,k-1) = cmfdq (i,k-1) + dq3(i)*rtdt*adjfac
741 :
742 : ! JJH changes to export cloud liquid water --------------------------------
743 0 : qc_sh (i,k ) = (grav*(totcond(i)-rnwtr(i))*rpdel(i,k))*rtdt*adjfac
744 0 : cmfdqr (i,k ) = cmfdqr(i,k ) + (grav*rnwtr(i)*rpdel(i,k))*rtdt*adjfac
745 0 : cmfmc_sh(i,k+1) = cmfmc_sh(i,k+1) + eta(i)*adjfac
746 0 : cmfmc_sh(i,k ) = cmfmc_sh(i,k ) + beta(i)*eta(i)*adjfac
747 :
748 : ! The following variables have units of w/m**2
749 0 : cmfsl (i,k+1) = cmfsl (i,k+1) + fslkp*adjfac
750 0 : cmfsl (i,k ) = cmfsl (i,k ) + fslkm*adjfac
751 0 : cmflq (i,k+1) = cmflq (i,k+1) + hlat*fqlkp*adjfac
752 0 : cmflq (i,k ) = cmflq (i,k ) + hlat*fqlkm*adjfac
753 : enddo
754 :
755 : ! Next, convectively modify passive constituents
756 : ! For now, when applying relaxation time scale to thermal fields after
757 : ! entire column has undergone convective overturning, constituents will
758 : ! be mixed using a "relaxed" value of the mass flux determined above
759 : ! Although this will be inconsistant with the treatment of the thermal
760 : ! fields, it's computationally much cheaper, no more-or-less justifiable,
761 : ! and consistent with how the history tape mass fluxes would be used in
762 : ! an off-line mode (i.e., using an off-line transport model)
763 0 : const_modify_loop: do m = 1, pcnst
764 : ! Water vapor needs to be skipped in the loop.
765 0 : if (m == const_wv_idx) then
766 : cycle const_modify_loop
767 : endif
768 :
769 : ! assign pd, rpd, pm temporary properties based on constituent dry/moist mixing ratio
770 0 : call const_props(m)%is_dry(const_is_dry, errflg, errmsg)
771 0 : if(const_is_dry) then
772 0 : pd (:ncol,:) = pdeldry (:ncol,:)
773 0 : rpd(:ncol,:) = rpdeldry(:ncol,:)
774 0 : pm (:ncol,:) = pmiddry (:ncol,:)
775 : else
776 0 : pd (:ncol,:) = pdel (:ncol,:)
777 0 : rpd(:ncol,:) = rpdel (:ncol,:)
778 0 : pm (:ncol,:) = pmid (:ncol,:)
779 : endif
780 :
781 0 : pcl1loop: do ii=1,len1
782 0 : i = indx1(ii)
783 :
784 : ! If any of the reported values of the constituent is negative in
785 : ! the three adjacent levels, nothing will be done to the profile
786 0 : if ((dq(i,k+1,m) < 0.0_kind_phys) .or. (dq(i,k,m) < 0.0_kind_phys) .or. (dq(i,k-1,m) < 0.0_kind_phys)) cycle pcl1loop
787 :
788 : ! Specify constituent interface values (linear interpolation)
789 0 : cmrh(i,k ) = 0.5_kind_phys*(dq(i,k-1,m) + dq(i,k ,m))
790 0 : cmrh(i,k+1) = 0.5_kind_phys*(dq(i,k ,m) + dq(i,k+1,m))
791 :
792 : ! Specify perturbation properties of constituents in PBL
793 0 : pblhgt = max(pblh(i),1.0_kind_phys)
794 0 : if ( (zm(i,k+1) <= pblhgt) .and. dzcld(i) == 0.0_kind_phys ) then
795 0 : fac1 = max(0.0_kind_phys,1.0_kind_phys-zm(i,k+1)/pblhgt)
796 : ! cmrc(i) = dq(i,k+1,m) + qpert(i,m)*fac1
797 : ! hplin - qpert for m>1 is always zero
798 0 : cmrc(i) = dq(i,k+1,m)
799 : else
800 0 : cmrc(i) = dq(i,k+1,m)
801 : end if
802 :
803 : ! Determine fluxes, flux divergence => changes due to convection
804 : ! Logic must be included to avoid producing negative values. A bit
805 : ! messy since there are no a priori assumptions about profiles.
806 : ! Tendency is modified (reduced) when pending disaster detected.
807 :
808 0 : botflx = etagdt(i)*(cmrc(i) - cmrh(i,k+1))*adjfac
809 0 : topflx = beta(i)*etagdt(i)*(cmrc(i)-cmrh(i,k))*adjfac
810 0 : dcmr1(i) = -botflx*rpd(i,k+1)
811 0 : efac1 = 1.0_kind_phys
812 0 : efac2 = 1.0_kind_phys
813 0 : efac3 = 1.0_kind_phys
814 :
815 0 : if (dq(i,k+1,m)+dcmr1(i) < 0.0_kind_phys) then
816 0 : if ( abs(dcmr1(i)) > 1.e-300_kind_phys ) then
817 0 : efac1 = max(tiny,abs(dq(i,k+1,m)/dcmr1(i)) - eps)
818 : else
819 0 : efac1 = tiny
820 : endif
821 : end if
822 :
823 0 : if (efac1 == tiny .or. efac1 > 1.0_kind_phys) efac1 = 0.0_kind_phys
824 0 : dcmr1(i) = -efac1*botflx*rpd(i,k+1)
825 0 : dcmr2(i) = (efac1*botflx - topflx)*rpd(i,k)
826 :
827 0 : if (dq(i,k,m)+dcmr2(i) < 0.0_kind_phys) then
828 0 : if ( abs(dcmr2(i)) > 1.e-300_kind_phys ) then
829 0 : efac2 = max(tiny,abs(dq(i,k ,m)/dcmr2(i)) - eps)
830 : else
831 0 : efac2 = tiny
832 : endif
833 : end if
834 :
835 0 : if (efac2 == tiny .or. efac2 > 1.0_kind_phys) efac2 = 0.0_kind_phys
836 0 : dcmr2(i) = (efac1*botflx - efac2*topflx)*rpd(i,k)
837 0 : dcmr3(i) = efac2*topflx*rpd(i,k-1)
838 :
839 0 : if ( (dq(i,k-1,m)+dcmr3(i) < 0.0_kind_phys ) ) then
840 0 : if ( abs(dcmr3(i)) > 1.e-300_kind_phys ) then
841 0 : efac3 = max(tiny,abs(dq(i,k-1,m)/dcmr3(i)) - eps)
842 : else
843 0 : efac3 = tiny
844 : endif
845 : end if
846 :
847 0 : if (efac3 == tiny .or. efac3 > 1.0_kind_phys) efac3 = 0.0_kind_phys
848 0 : efac3 = min(efac2,efac3)
849 0 : dcmr2(i) = (efac1*botflx - efac3*topflx)*rpd(i,k)
850 0 : dcmr3(i) = efac3*topflx*rpd(i,k-1)
851 :
852 0 : dq(i,k+1,m) = dq(i,k+1,m) + dcmr1(i)
853 0 : dq(i,k ,m) = dq(i,k ,m) + dcmr2(i)
854 0 : dq(i,k-1,m) = dq(i,k-1,m) + dcmr3(i)
855 : end do pcl1loop
856 : end do const_modify_loop
857 : ! Constituent modifications complete
858 :
859 : ! This if restructured from a goto
860 0 : if (k /= limcnv+1) then
861 : ! Complete update of thermodynamic structure at integer levels
862 : ! gather/scatter points that need new values of shbs and gamma
863 0 : do ii=1,len1
864 0 : i = indx1(ii)
865 0 : vtemp1(ii ) = tb(i,k)
866 0 : vtemp1(ii+len1) = tb(i,k-1)
867 0 : vtemp2(ii ) = pmid(i,k)
868 0 : vtemp2(ii+len1) = pmid(i,k-1)
869 : end do
870 0 : call qsat(vtemp1(1:2*len1), vtemp2(1:2*len1), &
871 0 : vtemp5(1:2*len1), vtemp3(1:2*len1), 2*len1, gam=vtemp4(1:2*len1))
872 0 : do ii=1,len1
873 0 : i = indx1(ii)
874 0 : shbs(i,k ) = vtemp3(ii )
875 0 : shbs(i,k-1) = vtemp3(ii+len1)
876 0 : gam(i,k ) = vtemp4(ii )
877 0 : gam(i,k-1) = vtemp4(ii+len1)
878 0 : sb (i,k ) = sb(i,k ) + ds2(i)
879 0 : sb (i,k-1) = sb(i,k-1) + ds3(i)
880 0 : hb (i,k ) = sb(i,k ) + hlat*shb(i,k )
881 0 : hb (i,k-1) = sb(i,k-1) + hlat*shb(i,k-1)
882 0 : hbs(i,k ) = sb(i,k ) + hlat*shbs(i,k )
883 0 : hbs(i,k-1) = sb(i,k-1) + hlat*shbs(i,k-1)
884 : end do
885 :
886 : ! Update thermodynamic information at half (i.e., interface) levels
887 0 : do ii=1,len1
888 0 : i = indx1(ii)
889 0 : sbh (i,k) = 0.5_kind_phys*(sb(i,k) + sb(i,k-1))
890 0 : shbh(i,k) = qhalf(shb(i,k-1),shb(i,k),shbs(i,k-1),shbs(i,k))
891 0 : hbh (i,k) = sbh(i,k) + hlat*shbh(i,k)
892 0 : sbh (i,k-1) = 0.5_kind_phys*(sb(i,k-1) + sb(i,k-2))
893 0 : shbh(i,k-1) = qhalf(shb(i,k-2),shb(i,k-1),shbs(i,k-2),shbs(i,k-1))
894 0 : hbh (i,k-1) = sbh(i,k-1) + hlat*shbh(i,k-1)
895 : end do
896 : end if ! k /= limcnv+1
897 :
898 : ! Ensure that dzcld is reset if convective mass flux zero
899 : ! specify the current vertical extent of the convective activity
900 : ! top of convective layer determined by size of overshoot param.
901 0 : do i=1,ncol
902 0 : etagt0 = eta(i).gt.0.0_kind_phys
903 0 : if ( .not. etagt0) dzcld(i) = 0.0_kind_phys
904 0 : if (etagt0 .and. beta(i) > betamn) then
905 0 : ktp = k-1
906 : else
907 : ktp = k
908 : end if
909 0 : if (etagt0) then
910 0 : cnt_sh(i) = min(cnt_sh(i),ktp)
911 0 : cnb_sh(i) = max(cnb_sh(i),k)
912 : end if
913 : end do
914 : end do kloop
915 :
916 : !---------------------------------------------------
917 : ! apply final thermodynamic tendencies
918 : !---------------------------------------------------
919 : ! Set output q tendencies...
920 : ! ...for water vapor
921 0 : dq(:ncol,:,const_wv_idx) = cmfdq(:ncol,:)
922 :
923 : ! ...for other tracers from passive tracer transport
924 0 : do m = 1, pcnst
925 0 : if (m .ne. const_wv_idx) then
926 0 : dq(:ncol,:,m) = (dq(:ncol,:,m) - q(:ncol,:,m))/ztodt
927 : endif
928 : enddo
929 :
930 : ! Kludge to prevent cnb_sh-cnt_sh from being zero (in the event
931 : ! someone decides that they want to divide by this quantity)
932 0 : do i=1,ncol
933 0 : if (cnb_sh(i) /= 0 .and. cnb_sh(i) == cnt_sh(i)) then
934 0 : cnt_sh(i) = cnt_sh(i) - 1
935 : end if
936 : end do
937 :
938 0 : do i=1,ncol
939 0 : precc(i) = prec(i)*rtdt
940 : end do
941 :
942 : ! Compute reserved liquid (not yet in cldliq) for energy integrals.
943 : ! Treat rliq_sh as flux out bottom, to be added back later.
944 0 : do k = 1, pver
945 0 : do i = 1, ncol
946 0 : rliq_sh(i) = rliq_sh(i) + qc_sh(i,k)*pdel(i,k)/grav
947 : end do
948 : end do
949 :
950 : ! rliq_sh is converted to precipitation units [m s-1]
951 0 : rliq_sh(:ncol) = rliq_sh(:ncol) / 1000._kind_phys
952 :
953 : ! Prepare boundary fluxes for check_energy [m s-1]
954 0 : flx_cnd(:ncol) = precc(:ncol) + rliq_sh(:ncol)
955 :
956 0 : if(debug_verbose) then
957 : ! DEBUG DIAGNOSTICS - show final result
958 0 : do i=1,ncol
959 0 : if (i == 1) then
960 0 : fac = grav*864._kind_phys
961 0 : write(iulog, 8010)
962 0 : do k=limcnv,pver
963 0 : rh = shb(i,k)/shbs(i,k)
964 0 : write(iulog, 8020) shbh(i,k),sbh(i,k),hbh(i,k),fac*cmfmc_sh(i,k), &
965 0 : cmfsl(i,k), cmflq(i,k)
966 0 : write(iulog, 8040) tb(i,k),shb(i,k),rh ,sb(i,k),hb(i,k), &
967 0 : hbs(i,k), ztodt*cmfdt(i,k),ztodt*cmfdq(i,k), &
968 0 : ztodt*cmfdqr(i,k)
969 : end do
970 0 : write(iulog, 8000) prec(i)
971 :
972 : ! approximate vertical integral of moist static energy and
973 : ! total preciptable water after adjustment and output changes
974 0 : hsum2 = 0.0_kind_phys
975 0 : qsum2 = 0.0_kind_phys
976 0 : do k=limcnv,pver
977 0 : hsum2 = hsum2 + pdel(i,k)*rgrav*hb(i,k)
978 0 : qsum2 = qsum2 + pdel(i,k)*rgrav*shb(i,k)
979 : end do
980 0 : write(iulog,8070) hsum1, hsum2, abs(hsum2-hsum1)/hsum2, &
981 0 : qsum1, qsum2, abs(qsum2-qsum1)/qsum2
982 : end if
983 : enddo
984 : endif
985 :
986 : ! Diagnostic use format strings
987 : 8000 format(///,10x,'PREC = ',3pf12.6,/)
988 : 8010 format('1** TB SHB RH SB', &
989 : ' HB HBS CAH CAM PRECC ', &
990 : ' ETA FSL FLQ **', /)
991 : 8020 format(' ----- ', 9x,3p,f7.3,2x,2p, 9x,-3p,f7.3,2x, &
992 : f7.3, 37x, 0p,2x,f8.2, 0p,2x,f8.2,2x,f8.2, ' ----- ')
993 : 8030 format(' ----- ', 0p,82x,f8.2, 0p,2x,f8.2,2x,f8.2, &
994 : ' ----- ')
995 : 8040 format(' - - - ',f7.3,2x,3p,f7.3,2x,2p,f7.3,2x,-3p,f7.3,2x, &
996 : f7.3, 2x,f8.3,2x,0p,f7.3,3p,2x,f7.3,2x,f7.3,30x, &
997 : ' - - - ')
998 : 8050 format(' ----- ',110x,' ----- ')
999 : 8060 format('1 K =>', i4,/, &
1000 : ' TB SHB RH SB', &
1001 : ' HB HBS CAH CAM PREC ', &
1002 : ' ETA FSL FLQ', /)
1003 : 8070 format(' VERTICALLY INTEGRATED MOIST STATIC ENERGY BEFORE, AFTER', &
1004 : ' AND PERCENTAGE DIFFERENCE => ',1p,2e15.7,2x,2p,f7.3,/, &
1005 : ' VERTICALLY INTEGRATED MOISTURE BEFORE, AFTER', &
1006 : ' AND PERCENTAGE DIFFERENCE => ',1p,2e15.7,2x,2p,f7.3,/)
1007 : 8080 format(' BETA, ETA => ', 1p,2e12.3)
1008 : 8090 format (' k+1, sc, shc, hc => ', 1x, i2, 1p, 3e12.4)
1009 0 : end subroutine hack_convect_shallow_run
1010 :
1011 : ! qhalf computes the specific humidity at interface levels between two model layers (interpolate moisture)
1012 0 : pure function qhalf(sh1,sh2,shbs1,shbs2) result(qh)
1013 : real(kind_phys), intent(in) :: sh1 ! humidity of layer 1 [kg kg-1]
1014 : real(kind_phys), intent(in) :: sh2 ! humidity of layer 2 [kg kg-1]
1015 : real(kind_phys), intent(in) :: shbs1 ! saturation specific humidity of layer 1 [kg kg-1]
1016 : real(kind_phys), intent(in) :: shbs2 ! saturation specific humidity of layer 2 [kg kg-1]
1017 : real(kind_phys) :: qh
1018 0 : qh = min(max(sh1,sh2),(shbs2*sh1 + shbs1*sh2)/(shbs1+shbs2))
1019 0 : end function qhalf
1020 : end module hack_convect_shallow
|