Line data Source code
1 : module subcol_SILHS
2 : !---------------------------------------------------------------------------
3 : ! Purpose:
4 : !
5 : ! Implement a subcolumn scheme based on the Subgrid Importance Latin Hypercube
6 : ! Sampling (SILHS) functionality of the CLUBB moist turbulence parameterization.
7 : !
8 : !---------------------------------------------------------------------------
9 :
10 : use shr_kind_mod, only: r8=>shr_kind_r8, r4=>shr_kind_r4, i4=>shr_kind_i4
11 : use physics_types, only: physics_state, physics_tend, physics_ptend
12 : use ppgrid, only: pcols, psubcols, pver, pverp, begchunk, endchunk
13 : use constituents, only: pcnst, cnst_get_ind
14 : use cam_abortutils, only: endrun
15 : use cam_logfile, only: iulog
16 : use cam_history, only: addfld, add_default, outfld, horiz_only
17 : use ref_pres, only: top_lev => trop_cloud_top_lev
18 : #ifdef CLUBB_SGS
19 : #ifdef SILHS
20 : use clubb_intr, only: &
21 : clubb_config_flags, &
22 : clubb_params_single_col, &
23 : stats_metadata, &
24 : stats_zt, stats_zm, stats_sfc, &
25 : pdf_params_chnk, &
26 : hm_metadata, &
27 : hydromet_dim, &
28 : pdf_dim
29 :
30 : use clubb_api_module, only: &
31 : hmp2_ip_on_hmm2_ip_slope_type, &
32 : hmp2_ip_on_hmm2_ip_intrcpt_type, &
33 : precipitation_fractions, &
34 : stats, &
35 : core_rknd
36 :
37 : use silhs_api_module, only: &
38 : silhs_config_flags_type
39 : #endif
40 : #endif
41 : use physconst, only: cpair, gravit, latvap, latice, rair, rga, cappa
42 :
43 : implicit none
44 : private
45 : save
46 :
47 : public :: subcol_register_SILHS !
48 : public :: subcol_init_SILHS ! Initialize
49 : public :: subcol_gen_SILHS ! Generate subcolumn fields by calling SILHS
50 : public :: subcol_readnl_SILHS ! SILHS namelist reader
51 : public :: subcol_ptend_avg_SILHS
52 : public :: subcol_SILHS_var_covar_driver
53 : public :: subcol_SILHS_fill_holes_conserv
54 : public :: subcol_SILHS_hydromet_conc_tend_lim
55 : public :: init_state_subcol
56 : private :: fill_holes_sedimentation
57 : private :: fill_holes_same_phase_vert
58 : #ifdef SILHS
59 : ! Calc subcol mean ! Calc subcol variance
60 : private :: meansc
61 : private :: stdsc
62 :
63 : type (stats), target :: stats_lh_zt, &
64 : stats_lh_sfc
65 : !$omp threadprivate(stats_lh_zt, stats_lh_sfc)
66 :
67 : real( kind = core_rknd ), dimension(:,:), allocatable :: &
68 : corr_array_n_cloud, &
69 : corr_array_n_below
70 :
71 : #endif
72 :
73 : !-----
74 : ! Private module vars
75 : !-----
76 :
77 : ! constituent indicies
78 : integer :: &
79 : ixq = 0, &
80 : ixcldliq = 0, &
81 : ixnumliq = 0, &
82 : ixcldice = 0, &
83 : ixnumice = 0, &
84 : ixrain = 0, &
85 : ixnumrain= 0, &
86 : ixsnow = 0, &
87 : ixnumsnow= 0
88 :
89 : ! Pbuf indicies
90 : integer :: thlm_idx, rtm_idx, ice_supersat_idx, &
91 : alst_idx, cld_idx, qrain_idx, qsnow_idx, &
92 : nrain_idx, nsnow_idx, ztodt_idx, tke_idx, kvh_idx, &
93 : prec_pcw_idx, snow_pcw_idx, prec_str_idx, snow_str_idx, &
94 : qcsedten_idx, qrsedten_idx, qisedten_idx, qssedten_idx, &
95 : vtrmc_idx, umr_idx, vtrmi_idx, ums_idx, qcsevap_idx, qisevap_idx
96 :
97 : logical :: subcol_SILHS_weight ! if set, sets up weights for averaging subcolumns for SILHS
98 : integer :: subcol_SILHS_numsubcol ! number of subcolumns for this run
99 : logical :: docldfracscaling = .false. ! Weight tendencies by cloud fraction
100 :
101 : character(len=256) :: subcol_SILHS_corr_file_path
102 : character(len=16) :: subcol_SILHS_corr_file_name
103 :
104 : logical :: subcol_SILHS_q_to_micro, &
105 : subcol_SILHS_n_to_micro, &
106 : subcol_SILHS_use_clear_col, &
107 : subcol_SILHS_meanice, &
108 : subcol_SILHS_constrainmn
109 :
110 : logical :: subcol_SILHS_var_covar_src
111 :
112 : real(r8) :: subcol_SILHS_ncnp2_on_ncnm2
113 :
114 : ! There may or may not be a better place to put this.
115 : real(r8), parameter :: p0_clubb = 100000._r8
116 :
117 :
118 : ! real(r8) :: subcol_SILHS_c6rt, subcol_SILHS_c7, subcol_SILHS_c8, subcol_SILHS_c11, &
119 : ! subcol_SILHS_c11b, subcol_SILHS_gamma_coef, &
120 : ! subcol_SILHS_mult_coef, subcol_SILHS_mu
121 :
122 : real(r8) :: ztodt ! model timestep
123 : #ifdef CLUBB_SGS
124 : #ifdef SILHS
125 : type(hmp2_ip_on_hmm2_ip_slope_type) :: subcol_SILHS_hmp2_ip_on_hmm2_ip_slope
126 : type(hmp2_ip_on_hmm2_ip_intrcpt_type) :: subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt
127 :
128 : type(silhs_config_flags_type) :: silhs_config_flags
129 : #endif
130 : #endif
131 :
132 : contains
133 :
134 0 : subroutine subcol_register_SILHS()
135 :
136 : !--------------------------------
137 : ! Register fields needed by SILHS in the physics buffer
138 : ! Currently, most fields needed by SILHS but calculated by CLUBB are registered
139 : ! by clubb in clubb_intr.F90.
140 : !
141 : !--------------------------------
142 : #ifdef CLUBB_SGS
143 : #ifdef SILHS
144 : #endif
145 : #endif
146 0 : end subroutine subcol_register_SILHS
147 :
148 :
149 0 : subroutine subcol_readnl_SILHS(nlfile)
150 : #ifdef CLUBB_SGS
151 : #ifdef SILHS
152 : use namelist_utils, only: find_group_name
153 : use spmd_utils, only: masterproc, masterprocid, mpicom
154 : use spmd_utils, only: mpi_integer, mpi_logical, mpi_character, mpir8, iam
155 : use clubb_api_module, only: core_rknd
156 : use silhs_api_module, only: set_default_silhs_config_flags_api, &
157 : initialize_silhs_config_flags_type_api, &
158 : print_silhs_config_flags_api
159 : #endif
160 : #endif
161 : character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
162 :
163 : ! Local variables
164 : integer :: unitn, ierr
165 : #ifdef CLUBB_SGS
166 : #ifdef SILHS
167 :
168 : integer :: &
169 : cluster_allocation_strategy
170 :
171 : logical :: &
172 : subcol_silhs_l_lh_importance_sampling, &
173 : subcol_silhs_l_Lscale_vert_avg, &
174 : subcol_silhs_l_lh_straight_mc, &
175 : subcol_silhs_l_lh_clustered_sampling, &
176 : subcol_silhs_l_rcm_in_cloud_k_lh_start, &
177 : subcol_silhs_l_random_k_lh_start, &
178 : subcol_silhs_l_max_overlap_in_cloud, &
179 : subcol_silhs_l_lh_instant_var_covar_src, &
180 : subcol_silhs_l_lh_limit_weights, &
181 : subcol_silhs_l_lh_var_frac, &
182 : subcol_silhs_l_lh_normalize_weights
183 :
184 : namelist /subcol_SILHS_nl/ subcol_SILHS_weight, &
185 : subcol_SILHS_numsubcol, &
186 : subcol_SILHS_corr_file_path, &
187 : subcol_SILHS_corr_file_name, &
188 : subcol_SILHS_q_to_micro, &
189 : subcol_SILHS_n_to_micro, &
190 : subcol_SILHS_ncnp2_on_ncnm2, &
191 : subcol_SILHS_hmp2_ip_on_hmm2_ip_slope, &
192 : subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt, &
193 : subcol_SILHS_meanice, &
194 : subcol_SILHS_use_clear_col, &
195 : subcol_SILHS_constrainmn, &
196 : subcol_SILHS_var_covar_src
197 : ! subcol_SILHS_c6rt, subcol_SILHS_c7, &
198 : ! subcol_SILHS_c8, subcol_SILHS_c11, subcol_SILHS_c11b, &
199 : ! subcol_SILHS_gamma_coef, subcol_SILHS_mult_coef, subcol_SILHS_mu
200 :
201 : namelist /silhs_config_flags_nl/ subcol_silhs_l_lh_importance_sampling, &
202 : subcol_silhs_l_Lscale_vert_avg, &
203 : subcol_silhs_l_lh_straight_mc, &
204 : subcol_silhs_l_lh_clustered_sampling, &
205 : subcol_silhs_l_rcm_in_cloud_k_lh_start, &
206 : subcol_silhs_l_random_k_lh_start, &
207 : subcol_silhs_l_max_overlap_in_cloud, &
208 : subcol_silhs_l_lh_instant_var_covar_src, &
209 : subcol_silhs_l_lh_limit_weights, &
210 : subcol_silhs_l_lh_var_frac, &
211 : subcol_silhs_l_lh_normalize_weights
212 :
213 : !-----------------------------------------------------------------------------
214 : ! Set defaults
215 :
216 : ! Eric Raut changed a default.
217 : subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%Ni = 0.0_core_rknd
218 : subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%Ni = 0.5_core_rknd
219 :
220 : if (masterproc) then
221 : open( newunit=unitn, file=trim(nlfile), status='old' )
222 : call find_group_name(unitn, 'subcol_SILHS_nl', status=ierr)
223 : if (ierr == 0) then
224 : read(unitn, subcol_SILHS_nl, iostat=ierr)
225 : if (ierr /= 0) then
226 : call endrun('subcol_readnl_SILHS: ERROR reading namelist')
227 : end if
228 : end if
229 : close(unitn)
230 : end if
231 :
232 : ! Set default silhs_config_flags entires
233 : call set_default_silhs_config_flags_api( cluster_allocation_strategy, &
234 : subcol_silhs_l_lh_importance_sampling, &
235 : subcol_silhs_l_Lscale_vert_avg, &
236 : subcol_silhs_l_lh_straight_mc, &
237 : subcol_silhs_l_lh_clustered_sampling, &
238 : subcol_silhs_l_rcm_in_cloud_k_lh_start, &
239 : subcol_silhs_l_random_k_lh_start, &
240 : subcol_silhs_l_max_overlap_in_cloud, &
241 : subcol_silhs_l_lh_instant_var_covar_src, &
242 : subcol_silhs_l_lh_limit_weights, &
243 : subcol_silhs_l_lh_var_frac, &
244 : subcol_silhs_l_lh_normalize_weights )
245 :
246 : ! Get silhs_config_flags entries from namelist
247 : if (masterproc) then
248 : open( newunit=unitn, file=trim(nlfile), status='old' )
249 : call find_group_name(unitn, 'silhs_config_flags_nl', status=ierr)
250 : if (ierr == 0) then
251 : read(unitn, silhs_config_flags_nl, iostat=ierr)
252 : if (ierr /= 0) then
253 : call endrun('silhs_config_flags_nl: ERROR reading namelist')
254 : end if
255 : end if
256 : close(unitn)
257 : end if
258 :
259 : ! Save silhs_config_flags entries into module variable silhs_config_flags
260 : call initialize_silhs_config_flags_type_api( cluster_allocation_strategy, &
261 : subcol_silhs_l_lh_importance_sampling, &
262 : subcol_silhs_l_Lscale_vert_avg, &
263 : subcol_silhs_l_lh_straight_mc, &
264 : subcol_silhs_l_lh_clustered_sampling, &
265 : subcol_silhs_l_rcm_in_cloud_k_lh_start, &
266 : subcol_silhs_l_random_k_lh_start, &
267 : subcol_silhs_l_max_overlap_in_cloud, &
268 : subcol_silhs_l_lh_instant_var_covar_src, &
269 : subcol_silhs_l_lh_limit_weights, &
270 : subcol_silhs_l_lh_var_frac, &
271 : subcol_silhs_l_lh_normalize_weights, &
272 : silhs_config_flags )
273 :
274 : ! Print the SILHS configurable flags
275 : call print_silhs_config_flags_api( iulog, silhs_config_flags ) ! Intent(in)
276 :
277 : #ifdef SPMD
278 : ! Broadcast namelist variables
279 : call mpi_bcast(subcol_SILHS_weight, 1, mpi_logical, masterprocid, mpicom, ierr)
280 : call mpi_bcast(subcol_SILHS_numsubcol, 1, mpi_integer, masterprocid, mpicom, ierr)
281 : call mpi_bcast(subcol_SILHS_corr_file_path, len(subcol_SILHS_corr_file_path), &
282 : mpi_character, masterprocid, mpicom, ierr)
283 : call mpi_bcast(subcol_SILHS_corr_file_name, len(subcol_SILHS_corr_file_name), &
284 : mpi_character, masterprocid, mpicom, ierr)
285 : call mpi_bcast(subcol_SILHS_use_clear_col, 1, mpi_logical, masterprocid, mpicom, ierr)
286 : call mpi_bcast(subcol_SILHS_constrainmn, 1, mpi_logical, masterprocid, mpicom, ierr)
287 : call mpi_bcast(subcol_SILHS_meanice, 1, mpi_logical, masterprocid, mpicom, ierr)
288 : call mpi_bcast(subcol_SILHS_q_to_micro, 1, mpi_logical, masterprocid, mpicom, ierr)
289 : call mpi_bcast(subcol_SILHS_n_to_micro, 1, mpi_logical, masterprocid, mpicom, ierr)
290 : call mpi_bcast(subcol_SILHS_var_covar_src,1,mpi_logical,masterprocid, mpicom, ierr)
291 : call mpi_bcast(subcol_SILHS_ncnp2_on_ncnm2, 1, mpir8, masterprocid, mpicom, ierr)
292 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%rr, 1, mpir8, masterprocid, mpicom, ierr)
293 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%Nr, 1, mpir8, masterprocid, mpicom, ierr)
294 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%ri, 1, mpir8, masterprocid, mpicom, ierr)
295 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%Ni, 1, mpir8, masterprocid, mpicom, ierr)
296 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%rs, 1, mpir8, masterprocid, mpicom, ierr)
297 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_slope%Ns, 1, mpir8, masterprocid, mpicom, ierr)
298 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%rr, 1, mpir8, masterprocid, mpicom, ierr)
299 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%Nr, 1, mpir8, masterprocid, mpicom, ierr)
300 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%ri, 1, mpir8, masterprocid, mpicom, ierr)
301 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%Ni, 1, mpir8, masterprocid, mpicom, ierr)
302 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%rs, 1, mpir8, masterprocid, mpicom, ierr)
303 : call mpi_bcast(subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt%Ns, 1, mpir8, masterprocid, mpicom, ierr)
304 : ! call mpi_bcast(subcol_SILHS_c6rt, 1, mpir8, masterprocid, mpicom, ierr)
305 : ! call mpi_bcast(subcol_SILHS_c7, 1, mpir8, masterprocid, mpicom, ierr)
306 : ! call mpi_bcast(subcol_SILHS_c8, 1, mpir8, masterprocid, mpicom, ierr)
307 : ! call mpi_bcast(subcol_SILHS_c11, 1, mpir8, masterprocid, mpicom, ierr)
308 : ! call mpi_bcast(subcol_SILHS_c11b, 1, mpir8, masterprocid, mpicom, ierr)
309 : ! call mpi_bcast(subcol_SILHS_gamma_coef, 1, mpir8, masterprocid, mpicom, ierr)
310 : ! call mpi_bcast(subcol_SILHS_mult_coef, 1, mpir8, masterprocid, mpicom, ierr)
311 : ! call mpi_bcast(subcol_SILHS_mu, 1, mpir8, masterprocid, mpicom, ierr)
312 : call mpi_bcast(silhs_config_flags%l_lh_importance_sampling, 1, mpi_logical, masterprocid, mpicom, ierr)
313 : call mpi_bcast(silhs_config_flags%l_Lscale_vert_avg, 1, mpi_logical, masterprocid, mpicom, ierr)
314 : call mpi_bcast(silhs_config_flags%l_lh_straight_mc, 1, mpi_logical, masterprocid, mpicom, ierr)
315 : call mpi_bcast(silhs_config_flags%l_lh_clustered_sampling, 1, mpi_logical, masterprocid, mpicom, ierr)
316 : call mpi_bcast(silhs_config_flags%l_rcm_in_cloud_k_lh_start, 1, mpi_logical, masterprocid, mpicom, ierr)
317 : call mpi_bcast(silhs_config_flags%l_random_k_lh_start, 1, mpi_logical, masterprocid, mpicom, ierr)
318 : call mpi_bcast(silhs_config_flags%l_max_overlap_in_cloud, 1, mpi_logical, masterprocid, mpicom, ierr)
319 : call mpi_bcast(silhs_config_flags%l_lh_instant_var_covar_src, 1, mpi_logical, masterprocid, mpicom, ierr)
320 : call mpi_bcast(silhs_config_flags%l_lh_limit_weights, 1, mpi_logical, masterprocid, mpicom, ierr)
321 : call mpi_bcast(silhs_config_flags%l_lh_var_frac, 1, mpi_logical, masterprocid, mpicom, ierr)
322 : call mpi_bcast(silhs_config_flags%l_lh_normalize_weights, 1, mpi_logical, masterprocid, mpicom, ierr)
323 :
324 : ! SPMD
325 : #endif
326 : ! SILHS
327 : #endif
328 : ! CLUBB_SGS
329 : #endif
330 0 : end subroutine subcol_readnl_SILHS
331 :
332 :
333 0 : subroutine subcol_init_SILHS(pbuf2d)
334 :
335 : !--------------------------------
336 : ! Read in parameters and initialize SILHS PDF fields.
337 : ! Set up indexes into Pbuf fields.
338 : ! Register history outputs.
339 : !--------------------------------
340 :
341 : use physics_buffer, only: physics_buffer_desc, pbuf_get_field, &
342 : dtype_r8, pbuf_get_index
343 : #ifdef CLUBB_SGS
344 : #ifdef SILHS
345 : use clubb_api_module, only: core_rknd, &
346 : setup_corr_varnce_array_api, &
347 : init_pdf_hydromet_arrays_api, &
348 : set_clubb_debug_level_api
349 :
350 : #endif
351 : #endif
352 :
353 : type(physics_buffer_desc), pointer :: pbuf2d(:,:)
354 :
355 : #ifdef CLUBB_SGS
356 : #ifdef SILHS
357 :
358 : integer :: iunit = 501 ! Default value, will get iunit from CAM
359 : !character(len=*), parameter :: default_corr_case = "arm_97"
360 : character(len=*), parameter :: &
361 : cloud_file_ext = "_corr_array_cloud.in", & ! File extensions for corr files
362 : below_file_ext = "_corr_array_below.in"
363 : character(len=256) :: corr_file_path_cloud, corr_file_path_below
364 :
365 : ! To set up CLUBB hydromet indices
366 : integer :: &
367 : iirr, & ! Hydrometeor array index for rain water mixing ratio, rr
368 : iirs, & ! Hydrometeor array index for snow mixing ratio, rs
369 : iiri, & ! Hydrometeor array index for ice mixing ratio, ri
370 : iirg, & ! Hydrometeor array index for graupel mixing ratio, rg
371 : iiNr, & ! Hydrometeor array index for rain drop concentration, Nr
372 : iiNs, & ! Hydrometeor array index for snow concentration, Ns
373 : iiNi, & ! Hydrometeor array index for ice concentration, Ni
374 : iiNg ! Hydrometeor array index for graupel concentration, Ng
375 :
376 : integer :: l, ierr=0 ! Loop variable, error check
377 :
378 : ! Set CLUBB's debug level
379 : ! This is called in module clubb_intr; no need to do it here.
380 : ! call set_clubb_debug_level_api( 0 )
381 :
382 : !-------------------------------
383 : ! CLUBB-SILHS Parameters (global module variables)
384 : !-------------------------------
385 : clubb_config_flags%l_fix_w_chi_eta_correlations = .true.
386 : clubb_config_flags%l_diagnose_correlations = .false.
387 : clubb_config_flags%l_calc_w_corr = .false.
388 : ! l_prescribed_avg_deltaz = .false.
389 : clubb_config_flags%l_use_cloud_cover = .false.
390 : clubb_config_flags%l_const_Nc_in_cloud = .true.
391 :
392 : ! Values from the namelist
393 : docldfracscaling = subcol_SILHS_use_clear_col
394 :
395 : ! Namelist "tuning" or set correlations
396 : ! KTC Todo: Move these to a tuning "in" file or into the namelist
397 : ! JHTODO: we might want these on CLUBB's API and ultimatively on a namelist for tuning
398 : ! C6rt = subcol_SILHS_c6rt
399 : ! C7 = subcol_SILHS_c7 ! to all ice clouds
400 : ! C8 = subcol_SILHS_c8
401 : ! C11 = subcol_SILHS_c11
402 : ! C11b = subcol_SILHS_c11b
403 : ! gamma_coef = subcol_SILHS_gamma_coef
404 : ! mult_coef = subcol_SILHS_mult_coef
405 : ! mu = subcol_SILHS_mu
406 :
407 : !call set_clubb_debug_level( 0 ) !#KTCtodo: Add a namelist variable to set debug level
408 :
409 : ! Get constituent indices
410 : call cnst_get_ind('Q', ixq)
411 : call cnst_get_ind('CLDLIQ', ixcldliq)
412 : call cnst_get_ind('NUMLIQ', ixnumliq)
413 : call cnst_get_ind('CLDICE', ixcldice)
414 : call cnst_get_ind('NUMICE', ixnumice)
415 : call cnst_get_ind('RAINQM', ixrain, abort=.false.)
416 : call cnst_get_ind('NUMRAI', ixnumrain, abort=.false.)
417 : call cnst_get_ind('SNOWQM', ixsnow, abort=.false.)
418 : call cnst_get_ind('NUMSNO', ixnumsnow, abort=.false.)
419 :
420 : ! Get physics buffer indexes
421 : thlm_idx = pbuf_get_index('THLM')
422 : rtm_idx = pbuf_get_index('RTM')
423 : cld_idx = pbuf_get_index('CLD')
424 : alst_idx = pbuf_get_index('ALST') ! SILHS expects clubb's cloud_frac liq stratus fraction
425 : ztodt_idx = pbuf_get_index('ZTODT')
426 : ice_supersat_idx = pbuf_get_index('ISS_FRAC')
427 : tke_idx = pbuf_get_index('tke')
428 : kvh_idx = pbuf_get_index('kvh')
429 : prec_pcw_idx = pbuf_get_index('PREC_PCW')
430 : snow_pcw_idx = pbuf_get_index('SNOW_PCW')
431 : prec_str_idx = pbuf_get_index('PREC_STR')
432 : snow_str_idx = pbuf_get_index('SNOW_STR')
433 : qcsedten_idx = pbuf_get_index('QCSEDTEN')
434 : qrsedten_idx = pbuf_get_index('QRSEDTEN')
435 : qisedten_idx = pbuf_get_index('QISEDTEN')
436 : qssedten_idx = pbuf_get_index('QSSEDTEN')
437 : vtrmc_idx = pbuf_get_index('VTRMC')
438 : umr_idx = pbuf_get_index('UMR')
439 : vtrmi_idx = pbuf_get_index('VTRMI')
440 : ums_idx = pbuf_get_index('UMS')
441 : qcsevap_idx = pbuf_get_index('QCSEVAP')
442 : qisevap_idx = pbuf_get_index('QISEVAP')
443 : qrain_idx = pbuf_get_index('QRAIN')
444 : qsnow_idx = pbuf_get_index('QSNOW')
445 : nrain_idx = pbuf_get_index('NRAIN')
446 : nsnow_idx = pbuf_get_index('NSNOW')
447 :
448 : !-------------------------------
449 : ! Set up SILHS hydrometeors #KTCtodo: move microphys specification to config time,
450 : ! Steve wants to set up a microphysics query so I can ask the microphysics
451 : ! scheme which hydrometeors to use. For the future.
452 : !-------------------------------
453 : iirr = 1
454 : iirs = 3
455 : iiri = 5
456 : iirg = -1
457 :
458 : iiNr = 2
459 : iiNs = 4
460 : iiNi = 6
461 : iiNg = -1
462 :
463 : hydromet_dim = 6
464 :
465 : ! Set up pdf indices, hydromet indicies, hydromet arrays, and hydromet variance ratios
466 : call init_pdf_hydromet_arrays_api( 1.0_core_rknd, 1.0_core_rknd, hydromet_dim, & ! intent(in)
467 : iirr, iiNr, iiri, iiNi, & ! intent(in)
468 : iirs, iiNs, iirg, iiNg, & ! intent(in)
469 : subcol_SILHS_ncnp2_on_ncnm2, & ! intent(in)
470 : hm_metadata, pdf_dim, & ! intent(out)
471 : subcol_SILHS_hmp2_ip_on_hmm2_ip_slope, & ! optional(in)
472 : subcol_SILHS_hmp2_ip_on_hmm2_ip_intrcpt ) ! optional(in)
473 :
474 : !-------------------------------
475 : ! Set up hydrometeors and correlation arrays for SILHS
476 : !-------------------------------
477 : allocate( corr_array_n_cloud(pdf_dim,pdf_dim), corr_array_n_below(pdf_dim,pdf_dim), stat=ierr)
478 : if( ierr /= 0 ) call endrun(' subcol_init_SILHS: failed to allocate corr_array fields ')
479 :
480 : corr_file_path_cloud = trim( subcol_SILHS_corr_file_path )//trim( subcol_SILHS_corr_file_name )//cloud_file_ext
481 : corr_file_path_below = trim( subcol_SILHS_corr_file_path )//trim( subcol_SILHS_corr_file_name )//below_file_ext
482 :
483 : call setup_corr_varnce_array_api( corr_file_path_cloud, corr_file_path_below, &
484 : pdf_dim, hm_metadata, newunit(iunit), &
485 : clubb_config_flags%l_fix_w_chi_eta_correlations, & ! In
486 : corr_array_n_cloud, corr_array_n_below )
487 :
488 : !-------------------------------
489 : ! Register output fields from SILHS
490 : !-------------------------------
491 : call addfld('SILHS_NCLD_SCOL', (/'psubcols', 'ilev '/), 'I', 'm^-3', &
492 : 'Subcolumn Cloud Number Concentration', flag_xyfill=.true., fill_value=1.e30_r8)
493 : call addfld('SILHS_NRAIN_SCOL', (/'psubcols', 'ilev '/), 'I', 'm^-3', &
494 : 'Subcolumn Number Concentration of Rain from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
495 : call addfld('SILHS_OMEGA_SCOL', (/'psubcols', 'ilev '/), 'I', 'Pa/s', &
496 : 'Subcolumn vertical pressure velocity', flag_xyfill=.true., fill_value=1.e30_r8)
497 : call addfld('SILHS_RCM_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', &
498 : 'Subcolumn Cloud Liquid Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
499 : call addfld('SILHS_RICLD_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', &
500 : 'Subcolumn Cloud Ice Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
501 : call addfld('SILHS_NICLD_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', &
502 : 'Subcolumn Cloud Ice Number Conc from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
503 : call addfld('SILHS_RRAIN_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg', &
504 : 'Subcolumn Precipitating Liquid Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
505 : call addfld('SILHS_RT_SCOL', (/'psubcols', 'ilev '/), 'I', 'kg/kg ', &
506 : 'Subcolumn Total Water from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
507 : call addfld('SILHS_THLM_SCOL', (/'psubcols', 'ilev '/), 'I', 'K', &
508 : 'Subcolumn liquid water pot temperature', flag_xyfill=.true., fill_value=1.e30_r8)
509 : call addfld('SILHS_WEIGHT_SCOL', (/'psubcols'/), 'I', 'frac', &
510 : 'Weights for each subcolumn', flag_xyfill=.true., fill_value=1.e30_r8)
511 : call addfld('SILHS_WM_SCOL', (/'psubcols', 'ilev '/), 'I', 'm/s', &
512 : 'Subcolumn vertical velocity from SILHS', flag_xyfill=.true., fill_value=1.e30_r8)
513 :
514 : call addfld('NR_IN_LH', (/ 'lev' /), 'I', 'm^-3', &
515 : 'Num Rain Conc as input to SILHS')
516 : call addfld('SILHS_RTM', (/ 'ilev' /), 'I', 'kg/kg', &
517 : 'Input total water mixing ratio')
518 : call addfld('SILHS_THLM', (/ 'ilev' /), 'I', 'K', &
519 : 'Input liquid water potential temperature')
520 : call addfld('SILHS_QC_IN', (/ 'lev' /), 'I', 'kg/kg', &
521 : 'Input cloud water mixing ratio')
522 : call addfld('SILHS_QI_IN', (/ 'lev' /), 'I', 'kg/kg', &
523 : 'Input cloud ice mixing ratio')
524 : call addfld('SILHS_NC_IN', (/ 'lev' /), 'I', '#/kg', &
525 : 'Input cloud water number concentration')
526 : call addfld('SILHS_NI_IN', (/ 'lev' /), 'I', '#/kg', &
527 : 'Input cloud ice number concentration')
528 : call addfld('AKM_CLUBB', (/ 'ilev' /), 'I', '(kg/kg)/s', &
529 : 'Exact Kessler autoconversion')
530 : call addfld('AKM_LH_CLUBB', (/ 'ilev' /), 'I', '(kg/kg)/s', &
531 : 'Monte Carlo estimate of Kessler autoconversion')
532 : call addfld('INVS_EXNER', (/ 'lev' /), 'I', 'none', &
533 : 'inverse EXNER function from state in subcol_SILHS')
534 : call addfld('SILHS_ZTODT', horiz_only, 'I', 's', &
535 : 'Length of Physics timestep (for debugging)')
536 : if ( subcol_SILHS_constrainmn ) then
537 : call addfld('SILHS_MSC_CLDICE', (/ 'lev' /), 'A', 'kg/kg', &
538 : 'Mean Cloud Ice across subcolumns')
539 : call addfld('SILHS_STDSC_CLDICE', (/ 'lev' /), 'A', 'kg/kg', &
540 : 'Standard deviation of Ice across subcolumns')
541 : if ( ixsnow > 0 ) then
542 : call addfld('SILHS_MSC_CLDLIQ', (/ 'lev' /), 'A', 'kg/kg', &
543 : 'Mean Cloud Liquid across subcolumns')
544 : call addfld('SILHS_STDSC_CLDLIQ', (/ 'lev' /), 'A', 'kg/kg', &
545 : 'Standard deviation of Liquid across subcolumns')
546 : call addfld('SILHS_MSC_Q', (/ 'lev' /), 'A', 'kg/kg', &
547 : 'Mean water vapor across subcolumns')
548 : call addfld('SILHS_STDSC_Q', (/ 'lev' /), 'A', 'kg/kg', &
549 : 'Standard deviation of water vapor across subcolumns')
550 : endif ! ixsnow > 0
551 : endif ! subcol_SILHS_constrainmn
552 : call addfld('SILHS_EFF_CLDFRAC', (/ 'lev' /), 'A', 'frac', &
553 : 'Calculated cloud fraction from subcolumn liq or ice')
554 :
555 : call addfld('SILHS_CLUBB_PRECIP_FRAC', (/ 'lev' /), 'A', 'frac', &
556 : 'Precipitation fraction from CLUBB (set_up_pdf_params_incl_hydromet)')
557 : call addfld('SILHS_CLUBB_ICE_SS_FRAC', (/ 'lev' /), 'A', 'frac', &
558 : 'Ice supersaturation fraction from CLUBB')
559 :
560 : call addfld ('QVHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Water vapor mixing ratio tendency from hole filling')
561 : call addfld ('QCHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud water mixing ratio tendency from hole filling')
562 : call addfld ('QRHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Rain water mixing ratio tendency from hole filling')
563 : call addfld ('QIHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Cloud ice mixing ratio tendency from hole filling')
564 : call addfld ('QSHFTEN', (/ 'lev' /), 'A', 'kg/kg/s', 'Snow mixing ratio tendency from hole filling')
565 : call addfld ('THFTEN', (/ 'lev' /), 'A', 'K/s', 'Temperature tendency from hole filling')
566 :
567 : #endif
568 : #endif
569 0 : end subroutine subcol_init_SILHS
570 : !==============================================================!
571 0 : subroutine init_state_subcol(state, tend, state_sc, tend_sc)
572 :
573 0 : use ppgrid, only : pver, pverp, pcols
574 :
575 : use subcol_utils, only : subcol_set_subcols
576 :
577 : implicit none
578 :
579 : type(physics_state), intent(inout) :: state
580 : type(physics_tend), intent(inout) :: tend
581 : type(physics_state), intent(inout) :: state_sc ! sub-column state
582 : type(physics_tend), intent(inout) :: tend_sc ! sub-column tend
583 :
584 : integer, dimension(pcols) :: numsubcol_arr ! To set up the state struct
585 :
586 0 : numsubcol_arr(:) = 0 ! Start over each chunk
587 0 : numsubcol_arr(:state%ngrdcol) = subcol_SILHS_numsubcol ! Only set for valid grid columns
588 0 : call subcol_set_subcols(state, tend, numsubcol_arr, state_sc, tend_sc)
589 :
590 0 : end subroutine init_state_subcol
591 : !==================================================================!
592 0 : subroutine subcol_gen_SILHS(state, tend, state_sc, tend_sc, pbuf)
593 : !-------------------------------
594 : ! This is where the subcolumns are created, and the call to
595 : ! generate_silhs_sample_mod_api
596 : ! goes out. Variables needed to make this call are pulled from the
597 : ! pbuf, from module data, and calculated based on the CAM state.
598 : !-------------------------------
599 :
600 0 : use physics_buffer, only : physics_buffer_desc, pbuf_get_index, &
601 : pbuf_get_field
602 : use time_manager, only : get_nstep
603 : use subcol_utils, only : subcol_set_subcols, subcol_set_weight
604 : use subcol_pack_mod, only : subcol_pack
605 : use phys_control, only : phys_getopts
606 : use spmd_utils, only : masterproc
607 : use shr_const_mod, only : SHR_CONST_PI, SHR_CONST_RHOFW
608 :
609 : #ifdef CLUBB_SGS
610 : #ifdef SILHS
611 : use clubb_api_module, only : setup_pdf_parameters_api, &
612 :
613 : zm2zt_api, setup_grid_heights_api, &
614 :
615 : core_rknd, &
616 :
617 : w_tol_sqd, zero_threshold, &
618 : em_min, cloud_frac_min, & ! rc_tol, &
619 :
620 : genrand_intg, genrand_init_api, &
621 :
622 : nparams, ic_K, &
623 : read_parameters_api, &
624 : Cp, Lv, &
625 : grid, setup_grid_api, &
626 : init_precip_fracs_api
627 :
628 : use silhs_api_module, only : generate_silhs_sample_api, & ! Ncn_to_Nc, &
629 : clip_transform_silhs_output_api, &
630 : est_kessler_microphys_api, &
631 : vert_decorr_coef
632 :
633 : #endif
634 : #endif
635 :
636 : ! CAM data structures
637 : type(physics_state), intent(inout) :: state
638 : type(physics_tend), intent(inout) :: tend
639 : type(physics_state), intent(inout) :: state_sc ! sub-column state
640 : type(physics_tend), intent(inout) :: tend_sc ! sub-column tend
641 : type(physics_buffer_desc), pointer :: pbuf(:)
642 :
643 : #ifdef CLUBB_SGS
644 : #ifdef SILHS
645 : !----------------
646 : ! Local variables
647 : !----------------
648 : logical, parameter :: &
649 : l_implemented = .true. ! Implemented in a host model
650 : logical, parameter :: rx_Nc = .false. ! Use NC calculated based on grid mean effective radius
651 : integer, parameter :: &
652 : grid_type = 3 ! The 3 grid centered on momentum levels
653 : real(r8), parameter :: cldmin = 0.001_r8 ! To use when cld frac = 0.0 to be consistant with micro_mg
654 : real(r8), parameter :: min_num_conc = 1.0e-12_r8
655 : real(r8), parameter :: qsmall = 1.0e-18_r8 ! Microphysics cut-off for cloud
656 :
657 : integer :: i, j, k, ngrdcol, ncol, lchnk, stncol
658 : real(r8) :: sfc_elevation(state%ngrdcol) ! Surface elevation
659 :
660 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: zt_g, zi_g ! Thermo & Momentum grids for clubb
661 :
662 : real(r8), dimension(pverp) :: scfrac ! cloud fraction based on sc distributions
663 : real(r8) :: msc, std, maxcldfrac, maxsccldfrac
664 : real(r8) :: scale = 1.0_r8
665 :
666 : real(r8) :: c_K ! CLUBB parameter c_K (for eddy diffusivity)
667 :
668 : integer( kind = genrand_intg ) :: &
669 : lh_seed ! Seed used in random number generator that will be different
670 : ! for each column, yet reproducible for a restart run
671 :
672 : !----------------
673 : ! Required for set_up_pdf_params_incl_hydromet
674 : !----------------
675 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: cld_frac_in ! Cloud fraction
676 :
677 : real(r8), dimension(state%ngrdcol, pverp-top_lev+1, pdf_dim, pdf_dim) :: &
678 : corr_array_1, corr_array_2 ! Correlation matrix for pdf components
679 :
680 : real(r8), dimension(state%ngrdcol, pverp-top_lev+1, pdf_dim) :: &
681 : mu_x_1, mu_x_2, & ! Mean array for PDF components
682 : sigma_x_1, sigma_x_2 ! Std dev arr for PDF components
683 :
684 : real(r8), dimension(state%ngrdcol, pverp-top_lev+1, pdf_dim, pdf_dim) :: &
685 : corr_cholesky_mtx_1, corr_cholesky_mtx_2 ! Transposed corr cholesky mtx
686 :
687 : real(r8), dimension(state%ngrdcol, pverp-top_lev+1) :: Nc_in_cloud
688 : real(r8), dimension(state%ngrdcol, pverp-top_lev+1) :: ice_supersat_frac_in
689 : real(r8), dimension(state%ngrdcol, pverp-top_lev+1, hydromet_dim) :: hydrometp2
690 :
691 :
692 : !----------------
693 : ! Input to generate_silhs_sample
694 : !----------------
695 : integer :: iter ! CLUBB iteration
696 : integer :: num_subcols ! Number of subcolumns
697 : integer, parameter :: sequence_length = 1 ! Number of timesteps btn subcol calls
698 :
699 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: rho_ds_zt ! Dry static density (kg/m^3) on thermo levs
700 : real(r8), dimension(state%ngrdcol,pver) :: dz_g ! thickness of layer
701 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: delta_zm ! Difference in u wind altitudes
702 :
703 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1,hydromet_dim) :: hydromet ! Hydrometeor species
704 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1,hydromet_dim) :: wphydrometp ! Hydrometeor flux
705 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: Ncm ! Mean cloud droplet concentration, <N_c>
706 :
707 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: tke ! TKE
708 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: khzm ! Eddy diffusivity coef
709 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: Lscale_zm ! CLUBB's length scale on momentum (zm) levels
710 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: Lscale ! CLUBB's length scale
711 :
712 : logical, parameter :: &
713 : l_calc_weights_all_levs = .false. ! .false. if all time steps use the same
714 : ! weights at all vertical grid levels
715 : logical :: &
716 : l_calc_weights_all_levs_itime, & ! .true. if we calculate sample weights separately at all
717 : ! grid levels at the current time step
718 : l_rad_itime ! .true. if we calculate radiation at the current time step
719 :
720 : !---------------
721 : !Output from generate_silhs_sample
722 : !--------------
723 : real(r8), dimension(state%ngrdcol,subcol_SILHS_numsubcol,pverp-top_lev+1,pdf_dim) :: X_nl_all_levs ! Sample transformed to normal-lognormal
724 : real(r8), dimension(state%ngrdcol,subcol_SILHS_numsubcol,pverp-top_lev+1) :: lh_sample_point_weights ! Subcolumn weights
725 : integer, dimension(state%ngrdcol,subcol_SILHS_numsubcol,pverp-top_lev+1) :: X_mixt_comp_all_levs ! Which Mixture Component
726 :
727 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1, subcol_SILHS_numsubcol) :: &
728 : rc_all_points, & ! Calculate RCM from LH output
729 : rain_all_pts, & ! Calculate Rain from LH output
730 : nrain_all_pts, & ! Calculate Rain Conc from LH
731 : snow_all_pts, & ! Calculate Snow from LH output
732 : nsnow_all_pts, & ! Calculate Snow Conc from LH
733 : w_all_points, & ! Calculate W from LH output
734 : ice_all_pts, & ! Calculate Cld Ice from LH output
735 : nice_all_pts, & ! Calculate Num cld ice from LH
736 : nclw_all_pts ! Calculate Num cld wat from LH
737 :
738 : !----------------
739 : ! Output from clip_transform_silhs_output_api
740 : !----------------
741 : real( kind = core_rknd ), dimension(state%ngrdcol,subcol_SILHS_numsubcol,pverp-top_lev+1) :: &
742 : lh_rt_clipped, & ! rt generated from silhs sample points
743 : lh_thl_clipped, & ! thl generated from silhs sample points
744 : lh_rc_clipped, & ! rc generated from silhs sample points
745 : lh_rv_clipped, & ! rv generated from silhs sample points
746 : lh_Nc_clipped ! Nc generated from silhs sample points
747 :
748 : logical, parameter :: &
749 : l_use_Ncn_to_Nc = .true. ! Whether to call Ncn_to_Nc (.true.) or not (.false.);
750 : ! Ncn_to_Nc might cause problems with the MG microphysics
751 : ! since the changes made here (Nc-tendency) are not fed into
752 : ! the microphysics
753 :
754 :
755 : !----------------
756 : ! Output to history
757 : !----------------
758 : ! V. Larson note: These variables are on the zt (full) levels: why do they
759 : ! have dimension pverp? The pverp level corresponds to the CLUBB
760 : ! below-ground level.
761 : ! The variables in this paragraph are oriented like CAM variables (k=1 is
762 : ! the model top).
763 : ! They are flipped versions of CLUBB variables, for the entire chunk.
764 : real(r8), dimension(pcols*psubcols, pverp) :: RT_lh_out
765 : real(r8), dimension(pcols*psubcols, pverp) :: THL_lh_out
766 : real(r8), dimension(pcols*psubcols, pverp) :: OMEGA_lh_out
767 : real(r8), dimension(pcols*psubcols, pverp) :: WM_lh_out
768 : real(r8), dimension(pcols*psubcols, pverp) :: RVM_lh_out
769 : real(r8), dimension(pcols*psubcols, pverp) :: RCM_lh_out
770 : real(r8), dimension(pcols*psubcols, pverp) :: NCLW_lh_out
771 : real(r8), dimension(pcols*psubcols, pverp) :: ICE_lh_out
772 : real(r8), dimension(pcols*psubcols, pverp) :: NICE_lh_out
773 : real(r8), dimension(pcols*psubcols, pverp) :: RAIN_lh_out
774 : real(r8), dimension(pcols*psubcols, pverp) :: NRAIN_lh_out
775 : real(r8), dimension(pcols*psubcols, pverp) :: SNOW_lh_out
776 : real(r8), dimension(pcols*psubcols, pverp) :: NSNOW_lh_out
777 :
778 : real(r8), dimension(state_sc%psetcols) :: weights ! Subcol weights
779 :
780 : real(r8), dimension(pcols, pver) :: meansc_ice
781 : real(r8), dimension(pcols, pver) :: stdsc_ice
782 :
783 : real(r8), dimension(pcols, pver) :: meansc_liq
784 : real(r8), dimension(pcols, pver) :: stdsc_liq
785 :
786 : real(r8), dimension(pcols, pver) :: meansc_vap
787 : real(r8), dimension(pcols, pver) :: stdsc_vap
788 : real(r8), dimension(pcols, pver) :: grmn_eff_rad
789 : real(r8), dimension(pcols, pver) :: eff_cldfrac
790 : real(r8), dimension(pcols, pver) :: precip_frac_out
791 :
792 : real(r8) :: tmp_mean, diff_mean, rcubed
793 :
794 : !----------------
795 : ! Output from Est_Kessler_microphys
796 : !----------------
797 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: lh_Akm ! Monte Carlo estimate of Kessler Autoconversion
798 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: AKm ! Exact Kessler autoconversion
799 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: AKstd ! Exact Stdev of gba Kessler
800 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: AKstd_cld ! Exact w/in cloud stdev of gba Kessler
801 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: AKm_rcm ! Exact local gba Kessler auto based on rcm
802 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: AKm_rcc ! Exact local gba Kessler based on w/in cloud rc
803 : real(r8), dimension(state%ngrdcol,pverp-top_lev+1) :: lh_rcm_avg ! LH estimate of grid box avg liquid water
804 : real(r8), dimension(pcols,pverp) :: lh_AKm_out, AKm_out
805 :
806 : !----------------
807 : ! Needed to update State
808 : !----------------
809 : real(r8), dimension(pver) :: Temp_prof ! Subcolumn LWPT converted to Abs Temp
810 : real(r8), dimension(pver) :: SE_prof ! Static Energy calculated from Abs Temp
811 : real(r8), dimension(pver) :: No_cloud = 0.0_r8 ! Clear air condensate profile
812 : real(r8), dimension(pcols, pver) :: invs_exner ! inverse exner sent to conversion codw
813 : ! pcols for output to history
814 : real(r8) :: eff_rad_coef = 1.0_r8/(4.0_r8/3.0_r8*SHR_CONST_RHOFW*SHR_CONST_PI)
815 :
816 : !----------------
817 : ! Pointers
818 : !----------------
819 : real(r8), pointer, dimension(:) :: ztodt_ptr
820 : real(r8), pointer, dimension(:,:) :: thlm ! Mean temperature
821 : real(r8), pointer, dimension(:,:) :: ice_supersat_frac ! ice cloud fraction
822 : real(r8), pointer, dimension(:,:) :: rtm ! mean moisture mixing ratio
823 : real(r8), pointer, dimension(:,:) :: cld ! CAM cloud fraction
824 : real(r8), pointer, dimension(:,:) :: alst ! CLUBB liq cloud fraction
825 : real(r8), pointer, dimension(:,:) :: qrain ! micro_mg rain from previous step
826 : real(r8), pointer, dimension(:,:) :: qsnow
827 : real(r8), pointer, dimension(:,:) :: nrain ! micro_mg rain num conc
828 : real(r8), pointer, dimension(:,:) :: nsnow
829 :
830 : real(r8), pointer, dimension(:,:) :: tke_in ! TKE
831 : real(r8), pointer, dimension(:,:) :: khzm_in ! Eddy diffusivity coef
832 :
833 : logical, parameter :: l_est_kessler_microphys = .false.
834 : logical, parameter :: l_outfld_subcol = .false.
835 :
836 : type(grid) :: gr
837 :
838 : type(precipitation_fractions) :: precip_fracs
839 :
840 : ! Used as shortcuts to avoid typing hm_metadata%iiPDF_xx
841 : integer :: &
842 : iiPDF_chi, iiPDF_rr, iiPDF_w, iiPDF_Nr, &
843 : iiPDF_ri, iiPDF_Ni, iiPDF_Ncn, iiPDF_rs, iiPDF_Ns, &
844 : iirr, iiNr, iirs, iiri, &
845 : iirg, iiNs, iiNi, iiNg
846 :
847 : !------------------------------------------------
848 : ! Begin Code
849 : !------------------------------------------------
850 :
851 : #ifdef SILHS_OPENACC
852 : if ( l_est_kessler_microphys ) then
853 : call endrun('subcol_gen error: compilation with OpenACC requires l_est_kessler_microphys = .false.')
854 : end if
855 :
856 : if ( subcol_SILHS_constrainmn ) then
857 : call endrun('subcol_gen error: compilation with OpenACC requires subcol_SILHS_constrainmn = .false.')
858 : end if
859 :
860 : if ( subcol_SILHS_weight ) then
861 : call endrun('subcol_gen error: Importance sampling is not enabled for SILHS when using OpenACC. Set subcol_SILHS_weight to false.')
862 : end if
863 : #endif
864 :
865 : if (.not. allocated(state_sc%lat)) then
866 : call endrun('subcol_gen error: state_sc must be allocated before calling subcol_gen')
867 : end if
868 :
869 : if( rx_Nc ) then
870 : call endrun('subcol_gen_SILHS: rx_Nc not enabled')
871 : endif
872 :
873 : if (subcol_SILHS_meanice) then
874 : call endrun('subcol_gen_SILHS: subcol_SILHS_meanice = T not currently available')
875 : end if
876 :
877 : ! Determine num of columns and which chunk we're working on and what timestep
878 : ngrdcol = state%ngrdcol
879 : ncol = state%ncol
880 : lchnk = state%lchnk
881 : iter = get_nstep() ! #KTCtodo: The model iteration is passed into SILHS without taking
882 : ! substepping into account. I may need to change this in
883 : ! the future. Also, why does SILHS need an iter, but CLUBB
884 : ! does not?
885 : ! #ERDBG: The model iteration number is not used in SILHS unless
886 : ! sequence_length > 1, but nobody runs with that option.
887 :
888 : ! Copy hm_metadata indices to shortcuts
889 : iiPDF_chi = hm_metadata%iiPDF_chi
890 : iiPDF_Ncn = hm_metadata%iiPDF_Ncn
891 : iiPDF_rr = hm_metadata%iiPDF_rr
892 : iiPDF_w = hm_metadata%iiPDF_w
893 : iiPDF_Nr = hm_metadata%iiPDF_Nr
894 : iiPDF_ri = hm_metadata%iiPDF_ri
895 : iiPDF_Ni = hm_metadata%iiPDF_Ni
896 : iiPDF_rs = hm_metadata%iiPDF_rs
897 : iiPDF_Ns = hm_metadata%iiPDF_Ns
898 : iirr = hm_metadata%iirr
899 : iiNr = hm_metadata%iiNr
900 : iirs = hm_metadata%iirs
901 : iiri = hm_metadata%iiri
902 : iirg = hm_metadata%iirg
903 : iiNs = hm_metadata%iiNs
904 : iiNi = hm_metadata%iiNi
905 : iiNg = hm_metadata%iiNg
906 :
907 : !----------------
908 : ! Establish associations between pointers and physics buffer fields
909 : !----------------
910 : call pbuf_get_field(pbuf, thlm_idx, thlm)
911 : call pbuf_get_field(pbuf, ztodt_idx, ztodt_ptr)
912 : call pbuf_get_field(pbuf, ice_supersat_idx, ice_supersat_frac)
913 : call pbuf_get_field(pbuf, rtm_idx, rtm)
914 : call pbuf_get_field(pbuf, alst_idx, alst)
915 : call pbuf_get_field(pbuf, cld_idx, cld)
916 : call pbuf_get_field(pbuf, qrain_idx, qrain)
917 : call pbuf_get_field(pbuf, qsnow_idx, qsnow)
918 : call pbuf_get_field(pbuf, nrain_idx, nrain)
919 : call pbuf_get_field(pbuf, nsnow_idx, nsnow)
920 : call pbuf_get_field(pbuf, tke_idx, tke_in)
921 : call pbuf_get_field(pbuf, kvh_idx, khzm_in)
922 :
923 : ! Pull c_K from clubb parameters.
924 : c_K = clubb_params_single_col(ic_K)
925 :
926 : !----------------
927 : ! Copy state and populate numbers and values of sub-columns
928 : !----------------
929 : ztodt = ztodt_ptr(1)
930 : num_subcols = subcol_SILHS_numsubcol
931 :
932 : ! The number of vertical grid levels used in CLUBB is pverp, which is originally
933 : ! set in the call to setup_clubb_core_api from subroutine clubb_ini_cam. This
934 : ! is stored in CLUBB in the object gr%nz. This isn't changed in CLUBB.
935 : ! However, when SILHS is used, SILHS only uses pverp - top_lev + 1 vertical grid
936 : ! levels and also uses the gr%nz object. The value of gr%nz needs to be reset
937 : ! for SILHS here and then set again for CLUBB in subroutine clubb_tend_cam.
938 : gr%nz = pverp - top_lev + 1
939 :
940 : ! Calculate sample weights separately at all grid levels when
941 : ! radiation is not called
942 : l_calc_weights_all_levs_itime = .false. ! subcol_utils cannot compute weighted avgs
943 : ! when the weights vary with height.
944 : ! Don't set to true until this is fixed!!
945 :
946 :
947 : ! Setup the CLUBB vertical grid object. This must be done for each
948 : ! column as the z-distance between hybrid pressure levels can
949 : ! change easily.
950 : ! Define the CLUBB momentum grid (in height, units of m)
951 : do k = 1, pverp-top_lev+1
952 : do i = 1, ngrdcol
953 : zi_g(i,k) = state%zi(i,pverp-k+1)-state%zi(i,pverp)
954 : end do
955 : end do
956 :
957 :
958 : ! Define the CLUBB thermodynamic grid (in units of m)
959 : do k = 1, pver-top_lev+1
960 : do i = 1, ngrdcol
961 : zt_g(i,k+1) = state%zm(i,pver-k+1)-state%zi(i,pverp)
962 :
963 : ! Thermodynamic ghost point is below surface
964 : zt_g(i,1) = -1._r8*zt_g(i,2)
965 : end do
966 : end do
967 :
968 : do i=1, ncol
969 : ! Set the elevation of the surface
970 : sfc_elevation(i) = state%zi(i,pver+1)
971 : end do
972 :
973 : ! Heights need to be set at each timestep.
974 : call setup_grid_api( pverp+1-top_lev, ncol, sfc_elevation(1:ncol), l_implemented, & ! intent(in)
975 : grid_type, zi_g(1:ncol,2), zi_g(1:ncol,1), zi_g(1:ncol,pverp+1-top_lev), & ! intent(in)
976 : zi_g(1:ncol,:), zt_g(1:ncol,:), & ! intent(in)
977 : gr )
978 :
979 : ! Calculate the distance between grid levels on the host model grid,
980 : ! using host model grid indices.
981 : do k = top_lev, pver
982 : do i = 1, ngrdcol
983 : dz_g(i,k) = state%zi(i,k)-state%zi(i,k+1)
984 : end do
985 : end do
986 :
987 : ! Inverse delta_zm is required for the 3-level L-scale averaging
988 : do k = 1, pver-top_lev+1
989 : do i = 1, ngrdcol
990 : delta_zm(i,k+1) = state%zi(i,pverp-k)-state%zi(i,pverp-k+1)
991 :
992 : ! Handle CLUBB sub-sfc ghost point as done in clubb grid_class.F90
993 : delta_zm(i,1) = delta_zm(i,2)
994 : end do
995 : end do
996 :
997 : ! Compute dry static density on CLUBB vertical grid
998 : do k = 1, pver-top_lev+1
999 : do i = 1, ngrdcol
1000 : rho_ds_zt(i,k+1) = (rga)*state%pdel(i,pverp-k)/dz_g(i,pverp-k)
1001 :
1002 : ! CLUBB ghost point under the surface
1003 : rho_ds_zt(i,1) = rho_ds_zt(i,2)
1004 : end do
1005 : end do
1006 :
1007 : ! Set up hydromet array, flipped from CAM vert grid to CLUBB
1008 : if ( iirr > 0 ) then
1009 : ! If ixrain and family are greater than zero, then MG2 is
1010 : ! being used, and rain and snow are part of state. Otherwise,
1011 : ! diagnostic rain and snow from MG1 are used in hydromet.
1012 : if (ixrain > 0) then
1013 : do k = 1, pver-top_lev+1
1014 : do i = 1, ngrdcol
1015 : hydromet(i,k+1,iirr) = state%q(i,pver-k+1,ixrain)
1016 : end do
1017 : end do
1018 : else
1019 : do k = 1, pver-top_lev+1
1020 : do i = 1, ngrdcol
1021 : hydromet(i,k+1,iirr) = qrain(i,pver-k+1)
1022 : end do
1023 : end do
1024 : endif
1025 : endif
1026 :
1027 : if ( iiNr > 0 ) then
1028 : if (ixnumrain > 0) then
1029 : do k = 1, pver-top_lev+1
1030 : do i = 1, ngrdcol
1031 : hydromet(i,k+1,iiNr) = state%q(i,pver-k+1,ixnumrain)
1032 : end do
1033 : end do
1034 : else
1035 : do k = 1, pver-top_lev+1
1036 : do i = 1, ngrdcol
1037 : hydromet(i,k+1,iiNr) = nrain(i,pver-k+1)
1038 : end do
1039 : end do
1040 : endif
1041 : endif
1042 :
1043 : if ( iirs > 0 ) then
1044 : if (ixsnow > 0) then
1045 : do k = 1, pver-top_lev+1
1046 : do i = 1, ngrdcol
1047 : hydromet(i,k+1,iirs) = state%q(i,pver-k+1,ixsnow)
1048 : end do
1049 : end do
1050 : else
1051 : do k = 1, pver-top_lev+1
1052 : do i = 1, ngrdcol
1053 : hydromet(i,k+1,iirs) = qsnow(i,pver-k+1)
1054 : end do
1055 : end do
1056 : endif
1057 : endif
1058 :
1059 : if ( iiNs > 0 ) then
1060 : if (ixnumsnow > 0) then
1061 : do k = 1, pver-top_lev+1
1062 : do i = 1, ngrdcol
1063 : hydromet(i,k+1,iiNs) = state%q(i,pver-k+1,ixnumsnow)
1064 : end do
1065 : end do
1066 : else
1067 : do k = 1, pver-top_lev+1
1068 : do i = 1, ngrdcol
1069 : hydromet(i,k+1,iiNs) = nsnow(i,pver-k+1)
1070 : end do
1071 : end do
1072 : endif
1073 : endif
1074 :
1075 : if ( iiri > 0 ) then
1076 : do k = 1, pver-top_lev+1
1077 : do i = 1, ngrdcol
1078 : hydromet(i,k+1,iiri) = state%q(i,pver-k+1,ixcldice)
1079 : end do
1080 : end do
1081 : endif
1082 :
1083 : if ( iiNi > 0 ) then
1084 : do k = 1, pver-top_lev+1
1085 : do i = 1, ngrdcol
1086 : hydromet(i,k+1,iiNi) = state%q(i,pver-k+1,ixnumice)
1087 : end do
1088 : end do
1089 : endif
1090 :
1091 : do k = 1, hydromet_dim ! ghost point below the surface
1092 : do i = 1, ngrdcol
1093 : hydromet(i,1,k) = hydromet(i,2,k)
1094 : end do
1095 : end do
1096 :
1097 : do k = 1, pver-top_lev+1
1098 : do i = 1, ngrdcol
1099 : Ncm(i,k+1) = state%q(i,pver-k+1,ixnumliq)
1100 : Ncm(i,1) = Ncm(i,2)
1101 : end do
1102 : end do
1103 :
1104 : ! Convert from CAM vertical grid to CLUBB
1105 : do k = 1, pverp-top_lev+1
1106 : do i = 1, ngrdcol
1107 : ice_supersat_frac_in(i,k) = ice_supersat_frac(i,pverp-k+1)
1108 : end do
1109 : end do
1110 :
1111 :
1112 : do k = 1, pver-top_lev+1
1113 : do i = 1, ngrdcol
1114 : cld_frac_in(i,k+1) = alst(i,pver-k+1)
1115 : cld_frac_in(i,1) = cld_frac_in(i,2) ! Ghost pt below surface
1116 : end do
1117 : end do
1118 :
1119 : ! Calculate a clubb-specific exner function
1120 : ! (This is grid mean, as pressure levels do not change in
1121 : ! the subcolumn state)
1122 : do k = 1, pver-top_lev+1
1123 : do i = 1, ngrdcol
1124 : invs_exner(i,k) = ((state%pmid(i,k)/p0_clubb)**(cappa))
1125 : end do
1126 : end do
1127 :
1128 : ! Call setup_pdf_parameters to get the CLUBB PDF ready for SILHS
1129 : ! Compute Num concentration of cloud nuclei
1130 : do k = 1, pverp-top_lev+1
1131 : do i = 1, ngrdcol
1132 : Nc_in_cloud(i,k) = Ncm(i,k) / max( cld_frac_in(i,k), cloud_frac_min )
1133 : end do
1134 : end do
1135 :
1136 : ! The variable wphydrometp is only used when l_calc_w_corr is enabled.
1137 : ! The l_calc_w_corr flag is turned off by default, so wphydrometp will
1138 : ! simply be set to 0 to simplify matters.
1139 : wphydrometp = 0.0_r8
1140 :
1141 : do k = 1, pverp-top_lev+1
1142 : do i = 1, ngrdcol
1143 : khzm(i,k) = khzm_in(i,pverp-k+1)
1144 : end do
1145 : end do
1146 :
1147 : ! Allocate 2D arrays in precip_fracs for all grid columns and vertical levels
1148 : call init_precip_fracs_api( pverp-top_lev+1, ngrdcol, &
1149 : precip_fracs )
1150 :
1151 : call setup_pdf_parameters_api( gr, pverp-top_lev+1, ngrdcol, pdf_dim, hydromet_dim, ztodt, & ! In
1152 : Nc_in_cloud, cld_frac_in, khzm, & ! In
1153 : ice_supersat_frac_in, hydromet, wphydrometp, & ! In
1154 : corr_array_n_cloud, corr_array_n_below, & ! In
1155 : hm_metadata, & ! In
1156 : pdf_params_chnk(lchnk), & ! In
1157 : clubb_params_single_col, & ! In
1158 : clubb_config_flags%iiPDF_type, & ! In
1159 : clubb_config_flags%l_use_precip_frac, & ! In
1160 : clubb_config_flags%l_predict_upwp_vpwp, & ! In
1161 : clubb_config_flags%l_diagnose_correlations, & ! In
1162 : clubb_config_flags%l_calc_w_corr, & ! In
1163 : clubb_config_flags%l_const_Nc_in_cloud, & ! In
1164 : clubb_config_flags%l_fix_w_chi_eta_correlations, & ! In
1165 : stats_metadata, & ! In
1166 : stats_zt, stats_zm, stats_sfc, & ! In
1167 : hydrometp2, & ! Inout
1168 : mu_x_1, mu_x_2, & ! Out
1169 : sigma_x_1, sigma_x_2, & ! Out
1170 : corr_array_1, corr_array_2, & ! Out
1171 : corr_cholesky_mtx_1, corr_cholesky_mtx_2, & ! Out
1172 : precip_fracs ) ! Inout
1173 :
1174 : ! In order for Lscale to be used properly, it needs to be passed out of
1175 : ! advance_clubb_core, saved to the pbuf, and then pulled out of the
1176 : ! pbuf for use here. The profile of Lscale is passed into subroutine
1177 : ! generate_silhs_sample_api for use in calculating the vertical
1178 : ! correlation coefficient. Rather than output Lscale directly, its
1179 : ! value can be calculated from other fields that are already output to
1180 : ! pbuf. The equation relating Lscale to eddy diffusivity is:
1181 : !
1182 : ! Kh = c_K * Lscale * sqrt( TKE ).
1183 : !
1184 : ! Both Kh and TKE are written to the pbuf, and c_K is easily extracted
1185 : ! from CLUBB's tunable parameters. The equation for Lscale is:
1186 : !
1187 : ! Lscale = Kh / ( c_K * sqrt( TKE ) ).
1188 : !
1189 : ! Since Kh and TKE are output on momentum (interface) grid levels, the
1190 : ! resulting calculation of Lscale is also found on momentum levels. It
1191 : ! needs to be interpolated back to thermodynamic (midpoint) grid levels
1192 : ! for further use.
1193 : do k = 1, pverp-top_lev+1
1194 : do i = 1, ngrdcol
1195 : tke(i,k) = tke_in(i,pverp-k+1)
1196 : end do
1197 : end do
1198 :
1199 : do k = 1, pverp-top_lev+1
1200 : do i = 1, ngrdcol
1201 : Lscale_zm(i,k) = khzm(i,k) / ( c_K * sqrt( max( tke(i,k), em_min ) ) )
1202 : end do
1203 : end do
1204 :
1205 : do i = 1, ngrdcol
1206 : Lscale(i,1) = Lscale_zm(i,1) + ( Lscale_zm(i,2) - Lscale_zm(i,1) ) &
1207 : * ( zt_g(i,1) - zi_g(i,1) ) / ( zi_g(i,2) - zi_g(i,1) )
1208 : end do
1209 :
1210 : do k = 2, pverp-top_lev+1
1211 : do i = 1, ngrdcol
1212 : Lscale(i,k) = Lscale_zm(i,k-1) + ( Lscale_zm(i,k) - Lscale_zm(i,k-1) ) &
1213 : * ( zt_g(i,k) - zi_g(i,k-1) ) / ( zi_g(i,k) - zi_g(i,k-1) )
1214 : end do
1215 : end do
1216 :
1217 : do k = 2, pverp-top_lev+1
1218 : do i = 1, ngrdcol
1219 : Lscale(i,:) = max( Lscale(i,:), 0.01_r8 )
1220 : end do
1221 : end do
1222 :
1223 : !$acc data create( X_mixt_comp_all_levs, X_nl_all_levs, lh_rc_clipped, lh_Nc_clipped, &
1224 : !$acc& lh_sample_point_weights, lh_rt_clipped, lh_rt_clipped, &
1225 : !$acc& lh_rv_clipped, lh_thl_clipped, THL_lh_out, &
1226 : !$acc& RT_lh_out, RCM_lh_out, NCLW_lh_out, ICE_lh_out, &
1227 : !$acc& NICE_lh_out, RVM_lh_out, THL_lh_out, RAIN_lh_out, &
1228 : !$acc& NRAIN_lh_out, SNOW_lh_out, NSNOW_lh_out, WM_lh_out, &
1229 : !$acc& OMEGA_lh_out ) &
1230 : !$acc& copyin( state, state%zm, state%phis, rho_ds_zt, invs_exner ) &
1231 : !$acc& copyout( state%t, state%s, state%omega, state_sc%q )
1232 : !$acc& async(1)
1233 :
1234 : ! Set the seed to the random number generator based on a quantity that
1235 : ! will be reproducible for restarts.
1236 : lh_seed = int( 1.0e4_r8 * rtm(1,pver), kind = genrand_intg )
1237 :
1238 : ! Let's generate some subcolumns!!!!!
1239 : call generate_silhs_sample_api( &
1240 : iter, pdf_dim, num_subcols, sequence_length, pverp-top_lev+1, ngrdcol, & ! In
1241 : l_calc_weights_all_levs_itime, & ! In
1242 : pdf_params_chnk(lchnk), delta_zm, Lscale, & ! In
1243 : lh_seed, hm_metadata, & ! In
1244 : rho_ds_zt, & ! In
1245 : mu_x_1, mu_x_2, sigma_x_1, sigma_x_2, & ! In
1246 : corr_cholesky_mtx_1, corr_cholesky_mtx_2, & ! In
1247 : precip_fracs, silhs_config_flags, & ! In
1248 : vert_decorr_coef, & ! In
1249 : stats_metadata, & ! In
1250 : stats_lh_zt, stats_lh_sfc, & ! InOut
1251 : X_nl_all_levs, X_mixt_comp_all_levs, & ! Out
1252 : lh_sample_point_weights) ! Out
1253 :
1254 : ! Extract clipped variables from subcolumns
1255 : call clip_transform_silhs_output_api( gr, pverp-top_lev+1, ngrdcol, num_subcols, & ! In
1256 : pdf_dim, hydromet_dim, hm_metadata, & ! In
1257 : X_mixt_comp_all_levs, & ! In
1258 : X_nl_all_levs, & ! In
1259 : pdf_params_chnk(lchnk), & ! In
1260 : l_use_Ncn_to_Nc, & ! In
1261 : lh_rt_clipped, lh_thl_clipped, & ! Out
1262 : lh_rc_clipped, lh_rv_clipped, & ! Out
1263 : lh_Nc_clipped ) ! Out
1264 : !$acc wait
1265 :
1266 : if ( l_est_kessler_microphys ) then
1267 : call endrun('subcol_SILHS: l_est_kessler_microphys = T is not currently supported')
1268 : end if
1269 :
1270 : !-------------------------------------------------------------------------
1271 : ! Convert from CLUBB vertical grid to CAM grid
1272 : !------------------------------------------------------------------------
1273 : ! This kernel is executed in stream 1:
1274 : !$acc parallel loop collapse(3) default(present) async(1)
1275 : do k = top_lev, pverp
1276 : do j = 1, num_subcols
1277 : do i = 1, ngrdcol
1278 : RT_lh_out( num_subcols*(i-1)+j,k ) = lh_rt_clipped(i,j,pverp-k+1)
1279 : RCM_lh_out( num_subcols*(i-1)+j,k ) = lh_rc_clipped(i,j,pverp-k+1)
1280 : NCLW_lh_out( num_subcols*(i-1)+j,k ) = lh_Nc_clipped(i,j,pverp-k+1)
1281 : RVM_lh_out( num_subcols*(i-1)+j,k ) = lh_rv_clipped(i,j,pverp-k+1)
1282 : THL_lh_out( num_subcols*(i-1)+j,k ) = lh_thl_clipped(i,j,pverp-k+1)
1283 : end do
1284 : end do
1285 : end do
1286 :
1287 : ! This kernel is executed in stream 2:
1288 : !$acc parallel loop collapse(3) default(present) async(2)
1289 : do k = top_lev, pverp
1290 : do j = 1, num_subcols
1291 : do i = 1, ngrdcol
1292 : ICE_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_ri)
1293 : NICE_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_Ni)
1294 : RAIN_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_rr)
1295 : NRAIN_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_Nr)
1296 : SNOW_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_rs)
1297 : NSNOW_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_Ns)
1298 : WM_lh_out( num_subcols*(i-1)+j,k ) = X_nl_all_levs(i,j,pverp-k+1,iiPDF_w)
1299 : end do
1300 : end do
1301 : end do
1302 :
1303 : ! This kernel is executed in stream 2 because WM_lh_out comes from stream 2:
1304 : !$acc parallel loop collapse(3) default(present) async(2)
1305 : do k = top_lev, pverp
1306 : do j = 1, num_subcols
1307 : do i = 1, ngrdcol
1308 : OMEGA_lh_out( num_subcols*(i-1)+j,k ) = -1._r8 * WM_lh_out(num_subcols*(i-1)+j,k) &
1309 : * rho_ds_zt(i,pverp-k+1) * gravit
1310 : end do
1311 : end do
1312 : end do
1313 :
1314 : if ( l_est_kessler_microphys ) then
1315 : do k = top_lev, pverp
1316 : do j = 1, num_subcols
1317 : do i = 1, ngrdcol
1318 : AKm_out(i,k) = AKm(i,pverp-k+1)
1319 : lh_AKm_out(i,k) = lh_AKm(i,pverp-k+1)
1320 : end do
1321 : end do
1322 : end do
1323 : end if
1324 :
1325 : ! Pack up weights
1326 : ! Using grid level 2 always won't work if weights vary with height.
1327 : call subcol_pack(lchnk, lh_sample_point_weights(:,:,2), weights )
1328 : call subcol_set_weight(lchnk, weights)
1329 :
1330 : ! Constrain the sample distribution of cloud water and ice to the same mean
1331 : ! as the grid to prevent negative condensate errors
1332 : if(subcol_SILHS_constrainmn) then
1333 :
1334 : do i = 1, ngrdcol
1335 :
1336 : stncol = num_subcols*(i-1)
1337 :
1338 : call subcol_constrainmn( num_subcols, ICE_lh_out(stncol+1:stncol+num_subcols,:), &
1339 : weights(stncol+1:stncol+num_subcols), &
1340 : state%q(i,:,ixcldice), meansc_ice(i,:), stdsc_ice(i,:) )
1341 : if ( ixrain > 0 ) &
1342 : call subcol_constrainmn( num_subcols, RAIN_lh_out(stncol+1:stncol+num_subcols,:), &
1343 : weights(stncol+1:stncol+num_subcols), &
1344 : state%q(i,:,ixrain) )
1345 : if ( ixsnow > 0 ) &
1346 : call subcol_constrainmn( num_subcols, SNOW_lh_out(stncol+1:stncol+num_subcols,:), &
1347 : weights(stncol+1:stncol+num_subcols), &
1348 : state%q(i,:,ixsnow) )
1349 : call subcol_constrainmn( num_subcols, RCM_lh_out(stncol+1:stncol+num_subcols,:), &
1350 : weights(stncol+1:stncol+num_subcols), &
1351 : state%q(i,:,ixcldliq), meansc_liq(i,:), stdsc_liq(i,:) )
1352 : call subcol_constrainmn( num_subcols, RVM_lh_out(stncol+1:stncol+num_subcols,:), &
1353 : weights(stncol+1:stncol+num_subcols), &
1354 : state%q(i,:,ixq), meansc_vap(i,:), stdsc_vap(i,:) )
1355 : call subcol_constrainmn( num_subcols, NICE_lh_out(stncol+1:stncol+num_subcols,:), &
1356 : weights(stncol+1:stncol+num_subcols), &
1357 : state%q(i,:,ixnumice) )
1358 : if ( ixnumrain > 0 ) &
1359 : call subcol_constrainmn( num_subcols, NRAIN_lh_out(stncol+1:stncol+num_subcols,:), &
1360 : weights(stncol+1:stncol+num_subcols), &
1361 : state%q(i,:,ixnumrain) )
1362 : if ( ixnumsnow > 0 ) &
1363 : call subcol_constrainmn( num_subcols, NSNOW_lh_out(stncol+1:stncol+num_subcols,:), &
1364 : weights(stncol+1:stncol+num_subcols), &
1365 : state%q(i,:,ixnumsnow) )
1366 : call subcol_constrainmn( num_subcols, NCLW_lh_out(stncol+1:stncol+num_subcols,:), &
1367 : weights(stncol+1:stncol+num_subcols), &
1368 : state%q(i,:,ixnumliq) )
1369 : do k = top_lev, pver
1370 : ! Look for exceptionally large values of condensate
1371 : if(ANY(ICE_lh_out(stncol+1:stncol+num_subcols,k) .gt. 0.01_r8)) then
1372 : ! Clip the large values
1373 : where(ICE_lh_out(stncol+1:stncol+num_subcols,k) .gt. 0.01_r8)
1374 : ICE_lh_out(stncol+1:stncol+num_subcols,k) = 0.01_r8
1375 : NICE_lh_out(stncol+1:stncol+num_subcols,k) = 1.5e+7_r8
1376 : end where
1377 : ! Recalculate the weighted subcolumn mean
1378 : tmp_mean = meansc( ICE_lh_out( stncol+1:stncol+num_subcols, k ), &
1379 : weights(stncol+1:stncol+num_subcols), &
1380 : real(num_subcols,r8) )
1381 : ! Calculate the difference between the weighted mean and grid mean
1382 : diff_mean = state%q(i,k,ixcldice)-tmp_mean
1383 : ! Add the difference to each subcolumn
1384 : ICE_lh_out(stncol+1:stncol+num_subcols,k) = &
1385 : ICE_lh_out(stncol+1:stncol+num_subcols,k)+diff_mean
1386 : ! Recalculate the weight subcolumn mean for ice num conc
1387 : tmp_mean = meansc( NICE_lh_out( stncol+1:stncol+num_subcols, k ), &
1388 : weights(stncol+1:stncol+num_subcols), &
1389 : real(num_subcols,r8) )
1390 : ! Calculate the difference between the weighted mean and grid mean
1391 : diff_mean = state%q(i,k,ixnumice)-tmp_mean
1392 : ! Add the difference to each subcolumn
1393 : if(diff_mean.gt.0.0_r8) then
1394 : NICE_lh_out(stncol+1:stncol+num_subcols,k) = &
1395 : NICE_lh_out(stncol+1:stncol+num_subcols,k)+diff_mean
1396 : else ! just use the grid mean in each subcolumn
1397 : NICE_lh_out(stncol+1:stncol+num_subcols,k) = &
1398 : state%q(i,k,ixnumice)
1399 : end if
1400 : ! Test adjusted means for debugging
1401 : tmp_mean = meansc( ICE_lh_out( stncol+1:stncol+num_subcols, k ), &
1402 : weights(stncol+1:stncol+num_subcols), &
1403 : real(num_subcols,r8) )
1404 : diff_mean = state%q(i,k,ixcldice)-tmp_mean
1405 : tmp_mean = meansc( NICE_lh_out( stncol+1:stncol+num_subcols, k ), &
1406 : weights(stncol+1:stncol+num_subcols), &
1407 : real(num_subcols,r8) )
1408 : diff_mean = state%q(i,k,ixnumice)-tmp_mean
1409 : endif
1410 : end do ! k = top_lev, pver
1411 : end do
1412 : endif ! subcol_silhs_constrainm
1413 :
1414 :
1415 : !---------------------------------------------------
1416 : ! Updating state variables
1417 : !---------------------------------------------------
1418 : ! Code to update the state variables for interactive runs
1419 : ! This kernel is executed in stream 3, but waits for stream 1
1420 : ! because THL_lh_out and RCM_lh_out come from stream 1:
1421 : !$acc parallel loop collapse(3) default(present) wait(1) async(3)
1422 : do k = 1, pver-top_lev+1
1423 : do j = 1, num_subcols
1424 : do i = 1, ngrdcol
1425 :
1426 : state_sc%t(num_subcols*(i-1)+j,k) = THL_lh_out(num_subcols*(i-1)+j,k) * invs_exner(i,k) &
1427 : + Lv * RCM_lh_out(num_subcols*(i-1)+j,k) / Cp
1428 :
1429 : state_sc%s(num_subcols*(i-1)+j,k) = cpair * state_sc%t(num_subcols*(i-1)+j,k) &
1430 : + gravit * state%zm(i,k) + state%phis(i)
1431 : end do
1432 : end do
1433 : end do
1434 :
1435 : ! This kernel is executed in stream 4, but waits for stream 1 and 2
1436 : ! because RVM_lh_out is from stream 1 and OMEGA_lh_out is from stream 2:
1437 : !$acc parallel loop collapse(3) default(present) wait(1,2) async(4)
1438 : do k = 1, pver-top_lev+1
1439 : do j = 1, num_subcols
1440 : do i = 1, ngrdcol
1441 : ! Vertical Velocity is not part of the energy conservation checks, but
1442 : ! we need to be careful here, because the SILHS output VV is noisy.
1443 : state_sc%omega(num_subcols*(i-1)+j,k) = OMEGA_lh_out(num_subcols*(i-1)+j,k)
1444 : state_sc%q(num_subcols*(i-1)+j,k,ixq) = RVM_lh_out(num_subcols*(i-1)+j,k)
1445 : end do
1446 : end do
1447 : end do
1448 :
1449 :
1450 : if (subcol_SILHS_q_to_micro) then ! Send SILHS predicted constituents to microp
1451 :
1452 : ! This kernel is executed in stream 5, but waits for stream 1 and 2
1453 : ! because RCM_lh_out is from stream 1 and ICE_lh_out is from stream 2:
1454 : !$acc parallel loop collapse(3) default(present) wait(1,2) async(5)
1455 : do k = 1, pver-top_lev+1
1456 : do j = 1, num_subcols
1457 : do i = 1, ngrdcol
1458 : state_sc%q(num_subcols*(i-1)+j,k,ixcldliq) = RCM_lh_out(num_subcols*(i-1)+j,k)
1459 : state_sc%q(num_subcols*(i-1)+j,k,ixcldice) = ICE_lh_out(num_subcols*(i-1)+j,k)
1460 : end do
1461 : end do
1462 : end do
1463 :
1464 : if (ixrain > 0) then
1465 : ! This kernel is executed in stream 6, but waits for stream 2
1466 : ! because RAIN_lh_out is from stream 2:
1467 : !$acc parallel loop collapse(3) default(present) wait(2) async(6)
1468 : do k = 1, pver-top_lev+1
1469 : do j = 1, num_subcols
1470 : do i = 1, ngrdcol
1471 : state_sc%q(num_subcols*(i-1)+j,k,ixrain) = RAIN_lh_out(num_subcols*(i-1)+j,k)
1472 : end do
1473 : end do
1474 : end do
1475 : end if
1476 :
1477 : if (ixsnow > 0) then
1478 : ! This kernel is executed in stream 7, but waits for stream 2
1479 : ! because SNOW_lh_out is from stream 2:
1480 : !$acc parallel loop collapse(3) default(present) wait(2) async(7)
1481 : do k = 1, pver-top_lev+1
1482 : do j = 1, num_subcols
1483 : do i = 1, ngrdcol
1484 : state_sc%q(num_subcols*(i-1)+j,k,ixsnow) = SNOW_lh_out(num_subcols*(i-1)+j,k)
1485 : end do
1486 : end do
1487 : end do
1488 : end if
1489 :
1490 : else
1491 :
1492 : do k = 1, pver-top_lev+1
1493 : do j = 1, num_subcols
1494 : do i = 1, ngrdcol
1495 : state_sc%q(num_subcols*(i-1)+j,k,ixcldliq) = state%q(i,k,ixcldliq)
1496 : state_sc%q(num_subcols*(i-1)+j,k,ixcldice) = state%q(i,k,ixcldice)
1497 : if (ixrain > 0) then
1498 : state_sc%q(num_subcols*(i-1)+j,k,ixrain) = state%q(i,k,ixrain)
1499 : end if
1500 : if (ixsnow > 0) then
1501 : state_sc%q(num_subcols*(i-1)+j,k,ixsnow) = state%q(i,k,ixsnow)
1502 : end if
1503 : end do
1504 : end do
1505 : end do
1506 :
1507 : endif
1508 :
1509 : if (subcol_SILHS_n_to_micro) then ! Send SILHS predicted number conc to microp
1510 :
1511 : ! This kernel is executed in stream 8, but waits for stream 1 and 2
1512 : ! because NCLW_lh_out is from stream 1 and NICE_lh_out is from stream 2:
1513 : !$acc parallel loop collapse(3) default(present) wait(1,2) async(8)
1514 : do k = 1, pver-top_lev+1
1515 : do j = 1, num_subcols
1516 : do i = 1, ngrdcol
1517 : state_sc%q(num_subcols*(i-1)+j,k,ixnumice) = NICE_lh_out(num_subcols*(i-1)+j,k)
1518 : state_sc%q(num_subcols*(i-1)+j,k,ixnumliq) = NCLW_lh_out(num_subcols*(i-1)+j,k)
1519 : end do
1520 : end do
1521 : end do
1522 :
1523 : if (ixnumrain > 0) then
1524 : ! This kernel is executed in stream 9, but waits for stream 2
1525 : ! because NRAIN_lh_out is from stream 2:
1526 : !$acc parallel loop collapse(3) default(present) wait(2) async(9)
1527 : do k = 1, pver-top_lev+1
1528 : do j = 1, num_subcols
1529 : do i = 1, ngrdcol
1530 : state_sc%q(num_subcols*(i-1)+j,k,ixnumrain) = NRAIN_lh_out(num_subcols*(i-1)+j,k)
1531 : end do
1532 : end do
1533 : end do
1534 : end if
1535 :
1536 : if (ixnumsnow > 0) then
1537 : ! This kernel is executed in stream 10, but waits for stream 2
1538 : ! because NSNOW_lh_out is from stream 2:
1539 : !$acc parallel loop collapse(3) default(present) wait(2) async(10)
1540 : do k = 1, pver-top_lev+1
1541 : do j = 1, num_subcols
1542 : do i = 1, ngrdcol
1543 : state_sc%q(num_subcols*(i-1)+j,k,ixnumsnow) = NSNOW_lh_out(num_subcols*(i-1)+j,k)
1544 : end do
1545 : end do
1546 : end do
1547 : end if
1548 :
1549 : else
1550 :
1551 : do k = 1, pver-top_lev+1
1552 : do j = 1, num_subcols
1553 : do i = 1, ngrdcol
1554 : state_sc%q(num_subcols*(i-1)+j,k,ixnumliq) = state%q(i,k,ixnumliq)
1555 : state_sc%q(num_subcols*(i-1)+j,k,ixnumice) = state%q(i,k,ixnumice)
1556 : if (ixnumrain > 0) then
1557 : state_sc%q(num_subcols*(i-1)+j,k,ixnumrain) = state%q(i,k,ixnumrain)
1558 : end if
1559 : if (ixnumsnow > 0) then
1560 : state_sc%q(num_subcols*(i-1)+j,k,ixnumsnow) = state%q(i,k,ixnumsnow)
1561 : end if
1562 : end do
1563 : end do
1564 : end do
1565 :
1566 : endif
1567 :
1568 : ! This kernel is executed in stream 8, because state_sc%q(:,:,ixnumliq) and
1569 : ! state_sc%q(:,:,ixnumice) are from stream 8
1570 : !$acc parallel loop collapse(3) default(present) async(8)
1571 : do k = 1, pver-top_lev+1
1572 : do j = 1, num_subcols
1573 : do i = 1, ngrdcol
1574 : ! Change liq and ice (and rain and snow) num conc zeros to min values (1e-12)
1575 : if (state_sc%q(num_subcols*(i-1)+j,k,ixnumliq) .lt. min_num_conc) then
1576 : state_sc%q(num_subcols*(i-1)+j,k,ixnumliq) = min_num_conc
1577 : end if
1578 :
1579 : if (state_sc%q(num_subcols*(i-1)+j,k,ixnumice) .lt. min_num_conc) then
1580 : state_sc%q(num_subcols*(i-1)+j,k,ixnumice) = min_num_conc
1581 : end if
1582 : end do
1583 : end do
1584 : end do
1585 :
1586 : if (ixnumrain > 0) then
1587 : ! This kernel is executed in stream 9, because state_sc%q(:,:,ixnumrain) is
1588 : ! from stream 9
1589 : !$acc parallel loop collapse(3) default(present) async(9)
1590 : do k = 1, pver-top_lev+1
1591 : do j = 1, num_subcols
1592 : do i = 1, ngrdcol
1593 : if(state_sc%q(num_subcols*(i-1)+j,k,ixnumrain) .lt. min_num_conc) then
1594 : state_sc%q(num_subcols*(i-1)+j,k,ixnumrain) = min_num_conc
1595 : end if
1596 : end do
1597 : end do
1598 : end do
1599 : endif
1600 :
1601 : if (ixnumsnow > 0) then
1602 : ! This kernel is executed in stream 10, because state_sc%q(:,:,ixnumsnow) is
1603 : ! from stream 10
1604 : !$acc parallel loop collapse(3) default(present) async(10)
1605 : do k = 1, pver-top_lev+1
1606 : do j = 1, num_subcols
1607 : do i = 1, ngrdcol
1608 : if(state_sc%q(num_subcols*(i-1)+j,k,ixnumsnow) .lt. min_num_conc) then
1609 : state_sc%q(num_subcols*(i-1)+j,k,ixnumsnow) = min_num_conc
1610 : end if
1611 : end do
1612 : end do
1613 : end do
1614 : endif
1615 :
1616 : if ( l_outfld_subcol ) then
1617 :
1618 : do k = 1, pver-top_lev+1
1619 : do i = 1, ngrdcol
1620 : do j = 1, num_subcols
1621 :
1622 : ! Calc effective cloud fraction for testing
1623 : if ( ( lh_rc_clipped(i,j,pverp-k+1) .gt. qsmall ) &
1624 : .or. ( X_nl_all_levs(i,j,pverp-k+1,iiPDF_ri) .gt. qsmall ) ) then
1625 : eff_cldfrac(i,k) = eff_cldfrac(i,k) + lh_sample_point_weights(i,j,pverp-k+1)
1626 : else
1627 : eff_cldfrac(i,k) = 0.0_r8
1628 : endif
1629 :
1630 : end do
1631 :
1632 : eff_cldfrac(i,k) = eff_cldfrac(i,k)/real(num_subcols, kind=r8)
1633 :
1634 : end do
1635 : end do
1636 :
1637 : ! Pack precip_frac for output
1638 : do k = 2, pverp-top_lev+1
1639 : do i = 1, ngrdcol
1640 : precip_frac_out(i,pver-k+2) = precip_fracs%precip_frac(i,k)
1641 : end do
1642 : end do
1643 :
1644 : call outfld( 'SILHS_THLM_SCOL', THL_lh_out, pcols*psubcols, lchnk )
1645 : call outfld( 'SILHS_RT_SCOL', RT_lh_out, pcols*psubcols, lchnk )
1646 : call outfld( 'SILHS_OMEGA_SCOL', OMEGA_lh_out, pcols*psubcols, lchnk )
1647 : call outfld( 'SILHS_WM_SCOL', WM_lh_out, pcols*psubcols, lchnk )
1648 : call outfld( 'SILHS_RCM_SCOL', RCM_lh_out, pcols*psubcols, lchnk )
1649 : call outfld( 'SILHS_RICLD_SCOL', ICE_lh_out, pcols*psubcols, lchnk )
1650 : call outfld( 'SILHS_NICLD_SCOL', NICE_lh_out, pcols*psubcols, lchnk )
1651 : call outfld( 'SILHS_NCLD_SCOL', NCLW_lh_out, pcols*psubcols, lchnk )
1652 : call outfld( 'SILHS_RRAIN_SCOL', RAIN_lh_out, pcols*psubcols, lchnk )
1653 : call outfld( 'SILHS_NRAIN_SCOL', NRAIN_lh_out, pcols*psubcols, lchnk )
1654 : call outfld( 'SILHS_WEIGHT_SCOL', weights, pcols*psubcols, lchnk )
1655 : call outfld( 'NR_IN_LH', nrain, pcols, lchnk )
1656 : call outfld( 'SILHS_RTM', rtm, pcols, lchnk )
1657 : call outfld( 'SILHS_THLM', thlm, pcols, lchnk )
1658 : call outfld( 'SILHS_QC_IN', state%q(:,:,ixcldliq), pcols, lchnk )
1659 : call outfld( 'SILHS_QI_IN', state%q(:,:,ixcldice), pcols, lchnk )
1660 : call outfld( 'SILHS_NC_IN', state%q(:,:,ixnumliq), pcols, lchnk )
1661 : call outfld( 'SILHS_NI_IN', state%q(:,:,ixnumice), pcols, lchnk )
1662 : if ( l_est_kessler_microphys ) then
1663 : call outfld( 'AKM_CLUBB', AKm_out, pcols, lchnk )
1664 : call outfld( 'AKM_LH_CLUBB', lh_AKm_out, pcols, lchnk )
1665 : end if
1666 : call outfld( 'INVS_EXNER', invs_exner, pcols, lchnk )
1667 : call outfld( 'SILHS_ZTODT', ztodt_ptr, pcols, lchnk )
1668 : if ( subcol_SILHS_constrainmn ) then
1669 : call outfld( 'SILHS_MSC_CLDICE', meansc_ice, pcols, lchnk )
1670 : call outfld( 'SILHS_STDSC_CLDICE', stdsc_ice, pcols, lchnk )
1671 : if ( ixsnow > 0 ) then
1672 : call outfld( 'SILHS_MSC_CLDLIQ', meansc_liq, pcols, lchnk )
1673 : call outfld( 'SILHS_STDSC_CLDLIQ', stdsc_liq, pcols, lchnk )
1674 : call outfld( 'SILHS_MSC_Q', meansc_vap, pcols, lchnk )
1675 : call outfld( 'SILHS_STDSC_Q', stdsc_vap, pcols, lchnk )
1676 : endif ! ixsnow > 0
1677 : endif ! subcol_SILHS_constrainmn
1678 : call outfld( 'SILHS_EFF_CLDFRAC', eff_cldfrac, pcols, lchnk )
1679 : call outfld( 'SILHS_CLUBB_PRECIP_FRAC', precip_frac_out, pcols, lchnk )
1680 : call outfld( 'SILHS_CLUBB_ICE_SS_FRAC', ice_supersat_frac, pcols, lchnk )
1681 : end if
1682 :
1683 : !$acc end data
1684 : !$acc wait
1685 :
1686 : #endif
1687 : #endif
1688 0 : end subroutine subcol_gen_SILHS
1689 :
1690 0 : subroutine subcol_ptend_avg_SILHS(ptend_sc, ngrdcol, lchnk, ptend)
1691 0 : use physics_buffer, only: physics_buffer_desc
1692 : use subcol_utils, only: subcol_ptend_get_firstsubcol, subcol_ptend_avg_shr, &
1693 : subcol_get_weight, subcol_get_filter, &
1694 : is_filter_set, is_weight_set
1695 :
1696 : !-----------------------------------
1697 : ! Average the subcolumns dimension (pcols*psubcols) to the grid dimension (pcols)
1698 : !-----------------------------------
1699 :
1700 : type(physics_ptend), intent(in) :: ptend_sc ! intent in
1701 : integer, intent(in) :: ngrdcol ! # grid cols
1702 : integer, intent(in) :: lchnk ! chunk index
1703 : type(physics_ptend), intent(inout) :: ptend
1704 : ! Because we can't get a state passed in here, we might have to use values from the
1705 : ! subcolumn generation. This would make any conservation checks invalid if this
1706 : ! function is called after another parameterization... hmm.
1707 :
1708 0 : call subcol_ptend_avg_shr(ptend_sc, ngrdcol, lchnk, ptend, is_filter_set(), is_weight_set())
1709 :
1710 0 : end subroutine subcol_ptend_avg_SILHS
1711 :
1712 0 : subroutine subcol_SILHS_var_covar_driver &
1713 : ( ztodt, state_sc, ptend_sc, &
1714 : pbuf )
1715 :
1716 : ! This subroutine calculates microphysical effects on five variances and
1717 : ! covariances: rtp2, thlp2, wprtp, wpthlp, and rtpthlp.
1718 : !
1719 : ! This code is experimental!!
1720 :
1721 0 : use physics_buffer, only: physics_buffer_desc, pbuf_get_index, pbuf_get_field
1722 : #ifdef CLUBB_SGS
1723 : #ifdef SILHS
1724 : use subcol_utils, only: subcol_get_weight
1725 : use subcol_pack_mod, only: subcol_unpack, subcol_get_nsubcol
1726 : use clubb_api_module, only: T_in_K2thlm_api, &
1727 : init_pdf_params_api, &
1728 : copy_multi_pdf_params_to_single,&
1729 : pdf_parameter
1730 : use silhs_api_module, only: lh_microphys_var_covar_driver_api
1731 : #endif
1732 : #endif
1733 :
1734 : implicit none
1735 :
1736 : ! Parameters
1737 : ! This fill value is set to catch errors; it should not be read.
1738 : real(r8), parameter :: fillvalue = -999._r8
1739 :
1740 : ! Input Variables
1741 : real(r8), intent(in) :: ztodt ! model time increment
1742 : type(physics_state), intent(in) :: state_sc ! state for sub-columns
1743 : type(physics_ptend), intent(in) :: ptend_sc ! ptend for sub-columns
1744 :
1745 : ! Pointers
1746 : type(physics_buffer_desc), pointer :: pbuf(:)
1747 :
1748 : #ifdef CLUBB_SGS
1749 : #ifdef SILHS
1750 : ! Local Variables
1751 : integer :: lchnk, ngrdcol, igrdcol, isubcol, ns, k
1752 : integer, dimension(pcols) :: nsubcol
1753 : real(r8), dimension(pcols*psubcols) :: weights_packed
1754 : real(r8), dimension(pcols,psubcols) :: weights
1755 : real(r8), dimension(pcols,psubcols,pverp) :: rc_all, rv_all, rt_all, w_all, thl_all
1756 : real(r8), dimension(pcols,psubcols,pver ) :: s_all, t_all, zm_all, omega_all, pmid_all
1757 : real(r8), dimension(pcols,psubcols) :: phis_all
1758 : real(r8), dimension(pcols,psubcols,pver ) :: stend, ttend
1759 : real(r8), dimension(pcols,psubcols,pverp) :: thltend, qctend, qvtend
1760 :
1761 : real(r8), dimension(pcols,psubcols,pver) :: dz_g, pdel_all, rho
1762 : real(r8), dimension(pcols,psubcols,pverp) :: zi_all
1763 :
1764 : real(r8), dimension(pcols,psubcols,pver ) :: exner
1765 :
1766 : ! Inputs to lh_microphys_var_covar_driver
1767 : real(r8), dimension(pcols,psubcols,pverp) :: rt_all_clubb, thl_all_clubb, w_all_clubb, &
1768 : qctend_clubb, qvtend_clubb, thltend_clubb
1769 : real(r8), dimension(pcols,psubcols,pverp-top_lev+1) :: height_depndt_weights
1770 :
1771 : ! Outputs from lh_microphys_var_covar_driver
1772 : real(r8), dimension(:,:), pointer :: rtp2_mc_zt, thlp2_mc_zt, wprtp_mc_zt, &
1773 : wpthlp_mc_zt, rtpthlp_mc_zt
1774 :
1775 : ! pbuf indices
1776 : integer :: &
1777 : rtp2_mc_zt_idx, &
1778 : thlp2_mc_zt_idx, &
1779 : wprtp_mc_zt_idx, &
1780 : wpthlp_mc_zt_idx, &
1781 : rtpthlp_mc_zt_idx
1782 :
1783 : type(pdf_parameter) :: pdf_params_single_col
1784 :
1785 : !----- Begin Code -----
1786 :
1787 : call init_pdf_params_api( pverp+1-top_lev, 1, pdf_params_single_col )
1788 :
1789 : ! Don't do anything if this option isn't enabled.
1790 : if ( .not. subcol_SILHS_var_covar_src ) return
1791 :
1792 : lchnk = state_sc%lchnk
1793 : ngrdcol = state_sc%ngrdcol
1794 :
1795 : ! Obtain indices
1796 : rtp2_mc_zt_idx = pbuf_get_index('rtp2_mc_zt')
1797 : thlp2_mc_zt_idx = pbuf_get_index('thlp2_mc_zt')
1798 : wprtp_mc_zt_idx = pbuf_get_index('wprtp_mc_zt')
1799 : wpthlp_mc_zt_idx = pbuf_get_index('wpthlp_mc_zt')
1800 : rtpthlp_mc_zt_idx = pbuf_get_index('rtpthlp_mc_zt')
1801 :
1802 : ! Obtain pbuf fields for output
1803 : call pbuf_get_field(pbuf, rtp2_mc_zt_idx, rtp2_mc_zt)
1804 : call pbuf_get_field(pbuf, thlp2_mc_zt_idx, thlp2_mc_zt)
1805 : call pbuf_get_field(pbuf, wprtp_mc_zt_idx, wprtp_mc_zt)
1806 : call pbuf_get_field(pbuf, wpthlp_mc_zt_idx, wpthlp_mc_zt)
1807 : call pbuf_get_field(pbuf, rtpthlp_mc_zt_idx, rtpthlp_mc_zt)
1808 :
1809 : ! Unpack needed tendencies from subcolumn ptends
1810 : call subcol_unpack(lchnk, ptend_sc%s(:,:), stend, fillvalue)
1811 : call subcol_unpack(lchnk, ptend_sc%q(:,:,ixcldliq), qctend(:,:,1:pver), fillvalue)
1812 : call subcol_unpack(lchnk, ptend_sc%q(:,:,ixq), qvtend(:,:,1:pver), fillvalue)
1813 :
1814 : ! Unpack sample point values from subcolumn states
1815 : call subcol_unpack(lchnk, state_sc%q(:,:,ixcldliq), rc_all(:,:,1:pver), fillvalue)
1816 : call subcol_unpack(lchnk, state_sc%q(:,:,ixq), rv_all(:,:,1:pver), fillvalue)
1817 : call subcol_unpack(lchnk, state_sc%omega(:,:), omega_all (:,:,:), fillvalue)
1818 : call subcol_unpack(lchnk, state_sc%s(:,:), s_all, fillvalue)
1819 : call subcol_unpack(lchnk, state_sc%zm, zm_all, fillvalue)
1820 : call subcol_unpack(lchnk, state_sc%phis, phis_all, fillvalue)
1821 : call subcol_unpack(lchnk, state_sc%zi, zi_all, fillvalue)
1822 : call subcol_unpack(lchnk, state_sc%pdel, pdel_all, fillvalue)
1823 : call subcol_unpack(lchnk, state_sc%pmid, pmid_all, fillvalue)
1824 :
1825 : ! Initialize fields to fillvalue.
1826 : rt_all = fillvalue
1827 : thl_all = fillvalue
1828 : w_all = fillvalue
1829 : qctend = fillvalue
1830 : qvtend = fillvalue
1831 : thltend = fillvalue
1832 :
1833 : ! How many subcolumns in each column?
1834 : call subcol_get_nsubcol(lchnk, nsubcol)
1835 :
1836 : do igrdcol = 1, ngrdcol
1837 : do isubcol = 1, nsubcol(igrdcol)
1838 :
1839 : rt_all(igrdcol,isubcol,top_lev:pver) = rc_all(igrdcol,isubcol,top_lev:pver) &
1840 : + rv_all(igrdcol,isubcol,top_lev:pver)
1841 :
1842 : ! Compute dry static density on CLUBB vertical grid
1843 : do k = top_lev, pver
1844 : dz_g(igrdcol,isubcol,k) = zi_all(igrdcol,isubcol,k) - zi_all(igrdcol,isubcol,k+1) ! thickness
1845 : rho(igrdcol,isubcol,k) = (rga)*pdel_all(igrdcol,isubcol,k)/dz_g(igrdcol,isubcol,k)
1846 : end do
1847 :
1848 : ! Compute w from omega
1849 : w_all(igrdcol,isubcol,top_lev:pver) = -omega_all(igrdcol,isubcol,top_lev:pver) &
1850 : / ( rho(igrdcol,isubcol,top_lev:pver) * gravit )
1851 :
1852 : ! Convert stend and s_all to ttend and t_all
1853 : ! Note 1: With subcolumns, cpair is truly a constant (I think).
1854 : ! Note 2: For tendencies, the extra terns zm and phis should
1855 : ! not be included in the calculation.
1856 : ttend(igrdcol,isubcol,top_lev:pver) = stend(igrdcol,isubcol,top_lev:pver) / cpair
1857 :
1858 : do k = top_lev, pver
1859 : t_all(igrdcol,isubcol,k) = ( s_all(igrdcol,isubcol,k) &
1860 : - gravit * zm_all(igrdcol,isubcol,k) &
1861 : - phis_all(igrdcol,isubcol) ) / cpair
1862 : end do ! k = 1, pver
1863 :
1864 : ! This formula is taken from earlier in this file.
1865 : exner(igrdcol,isubcol,top_lev:pver) &
1866 : = ( pmid_all(igrdcol,isubcol,top_lev:pver) / p0_clubb )**(rair/cpair)
1867 :
1868 : ! Note: all tendencies or all means should be used in the call to
1869 : ! T_in_K2thlm_api (with the exception of exner)
1870 : do k = top_lev, pver
1871 : thltend(igrdcol,isubcol,k) &
1872 : = T_in_K2thlm_api( ttend(igrdcol,isubcol,k), exner(igrdcol,isubcol,k), &
1873 : qctend(igrdcol,isubcol,k) )
1874 : thl_all(igrdcol,isubcol,k) &
1875 : = T_in_K2thlm_api( t_all(igrdcol,isubcol,k), exner(igrdcol,isubcol,k), &
1876 : rc_all(igrdcol,isubcol,k) )
1877 : end do ! k = 1, pver
1878 :
1879 : ! Add ghost points
1880 : rt_all (igrdcol,isubcol,pverp) = rt_all (igrdcol,isubcol,pver)
1881 : thl_all(igrdcol,isubcol,pverp) = thl_all(igrdcol,isubcol,pver)
1882 : w_all (igrdcol,isubcol,pverp) = w_all (igrdcol,isubcol,pver)
1883 : qctend (igrdcol,isubcol,pverp) = qctend (igrdcol,isubcol,pver)
1884 : qvtend (igrdcol,isubcol,pverp) = qvtend (igrdcol,isubcol,pver)
1885 : thltend(igrdcol,isubcol,pverp) = thltend(igrdcol,isubcol,pver)
1886 :
1887 : ! Flip inputs to CLUBB's grid. Note the dimension ordering change.
1888 : rt_all_clubb(igrdcol,isubcol,1:pverp) = clubb_flip_grid( rt_all(igrdcol,isubcol,1:pverp) )
1889 : thl_all_clubb(igrdcol,isubcol,1:pverp) = clubb_flip_grid( thl_all(igrdcol,isubcol,1:pverp) )
1890 : w_all_clubb(igrdcol,isubcol,1:pverp) = clubb_flip_grid( w_all(igrdcol,isubcol,1:pverp) )
1891 : qctend_clubb(igrdcol,isubcol,1:pverp) = clubb_flip_grid( qctend(igrdcol,isubcol,1:pverp) )
1892 : qvtend_clubb(igrdcol,isubcol,1:pverp) = clubb_flip_grid( qvtend(igrdcol,isubcol,1:pverp) )
1893 : thltend_clubb(igrdcol,isubcol,1:pverp) = clubb_flip_grid( thltend(igrdcol,isubcol,1:pverp) )
1894 :
1895 : end do ! isubcol = 1, nsubcol(igrdcol)
1896 : end do ! igrdcol = 1, ngrdcol
1897 :
1898 : ! Obtain weights
1899 : call subcol_get_weight(lchnk, weights_packed)
1900 : call subcol_unpack(lchnk, weights_packed, weights, fillvalue)
1901 :
1902 : ! Call lh_microphys_var_covar_driver for each column
1903 : do igrdcol=1, ngrdcol
1904 : ns = nsubcol(igrdcol)
1905 :
1906 : ! This code assumes that the weights are height independent.
1907 : ! It will have to change once the weights vary with altitude!
1908 : ! I'm not sure whether the grid will need to be flipped.
1909 : do k = 1, pverp-top_lev+1
1910 : height_depndt_weights(igrdcol,1:ns,k) = weights(igrdcol,1:ns)
1911 : end do
1912 :
1913 : ! Copy the igrdcol column from the multicolumn pdf_params_chnk to the single column
1914 : ! version of pdf_params_single_col since lh_microphys_var_covar_driver_api only
1915 : ! works over 1 column currently
1916 : call copy_multi_pdf_params_to_single( pdf_params_chnk(lchnk), igrdcol, &
1917 : pdf_params_single_col )
1918 :
1919 : ! Make the call!!!!!
1920 : call lh_microphys_var_covar_driver_api &
1921 : ( pverp-top_lev+1, ns, ztodt, height_depndt_weights(igrdcol,1:ns,1:pverp-top_lev+1), &
1922 : pdf_params_single_col, &
1923 : rt_all_clubb(igrdcol,1:ns,1:pverp-top_lev+1), thl_all_clubb(igrdcol,1:ns,1:pverp-top_lev+1), &
1924 : w_all_clubb(igrdcol,1:ns,1:pverp-top_lev+1), qctend_clubb(igrdcol,1:ns,1:pverp-top_lev+1), &
1925 : qvtend_clubb(igrdcol,1:ns,1:pverp-top_lev+1), thltend_clubb(igrdcol,1:ns,1:pverp-top_lev+1), &
1926 : silhs_config_flags%l_lh_instant_var_covar_src, &
1927 : rtp2_mc_zt(igrdcol,1:pverp-top_lev+1), thlp2_mc_zt(igrdcol,1:pverp-top_lev+1), &
1928 : wprtp_mc_zt(igrdcol,1:pverp-top_lev+1), wpthlp_mc_zt(igrdcol,1:pverp-top_lev+1), &
1929 : rtpthlp_mc_zt(igrdcol,1:pverp-top_lev+1) )
1930 :
1931 : ! The *_mc_zt microphysics tendencies are passed out of SILHS and back
1932 : ! to CLUBB without being used at all in the rest of the host model code.
1933 : ! The arrays aren't flipped for the *_mc_zt microphysics tendencies, and
1934 : ! they don't need to be.
1935 :
1936 : ! CLUBB used pverp vertical levels, but SILHS only uses
1937 : ! pverp - top_lev + 1 vertical levels.
1938 : ! Fill the upper levels with 0s when necessary.
1939 : if ( pverp > pverp-top_lev+1 ) then
1940 : rtp2_mc_zt(igrdcol,pverp-top_lev+2:pverp) = 0.0_r8
1941 : thlp2_mc_zt(igrdcol,pverp-top_lev+2:pverp) = 0.0_r8
1942 : wprtp_mc_zt(igrdcol,pverp-top_lev+2:pverp) = 0.0_r8
1943 : wpthlp_mc_zt(igrdcol,pverp-top_lev+2:pverp) = 0.0_r8
1944 : rtpthlp_mc_zt(igrdcol,pverp-top_lev+2:pverp) = 0.0_r8
1945 : endif ! pverp > pverp-top_lev+1
1946 :
1947 : end do ! igrdcol = 1, ngrdcol
1948 : #endif
1949 : #endif
1950 :
1951 0 : return
1952 0 : end subroutine subcol_SILHS_var_covar_driver
1953 : #ifdef SILHS
1954 : real(r8) function meansc(arr_in, w_in, ns) result(val)
1955 : real(r8), intent(in) :: ns ! Length of Array
1956 : real(r8), dimension(int(ns)), intent(in) :: arr_in ! Input array
1957 : real(r8), dimension(int(ns)), intent(in) :: w_in ! Weights
1958 : real(r8) :: acc ! accumulator
1959 : integer :: i
1960 : acc = 0
1961 : val = 0
1962 : do i=1,ns
1963 : acc = acc + arr_in(i)*w_in(i)
1964 : end do
1965 : val = acc/ns
1966 : end function
1967 :
1968 : real(r8) function stdsc(arr_in, w_in, mn_in, ns) result(val)
1969 : real(r8), intent(in) :: ns ! Number of elements (subcolumns)
1970 : real(r8), dimension(int(ns)), intent(in) :: arr_in, w_in !Input array and weights
1971 : real(r8), intent(in) :: mn_in ! The mean of arr_in
1972 : real(r8) :: accvar, var
1973 : integer :: i
1974 : accvar = 0
1975 : do i=1,ns
1976 : accvar = accvar + ((arr_in(i)-mn_in)**2)*w_in(i)
1977 : end do
1978 : var = accvar/ns
1979 : val = sqrt(var)
1980 : end function
1981 :
1982 : subroutine THL_profile(nz, ABST_prof, ex_prof, rcm_prof, THL_prof)
1983 :
1984 : use clubb_api_module, only : T_in_K2thlm_api
1985 :
1986 : integer, intent(in) :: nz ! Num vert levels
1987 : real(r8), dimension(nz), intent(in) :: ABST_prof ! Abs Temp prof
1988 : real(r8), dimension(nz), intent(in) :: ex_prof ! Profile of Exner func
1989 : real(r8), dimension(nz), intent(in) :: rcm_prof ! Profile of Cld Wat MR
1990 : real(r8), dimension(nz), intent(out) :: THL_prof ! LWPT prof
1991 : integer :: i
1992 :
1993 : do i=1,nz
1994 : THL_prof(i) = T_in_K2thlm_api(ABST_prof(i), ex_prof(i), rcm_prof(i))
1995 : end do
1996 :
1997 : end subroutine
1998 :
1999 : subroutine subcol_constrainmn( num_subcols, samples, weights, grid_mean, mean_sc, std_sc )
2000 :
2001 : ! Input/Output Variables
2002 : integer, intent(in) :: num_subcols
2003 : real(r8), dimension(num_subcols, pverp), intent(inout) :: samples
2004 : real(r8), dimension(num_subcols), intent(in) :: weights
2005 : real(r8), dimension(pverp), intent(in) :: grid_mean
2006 : real(r8), dimension(pver), intent(out), optional :: mean_sc, std_sc
2007 :
2008 : ! Local Variables
2009 : real(r8) :: meansc_loc, adj_rat
2010 : integer :: k
2011 : !------------------------------------------------------------------
2012 : !----- Begin Code -----
2013 : do k=1, pver
2014 : meansc_loc = meansc( samples(:,k), weights(:), real(num_subcols, r8) )
2015 :
2016 : if (present(mean_sc)) &
2017 : mean_sc(k) = meansc_loc
2018 : if (present(std_sc)) &
2019 : std_sc(k) = stdsc( samples(:,k), weights(:), meansc_loc, &
2020 : real(num_subcols, r8) )
2021 :
2022 : if ( meansc_loc > 0.0_r8 ) then
2023 : adj_rat = grid_mean(k)/meansc_loc
2024 : else
2025 : ! If the mean is zero, then zero out all subcolumns to avoid
2026 : ! negative samples
2027 : adj_rat = 0.0_r8
2028 : end if
2029 : samples(:,k) = samples(:,k) * adj_rat
2030 : end do
2031 : end subroutine subcol_constrainmn
2032 :
2033 : ! =============================================================================== !
2034 : ! !
2035 : ! =============================================================================== !
2036 : function clubb_flip_grid ( profile ) result( profile_flipped )
2037 :
2038 : ! Description:
2039 : ! Swaps the elements in profile so they are in reverse order. CAM and
2040 : ! CLUBB's grids are flipped with respect to each other.
2041 : !
2042 : ! Usage:
2043 : ! clubb_var = clubb_flip_grid( cam_var )
2044 : ! cam_var = clubb_flip_grid( clubb_var )
2045 :
2046 : implicit none
2047 :
2048 : ! Input Variable
2049 : real(r8), dimension(pverp), intent(in) :: profile
2050 :
2051 : ! Output Variable
2052 : real(r8), dimension(pverp) :: profile_flipped
2053 :
2054 : ! Local Variable
2055 : integer :: k
2056 :
2057 : do k=1, pverp
2058 : profile_flipped(k) = profile(pverp-k+1)
2059 : end do ! k=1, pverp
2060 :
2061 : return
2062 : end function clubb_flip_grid
2063 : ! =============================================================================== !
2064 : ! !
2065 : ! =============================================================================== !
2066 : #endif
2067 : !============================================================================
2068 0 : subroutine subcol_SILHS_fill_holes_conserv( state, dt, ptend, pbuf )
2069 :
2070 : ! The William F. Buckley Jr. Conservative Hole Filler.
2071 :
2072 : ! Description:
2073 : ! Stops holes from forming in a hydrometeor mixing ratio by reducing the
2074 : ! microphysics tendency of that hydrometeor mixing ratio which would
2075 : ! otherwise cause that hydrometeor mixing ratio to have a negative value
2076 : ! once the microphysics tendency is applied. This code is used to prevent
2077 : ! holes in water mass, not number concentration.
2078 : !
2079 : ! This subroutine is called after microphysics has completed and after
2080 : ! microphysics fields from subcolumns have been averaged back to grid
2081 : ! columns, but before the grid-column microphysics tendencies have been
2082 : ! applied in physics_update. This code is meant for use with the SILHS
2083 : ! subcolumn approach. This code needs to be applied to grid columns, not
2084 : ! subcolumns.
2085 : !
2086 : ! This code adjusts the tendencies (ptend) before they are used to update
2087 : ! the grid mean fields (state variables).
2088 : !
2089 : ! The column-integrated total water needs to be conserved during
2090 : ! microphysics. The conserved amount includes the amount of water that
2091 : ! precipitated to the ground from sedimentation during microphysics.
2092 : ! The conservation equation for each grid column is:
2093 : !
2094 : ! SUM(k=top_lev:pver) ( rv_start(k) + rc_start(k) + rr_start(k)
2095 : ! + ri_start(k) + rs_start(k) ) * pdel(k) / g
2096 : ! = SUM(k=top_lev:pver) ( rv(k) + rc(k) + rr(k) + ri(k) + rs(k) )
2097 : ! * pdel(k) / g
2098 : ! + prect * dt * 1000;
2099 : !
2100 : ! where rv_start, rc_start, rr_start, ri_start, and rs_start are water
2101 : ! vapor, cloud water, rain water, cloud ice, and snow mixing ratios before
2102 : ! microphysics is called; rv, rc, rr, ri, and rs are water vapor, cloud
2103 : ! water, rain water, cloud ice, and snow mixing ratios after being updated
2104 : ! by microphysics; pdel is the pressure difference between vertical levels,
2105 : ! g is gravity, and prect * dt * 1000 is the total amount of water (from
2106 : ! all precipitating hydrometeors) that sedimented to the ground during
2107 : ! microphysics (dt is the timestep used for microphysics). The units of
2108 : ! column-integrated total water are kg (water) / m^2.
2109 : !
2110 : ! All the updated hydrometeor fields are related to the hydrometeor fields
2111 : ! at the start by:
2112 : !
2113 : ! rv(k) = rv_start(k) + rv_tend(k) * dt;
2114 : ! rc(k) = rc_start(k) + rc_tend(k) * dt;
2115 : ! rr(k) = rr_start(k) + rr_tend(k) * dt;
2116 : ! ri(k) = ri_start(k) + ri_tend(k) * dt; and
2117 : ! rs(k) = rs_start(k) + rs_tend(k) * dt;
2118 : !
2119 : ! where rv_tend, rc_tend, rr_tend, ri_tend, and rs_tend are water vapor,
2120 : ! cloud water, rain water, cloud ice, and snow mixing ratio tendencies
2121 : ! from microphysics, which includes the sum of microphysics process rates
2122 : ! and sedimentation. When these equations are applied to the equation
2123 : ! for column-integrated total water, that equation becomes:
2124 : !
2125 : ! SUM(k=top_lev:pver) ( rv_tend(k) + rc_tend(k) + rr_tend(k)
2126 : ! + ri_tend(k) + rs_tend(k) ) * dt * pdel(k) / g
2127 : ! + prect * dt * 1000 = 0.
2128 : !
2129 : ! As stated above, the hydrometeor tendencies are the sum of tendencies
2130 : ! from microphysics process rates and tendencies from sedimentation:
2131 : !
2132 : ! rv_tend(k) = rv_mc_tend(k);
2133 : ! rc_tend(k) = rc_mc_tend(k) + rc_sed_tend(k);
2134 : ! rr_tend(k) = rr_mc_tend(k) + rr_sed_tend(k);
2135 : ! ri_tend(k) = ri_mc_tend(k) + ri_sed_tend(k); and
2136 : ! rs_tend(k) = rs_mc_tend(k) + rs_sed_tend(k);
2137 : !
2138 : ! where rv_mc_tend, rc_mc_tend, rr_mc_tend, ri_mc_tend, and rs_mc_tend are
2139 : ! the tendencies of water vapor, cloud water, rain water, cloud ice, and
2140 : ! snow from microphysics process rates, and rc_sed_tend, rr_sed_tend,
2141 : ! ri_sed_tend, and rs_sed_tend are the tendencies of cloud water,
2142 : ! rain water, cloud ice, and snow from sedimentation. When these equations
2143 : ! are applied to the equation for column-integrated total water, that
2144 : ! equation becomes:
2145 : !
2146 : ! SUM(k=top_lev:pver) ( rv_mc_tend(k) + rc_mc_tend(k) + rr_mc_tend(k)
2147 : ! + ri_mc_tend(k) + rs_mc_tend(k) )
2148 : ! * dt * pdel(k) / g
2149 : ! + SUM(k=top_lev:pver) ( rc_sed_tend(k) + rr_sed_tend(k) + ri_sed_tend(k)
2150 : ! + rs_sed_tend(k) ) * dt * pdel(k) / g
2151 : ! + prect * dt * 1000 = 0.
2152 : !
2153 : ! At any vertical level, the tendencies from microphysics process rates
2154 : ! (mc_tend variables) must balance:
2155 : !
2156 : ! rv_mc_tend(k) + rc_mc_tend(k) + rr_mc_tend(k)
2157 : ! + ri_mc_tend(k) + rs_mc_tend(k) = 0; for all k from top_lev to pver.
2158 : !
2159 : ! The column-integrated total water equation can be applied to
2160 : ! sedimentation:
2161 : !
2162 : ! SUM(k=top_lev:pver) ( rc_sed_tend(k) + rr_sed_tend(k) + ri_sed_tend(k)
2163 : ! + rs_sed_tend(k) ) * dt * pdel(k) / g
2164 : ! + prect * dt * 1000 = 0.
2165 : !
2166 : ! The total precipitation rate, prect, can be split into liquid
2167 : ! precipitation rate, precl, and frozen precipitation rate, preci:
2168 : !
2169 : ! prect = precl + preci.
2170 : !
2171 : ! The microphysics code outputs prect and preci, so precl can be calculated
2172 : ! by precl = prect - preci. The column-integrated total water equation can
2173 : ! be split into:
2174 : !
2175 : ! SUM(k=top_lev:pver) ( rc_sed_tend(k) + rr_sed_tend(k) )
2176 : ! * dt * pdel(k) / g
2177 : ! + precl * dt * 1000 = 0; and
2178 : !
2179 : ! SUM(k=top_lev:pver) ( ri_sed_tend(k) + rs_sed_tend(k) )
2180 : ! * dt * pdel(k) / g
2181 : ! + preci * dt * 1000 = 0.
2182 : !
2183 : ! Overall, the conservation methods used in this subroutine are:
2184 : !
2185 : ! 1) When adjusting the tendencies from microphysics process rates,
2186 : ! conserve:
2187 : !
2188 : ! rv_mc_tend(k) + rc_mc_tend(k) + rr_mc_tend(k)
2189 : ! + ri_mc_tend(k) + rs_mc_tend(k) = 0; for all k from top_lev to pver.
2190 : !
2191 : ! 2) When adjusting the tendencies from microphysics process rates, adjust
2192 : ! dry static energy appropriately. The change in dry static energy
2193 : ! is necessary because of phase changes. This "puts back" the extra dry
2194 : ! static energy that was "taken out" when an excessive phase-changing
2195 : ! process rate was produced by microphysics.
2196 : !
2197 : ! 3) When adjusting the hydrometeor tendency from sedimentation of a
2198 : ! liquid hydrometeor (cloud water or rain water), conserve:
2199 : !
2200 : ! SUM(k=top_lev:pver) ( rc_sed_tend(k) + rr_sed_tend(k) )
2201 : ! * dt * pdel(k) / g
2202 : ! + precl * dt * 1000 = 0.
2203 : !
2204 : ! 4) When adjusting the hydrometeor tendency from sedimentation of a
2205 : ! frozen hydrometeor (cloud ice or snow), conserve:
2206 : !
2207 : ! SUM(k=top_lev:pver) ( ri_sed_tend(k) + rs_sed_tend(k) )
2208 : ! * dt * pdel(k) / g
2209 : ! + preci * dt * 1000 = 0.
2210 : !
2211 : ! The conservative hole filler works as follows. The total microphysics
2212 : ! tendency for each hydrometeor is provided in ptend. This is the sum of
2213 : ! the microphysics process rate tendency and sedimentation tendency for
2214 : ! each hydrometeor. The sedimentation tendency is provided in pbuf. The
2215 : ! sedimentation tendency is subtracted off the total microphysics tendency
2216 : ! to produce the microphysics process rate tendency for each hydrometeor.
2217 : ! The microphysics process rate tendency is adjusted when necessary so that
2218 : ! holes in the hydrometeor are not produced by microphysics process rates.
2219 : ! When a hydrometeor's negative microphysics process rate tendency needs to
2220 : ! be made smaller in magnitude to avoid a hole, all hydrometeor tendencies
2221 : ! that are positive at that grid level are also decreased proportionately
2222 : ! to maintain a balance. Dry static energy tendency is also adjusted
2223 : ! appropriately when necessary. After this, the vertical integral of each
2224 : ! hydrometeor species is greater than or equal to 0.
2225 : !
2226 : ! The sedimentation tendency is then added back onto the new microphysics
2227 : ! process rate tendency to produce a new total microphysics tendency for
2228 : ! each hydrometeor. Since the sedimentation tendency was based on the old
2229 : ! value of hydrometeor, before the hole-filling adjustment, it is possible
2230 : ! that the new total microphysics tendency may produce holes. When this
2231 : ! happens, sedimentation hole filling fills holes in the vertical profile
2232 : ! of each hydrometeor. Holes are filled using mass from other vertical
2233 : ! levels for the same hydrometeor (or from a same-phase hydrometeor when
2234 : ! necessary). Since the vertical integral of sedimentation tendency
2235 : ! (including surface precipitation rate) is 0, the vertical integral of the
2236 : ! hydrometeor must be greater than or equal to 0, which means that all
2237 : ! holes can be filled. The result is that all holes in any hydrometeor
2238 : ! mixing ratio are filled completely and conservatively. The value of
2239 : ! ptend is updated appropriately so that it can be applied later in
2240 : ! physics_update.
2241 :
2242 : !----------------------------------------------------------------------
2243 :
2244 0 : use physics_buffer, only: &
2245 : physics_buffer_desc, &
2246 : pbuf_get_field
2247 :
2248 : use ppgrid, only: &
2249 : pcols
2250 :
2251 : use constituents, only: &
2252 : qmin
2253 :
2254 : use ref_pres, only: &
2255 : top_lev => trop_cloud_top_lev
2256 :
2257 : implicit none
2258 :
2259 : ! Input Variables
2260 : type(physics_state), intent(in) :: state ! Physics state variables
2261 : real(r8), intent(in) :: dt ! Time step duration
2262 :
2263 : ! Input/Output Variables
2264 : type(physics_ptend), intent(inout) :: ptend ! Parameterization tendencies
2265 : type(physics_buffer_desc), pointer :: pbuf(:) ! Physics buffer
2266 :
2267 : ! Local Variables
2268 : real(r8), dimension(pcols,pver) :: &
2269 : rv_start, & ! Water vapor mixing ratio at start of microphysics [kg/kg]
2270 : rc_start, & ! Cloud water mixing ratio at start of microphysics [kg/kg]
2271 : rr_start, & ! Rain water mixing ratio at start of microphysics [kg/kg]
2272 : ri_start, & ! Cloud ice mixing ratio at start of microphysics [kg/kg]
2273 : rs_start ! Snow mixing ratio at start of microphysics [kg/kg]
2274 :
2275 : real(r8), dimension(pcols,pver) :: &
2276 : rv_tend, & ! Water vapor mixing ratio tendency [kg/kg/s]
2277 : rc_tend, & ! Cloud water mixing ratio tendency [kg/kg/s]
2278 : rr_tend, & ! Rain water mixing ratio tendency [kg/kg/s]
2279 : ri_tend, & ! Cloud ice mixing ratio tendency [kg/kg/s]
2280 : rs_tend, & ! Snow mixing ratio tendency [kg/kg/s]
2281 : stend ! Dry static energy tendency [J/kg/s]
2282 :
2283 : real(r8), dimension(:), pointer :: &
2284 0 : prect, & ! Total microphysics precipitation rate (surface) [m/s]
2285 0 : preci, & ! Ice-phase microphysics precipitation rate (surface) [m/s]
2286 0 : prec_str, & ! Total surface precipitation rate from stratoform [m/s]
2287 0 : snow_str ! Snow surface precipitation rate from stratoform [m/s]
2288 :
2289 : real(r8), dimension(:,:), pointer :: &
2290 0 : rc_sed_tend, & ! Mean cloud water sedimentation tendency [kg/kg/s]
2291 0 : rr_sed_tend, & ! Mean rain water sedimentation tendency [kg/kg/s]
2292 0 : ri_sed_tend, & ! Mean cloud ice sedimentation tendency [kg/kg/s]
2293 0 : rs_sed_tend, & ! Mean snow sedimentation tendency [kg/kg/s]
2294 0 : vtrmc, & ! Mean cloud water sedimentation velocity [m/s]
2295 0 : umr, & ! Mean rain water sedimentation velocity [m/s]
2296 0 : vtrmi, & ! Mean cloud ice sedimentation velocity [m/s]
2297 0 : ums, & ! Mean snow sedimentation velocity [m/s]
2298 0 : rc_sed_evap, & ! Mean evap of cloud water during sedimentation [kg/kg/s]
2299 0 : ri_sed_subl ! Mean subl of cloud ice during sedimentation [kg/kg/s]
2300 :
2301 : real(r8), dimension(pcols,pver) :: &
2302 : rv_mc_tend, & ! Water vapor mixing ratio microphysics tendency [kg/kg/s]
2303 : rc_mc_tend, & ! Cloud water mixing ratio microphysics tendency [kg/kg/s]
2304 : rr_mc_tend, & ! Rain water mixing ratio microphysics tendency [kg/kg/s]
2305 : ri_mc_tend, & ! Cloud ice mixing ratio microphysics tendency [kg/kg/s]
2306 : rs_mc_tend ! Snow mixing ratio microphysics tendency [kg/kg/s]
2307 :
2308 : real(r8) :: &
2309 : rv_curr, & ! Current water vapor mixing ratio [kg/kg]
2310 : rc_curr, & ! Current cloud water mixing ratio [kg/kg]
2311 : rr_curr, & ! Current rain water mixing ratio [kg/kg]
2312 : ri_curr, & ! Current cloud ice mixing ratio [kg/kg]
2313 : rs_curr ! Current snow mixing ratio [kg/kg]
2314 :
2315 : logical :: &
2316 : l_pos_rv_mc_tend, & ! Flag for positive water vapor mixing ratio mc tend.
2317 : l_pos_rc_mc_tend, & ! Flag for positive cloud water mixing ratio mc tend.
2318 : l_pos_rr_mc_tend, & ! Flag for positive rain water mixing ratio mc tend.
2319 : l_pos_ri_mc_tend, & ! Flag for positive cloud ice mixing ratio mc tend.
2320 : l_pos_rs_mc_tend ! Flag for positive snow mixing ratio mc tend.
2321 :
2322 : real(r8) :: &
2323 : mc_tend_max_mag, & ! Max. allowable mag. of (neg.) mc tend [kg/kg/s]
2324 : mc_tend_correction, & ! Amnt. correction necessary to mc tend [kg/kg/s]
2325 : total_mc_positive, & ! Total of all positive mc tendencies [kg/kg/s]
2326 : mc_correction_ratio ! Ratio: mc_tend_correction/total_mc_positive [-]
2327 :
2328 : real(r8), dimension(pcols) :: &
2329 : precl ! Liquid-phase precipitation rate (surface) [m/s]
2330 :
2331 : ! Budgeting terms for hole filling.
2332 : ! These variables are for use in stats output.
2333 : real(r8), dimension(pcols,pver) :: &
2334 : rv_hf_tend, & ! Water vapor mixing ratio hole-filling tendency [kg/kg/s]
2335 : rc_hf_tend, & ! Cloud water mixing ratio hole-filling tendency [kg/kg/s]
2336 : rr_hf_tend, & ! Rain water mixing ratio hole-filling tendency [kg/kg/s]
2337 : ri_hf_tend, & ! Cloud ice mixing ratio hole-filling tendency [kg/kg/s]
2338 : rs_hf_tend, & ! Snow mixing ratio hole-filling tendency [kg/kg/s]
2339 : s_hf_tend ! Dry static energy hole-filling tendency [J/kg/s]
2340 :
2341 : integer :: ncol ! Number of grid columns
2342 :
2343 : integer :: icol, k ! Loop indices
2344 :
2345 : ! Flag to perform hole filling after the original sedimentation tendency
2346 : ! is added back on to the new microphysics process tendency. This calls
2347 : ! the sedimentation hole filler.
2348 : logical, parameter :: &
2349 : l_sed_hole_fill = .true.
2350 :
2351 : logical, parameter :: &
2352 : l_check_conservation = .true. ! Flag to perform water conservation check
2353 :
2354 : ! Vertically-integrated grand total water (rv+rc+rr+ri+rs) [kg/m^2]
2355 : real(r8), dimension(pcols) :: &
2356 : grand_total_water_column_start, & ! Column integral at start
2357 : grand_total_water_column_finish ! Column integral at finish
2358 :
2359 : ! Vertically-integrated total water energy [J/m^2]
2360 : real(r8), dimension(pcols) :: &
2361 : total_energy_column_start, & ! Column integral at start
2362 : total_energy_column_finish ! Column integral at finish
2363 :
2364 : real(r8), dimension(pcols) :: &
2365 : tot_water_rel_err, & ! Relative error: vert-integrated grand total water
2366 : tot_energy_rel_err ! Relative error: vert-integrated total energy
2367 :
2368 : real(r8), parameter :: &
2369 : err_thresh = 1.0e-14_r8 ! Threshold of relative error
2370 :
2371 :
2372 : ! Get the number of grid columns.
2373 0 : ncol = state%ncol
2374 :
2375 : ! Get fields from the pbuf.
2376 0 : call pbuf_get_field(pbuf, prec_pcw_idx, prect)
2377 0 : call pbuf_get_field(pbuf, snow_pcw_idx, preci)
2378 0 : call pbuf_get_field(pbuf, prec_str_idx, prec_str)
2379 0 : call pbuf_get_field(pbuf, snow_str_idx, snow_str)
2380 0 : call pbuf_get_field(pbuf, qcsedten_idx, rc_sed_tend)
2381 0 : call pbuf_get_field(pbuf, qrsedten_idx, rr_sed_tend)
2382 0 : call pbuf_get_field(pbuf, qisedten_idx, ri_sed_tend)
2383 0 : call pbuf_get_field(pbuf, qssedten_idx, rs_sed_tend)
2384 0 : call pbuf_get_field(pbuf, vtrmc_idx, vtrmc)
2385 0 : call pbuf_get_field(pbuf, umr_idx, umr)
2386 0 : call pbuf_get_field(pbuf, vtrmi_idx, vtrmi)
2387 0 : call pbuf_get_field(pbuf, ums_idx, ums)
2388 0 : call pbuf_get_field(pbuf, qcsevap_idx, rc_sed_evap)
2389 0 : call pbuf_get_field(pbuf, qisevap_idx, ri_sed_subl)
2390 :
2391 : ! Calculate liquid precipitation rate (precl) from the total precipitation
2392 : ! rate (prect) and the frozen preciptation rate (preci). This should never
2393 : ! be negative, but just to be safe, threshold at 0.
2394 0 : precl(:ncol) = max( prect(:ncol) - preci(:ncol), 0.0_r8 )
2395 :
2396 : ! Perform total water and total energy conservation checks.
2397 : if ( l_check_conservation ) then
2398 :
2399 : ! Calculate total water in each column.
2400 : ! This calculation is the vertically-integrated grand total water (where
2401 : ! grand total water is the sum of water vapor, cloud water, rain water,
2402 : ! cloud ice, and snow, as well as the amount of water that precipitated
2403 : ! to the surface) in each grid column after microphysics, but at the
2404 : ! start of hole filling.
2405 0 : do icol = 1, ncol
2406 0 : grand_total_water_column_start(icol) = 0.0_r8
2407 0 : do k = top_lev, pver
2408 : grand_total_water_column_start(icol) &
2409 : = grand_total_water_column_start(icol) &
2410 0 : + ( state%q(icol,k,1) + ptend%q(icol,k,1) * dt &
2411 0 : + state%q(icol,k,ixcldliq) &
2412 0 : + ptend%q(icol,k,ixcldliq) * dt &
2413 0 : + state%q(icol,k,ixcldice) &
2414 0 : + ptend%q(icol,k,ixcldice) * dt ) &
2415 0 : * state%pdel(icol,k) * rga
2416 0 : if ( ixrain > 0 ) then
2417 : grand_total_water_column_start(icol) &
2418 : = grand_total_water_column_start(icol) &
2419 0 : + ( state%q(icol,k,ixrain) + ptend%q(icol,k,ixrain) * dt ) &
2420 0 : * state%pdel(icol,k) * rga
2421 : endif
2422 0 : if ( ixsnow > 0 ) then
2423 : grand_total_water_column_start(icol) &
2424 : = grand_total_water_column_start(icol) &
2425 0 : + ( state%q(icol,k,ixsnow) + ptend%q(icol,k,ixsnow) * dt ) &
2426 0 : * state%pdel(icol,k) * rga
2427 : endif
2428 : end do ! k = top_lev, pver
2429 : grand_total_water_column_start(icol) &
2430 : = grand_total_water_column_start(icol) &
2431 0 : + prect(icol) * dt * 1000.0_r8
2432 : end do ! icol = 1, ncol
2433 :
2434 : ! Calculate total energy in each column.
2435 : ! This calculation is the vertically-integrated total energy in each
2436 : ! grid column after microphysics, but at the start of hole filling.
2437 : ! Since the microphysics and hole filling code does not directly change
2438 : ! kinetic energy, 0.5 * ( u^2 + v^2 ), it can be skipped as part of the
2439 : ! energy conservation check.
2440 0 : do icol = 1, ncol
2441 0 : total_energy_column_start(icol) = 0.0_r8
2442 0 : do k = top_lev, pver
2443 : total_energy_column_start(icol) &
2444 : = total_energy_column_start(icol) &
2445 0 : + ( state%s(icol,k) + ptend%s(icol,k) * dt &
2446 : + ( latvap + latice ) &
2447 0 : * ( state%q(icol,k,1) + ptend%q(icol,k,1) * dt ) &
2448 0 : + latice * ( state%q(icol,k,ixcldliq) &
2449 0 : + ptend%q(icol,k,ixcldliq) * dt ) ) &
2450 0 : * state%pdel(icol,k) * rga
2451 0 : if ( ixrain > 0 ) then
2452 : total_energy_column_start(icol) &
2453 : = total_energy_column_start(icol) &
2454 0 : + latice * ( state%q(icol,k,ixrain) &
2455 0 : + ptend%q(icol,k,ixrain) * dt ) &
2456 0 : * state%pdel(icol,k) * rga
2457 : endif
2458 : end do ! k = top_lev, pver
2459 : total_energy_column_start(icol) &
2460 : = total_energy_column_start(icol) &
2461 0 : + latice * precl(icol) * dt * 1000.0_r8
2462 : end do ! icol = 1, ncol
2463 :
2464 : endif ! l_check_conservation
2465 :
2466 : ! The fields within state haven't been updated yet, since this is before
2467 : ! the call to physics_update.
2468 0 : rv_start = state%q(:,:,1)
2469 0 : rc_start = state%q(:,:,ixcldliq)
2470 0 : if ( ixrain > 0 ) then
2471 0 : rr_start = state%q(:,:,ixrain)
2472 : endif
2473 0 : ri_start = state%q(:,:,ixcldice)
2474 0 : if ( ixsnow > 0 ) then
2475 0 : rs_start = state%q(:,:,ixsnow)
2476 : endif
2477 :
2478 : ! Unpack the current total tendencies for hydrometeor mixing ratio fields.
2479 0 : rv_tend = ptend%q(:,:,1)
2480 0 : rc_tend = ptend%q(:,:,ixcldliq)
2481 0 : if ( ixrain > 0 ) then
2482 0 : rr_tend = ptend%q(:,:,ixrain)
2483 : endif
2484 0 : ri_tend = ptend%q(:,:,ixcldice)
2485 0 : if ( ixsnow > 0 ) then
2486 0 : rs_tend = ptend%q(:,:,ixsnow)
2487 : endif
2488 :
2489 : ! Unpack the current tendency for dry static energy.
2490 0 : stend = ptend%s
2491 :
2492 : ! The total hydrometeor tendencies are the sum of microphysics process
2493 : ! rates and sedimentation rates. Calculate the microphysics process
2494 : ! tendencies by subtracting the sedimentation tendencies from the overall
2495 : ! tendencies.
2496 : ! The sedimentation tendencies for cloud water (rc_sed_tend) and cloud ice
2497 : ! (ri_sed_tend) include the evaporation of cloud water during sedimentation
2498 : ! and the sublimation of cloud ice during sedimentation, respectively. The
2499 : ! true sedimentation of cloud water is the sum of rc_sed_tend and
2500 : ! rc_sed_evap, and the true sedimentation of cloud ice is the sum of
2501 : ! ri_sed_tend and ri_sed_subl. Subtract off only the true sedimentation
2502 : ! rates, as evaporation and sublimation need to be included in the
2503 : ! microphysics process rates.
2504 0 : rv_mc_tend(:ncol,:) = rv_tend(:ncol,:)
2505 0 : rc_mc_tend(:ncol,:) = rc_tend(:ncol,:) - ( rc_sed_tend(:ncol,:) + rc_sed_evap(:ncol,:) )
2506 0 : if ( ixrain > 0 ) then
2507 0 : rr_mc_tend(:ncol,:) = rr_tend(:ncol,:) - rr_sed_tend(:ncol,:)
2508 : endif
2509 0 : ri_mc_tend(:ncol,:) = ri_tend(:ncol,:) - ( ri_sed_tend(:ncol,:) + ri_sed_subl(:ncol,:) )
2510 0 : if ( ixsnow > 0 ) then
2511 0 : rs_mc_tend(:ncol,:) = rs_tend(:ncol,:) - rs_sed_tend(:ncol,:)
2512 : endif
2513 :
2514 : ! This section adjusts microphysics process rate tendencies so that the
2515 : ! resulting values of all hydrometeor mixing ratios are greater than or
2516 : ! equal to qmin after this section is complete. Once sedimentation is
2517 : ! added back on after this section, some of the hydrometeor mixing ratios
2518 : ! may become less than qmin again.
2519 : !
2520 : ! This section, which again is concerned only with adjusting microphysics
2521 : ! process rates, makes use of the following two principles:
2522 : !
2523 : ! 1) When adjusting the tendencies from microphysics process rates,
2524 : ! conserve:
2525 : !
2526 : ! rv_mc_tend(k) + rc_mc_tend(k) + rr_mc_tend(k)
2527 : ! + ri_mc_tend(k) + rs_mc_tend(k) = 0; for all k from top_lev to pver.
2528 : !
2529 : ! 2) When adjusting the tendencies from microphysics process rates, adjust
2530 : ! dry static energy appropriately. The change in dry static energy
2531 : ! is necessary because of phase changes. This "puts back" the extra dry
2532 : ! static energy that was "taken out" when an excessive phase-changing
2533 : ! process rate was produced by microphysics.
2534 :
2535 : ! Loop over all columns, performing any tendency adjustments one column
2536 : ! at a time.
2537 0 : do icol = 1, ncol
2538 :
2539 : ! Loop over all vertical levels, performing any microphysics process
2540 : ! tendency adjustments one level at a time.
2541 0 : do k = top_lev, pver
2542 :
2543 : ! Find which hydrometeors have positive microphysics process
2544 : ! tendencies at this level.
2545 0 : if ( rv_mc_tend(icol,k) >= 0.0_r8 ) then
2546 : l_pos_rv_mc_tend = .true.
2547 : else
2548 0 : l_pos_rv_mc_tend = .false.
2549 : endif
2550 0 : if ( rc_mc_tend(icol,k) >= 0.0_r8 ) then
2551 : l_pos_rc_mc_tend = .true.
2552 : else
2553 0 : l_pos_rc_mc_tend = .false.
2554 : endif
2555 0 : if ( ixrain > 0 ) then
2556 0 : if ( rr_mc_tend(icol,k) >= 0.0_r8 ) then
2557 : l_pos_rr_mc_tend = .true.
2558 : else
2559 0 : l_pos_rr_mc_tend = .false.
2560 : endif
2561 : endif
2562 0 : if ( ri_mc_tend(icol,k) >= 0.0_r8 ) then
2563 : l_pos_ri_mc_tend = .true.
2564 : else
2565 0 : l_pos_ri_mc_tend = .false.
2566 : endif
2567 0 : if ( ixsnow > 0 ) then
2568 0 : if ( rs_mc_tend(icol,k) >= 0.0_r8 ) then
2569 : l_pos_rs_mc_tend = .true.
2570 : else
2571 0 : l_pos_rs_mc_tend = .false.
2572 : endif
2573 : endif
2574 :
2575 : !!! Check for holes in water vapor mixing ratio
2576 0 : if ( .not. l_pos_rv_mc_tend ) then
2577 :
2578 : ! Calculate the water vapor mixing ratio as it would be with the
2579 : ! current microphysics process tendency.
2580 0 : rv_curr = rv_start(icol,k) + rv_mc_tend(icol,k) * dt
2581 :
2582 0 : if ( rv_curr < qmin(1) ) then
2583 :
2584 : ! Microphysics processes are causing a hole in water vapor
2585 : ! mixing ratio.
2586 :
2587 : ! Calculate the maximum allowable magnitude of (negative) water
2588 : ! vapor microphysics process tendency.
2589 0 : mc_tend_max_mag = ( qmin(1) - rv_start(icol,k) ) / dt
2590 :
2591 : ! Calculate the amount of the correction that needs to be made
2592 : ! to the water vapor mixing ratio microphysics process
2593 : ! tendency. This number is positive.
2594 0 : mc_tend_correction = mc_tend_max_mag - rv_mc_tend(icol,k)
2595 :
2596 : ! Calculate the total amount of positive microphysics process
2597 : ! tendencies for all hydrometeor mixing ratios.
2598 0 : total_mc_positive = 0.0_r8
2599 0 : if ( l_pos_rc_mc_tend ) then
2600 0 : total_mc_positive = total_mc_positive + rc_mc_tend(icol,k)
2601 : endif
2602 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
2603 0 : total_mc_positive = total_mc_positive + rr_mc_tend(icol,k)
2604 : endif
2605 0 : if ( l_pos_ri_mc_tend ) then
2606 0 : total_mc_positive = total_mc_positive + ri_mc_tend(icol,k)
2607 : endif
2608 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2609 0 : total_mc_positive = total_mc_positive + rs_mc_tend(icol,k)
2610 : endif
2611 :
2612 : ! Calculate the correction ratio.
2613 : ! In principle, this should never be greater than 1 outside of
2614 : ! numerical round-off errors. This is limited at 1 to be safe.
2615 : mc_correction_ratio &
2616 : = min( mc_tend_correction &
2617 0 : / max( total_mc_positive, 1.0e-30_r8 ), 1.0_r8 )
2618 :
2619 : ! Adjust (decrease) the tendencies of all positive hydrometeor
2620 : ! mixing ratio tendencies to balance the adjustment (increase)
2621 : ! to the excessively negative water vapor mixing ratio.
2622 : ! Transfer dry static energy appropriately (in response to the
2623 : ! excessive depletion of water vapor).
2624 0 : if ( l_pos_rc_mc_tend ) then
2625 : ! Changing cloud water to water vapor cools and reduces
2626 : ! dry static energy.
2627 : stend(icol,k) &
2628 : = stend(icol,k) &
2629 0 : - latvap * mc_correction_ratio * rc_mc_tend(icol,k)
2630 : ! Update cloud water mixing ratio microphysics tendency.
2631 : rc_mc_tend(icol,k) &
2632 0 : = rc_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2633 : endif
2634 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
2635 : ! Changing rain water to water vapor cools and reduces
2636 : ! dry static energy.
2637 : stend(icol,k) &
2638 : = stend(icol,k) &
2639 0 : - latvap * mc_correction_ratio * rr_mc_tend(icol,k)
2640 : ! Update rain water mixing ratio microphysics tendency.
2641 : rr_mc_tend(icol,k) &
2642 0 : = rr_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2643 : endif
2644 0 : if ( l_pos_ri_mc_tend ) then
2645 : ! Changing cloud ice to water vapor cools and reduces
2646 : ! dry static energy.
2647 : stend(icol,k) &
2648 : = stend(icol,k) &
2649 : - ( latvap + latice ) &
2650 0 : * mc_correction_ratio * ri_mc_tend(icol,k)
2651 : ! Update cloud ice mixing ratio microphysics tendency.
2652 : ri_mc_tend(icol,k) &
2653 0 : = ri_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2654 : endif
2655 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2656 : ! Changing snow to water vapor cools and reduces dry
2657 : ! static energy.
2658 : stend(icol,k) &
2659 : = stend(icol,k) &
2660 : - ( latvap + latice ) &
2661 0 : * mc_correction_ratio * rs_mc_tend(icol,k)
2662 : ! Update snow mixing ratio microphysics tendency.
2663 : rs_mc_tend(icol,k) &
2664 0 : = rs_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2665 : endif
2666 :
2667 : ! Calculate the new water vapor mixing ratio microphysics
2668 : ! process tendency. This should be equal to the maximum
2669 : ! magnitude (negative) amount allowed, mc_tend_max_mag.
2670 : rv_mc_tend(icol,k) &
2671 : = rv_mc_tend(icol,k) &
2672 0 : + mc_correction_ratio * total_mc_positive
2673 :
2674 : endif ! rv_curr < qmin(1)
2675 :
2676 : endif ! .not. l_pos_rv_mc_tend
2677 :
2678 : !!! Check for holes in cloud water mixing ratio
2679 0 : if ( .not. l_pos_rc_mc_tend ) then
2680 :
2681 : ! Calculate the cloud water mixing ratio as it would be with the
2682 : ! current microphysics process tendency.
2683 0 : rc_curr = rc_start(icol,k) + rc_mc_tend(icol,k) * dt
2684 :
2685 0 : if ( rc_curr < qmin(ixcldliq) ) then
2686 :
2687 : ! Microphysics processes are causing a hole in cloud water
2688 : ! mixing ratio.
2689 :
2690 : ! Calculate the maximum allowable magnitude of (negative) cloud
2691 : ! water microphysics process tendency.
2692 0 : mc_tend_max_mag = ( qmin(ixcldliq) - rc_start(icol,k) ) / dt
2693 :
2694 : ! Calculate the amount of the correction that needs to be made
2695 : ! to the cloud water mixing ratio microphysics process
2696 : ! tendency. This number is positive.
2697 0 : mc_tend_correction = mc_tend_max_mag - rc_mc_tend(icol,k)
2698 :
2699 : ! Calculate the total amount of positive microphysics process
2700 : ! tendencies for all hydrometeor mixing ratios.
2701 0 : total_mc_positive = 0.0_r8
2702 0 : if ( l_pos_rv_mc_tend ) then
2703 0 : total_mc_positive = total_mc_positive + rv_mc_tend(icol,k)
2704 : endif
2705 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
2706 0 : total_mc_positive = total_mc_positive + rr_mc_tend(icol,k)
2707 : endif
2708 0 : if ( l_pos_ri_mc_tend ) then
2709 0 : total_mc_positive = total_mc_positive + ri_mc_tend(icol,k)
2710 : endif
2711 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2712 0 : total_mc_positive = total_mc_positive + rs_mc_tend(icol,k)
2713 : endif
2714 :
2715 : ! Calculate the correction ratio.
2716 : ! In principle, this should never be greater than 1 outside of
2717 : ! numerical round-off errors. This is limited at 1 to be safe.
2718 : mc_correction_ratio &
2719 : = min( mc_tend_correction &
2720 0 : / max( total_mc_positive, 1.0e-30_r8 ), 1.0_r8 )
2721 :
2722 : ! Adjust (decrease) the tendencies of all positive hydrometeor
2723 : ! mixing ratio tendencies to balance the adjustment (increase)
2724 : ! to the excessively negative cloud water mixing ratio.
2725 : ! Transfer dry static energy appropriately (in response to the
2726 : ! excessive depletion of cloud water).
2727 0 : if ( l_pos_rv_mc_tend ) then
2728 : ! Changing water vapor to cloud water heats and increases
2729 : ! dry static energy.
2730 : stend(icol,k) &
2731 : = stend(icol,k) &
2732 0 : + latvap * mc_correction_ratio * rv_mc_tend(icol,k)
2733 : ! Update water vapor mixing ratio microphysics tendency.
2734 : rv_mc_tend(icol,k) &
2735 0 : = rv_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2736 : endif
2737 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
2738 : ! Changing rain water to cloud water does not change
2739 : ! dry static energy.
2740 : ! Update rain water mixing ratio microphysics tendency.
2741 : rr_mc_tend(icol,k) &
2742 0 : = rr_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2743 : endif
2744 0 : if ( l_pos_ri_mc_tend ) then
2745 : ! Changing cloud ice to cloud water cools and reduces
2746 : ! dry static energy.
2747 : stend(icol,k) &
2748 : = stend(icol,k) &
2749 0 : - latice * mc_correction_ratio * ri_mc_tend(icol,k)
2750 : ! Update cloud ice mixing ratio microphysics tendency.
2751 : ri_mc_tend(icol,k) &
2752 0 : = ri_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2753 : endif
2754 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2755 : ! Changing snow to cloud water cools and reduces dry
2756 : ! static energy.
2757 : stend(icol,k) &
2758 : = stend(icol,k) &
2759 0 : - latice * mc_correction_ratio * rs_mc_tend(icol,k)
2760 : ! Update snow mixing ratio microphysics tendency.
2761 : rs_mc_tend(icol,k) &
2762 0 : = rs_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2763 : endif
2764 :
2765 : ! Calculate the new cloud water mixing ratio microphysics
2766 : ! process tendency. This should be equal to the maximum
2767 : ! magnitude (negative) amount allowed, mc_tend_max_mag.
2768 : rc_mc_tend(icol,k) &
2769 : = rc_mc_tend(icol,k) &
2770 0 : + mc_correction_ratio * total_mc_positive
2771 :
2772 : endif ! rc_curr < qmin(ixcldliq)
2773 :
2774 : endif ! .not. l_pos_rc_mc_tend
2775 :
2776 : !!! Check for holes in rain water mixing ratio
2777 0 : if ( ixrain > 0 .and. ( .not. l_pos_rr_mc_tend ) ) then
2778 :
2779 : ! Calculate the rain water mixing ratio as it would be with the
2780 : ! current microphysics process tendency.
2781 0 : rr_curr = rr_start(icol,k) + rr_mc_tend(icol,k) * dt
2782 :
2783 0 : if ( rr_curr < qmin(ixrain) ) then
2784 :
2785 : ! Microphysics processes are causing a hole in rain water
2786 : ! mixing ratio.
2787 :
2788 : ! Calculate the maximum allowable magnitude of (negative) rain
2789 : ! water microphysics process tendency.
2790 0 : mc_tend_max_mag = ( qmin(ixrain) - rr_start(icol,k) ) / dt
2791 :
2792 : ! Calculate the amount of the correction that needs to be made
2793 : ! to the rain water mixing ratio microphysics process
2794 : ! tendency. This number is positive.
2795 0 : mc_tend_correction = mc_tend_max_mag - rr_mc_tend(icol,k)
2796 :
2797 : ! Calculate the total amount of positive microphysics process
2798 : ! tendencies for all hydrometeor mixing ratios.
2799 0 : total_mc_positive = 0.0_r8
2800 0 : if ( l_pos_rv_mc_tend ) then
2801 0 : total_mc_positive = total_mc_positive + rv_mc_tend(icol,k)
2802 : endif
2803 0 : if ( l_pos_rc_mc_tend ) then
2804 0 : total_mc_positive = total_mc_positive + rc_mc_tend(icol,k)
2805 : endif
2806 0 : if ( l_pos_ri_mc_tend ) then
2807 0 : total_mc_positive = total_mc_positive + ri_mc_tend(icol,k)
2808 : endif
2809 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2810 0 : total_mc_positive = total_mc_positive + rs_mc_tend(icol,k)
2811 : endif
2812 :
2813 : ! Calculate the correction ratio.
2814 : ! In principle, this should never be greater than 1 outside of
2815 : ! numerical round-off errors. This is limited at 1 to be safe.
2816 : mc_correction_ratio &
2817 : = min( mc_tend_correction &
2818 0 : / max( total_mc_positive, 1.0e-30_r8 ), 1.0_r8 )
2819 :
2820 : ! Adjust (decrease) the tendencies of all positive hydrometeor
2821 : ! mixing ratio tendencies to balance the adjustment (increase)
2822 : ! to the excessively negative rain water mixing ratio.
2823 : ! Transfer dry static energy appropriately (in response to the
2824 : ! excessive depletion of rain water).
2825 0 : if ( l_pos_rv_mc_tend ) then
2826 : ! Changing water vapor to rain water heats and increases
2827 : ! dry static energy.
2828 : stend(icol,k) &
2829 : = stend(icol,k) &
2830 0 : + latvap * mc_correction_ratio * rv_mc_tend(icol,k)
2831 : ! Update water vapor mixing ratio microphysics tendency.
2832 : rv_mc_tend(icol,k) &
2833 0 : = rv_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2834 : endif
2835 0 : if ( l_pos_rc_mc_tend ) then
2836 : ! Changing cloud water to rain water does not change
2837 : ! dry static energy.
2838 : ! Update cloud water mixing ratio microphysics tendency.
2839 : rc_mc_tend(icol,k) &
2840 0 : = rc_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2841 : endif
2842 0 : if ( l_pos_ri_mc_tend ) then
2843 : ! Changing cloud ice to rain water cools and reduces
2844 : ! dry static energy.
2845 : stend(icol,k) &
2846 : = stend(icol,k) &
2847 0 : - latice * mc_correction_ratio * ri_mc_tend(icol,k)
2848 : ! Update cloud ice mixing ratio microphysics tendency.
2849 : ri_mc_tend(icol,k) &
2850 0 : = ri_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2851 : endif
2852 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2853 : ! Changing snow to rain water cools and reduces dry
2854 : ! static energy.
2855 : stend(icol,k) &
2856 : = stend(icol,k) &
2857 0 : - latice * mc_correction_ratio * rs_mc_tend(icol,k)
2858 : ! Update snow mixing ratio microphysics tendency.
2859 : rs_mc_tend(icol,k) &
2860 0 : = rs_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2861 : endif
2862 :
2863 : ! Calculate the new rain water mixing ratio microphysics
2864 : ! process tendency. This should be equal to the maximum
2865 : ! magnitude (negative) amount allowed, mc_tend_max_mag.
2866 : rr_mc_tend(icol,k) &
2867 : = rr_mc_tend(icol,k) &
2868 0 : + mc_correction_ratio * total_mc_positive
2869 :
2870 : endif ! rr_curr < qmin(ixrain)
2871 :
2872 : endif ! ixrain > 0 .and. ( .not. l_pos_rr_mc_tend )
2873 :
2874 : !!! Check for holes in cloud ice mixing ratio
2875 0 : if ( .not. l_pos_ri_mc_tend ) then
2876 :
2877 : ! Calculate the cloud ice mixing ratio as it would be with the
2878 : ! current microphysics process tendency.
2879 0 : ri_curr = ri_start(icol,k) + ri_mc_tend(icol,k) * dt
2880 :
2881 0 : if ( ri_curr < qmin(ixcldice) ) then
2882 :
2883 : ! Microphysics processes are causing a hole in cloud ice
2884 : ! mixing ratio.
2885 :
2886 : ! Calculate the maximum allowable magnitude of (negative) cloud
2887 : ! ice microphysics process tendency.
2888 0 : mc_tend_max_mag = ( qmin(ixcldice) - ri_start(icol,k) ) / dt
2889 :
2890 : ! Calculate the amount of the correction that needs to be made
2891 : ! to the cloud ice mixing ratio microphysics process
2892 : ! tendency. This number is positive.
2893 0 : mc_tend_correction = mc_tend_max_mag - ri_mc_tend(icol,k)
2894 :
2895 : ! Calculate the total amount of positive microphysics process
2896 : ! tendencies for all hydrometeor mixing ratios.
2897 0 : total_mc_positive = 0.0_r8
2898 0 : if ( l_pos_rv_mc_tend ) then
2899 0 : total_mc_positive = total_mc_positive + rv_mc_tend(icol,k)
2900 : endif
2901 0 : if ( l_pos_rc_mc_tend ) then
2902 0 : total_mc_positive = total_mc_positive + rc_mc_tend(icol,k)
2903 : endif
2904 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
2905 0 : total_mc_positive = total_mc_positive + rr_mc_tend(icol,k)
2906 : endif
2907 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2908 0 : total_mc_positive = total_mc_positive + rs_mc_tend(icol,k)
2909 : endif
2910 :
2911 : ! Calculate the correction ratio.
2912 : ! In principle, this should never be greater than 1 outside of
2913 : ! numerical round-off errors. This is limited at 1 to be safe.
2914 : mc_correction_ratio &
2915 : = min( mc_tend_correction &
2916 0 : / max( total_mc_positive, 1.0e-30_r8 ), 1.0_r8 )
2917 :
2918 : ! Adjust (decrease) the tendencies of all positive hydrometeor
2919 : ! mixing ratio tendencies to balance the adjustment (increase)
2920 : ! to the excessively negative cloud ice mixing ratio.
2921 : ! Transfer dry static energy appropriately (in response to the
2922 : ! excessive depletion of cloud ice).
2923 0 : if ( l_pos_rv_mc_tend ) then
2924 : ! Changing water vapor to cloud ice heats and increases
2925 : ! dry static energy.
2926 : stend(icol,k) &
2927 : = stend(icol,k) &
2928 : + ( latvap + latice ) &
2929 0 : * mc_correction_ratio * rv_mc_tend(icol,k)
2930 : ! Update water vapor mixing ratio microphysics tendency.
2931 : rv_mc_tend(icol,k) &
2932 0 : = rv_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2933 : endif
2934 0 : if ( l_pos_rc_mc_tend ) then
2935 : ! Changing cloud water to cloud ice heats and increases
2936 : ! dry static energy.
2937 : stend(icol,k) &
2938 : = stend(icol,k) &
2939 0 : + latice * mc_correction_ratio * rc_mc_tend(icol,k)
2940 : ! Update cloud water mixing ratio microphysics tendency.
2941 : rc_mc_tend(icol,k) &
2942 0 : = rc_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2943 : endif
2944 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
2945 : ! Changing rain water to cloud ice heats and increases
2946 : ! dry static energy.
2947 : stend(icol,k) &
2948 : = stend(icol,k) &
2949 0 : + latice * mc_correction_ratio * rr_mc_tend(icol,k)
2950 : ! Update rain water mixing ratio microphysics tendency.
2951 : rr_mc_tend(icol,k) &
2952 0 : = rr_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2953 : endif
2954 0 : if ( ixsnow > 0 .and. l_pos_rs_mc_tend ) then
2955 : ! Changing snow to cloud ice does not change dry static
2956 : ! energy.
2957 : ! Update snow mixing ratio microphysics tendency.
2958 : rs_mc_tend(icol,k) &
2959 0 : = rs_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
2960 : endif
2961 :
2962 : ! Calculate the new cloud ice mixing ratio microphysics
2963 : ! process tendency. This should be equal to the maximum
2964 : ! magnitude (negative) amount allowed, mc_tend_max_mag.
2965 : ri_mc_tend(icol,k) &
2966 : = ri_mc_tend(icol,k) &
2967 0 : + mc_correction_ratio * total_mc_positive
2968 :
2969 : endif ! ri_curr < qmin(ixcldice)
2970 :
2971 : endif ! .not. l_pos_ri_mc_tend
2972 :
2973 : !!! Check for holes in snow mixing ratio
2974 0 : if ( ixsnow > 0 .and. ( .not. l_pos_rs_mc_tend ) ) then
2975 :
2976 : ! Calculate the snow mixing ratio as it would be with the
2977 : ! current microphysics process tendency.
2978 0 : rs_curr = rs_start(icol,k) + rs_mc_tend(icol,k) * dt
2979 :
2980 0 : if ( rs_curr < qmin(ixsnow) ) then
2981 :
2982 : ! Microphysics processes are causing a hole in snow mixing
2983 : ! ratio.
2984 :
2985 : ! Calculate the maximum allowable magnitude of (negative) snow
2986 : ! microphysics process tendency.
2987 0 : mc_tend_max_mag = ( qmin(ixsnow) - rs_start(icol,k) ) / dt
2988 :
2989 : ! Calculate the amount of the correction that needs to be made
2990 : ! to the snow mixing ratio microphysics process tendency.
2991 : ! This number is positive.
2992 0 : mc_tend_correction = mc_tend_max_mag - rs_mc_tend(icol,k)
2993 :
2994 : ! Calculate the total amount of positive microphysics process
2995 : ! tendencies for all hydrometeor mixing ratios.
2996 0 : total_mc_positive = 0.0_r8
2997 0 : if ( l_pos_rv_mc_tend ) then
2998 0 : total_mc_positive = total_mc_positive + rv_mc_tend(icol,k)
2999 : endif
3000 0 : if ( l_pos_rc_mc_tend ) then
3001 0 : total_mc_positive = total_mc_positive + rc_mc_tend(icol,k)
3002 : endif
3003 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
3004 0 : total_mc_positive = total_mc_positive + rr_mc_tend(icol,k)
3005 : endif
3006 0 : if ( l_pos_ri_mc_tend ) then
3007 0 : total_mc_positive = total_mc_positive + ri_mc_tend(icol,k)
3008 : endif
3009 :
3010 : ! Calculate the correction ratio.
3011 : ! In principle, this should never be greater than 1 outside of
3012 : ! numerical round-off errors. This is limited at 1 to be safe.
3013 : mc_correction_ratio &
3014 : = min( mc_tend_correction &
3015 0 : / max( total_mc_positive, 1.0e-30_r8 ), 1.0_r8 )
3016 :
3017 : ! Adjust (decrease) the tendencies of all positive hydrometeor
3018 : ! mixing ratio tendencies to balance the adjustment (increase)
3019 : ! to the excessively negative snow mixing ratio.
3020 : ! Transfer dry static energy appropriately (in response to the
3021 : ! excessive depletion of snow).
3022 0 : if ( l_pos_rv_mc_tend ) then
3023 : ! Changing water vapor to snow heats and increases dry
3024 : ! static energy.
3025 : stend(icol,k) &
3026 : = stend(icol,k) &
3027 : + ( latvap + latice ) &
3028 0 : * mc_correction_ratio * rv_mc_tend(icol,k)
3029 : ! Update water vapor mixing ratio microphysics tendency.
3030 : rv_mc_tend(icol,k) &
3031 0 : = rv_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
3032 : endif
3033 0 : if ( l_pos_rc_mc_tend ) then
3034 : ! Changing cloud water to snow heats and increases dry
3035 : ! static energy.
3036 : stend(icol,k) &
3037 : = stend(icol,k) &
3038 0 : + latice * mc_correction_ratio * rc_mc_tend(icol,k)
3039 : ! Update cloud water mixing ratio microphysics tendency.
3040 : rc_mc_tend(icol,k) &
3041 0 : = rc_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
3042 : endif
3043 0 : if ( ixrain > 0 .and. l_pos_rr_mc_tend ) then
3044 : ! Changing rain water to snow heats and increases dry
3045 : ! static energy.
3046 : stend(icol,k) &
3047 : = stend(icol,k) &
3048 0 : + latice * mc_correction_ratio * rr_mc_tend(icol,k)
3049 : ! Update rain water mixing ratio microphysics tendency.
3050 : rr_mc_tend(icol,k) &
3051 0 : = rr_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
3052 : endif
3053 0 : if ( l_pos_ri_mc_tend ) then
3054 : ! Changing cloud ice to snow does not change dry static
3055 : ! energy.
3056 : ! Update cloud ice mixing ratio microphysics tendency.
3057 : ri_mc_tend(icol,k) &
3058 0 : = ri_mc_tend(icol,k) * ( 1.0_r8 - mc_correction_ratio )
3059 : endif
3060 :
3061 : ! Calculate the new snow mixing ratio microphysics process
3062 : ! tendency. This should be equal to the maximum magnitude
3063 : ! (negative) amount allowed, mc_tend_max_mag.
3064 : rs_mc_tend(icol,k) &
3065 : = rs_mc_tend(icol,k) &
3066 0 : + mc_correction_ratio * total_mc_positive
3067 :
3068 : endif ! rs_curr < qmin(ixsnow)
3069 :
3070 : endif ! ixsnow > 0 .and. ( .not. l_pos_rs_mc_tend )
3071 :
3072 : end do ! k = top_lev, pver
3073 :
3074 : end do ! icol = 1, ncol
3075 :
3076 : ! Calculate the new overall tendencies by adding the sedimentation
3077 : ! tendencies back onto the new microphysics process tendencies.
3078 : ! For cloud water and cloud ice, the sedimentation tendencies that are
3079 : ! added back on are the true sedimentation tendencies. For cloud water,
3080 : ! this is the sum of rc_sed_tend and rc_sed_evap, and for cloud ice, this
3081 : ! is the sum of ri_sed_tend and ri_sed_subl.
3082 0 : rv_tend(:ncol,:) = rv_mc_tend(:ncol,:)
3083 0 : rc_tend(:ncol,:) = rc_mc_tend(:ncol,:) + ( rc_sed_tend(:ncol,:) + rc_sed_evap(:ncol,:) )
3084 0 : if ( ixrain > 0 ) then
3085 0 : rr_tend(:ncol,:) = rr_mc_tend(:ncol,:) + rr_sed_tend(:ncol,:)
3086 : endif
3087 0 : ri_tend(:ncol,:) = ri_mc_tend(:ncol,:) + ( ri_sed_tend(:ncol,:) + ri_sed_subl(:ncol,:) )
3088 0 : if ( ixsnow > 0 ) then
3089 0 : rs_tend(:ncol,:) = rs_mc_tend(:ncol,:) + rs_sed_tend(:ncol,:)
3090 : endif
3091 :
3092 : ! Now that the original sedimentation tendency has been added to the
3093 : ! new microphysics process tendency, the new total microphysics tendency
3094 : ! can still cause holes to form. After the microphysics process rates were
3095 : ! adjusted, the values of the hydrometeor fields were greater than or equal
3096 : ! to 0 at all grid levels, which means their vertical integrals were also
3097 : ! greater than or equal to 0. Sedimentation by itself has a vertical
3098 : ! integral of 0 (including the amount that sedimented to the surface).
3099 : ! This means that after the microphysics process rates have been adjusted
3100 : ! and sedimentation has been added back on, the resulting hydrometeor
3101 : ! fields all still have vertical integrals that are greater than or equal
3102 : ! to 0. Holes that develop at any particular grid level can be filled.
3103 : ! These holes can be filled conservatively using the sedimentation hole
3104 : ! filler.
3105 : if ( l_sed_hole_fill ) then
3106 :
3107 : ! This section makes use of the following principle:
3108 : !
3109 : ! 3) When adjusting the hydrometeor tendency from sedimentation of a
3110 : ! liquid hydrometeor (cloud water or rain water), conserve:
3111 : !
3112 : ! SUM(k=top_lev:pver) ( rc_sed_tend(k) + rr_sed_tend(k) )
3113 : ! * dt * pdel(k) / g
3114 : ! + precl * dt * 1000 = 0.
3115 :
3116 : ! Call the sedimentation hole filler for rain water mixing ratio.
3117 : ! This can update rr_tend and precl.
3118 0 : if ( ixrain > 0 ) then
3119 : call fill_holes_sedimentation( dt, ncol, rr_start, state%pdel, &
3120 0 : umr, state%zi, qmin(ixrain), &
3121 0 : rr_tend, precl )
3122 : endif ! ixrain > 0
3123 :
3124 : ! Call the sedimentation hole filler for cloud water mixing ratio.
3125 : ! This can update rc_tend and precl.
3126 : call fill_holes_sedimentation( dt, ncol, rc_start, state%pdel, &
3127 0 : vtrmc, state%zi, qmin(ixcldliq), &
3128 0 : rc_tend, precl )
3129 :
3130 : ! Occasionally, a situation can occur where filling a hole in rain can
3131 : ! deplete all the surface liquid-phase precipitation (precl), resulting
3132 : ! in not enough water mass in the vertical profile of cloud water to
3133 : ! fill a hole in cloud water. When this happens, there must be liquid
3134 : ! water found in the vertical profile of rain, so pull the water from
3135 : ! rain to fill any remaining holes in cloud water.
3136 0 : if ( ixrain > 0 ) then
3137 : call fill_holes_same_phase_vert( dt, ncol, rc_start, rr_start, &
3138 0 : state%pdel, qmin(ixcldliq), &
3139 0 : qmin(ixrain), &
3140 0 : rc_tend, rr_tend )
3141 : endif ! ixrain > 0
3142 :
3143 : ! This section makes use of the following principle:
3144 : !
3145 : ! 4) When adjusting the hydrometeor tendency from sedimentation of a
3146 : ! frozen hydrometeor (cloud ice or snow), conserve:
3147 : !
3148 : ! SUM(k=top_lev:pver) ( ri_sed_tend(k) + rs_sed_tend(k) )
3149 : ! * dt * pdel(k) / g
3150 : ! + preci * dt * 1000 = 0.
3151 :
3152 : ! Call the sedimentation hole filler for snow mixing ratio.
3153 : ! This can update rs_tend and preci.
3154 0 : if ( ixsnow > 0 ) then
3155 : call fill_holes_sedimentation( dt, ncol, rs_start, state%pdel, &
3156 0 : ums, state%zi, qmin(ixsnow), &
3157 0 : rs_tend, preci )
3158 : endif ! ixsnow > 0
3159 :
3160 : ! Call the sedimentation hole filler for cloud ice mixing ratio.
3161 : ! This can update ri_tend and preci.
3162 : call fill_holes_sedimentation( dt, ncol, ri_start, state%pdel, &
3163 0 : vtrmi, state%zi, qmin(ixcldice), &
3164 0 : ri_tend, preci )
3165 :
3166 : ! Occasionally, a situation can occur where filling a hole in snow can
3167 : ! deplete all the surface ice-phase precipitation (preci), resulting
3168 : ! in not enough water mass in the vertical profile of cloud ice to
3169 : ! fill a hole in cloud ice. When this happens, there must be ice-phase
3170 : ! water found in the vertical profile of snow, so pull the water from
3171 : ! snow to fill any remaining holes in cloud ice.
3172 0 : if ( ixsnow > 0 ) then
3173 : call fill_holes_same_phase_vert( dt, ncol, ri_start, rs_start, &
3174 0 : state%pdel, qmin(ixcldice), &
3175 0 : qmin(ixsnow), &
3176 0 : ri_tend, rs_tend )
3177 : endif ! ixsnow > 0
3178 :
3179 : ! Update the total precipitation rate (prect) from the updated liquid
3180 : ! precipitation rate (precl) and the updated frozen preciptation rate
3181 : ! (preci).
3182 0 : prect(:ncol) = precl(:ncol) + preci(:ncol)
3183 :
3184 : ! The MG code sets prec_str equal to prect (prec_pcw) and snow_str equal
3185 : ! to preci (snow_pcw). The prec_str and snow_str variables are used
3186 : ! in the calculations for energy and water conservation. Since prect
3187 : ! and preci are adjusted here, when necessary, prec_str and snow_str
3188 : ! also need to be adjusted.
3189 0 : prec_str(:ncol) = prect(:ncol)
3190 0 : snow_str(:ncol) = preci(:ncol)
3191 :
3192 : endif ! l_sed_hole_fill
3193 :
3194 : ! The updated total microphysics tendencies after hole filling have not
3195 : ! been used to update ptend yet, so record the budget terms for hole
3196 : ! filling first.
3197 0 : rv_hf_tend = rv_tend - ptend%q(:,:,1)
3198 0 : rc_hf_tend = rc_tend - ptend%q(:,:,ixcldliq)
3199 0 : if ( ixrain > 0 ) then
3200 0 : rr_hf_tend = rr_tend - ptend%q(:,:,ixrain)
3201 : endif ! ixrain > 0
3202 0 : ri_hf_tend = ri_tend - ptend%q(:,:,ixcldice)
3203 0 : if ( ixsnow > 0 ) then
3204 0 : rs_hf_tend = rs_tend - ptend%q(:,:,ixsnow)
3205 : endif ! ixsnow > 0
3206 :
3207 : ! The updated dry static energy tendency after hole filling has not been
3208 : ! used to update ptend yet, so record the budget term for hole filling
3209 : ! first.
3210 0 : s_hf_tend = stend - ptend%s
3211 :
3212 : ! Pack the current total tendencies for hydrometeor mixing ratio fields.
3213 0 : ptend%q(:,:,1) = rv_tend
3214 0 : ptend%q(:,:,ixcldliq) = rc_tend
3215 0 : if ( ixrain > 0 ) then
3216 0 : ptend%q(:,:,ixrain) = rr_tend
3217 : endif
3218 0 : ptend%q(:,:,ixcldice) = ri_tend
3219 0 : if ( ixsnow > 0 ) then
3220 0 : ptend%q(:,:,ixsnow) = rs_tend
3221 : endif
3222 :
3223 : ! Pack the current tendency for dry static energy.
3224 0 : ptend%s = stend
3225 :
3226 : ! Output stats for hole filling tendencies.
3227 0 : call outfld( 'QVHFTEN', rv_hf_tend, pcols, state%lchnk )
3228 0 : call outfld( 'QCHFTEN', rc_hf_tend, pcols, state%lchnk )
3229 0 : call outfld( 'QRHFTEN', rr_hf_tend, pcols, state%lchnk )
3230 0 : call outfld( 'QIHFTEN', ri_hf_tend, pcols, state%lchnk )
3231 0 : call outfld( 'QSHFTEN', rs_hf_tend, pcols, state%lchnk )
3232 0 : call outfld( 'THFTEN', s_hf_tend / cpair, pcols, state%lchnk )
3233 :
3234 : ! Perform total water and total energy conservation checks.
3235 : if ( l_check_conservation ) then
3236 :
3237 : ! Calculate total water in each grid column.
3238 : ! This calculation is the vertically-integrated grand total water
3239 : ! in each grid column updated for all microphysics and hole filling.
3240 : ! This includes the amount that precipitated to the surface.
3241 0 : do icol = 1, ncol
3242 0 : grand_total_water_column_finish(icol) = 0.0_r8
3243 0 : do k = top_lev, pver
3244 : grand_total_water_column_finish(icol) &
3245 : = grand_total_water_column_finish(icol) &
3246 0 : + ( state%q(icol,k,1) &
3247 0 : + ptend%q(icol,k,1) * dt &
3248 0 : + state%q(icol,k,ixcldliq) &
3249 0 : + ptend%q(icol,k,ixcldliq) * dt &
3250 0 : + state%q(icol,k,ixcldice) &
3251 0 : + ptend%q(icol,k,ixcldice) * dt ) &
3252 0 : * state%pdel(icol,k) * rga
3253 0 : if ( ixrain > 0 ) then
3254 : grand_total_water_column_finish(icol) &
3255 : = grand_total_water_column_finish(icol) &
3256 0 : + ( state%q(icol,k,ixrain) + ptend%q(icol,k,ixrain) * dt ) &
3257 0 : * state%pdel(icol,k) * rga
3258 : endif
3259 0 : if ( ixsnow > 0 ) then
3260 : grand_total_water_column_finish(icol) &
3261 : = grand_total_water_column_finish(icol) &
3262 0 : + ( state%q(icol,k,ixsnow) + ptend%q(icol,k,ixsnow) * dt ) &
3263 0 : * state%pdel(icol,k) * rga
3264 : endif
3265 : end do ! k = top_lev, pver
3266 : grand_total_water_column_finish(icol) &
3267 : = grand_total_water_column_finish(icol) &
3268 0 : + prect(icol) * dt * 1000.0_r8
3269 : end do ! icol = 1, ncol
3270 :
3271 : ! Calculate total energy in each column.
3272 : ! This calculation is the vertically-integrated total energy in each
3273 : ! grid column updated for all microphysics and hole filling. This
3274 : ! includes the amount that precipitated to the surface. Since, the
3275 : ! microphysics code does not directly change kinetic energy,
3276 : ! 0.5 * ( u^2 + v^2 ), it can be skipped as part of the energy
3277 : ! conservation check.
3278 0 : do icol = 1, ncol
3279 0 : total_energy_column_finish(icol) = 0.0_r8
3280 0 : do k = top_lev, pver
3281 : total_energy_column_finish(icol) &
3282 : = total_energy_column_finish(icol) &
3283 0 : + ( state%s(icol,k) + ptend%s(icol,k) * dt &
3284 : + ( latvap + latice ) &
3285 0 : * ( state%q(icol,k,1) + ptend%q(icol,k,1) * dt ) &
3286 0 : + latice * ( state%q(icol,k,ixcldliq) &
3287 0 : + ptend%q(icol,k,ixcldliq) * dt ) ) &
3288 0 : * state%pdel(icol,k) * rga
3289 0 : if ( ixrain > 0 ) then
3290 : total_energy_column_finish(icol) &
3291 : = total_energy_column_finish(icol) &
3292 0 : + latice * ( state%q(icol,k,ixrain) &
3293 0 : + ptend%q(icol,k,ixrain) * dt ) &
3294 0 : * state%pdel(icol,k) * rga
3295 : endif
3296 : end do ! k = top_lev, pver
3297 : total_energy_column_finish(icol) &
3298 : = total_energy_column_finish(icol) &
3299 0 : + latice * precl(icol) * dt * 1000.0_r8
3300 : end do ! icol = 1, ncol
3301 :
3302 : ! Calculate the total relative error in each grid column.
3303 0 : do icol = 1, ncol
3304 :
3305 0 : tot_water_rel_err(icol) &
3306 : = abs( ( grand_total_water_column_finish(icol) &
3307 : - grand_total_water_column_start(icol) ) ) &
3308 : / min( grand_total_water_column_finish(icol), &
3309 0 : grand_total_water_column_start(icol) )
3310 :
3311 : tot_energy_rel_err(icol) &
3312 : = abs( ( total_energy_column_finish(icol) &
3313 : - total_energy_column_start(icol) ) ) &
3314 : / min( total_energy_column_finish(icol), &
3315 0 : total_energy_column_start(icol) )
3316 :
3317 : end do ! icol = 1, ncol
3318 :
3319 : ! Print an error message if any total water relative error is found to
3320 : ! be greater than the threshold.
3321 0 : if ( any( tot_water_rel_err(:ncol) >= err_thresh ) ) then
3322 0 : write(iulog,*) "Water conservation error reported in hole filling"
3323 0 : do icol = 1, ncol
3324 0 : if ( tot_water_rel_err(icol) >= err_thresh ) then
3325 0 : write(iulog,*) "Column = ", icol, &
3326 0 : "Relative error = ", tot_water_rel_err(icol), &
3327 0 : "Column-integrated grand total water at start = ", &
3328 0 : grand_total_water_column_start(icol), &
3329 0 : "Column-integrated grand total water at finish = ", &
3330 0 : grand_total_water_column_finish(icol)
3331 : endif ! tot_water_rel_err(icol) >= err_thresh
3332 : end do ! icol = 1, ncol
3333 : endif ! any( tot_water_rel_err >= err_thresh )
3334 :
3335 : ! Print an error message if any total energy relative error is found to
3336 : ! be greater than the threshold.
3337 0 : if ( any( tot_energy_rel_err(:ncol) >= err_thresh ) ) then
3338 0 : write(iulog,*) "Energy conservation error reported in hole filling"
3339 0 : do icol = 1, ncol
3340 0 : if ( tot_energy_rel_err(icol) >= err_thresh ) then
3341 0 : write(iulog,*) "Column = ", icol, &
3342 0 : "Relative error = ", tot_energy_rel_err(icol), &
3343 0 : "Column-integrated total energy at start = ", &
3344 0 : total_energy_column_start(icol), &
3345 0 : "Column-integrated total energy at finish = ", &
3346 0 : total_energy_column_finish(icol)
3347 : endif ! tot_energy_rel_err(icol) >= err_thresh
3348 : end do ! icol = 1, ncol
3349 : endif ! any( tot_energy_rel_err >= err_thresh )
3350 :
3351 : endif ! l_check_conservation
3352 :
3353 :
3354 0 : return
3355 :
3356 0 : end subroutine subcol_SILHS_fill_holes_conserv
3357 :
3358 : !============================================================================
3359 0 : subroutine fill_holes_sedimentation( dt, ncol, hm_start, pdel, &
3360 : fallspeed_m_per_s, zi, qmin_hm, &
3361 : hm_tend, prec )
3362 :
3363 : ! Description:
3364 : ! After hydrometeor tendencies from microphysics processes were adjusted
3365 : ! so that holes don't form in a hydrometeor field from microphysics
3366 : ! processes, the sedimentation tendency was added back on to produce an
3367 : ! updated total microphysics tendency. The first-order "up-gravity"
3368 : ! sedimentation method that was originally used is positive definite.
3369 : ! However, since the microphysics process tendencies were altered so that
3370 : ! holes don't form, it is possible that adding the old sedimentation
3371 : ! tendencies back onto the new microphysics process tendencies could
3372 : ! produce new total microphysics tendencies that cause holes to form.
3373 : !
3374 : ! In this subroutine, holes in a hydrometeor field are checked for after
3375 : ! the updated microphysics tendency is applied. If any are found, they are
3376 : ! filled from positive hydrometeor mass found at grid levels below where
3377 : ! the hole is found. The levels that are used to fill are within range
3378 : ! based on fallspeed of the hydrometeor. If the level that contains the
3379 : ! hole is within proximity to the surface, then the water that sedimented
3380 : ! to the surface can be used to fill the hole, as well.
3381 : !
3382 : ! If there isn't enough total hydrometeor mass within the fall range to
3383 : ! fill the hole, then positive hydrometeor mass from levels below the fall
3384 : ! range is to be added to the total available mass to fill the hole. Mass
3385 : ! is added one level at a time until enough mass is found to fill the hole
3386 : ! or until the surface is reached and the surface precipitation is added to
3387 : ! the total available fill mass.
3388 : !
3389 : ! After this, if there still isn't enough available mass to fill the hole,
3390 : ! then positive hydrometeor mass is added from all levels above the hole to
3391 : ! the total mass that is available to fill the hole.
3392 :
3393 : !----------------------------------------------------------------------
3394 :
3395 0 : use ppgrid, only: &
3396 : pcols
3397 :
3398 : use ref_pres, only: &
3399 : top_lev => trop_cloud_top_lev
3400 :
3401 : implicit none
3402 :
3403 : ! Input Variables
3404 : real(r8), intent(in) :: dt ! Time step duration
3405 :
3406 : integer, intent(in) :: ncol ! Number of grid columns
3407 :
3408 : real(r8), dimension(pcols,pver), intent(in) :: &
3409 : hm_start, & ! Hydrometeor mixing ratio at start of microphysics [kg/kg]
3410 : pdel ! Pressure difference between grid levels [Pa]
3411 :
3412 : real(r8), dimension(pcols,pver), intent(in) :: &
3413 : fallspeed_m_per_s ! Hydrometeor mixing ratio fall speed [m/s]
3414 :
3415 : real(r8), dimension(pcols,pverp), intent(in) :: &
3416 : zi ! Height of momentum (interface) grid levels [m]
3417 :
3418 : real(r8), intent(in) :: &
3419 : qmin_hm ! Minimum threshold value of hydrometeor mixing ratio [kg/kg]
3420 :
3421 : ! Input/Output Variables
3422 : real(r8), dimension(pcols,pver), intent(inout) :: &
3423 : hm_tend ! Hydrometeor mixing ratio tendency [kg/kg/s]
3424 :
3425 : real(r8), dimension(pcols), intent(inout) :: &
3426 : prec ! Precipitation rate (surface) [m/s]
3427 :
3428 : ! Local Variables
3429 : real(r8), dimension(pver) :: &
3430 : hm_update, & ! Hydrometeor mixing ratio; start of sed. hole fill [kg/kg]
3431 : hm_curr ! Current value of hydrometeor mixing ratio [kg/kg]
3432 :
3433 : real(r8) :: &
3434 : total_hole, & ! Total mass of hole in hydrometeor [kg/m^2]
3435 : total_fill_mass, & ! Total mass available to fill hole [kg/m^2]
3436 : hole_fillmass_ratio, & ! Ratio: total_hole / total_fill_mass [-]
3437 : fallspeed_Pa_per_s, & ! Hydrometeor mixing ratio fall speed [Pa/s]
3438 : total_fall_Pa, & ! Pressure "distance" hydrometeor fell [Pa]
3439 : sum_pdel ! Sum of pdel over levels [Pa]
3440 :
3441 : logical, dimension(pver) :: &
3442 : l_pos_hm ! Flag for a hydrometeor having a positive (>= qmin_hm) value
3443 :
3444 : ! Flag for whether surface precipitation mass needs to be included in
3445 : ! the total_fill_mass for hole filling.
3446 : logical :: l_reached_surface
3447 :
3448 : ! Flag for whether hydrometeor mass from levels above the hole needs to be
3449 : ! included in the total_fill_mass for hole filling.
3450 : logical :: l_fill_from_above
3451 :
3452 : integer :: icol ! Grid column index
3453 :
3454 : integer :: k, idx ! Vertical grid level indices
3455 :
3456 : ! Index of the lowest vertical grid level that needs to be included in the
3457 : ! total_fill_mass for hole filling.
3458 : integer :: lowest_level_idx
3459 :
3460 :
3461 : ! Loop over all columns, performing any adjustments one column at a time.
3462 0 : do icol = 1, ncol
3463 :
3464 : ! Calculate the updated value of the hydrometeor field based on the
3465 : ! updated microphysics tendency. Since the original sedimentation
3466 : ! tendency has been added to the updated microphysics process tendency
3467 : ! to produce the updated total microphysics tendency (hm_tend), the
3468 : ! updated value of the hydrometeor field (hm_update) could be negative.
3469 0 : hm_update = hm_start(icol,:) + hm_tend(icol,:) * dt
3470 0 : hm_curr = hm_update
3471 :
3472 : ! Check for any holes in the vertical profile
3473 0 : if ( any( hm_curr(top_lev:pver) < qmin_hm ) ) then
3474 :
3475 : ! At least one hole is found in this hydrometeor species in this
3476 : ! grid column. The holes must be filled conservatively.
3477 :
3478 : ! Check which levels have values of the hydrometeor that are at or
3479 : ! above the minimum threshold value.
3480 0 : do k = top_lev, pver
3481 0 : if ( hm_curr(k) >= qmin_hm ) then
3482 0 : l_pos_hm(k) = .true.
3483 : else ! hm_curr < qmin_hm
3484 0 : l_pos_hm(k) = .false.
3485 : endif ! hm_curr >= qmin_hm
3486 : end do ! k = top_lev, pver
3487 :
3488 0 : do k = pver, top_lev, -1
3489 :
3490 0 : if ( .not. l_pos_hm(k) ) then
3491 :
3492 : ! A hole is found in the hydrometeor at this grid level.
3493 :
3494 : ! Calculate the total hydrometeor mass of the hole that needs
3495 : ! to be filled.
3496 : ! The value of the hydrometeor mixing ratio is negative, but
3497 : ! the value of total_hole is positive.
3498 0 : total_hole = ( qmin_hm - hm_curr(k) ) * pdel(icol,k) * rga
3499 :
3500 : ! Calculate the total hydrometeor mass available from below
3501 : ! to fill the hole.
3502 0 : if ( k == pver ) then
3503 :
3504 : ! A hole is found at the lowermost level.
3505 : ! The only place the hydrometeor could have sedimented
3506 : ! to is the surface, so fill from only the surface.
3507 0 : l_reached_surface = .true.
3508 :
3509 : ! Calculate the available amount of hydrometeor mass to
3510 : ! fill the hole.
3511 0 : total_fill_mass = prec(icol) * dt * 1000.0_r8
3512 :
3513 : else ! top_lev <= k < pver
3514 :
3515 : ! Calculate the hydrometeor fallspeed in Pa/s.
3516 : ! In MG2, the equation for this is given by:
3517 : !
3518 : ! fallspeed([Pa/s]) = g * rho * fallspeed([m/s]).
3519 : !
3520 : ! The value of rho is typically calculated from the
3521 : ! hydrostatic approximation:
3522 : !
3523 : ! rho = - ( 1 / g ) * dp/dz.
3524 : !
3525 : ! The equation for fallspeed in Pa/s becomes:
3526 : !
3527 : ! fallspeed([Pa/s]) = - dp/dz * fallspeed([m/s]).
3528 : fallspeed_Pa_per_s &
3529 : = fallspeed_m_per_s(icol,k) &
3530 0 : * pdel(icol,k) / ( zi(icol,k) - zi(icol,k+1) )
3531 :
3532 : ! Calculate the fall "distance" in Pa.
3533 0 : total_fall_Pa = fallspeed_Pa_per_s * dt
3534 :
3535 : ! Find the index of the vertical level that the hydrometeor
3536 : ! sedimented to in one timestep. It must sediment at least
3537 : ! one level.
3538 0 : sum_pdel = 0.0_r8
3539 0 : idx = k + 1
3540 0 : do
3541 : ! Update the total pressure difference between the
3542 : ! level of origin and the current level.
3543 0 : sum_pdel = sum_pdel + pdel(icol,idx)
3544 0 : if ( sum_pdel >= total_fall_Pa ) then
3545 : ! The total pressure difference between the level of
3546 : ! origin and the current level exceeds the total
3547 : ! hydrometeor fall "distance" (in Pa).
3548 : lowest_level_idx = idx
3549 : l_reached_surface = .false.
3550 : exit
3551 : else ! sum_pdel < total_fall_Pa
3552 : ! The total hydrometeor fall "distance" (in Pa)
3553 : ! exceeds the total pressure difference between the
3554 : ! level of origin and the current level.
3555 0 : if ( idx == pver ) then
3556 : ! The lowest level of the model has been reached.
3557 : ! The hydrometeor sedimented to the surface.
3558 : lowest_level_idx = pver
3559 : l_reached_surface = .true.
3560 : exit
3561 : else ! idx < pver
3562 : ! Increment idx and keep going.
3563 0 : idx = idx + 1
3564 : endif ! idx == pver
3565 : endif ! sum_pdel >= total_fall_Pa
3566 : end do
3567 :
3568 : ! Calculate the available amount of hydrometeor mass to
3569 : ! fill the hole.
3570 : total_fill_mass = 0.0_r8
3571 : if ( l_reached_surface ) then
3572 : ! The hydrometeor sedimented to the surface, so
3573 : ! automatically loop down to pver and include the
3574 : ! surface mass.
3575 0 : do idx = k+1, pver, 1
3576 0 : if ( l_pos_hm(idx) ) then
3577 : total_fill_mass &
3578 : = total_fill_mass &
3579 : + ( hm_curr(idx) - qmin_hm ) &
3580 0 : * pdel(icol,idx) * rga
3581 : endif ! l_pos_hm(idx)
3582 : end do ! idx = k+1, pver, 1
3583 : ! Contribution to total fill mass from the surface.
3584 : total_fill_mass &
3585 0 : = total_fill_mass + prec(icol) * dt * 1000.0_r8
3586 : else ! .not. l_reached_surface
3587 : ! The hydrometeor sedimented to lowest_level_idx.
3588 : idx = k + 1
3589 : do
3590 0 : if ( l_pos_hm(idx) ) then
3591 : total_fill_mass &
3592 : = total_fill_mass &
3593 : + ( hm_curr(idx) - qmin_hm ) &
3594 0 : * pdel(icol,idx) * rga
3595 : endif ! l_pos_hm(idx)
3596 0 : if ( idx >= lowest_level_idx ) then
3597 : ! Check if enough mass has been gathered in
3598 : ! total_fill_mass to fill the hole.
3599 0 : if ( total_fill_mass >= total_hole ) then
3600 : ! There has been enough total_fill_mass
3601 : ! gathered to completely fill the hole.
3602 : lowest_level_idx = idx
3603 : exit
3604 : else ! total_fill_mass < total_hole
3605 : ! Even though lowest_level_idx has been reached,
3606 : ! more total_fill_mass needs to be added in
3607 : ! order to completely fill the hole, so keep
3608 : ! going.
3609 0 : if ( idx == pver ) then
3610 : ! The lowest vertical level has already been
3611 : ! reached, so go to the surface.
3612 0 : lowest_level_idx = pver
3613 0 : l_reached_surface = .true.
3614 : ! Contribution to total fill mass from the
3615 : ! surface.
3616 : total_fill_mass &
3617 : = total_fill_mass &
3618 0 : + prec(icol) * dt * 1000.0_r8
3619 0 : exit
3620 : else ! idx < pver
3621 : ! Haven't reached pver yet, so increment
3622 : ! and keep going.
3623 0 : idx = idx + 1
3624 : endif ! idx == pver
3625 : endif ! total_fill_mass >= total_hole
3626 : else ! idx < lowest_level_idx
3627 : ! Haven't reached lowest_level_idx yet, so
3628 : ! increment and keep going.
3629 0 : idx = idx + 1
3630 : endif ! idx >= lowest_level_idx
3631 : end do
3632 : endif ! l_reached_surface
3633 :
3634 : endif ! k == pver
3635 :
3636 : ! If mass has been added all the way down to the surface and
3637 : ! there's still not enough mass to fill the hole, then fill the
3638 : ! hole pulling mass from above.
3639 0 : if ( total_fill_mass >= total_hole ) then
3640 : l_fill_from_above = .false.
3641 : else ! total_fill_mass < total_hole
3642 0 : l_fill_from_above = .true.
3643 0 : do idx = top_lev, k-1, 1
3644 0 : if ( l_pos_hm(idx) ) then
3645 : total_fill_mass &
3646 : = total_fill_mass &
3647 : + ( hm_curr(idx) - qmin_hm ) &
3648 0 : * pdel(icol,idx) * rga
3649 : endif ! l_pos_hm(idx)
3650 : end do ! idx = top_lev, k-1, 1
3651 : endif ! total_fill_mass >= total_hole
3652 :
3653 : ! Calculate the ratio of total hole to total fill mass. This
3654 : ! should not exceed 1 except as a result of numerical round-off
3655 : ! errors. Use thresholding to be safe.
3656 : hole_fillmass_ratio &
3657 : = min( total_hole / max( total_fill_mass, 1.0e-30_r8 ), &
3658 0 : 1.0_r8 )
3659 :
3660 0 : if ( k < pver ) then
3661 : ! Modify (reduce) the amount of the hydrometeor at levels
3662 : ! that were used to fill the hole.
3663 0 : do idx = k+1, lowest_level_idx
3664 0 : if ( l_pos_hm(idx) ) then
3665 : ! Since pdel at a grid level does not change and
3666 : ! gravit is constant, the only variable that needs to
3667 : ! be modified proportionately is hm_curr.
3668 : hm_curr(idx) &
3669 : = qmin_hm &
3670 : + ( hm_curr(idx) - qmin_hm ) &
3671 0 : * ( 1.0_r8 - hole_fillmass_ratio )
3672 : endif ! l_pos_hm(idx)
3673 : end do ! idx = k+1, lowest_level_idx
3674 : endif ! k < pver
3675 :
3676 0 : if ( l_reached_surface ) then
3677 : ! Modify (reduce) the amount of surface precipitation in
3678 : ! order to fill the hole. Since dt and 1000 are constants,
3679 : ! the only variable that needs to be modified
3680 : ! proportionately is prec.
3681 0 : prec(icol) = prec(icol) * ( 1.0_r8 - hole_fillmass_ratio )
3682 : endif ! l_reached_surface
3683 :
3684 0 : if ( l_fill_from_above ) then
3685 : ! Modify (reduce) the amount of the hydrometeor at levels
3686 : ! that were used to fill the hole.
3687 0 : do idx = top_lev, k-1
3688 0 : if ( l_pos_hm(idx) ) then
3689 : ! Since pdel at a grid level does not change and
3690 : ! gravit is constant, the only variable that needs to
3691 : ! be modified proportionately is hm_curr.
3692 : hm_curr(idx) &
3693 : = qmin_hm &
3694 : + ( hm_curr(idx) - qmin_hm ) &
3695 0 : * ( 1.0_r8 - hole_fillmass_ratio )
3696 : endif ! l_pos_hm(idx)
3697 : end do ! idx = top_lev, k-1
3698 : endif ! l_fill_from_above
3699 :
3700 : ! Update the value of the hydrometeor at the level where the
3701 : ! hole was found. Mathematically, as long as the available
3702 : ! mass was able to fill the entire hole, the new value of the
3703 : ! hydrometeor mixing ratio (hm_curr) should be qmin_hm.
3704 : hm_curr(k) &
3705 : = hm_curr(k) &
3706 : + hole_fillmass_ratio * total_fill_mass &
3707 0 : * gravit / pdel(icol,k)
3708 :
3709 : endif ! .not. l_pos_hm(k)
3710 :
3711 : end do ! k = pver, top_lev, -1
3712 :
3713 : endif ! any( hm_curr(top_lev:pver) < qmin_hm )
3714 :
3715 : ! Update the value of total microphysics tendency after hole filling.
3716 0 : hm_tend(icol,:) = hm_tend(icol,:) + ( hm_curr - hm_update ) / dt
3717 :
3718 : end do ! icol = 1, ncol
3719 :
3720 :
3721 0 : return
3722 :
3723 0 : end subroutine fill_holes_sedimentation
3724 :
3725 : !============================================================================
3726 0 : subroutine fill_holes_same_phase_vert( dt, ncol, hm_start, hm_start_filler, &
3727 : pdel, qmin_hm, qmin_hm_filler, &
3728 : hm_tend, hm_tend_filler )
3729 :
3730 : ! Description:
3731 : ! Fills remaining holes in a hydrometeor with mass from the the vertical
3732 : ! profile of another hydrometeor of the same phase. Remaining holes in
3733 : ! cloud water are filled with rain water and remaining holes in snow are
3734 : ! filled with cloud ice.
3735 : !
3736 : ! This subroutine, combined with subroutine fill_holes_sedimentation, fill
3737 : ! holes making use of the following principles:
3738 : !
3739 : ! 3) When adjusting the hydrometeor tendency from sedimentation of a
3740 : ! liquid hydrometeor (cloud water or rain water), conserve:
3741 : !
3742 : ! SUM(k=top_lev:pver) ( rc_sed_tend(k) + rr_sed_tend(k) )
3743 : ! * dt * pdel(k) / g
3744 : ! + precl * dt * 1000 = 0.
3745 : !
3746 : ! 4) When adjusting the hydrometeor tendency from sedimentation of a
3747 : ! frozen hydrometeor (cloud ice or snow), conserve:
3748 : !
3749 : ! SUM(k=top_lev:pver) ( ri_sed_tend(k) + rs_sed_tend(k) )
3750 : ! * dt * pdel(k) / g
3751 : ! + preci * dt * 1000 = 0.
3752 : !
3753 : ! These two equations (one for liquid-phase hydrometeors and one for
3754 : ! ice-phase hydrometeors) could be further split into one equation for
3755 : ! each hydrometeor if there was prec output for each hydrometeor. However,
3756 : ! there's only prec output for ice-phase precipitation rate and total
3757 : ! precipitation rate (liquid preciptation rate is total rate minus
3758 : ! ice-phase rate).
3759 : !
3760 : ! Since only liquid-phase precipitation rate (precl) and ice-phase
3761 : ! precipitation rate (preci) are available, and there are two hydrometeors
3762 : ! in each category, one hydrometeor from each category must fill before
3763 : ! the other hydrometeor from its category and get priority access to precl
3764 : ! or preci. Since a vast majority of liquid precipitation comes from rain
3765 : ! rather than sedimenting cloud water, rain is filled before cloud water
3766 : ! and gets priority access to precl. Likewise, since a vast majority of
3767 : ! frozen precipitation comes from snow rather than sedimenting cloud ice,
3768 : ! snow is filled before cloud ice and gets priority access to preci.
3769 : !
3770 : ! The order of sedimentation hole filling is as follows. First, a level
3771 : ! with a hole in it is identified. The fall distance for the hydrometeor
3772 : ! that originated at a level is calculated. Total mass to fill the hole is
3773 : ! calculated from all levels within the fall range that have positive
3774 : ! values of the hydrometeor. The amount that precipitated to the surface
3775 : ! is also included if the hydrometeor fell that far. If that isn't enough
3776 : ! mass to fill the hole, then levels that are lower in the profile are
3777 : ! included (if the hydrometeor has a positive value) until enough mass is
3778 : ! found to fill the hole or until the surface is reached. If there isn't
3779 : ! enough mass found in all levels below the hole, including the amount that
3780 : ! precipitated to the ground, to fill the hole, then the hydrometeor mass
3781 : ! from all levels above the hole (again, where a positive value of the
3782 : ! hydrometeor is found) are included in the total available mass to fill
3783 : ! the hole.
3784 : !
3785 : ! Occasionally, a situation can occur where both hydrometeors in a category
3786 : ! contributed to surface precipitation rate, and filling a hole in rain
3787 : ! (or snow) can deplete all the surface precl (or preci), resulting in not
3788 : ! enough water mass in the vertical profile (including the surface) of
3789 : ! cloud water (or cloud ice) to fill a hole in cloud water (or cloud ice).
3790 : ! When this happens, there must still be liquid water (or frozen water)
3791 : ! found in the vertical profile of rain (or snow), so pull the water from
3792 : ! rain (or snow) to fill any remaining holes in cloud water (or cloud ice).
3793 :
3794 : !----------------------------------------------------------------------
3795 :
3796 0 : use ppgrid, only: &
3797 : pcols
3798 :
3799 : use ref_pres, only: &
3800 : top_lev => trop_cloud_top_lev
3801 :
3802 : implicit none
3803 :
3804 : ! Input Variables
3805 : real(r8), intent(in) :: dt ! Time step duration
3806 :
3807 : integer, intent(in) :: ncol ! Number of grid columns
3808 :
3809 : real(r8), dimension(pcols,pver), intent(in) :: &
3810 : hm_start, & ! Hydrometeor mixing ratio (microphys start) [kg/kg]
3811 : hm_start_filler, & ! Filler hydromet mix ratio (microphys start) [kg/kg]
3812 : pdel ! Pressure difference between grid levels [Pa]
3813 :
3814 : real(r8), intent(in) :: &
3815 : qmin_hm, & ! Minimum threshold hydrometeor mixing ratio [kg/kg]
3816 : qmin_hm_filler ! Min threshold filler hydromet mixing ratio [kg/kg]
3817 :
3818 : ! Input/Output Variables
3819 : real(r8), dimension(pcols,pver), intent(inout) :: &
3820 : hm_tend, & ! Hydrometeor mixing ratio tendency [kg/kg/s]
3821 : hm_tend_filler ! Filler hydrometeor mixing ratio tendency [kg/kg/s]
3822 :
3823 : ! Local Variables
3824 : real(r8), dimension(pver) :: &
3825 : hm_update, & ! Hydrometeor mixing ratio; start [kg/kg]
3826 : hm_update_filler, & ! Filler Hydrometeor mixing ratio; start [kg/kg]
3827 : hm_curr, & ! Current hydrometeor mixing ratio [kg/kg]
3828 : hm_curr_filler ! Current filler hydrometeor mixing ratio [kg/kg]
3829 :
3830 : real(r8) :: &
3831 : total_hole, & ! Total mass of hole in hydrometeor [kg/m^2]
3832 : total_fill_mass, & ! Total mass available to fill hole [kg/m^2]
3833 : hole_fillmass_ratio ! Ratio: total_hole / total_fill_mass [-]
3834 :
3835 : logical, dimension(pver) :: &
3836 : l_pos_hm, & ! Flag: hydrometeor has positive (>= qmin_hm) value
3837 : l_pos_hm_filler ! Flag: filler hydrometeor has positive value
3838 :
3839 : integer :: icol ! Grid column index
3840 :
3841 : integer :: k, idx ! Vertical grid level indices
3842 :
3843 :
3844 : ! Loop over all columns, performing any adjustments one column at a time.
3845 0 : do icol = 1, ncol
3846 :
3847 : ! Calculate the updated value of the hydrometeor field based on the
3848 : ! updated microphysics tendency.
3849 0 : hm_update = hm_start(icol,:) + hm_tend(icol,:) * dt
3850 0 : hm_curr = hm_update
3851 :
3852 : ! Calculate the updated value of the filler hydrometeor field based on
3853 : ! the updated microphysics tendency.
3854 0 : hm_update_filler = hm_start_filler(icol,:) + hm_tend_filler(icol,:) * dt
3855 0 : hm_curr_filler = hm_update_filler
3856 :
3857 : ! Check for any holes in the vertical profile
3858 0 : if ( any( hm_curr(top_lev:pver) < qmin_hm ) ) then
3859 :
3860 : ! At least one hole is found in this hydrometeor species in this
3861 : ! grid column. The holes must be filled conservatively.
3862 :
3863 : ! Check which levels have values of the hydrometeor that are at or
3864 : ! above the minimum threshold value.
3865 0 : do k = top_lev, pver
3866 : ! Check for the hydrometeor that might need to be filled.
3867 0 : if ( hm_curr(k) >= qmin_hm ) then
3868 0 : l_pos_hm(k) = .true.
3869 : else ! hm_curr < qmin_hm
3870 0 : l_pos_hm(k) = .false.
3871 : endif ! hm_curr >= qmin_hm
3872 : ! Check for the filler hydrometeor, as some levels might have
3873 : ! numerical round-off level, small negative values.
3874 0 : if ( hm_curr_filler(k) >= qmin_hm_filler ) then
3875 0 : l_pos_hm_filler(k) = .true.
3876 : else ! hm_curr_filler < qmin_hm_filler
3877 0 : l_pos_hm_filler(k) = .false.
3878 : endif ! hm_curr_filler >= qmin_hm_filler
3879 : end do ! k = top_lev, pver
3880 :
3881 0 : do k = top_lev, pver
3882 :
3883 0 : if ( .not. l_pos_hm(k) ) then
3884 :
3885 : ! A hole is found in the hydrometeor at this grid level.
3886 :
3887 : ! Calculate the total hydrometeor mass of the hole that needs
3888 : ! to be filled.
3889 : ! The value of the hydrometeor mixing ratio is negative, but
3890 : ! the value of total_hole is positive.
3891 0 : total_hole = ( qmin_hm - hm_curr(k) ) * pdel(icol,k) * rga
3892 :
3893 : ! Calculate the total hydrometeor mass available from the
3894 : ! filler hydrometeor to fill the hole.
3895 0 : total_fill_mass = 0.0_r8
3896 0 : do idx = top_lev, pver, 1
3897 0 : if ( l_pos_hm_filler(idx) ) then
3898 : total_fill_mass &
3899 : = total_fill_mass &
3900 : + ( hm_curr_filler(idx) - qmin_hm_filler ) &
3901 0 : * pdel(icol,idx) * rga
3902 : endif ! l_pos_hm_filler(idx)
3903 : end do ! idx = top_lev, pver, 1
3904 :
3905 : ! Calculate the ratio of total hole to total fill mass. This
3906 : ! should not exceed 1 except as a result of numerical round-off
3907 : ! errors. Use thresholding to be safe.
3908 : hole_fillmass_ratio &
3909 : = min( total_hole / max( total_fill_mass, 1.0e-30_r8 ), &
3910 0 : 1.0_r8 )
3911 :
3912 : ! Modify (reduce) the amount of the filler hydrometeor.
3913 0 : do idx = top_lev, pver
3914 0 : if ( l_pos_hm_filler(idx) ) then
3915 : ! Since pdel at a grid level does not change and gravit
3916 : ! is constant, the only variable that needs to be
3917 : ! modified proportionately is hm_curr_filler.
3918 : hm_curr_filler(idx) &
3919 : = qmin_hm_filler &
3920 : + ( hm_curr_filler(idx) - qmin_hm_filler ) &
3921 0 : * ( 1.0_r8 - hole_fillmass_ratio )
3922 : endif ! l_pos_hm_filler(idx)
3923 : end do ! idx = top_lev, pver
3924 :
3925 : ! Update the value of the hydrometeor at the level where the
3926 : ! hole was found. Mathematically, as long as the available
3927 : ! mass was able to fill the entire hole, the new value of the
3928 : ! hydrometeor mixing ratio (hm_curr) should be qmin_hm.
3929 : hm_curr(k) &
3930 : = hm_curr(k) &
3931 : + hole_fillmass_ratio * total_fill_mass &
3932 0 : * gravit / pdel(icol,k)
3933 :
3934 : endif ! .not. l_pos_hm(k)
3935 :
3936 : end do ! k = top_lev, pver
3937 :
3938 : endif ! any( hm_curr(top_lev:pver) < qmin_hm )
3939 :
3940 : ! Update the value of total microphysics tendency after hole filling.
3941 0 : hm_tend(icol,:) = hm_tend(icol,:) + ( hm_curr - hm_update ) / dt
3942 :
3943 : ! Update the value of total microphysics tendency after hole filling for
3944 : ! the filler hydrometeor.
3945 : hm_tend_filler(icol,:) &
3946 0 : = hm_tend_filler(icol,:) + ( hm_curr_filler - hm_update_filler ) / dt
3947 :
3948 : end do ! icol = 1, ncol
3949 :
3950 :
3951 0 : return
3952 :
3953 0 : end subroutine fill_holes_same_phase_vert
3954 :
3955 : !============================================================================
3956 0 : subroutine subcol_SILHS_hydromet_conc_tend_lim( state, dt, ptend )
3957 :
3958 : ! Description:
3959 : ! Limits the values of mean hydrometeor concentrations so that the mean
3960 : ! drop size for the hydrometeor type remains reasonable and does not become
3961 : ! too large.
3962 :
3963 : !----------------------------------------------------------------------
3964 :
3965 0 : use shr_const_mod, only: &
3966 : shr_const_pi, &
3967 : shr_const_rhofw
3968 :
3969 : use constituents, only: &
3970 : qmin
3971 :
3972 : use ref_pres, only: &
3973 : top_lev => trop_cloud_top_lev
3974 :
3975 : implicit none
3976 :
3977 : ! Input Variables
3978 : type(physics_state), intent(in) :: state ! Physics state variables
3979 : real(r8), intent(in) :: dt ! Time step duration
3980 :
3981 : ! Input/Output Variable
3982 : type(physics_ptend), intent(inout) :: ptend ! Parameterization tendencies
3983 :
3984 : ! Local Variables
3985 : real( r8 ) :: &
3986 : rcm_update, & ! New value of mean cloud water mixing ratio [kg/kg]
3987 : rrm_update, & ! New value of mean rain water mixing ratio [kg/kg]
3988 : rim_update, & ! New value of mean ice mixing ratio [kg/kg]
3989 : rsm_update ! New value of mean snow mixing ratio [kg/kg]
3990 :
3991 : real( r8 ) :: &
3992 : Nc_tend_min, & ! Minimum value of cloud droplet conc. tendency [num/kg/s]
3993 : Nr_tend_min, & ! Minimum value of rain drop conc. tendency [num/kg/s]
3994 : Ni_tend_min, & ! Minimum value of ice conc. tendency [num/kg/s]
3995 : Ns_tend_min ! Minimum value of snow conc. tendency [num/kg/s]
3996 :
3997 : real( r8 ), parameter :: &
3998 : four_thirds = 4.0_r8/3.0_r8, & ! 4/3
3999 : rho_ice = 917.0_r8, & ! Density of ice [kg/m^3]
4000 : rho_lw = shr_const_rhofw, & ! Density of liquid water [kg/m^3]
4001 : pi = shr_const_pi ! Pi
4002 :
4003 : real( r8 ), parameter :: &
4004 : mvr_cloud_max = 1.6E-5_r8, & ! Max. avg. mean vol. rad. cloud [m]
4005 : mvr_rain_max = 5.0E-3_r8, & ! Max. avg. mean vol. rad. rain [m]
4006 : mvr_ice_max = 1.3E-4_r8, & ! Max. avg. mean vol. rad. ice [m]
4007 : mvr_snow_max = 1.0E-2_r8 ! Max. avg. mean vol. rad. snow [m]
4008 :
4009 : ! Calculate the coefficient for the minimum mean cloud droplet
4010 : ! concentration, where <Nc>|_min = Ncm_min_coef * <rc> and has units of
4011 : ! 1/kg.
4012 : real( r8 ), parameter :: &
4013 : Ncm_min_coef = 1.0_r8 / ( four_thirds * pi * rho_lw * mvr_cloud_max**3 )
4014 :
4015 : ! Calculate the coefficient for the minimum mean rain drop concentration,
4016 : ! where <Nr>|_min = Nrm_min_coef * <rr> and has units of 1/kg.
4017 : real( r8 ), parameter :: &
4018 : Nrm_min_coef = 1.0_r8 / ( four_thirds * pi * rho_lw * mvr_rain_max**3 )
4019 :
4020 : ! Calculate the coefficient for the minimum mean ice crystal concentration,
4021 : ! where <Ni>|_min = Nim_min_coef * <ri> and has units of 1/kg.
4022 : real( r8 ), parameter :: &
4023 : Nim_min_coef = 1.0_r8 / ( four_thirds * pi * rho_ice * mvr_ice_max**3 )
4024 :
4025 : ! Calculate the coefficient for the minimum mean snow flake concentration,
4026 : ! where <Ns>|_min = Nsm_min_coef * <rs> and has units of 1/kg.
4027 : real( r8 ), parameter :: &
4028 : Nsm_min_coef = 1.0_r8 / ( four_thirds * pi * rho_ice * mvr_snow_max**3 )
4029 :
4030 : integer :: ncol ! Number of grid columns
4031 :
4032 : integer :: icol ! Column loop index
4033 :
4034 : integer :: k ! Vertical level loop index
4035 :
4036 :
4037 : ! Get the number of grid columns.
4038 0 : ncol = state%ncol
4039 :
4040 : ! Loop over all grid columns.
4041 0 : do icol = 1, ncol
4042 :
4043 : ! Loop over all vertical levels from top_lev to pver.
4044 0 : do k = top_lev, pver
4045 :
4046 : ! Cloud droplet concentration
4047 0 : if ( ixcldliq > 0 .and. ixnumliq > 0 ) then
4048 :
4049 : ! Calculate the value of cloud water mixing ratio after the
4050 : ! update.
4051 : rcm_update &
4052 0 : = max( state%q(icol,k,ixcldliq) + ptend%q(icol,k,ixcldliq) * dt, &
4053 0 : qmin(ixcldliq) )
4054 :
4055 : ! Calculate the limiting cloud droplet concentration tendency so
4056 : ! that cloud maintains a reasonable (not too big) mean volume
4057 : ! radius.
4058 : Nc_tend_min &
4059 0 : = ( Ncm_min_coef * rcm_update - state%q(icol,k,ixnumliq) ) / dt
4060 :
4061 : ! The cloud droplet concentration tendency needs to be the greater
4062 : ! of the current Nc_tend and Nc_tend_min.
4063 0 : ptend%q(icol,k,ixnumliq) &
4064 0 : = max( ptend%q(icol,k,ixnumliq), Nc_tend_min )
4065 :
4066 : endif ! ixcldliq > 0 .and. ixnumliq > 0
4067 :
4068 : ! Rain drop concentration
4069 0 : if ( ixrain > 0 .and. ixnumrain > 0 ) then
4070 :
4071 : ! Calculate the value of rain water mixing ratio after the update.
4072 : rrm_update &
4073 0 : = max( state%q(icol,k,ixrain) + ptend%q(icol,k,ixrain) * dt, &
4074 0 : qmin(ixrain) )
4075 :
4076 : ! Calculate the limiting rain drop concentration tendency so that
4077 : ! rain maintains a reasonable (not too big) mean volume radius.
4078 : Nr_tend_min &
4079 0 : = ( Nrm_min_coef * rrm_update - state%q(icol,k,ixnumrain) ) / dt
4080 :
4081 : ! The rain drop concentration tendency needs to be the greater of
4082 : ! the current Nr_tend and Nr_tend_min.
4083 0 : ptend%q(icol,k,ixnumrain) &
4084 0 : = max( ptend%q(icol,k,ixnumrain), Nr_tend_min )
4085 :
4086 : endif ! ixrain > 0 .and. ixnumrain > 0
4087 :
4088 : ! Ice crystal concentration
4089 0 : if ( ixcldice > 0 .and. ixnumice > 0 ) then
4090 :
4091 : ! Calculate the value of ice mixing ratio after the update.
4092 : rim_update &
4093 0 : = max( state%q(icol,k,ixcldice) + ptend%q(icol,k,ixcldice) * dt, &
4094 0 : qmin(ixcldice) )
4095 :
4096 : ! Calculate the limiting ice crystal concentration tendency so
4097 : ! that ice maintains a reasonable (not too big) mean volume
4098 : ! radius.
4099 : Ni_tend_min &
4100 0 : = ( Nim_min_coef * rim_update - state%q(icol,k,ixnumice) ) / dt
4101 :
4102 : ! The ice crystal concentration tendency needs to be the greater
4103 : ! of the current Ni_tend and Ni_tend_min.
4104 0 : ptend%q(icol,k,ixnumice) &
4105 0 : = max( ptend%q(icol,k,ixnumice), Ni_tend_min )
4106 :
4107 : endif ! ixcldice > 0 .and. ixnumice > 0
4108 :
4109 : ! Snow flake concentration
4110 0 : if ( ixsnow > 0 .and. ixnumsnow > 0 ) then
4111 :
4112 : ! Calculate the value of snow mixing ratio after the update.
4113 : rsm_update &
4114 0 : = max( state%q(icol,k,ixsnow) + ptend%q(icol,k,ixsnow) * dt, &
4115 0 : qmin(ixsnow) )
4116 :
4117 : ! Calculate the limiting snow flake concentration tendency so that
4118 : ! snow maintains a reasonable (not too big) mean volume radius.
4119 : Ns_tend_min &
4120 0 : = ( Nsm_min_coef * rsm_update - state%q(icol,k,ixnumsnow) ) / dt
4121 :
4122 : ! The snow flake concentration tendency needs to be the greater of
4123 : ! the current Ns_tend and Ns_tend_min.
4124 0 : ptend%q(icol,k,ixnumsnow) &
4125 0 : = max( ptend%q(icol,k,ixnumsnow), Ns_tend_min )
4126 :
4127 : endif ! ixsnow > 0 .and. ixnumsnow > 0
4128 :
4129 : end do ! k = top_lev, pver
4130 :
4131 : end do ! icol = 1, ncol
4132 :
4133 :
4134 0 : return
4135 :
4136 0 : end subroutine subcol_SILHS_hydromet_conc_tend_lim
4137 :
4138 : !============================================================================
4139 :
4140 : ! Getunit and Freeunit are depreciated in Fortran going forward, so this is a
4141 : ! small function to get an unused stream identifier to send to setup_corr_varnce_array_api
4142 : ! or any other silhs/clubb functions that require a unit number argument
4143 : ! This comes directly from the Fortran wiki
4144 : integer function newunit(unit)
4145 : integer, intent(out), optional :: unit
4146 :
4147 : integer, parameter :: LUN_MIN=10, LUN_MAX=1000
4148 : logical :: opened
4149 : integer :: lun
4150 :
4151 : newunit=-1
4152 : do lun=LUN_MIN,LUN_MAX
4153 : inquire(unit=lun,opened=opened)
4154 : if (.not. opened) then
4155 : newunit=lun
4156 : exit
4157 : end if
4158 : end do
4159 : if (present(unit)) unit=newunit
4160 0 : end function newunit
4161 :
4162 : end module subcol_SILHS
|