CCPP SciDoc v7.0.0  v7.0.0
Common Community Physics Package Developed at DTC
 
Loading...
Searching...
No Matches
module_mp_tempo_tables.F90
2 !! initialize variables for tempo microphysics
3 !!
4 !! includes a procedure to build and save tempo lookup tables
6 use module_mp_tempo_params, only : wp, sp, dp
7 use module_mp_tempo_utils, only : snow_moments, calc_gamma_p, get_nuc
8
9#ifdef build_tables_with_mpi
10 use mpi_f08
11#endif
12
13 implicit none
14 private
15
16 public :: tempo_build_tables
17
18 type(ty_tempo_table_cfgs) :: tempo_table_cfgs
19
20 contains
21
22 subroutine tempo_build_tables(build_tables_rank, build_tables_num_proc, tempo_cfgs)
23 !! builds three lookup tables for tempo microphysics
24 use module_mp_tempo_params, only : get_version, tempo_version, &
25 initialize_graupel_vars, initialize_parameters, initialize_bins_for_tables
26
27 type(ty_tempo_cfgs), intent(in) :: tempo_cfgs
28 integer, intent(in) :: build_tables_rank, build_tables_num_proc
29
30 character(len=100) :: table_filename
31 logical, parameter :: build_table_hail_flag = .true.
32
33 ! MPI to speed up the table building process
34 integer :: rank, num_proc
35
36 ! set global variables rank and num_proc from MPI_Comm in build_tables program
37 rank = build_tables_rank
38 num_proc = build_tables_num_proc
39
40 ! get tempo version from readme file
41 call get_version(tempo_version, tempo_cfgs%verbose)
42
43#ifdef build_tables_with_mpi
44 if (tempo_cfgs%verbose) write(*,'(A,I4,A)') 'tempo_build_tables() --- building lookup tables with MPI and', num_proc, ' process(es)'
45#else
46 if (tempo_cfgs%verbose) write(*,'(A,I4,A)') 'tempo_build_tables() --- building lookup tables with', num_proc, ' process'
47#endif
48
49 ! hard-code hail aware = true to build lookup tables
50 call initialize_graupel_vars(build_table_hail_flag)
51 if (tempo_cfgs%verbose) write(*,'(A,L)') 'tempo_build_tables() --- initialized graupel variables using hail aware = ', build_table_hail_flag
52
53 ! set parameters that can depend on the host model
54 call initialize_parameters()
55 if (tempo_cfgs%verbose) write(*,'(A)') 'tempo_build_tables() --- initialized parameters'
56
57 ! creates log-spaced bins of hydrometers for tables
58 call initialize_bins_for_tables()
59 if (tempo_cfgs%verbose) write(*,'(A)') 'tempo_build_tables() --- initialized bins for lookup tables'
60
61 ! freeze water collection lookup table
62 table_filename = tempo_table_cfgs%freezewater_table_name
63 if (tempo_cfgs%verbose) write(*,'(2A)') 'tempo_build_tables() --- building table ', trim(table_filename)
64 call build_table_freezewater(tempo_cfgs)
65 if (rank == 0) call write_table_freezewater(trim(table_filename), tempo_cfgs)
66
67 ! rain-snow collection lookup table
68 table_filename = tempo_table_cfgs%qrqs_table_name
69 if (tempo_cfgs%verbose) write(*,'(2A)') 'tempo_build_tables() --- building table ', trim(table_filename)
70 call build_table_qr_acr_qs(rank, num_proc)
71 if (rank == 0) call write_table_qr_acr_qs(trim(table_filename), tempo_cfgs)
72
73 ! rain-graupel collection lookup table
74 table_filename = tempo_table_cfgs%qrqg_table_name
75 if (tempo_cfgs%verbose) write(*,'(2A)') 'tempo_build_tables() --- building table ', trim(table_filename)
76 call build_table_qr_acr_qg(rank, num_proc)
77 if (rank == 0) call write_table_qr_acr_qg(trim(table_filename), tempo_cfgs)
78 end subroutine tempo_build_tables
79
80
81 subroutine build_table_freezewater(tempo_cfgs)
82 !! build lookup table data for frozen cloud and rain water
83 use module_mp_tempo_params, only : initialize_arrays_freezewater
84
85 type(ty_tempo_cfgs), intent(in) :: tempo_cfgs
86 real(wp) :: timing_start, timing_end
87
88 call initialize_arrays_freezewater()
89 call cpu_time(timing_start)
90 call freezewater()
91 call cpu_time(timing_end)
92 if (tempo_cfgs%verbose) write(*,'(A,I5,A)') 'build_table_freezewater() --- time to build table: ', int(timing_end - timing_start), ' s'
93 end subroutine build_table_freezewater
94
95
96 subroutine write_table_freezewater(filename, tempo_cfgs)
97 !! write data for frozen cloud water and rain to a file
98 use module_mp_tempo_params, only : tpi_qrfz, tni_qrfz, tpg_qrfz, &
99 tnr_qrfz, tpi_qcfz, tni_qcfz
100
101 type(ty_tempo_cfgs), intent(in) :: tempo_cfgs
102 character(len=*), intent(in) :: filename
103 integer :: mp_unit, istat
104 logical :: fileexists
105
106 inquire(file=filename, exist=fileexists)
107 if (fileexists) then
108 if (tempo_cfgs%verbose) then
109 write(*,*) 'write_table_freezewater() --- please delete or move lookup table ', trim(filename), &
110 ' before attempted to create a new table'
111 ! error stop 'attempting to overwrite a table that already exists'
112 endif
113 endif
114
115 mp_unit = 11
116 open(unit=mp_unit, file=filename, form='unformatted', status='new', access='stream', &
117 iostat=istat &
118#ifndef TEMPO_IGNORE_CONVERT_ARG
119 , convert='big_endian' &
120#endif
121 )
122 write(mp_unit) tpi_qrfz
123 write(mp_unit) tni_qrfz
124 write(mp_unit) tpg_qrfz
125 write(mp_unit) tnr_qrfz
126 write(mp_unit) tpi_qcfz
127 write(mp_unit) tni_qcfz
128 close(unit=mp_unit)
129 end subroutine write_table_freezewater
130
131
132 subroutine build_table_qr_acr_qs(rank, num_proc)
133 !! build lookup table data for rain-snow collection
134 use module_mp_tempo_params, only : table_dp, initialize_arrays_qr_acr_qs, &
135 tcs_racs1, tmr_racs1, tcs_racs2, tmr_racs2, tcr_sacr1, tms_sacr1, & ! data arrays
136 tcr_sacr2, tms_sacr2, tnr_racs1, tnr_racs2, tnr_sacr1, tnr_sacr2, & ! data arrays
137 ntb_s, ntb_t, ntb_r1, ntb_r ! dimensions
138
139 integer, intent(in) :: rank, num_proc
140#ifdef build_tables_with_mpi
141 integer :: ierror
142#endif
143
144 real(wp) :: timing_start, timing_end
145 integer :: start_idx, end_idx, local_dim_size, local_flat_size
146 integer, allocatable, dimension(:) :: sendcounts, displacements
147 real(table_dp), allocatable, dimension(:) :: tcs_racs1_flat, tmr_racs1_flat, &
148 tcs_racs2_flat, tmr_racs2_flat, tcr_sacr1_flat, tms_sacr1_flat, &
149 tcr_sacr2_flat, tms_sacr2_flat, tnr_racs1_flat, tnr_racs2_flat, &
150 tnr_sacr1_flat, tnr_sacr2_flat
151 real(table_dp), allocatable, dimension(:,:,:,:) :: tcs_racs1_, tmr_racs1_, &
152 tcs_racs2_, tmr_racs2_, tcr_sacr1_, tms_sacr1_, tcr_sacr2_, &
153 tms_sacr2_, tnr_racs1_, tnr_racs2_, tnr_sacr1_, tnr_sacr2_
154
155 if (rank == 0) then
156 ! initialize lookup table arrays and flatten for MPI
157 call initialize_arrays_qr_acr_qs()
158 allocate(tcs_racs1_flat(size(tcs_racs1)))
159 allocate(tmr_racs1_flat(size(tmr_racs1)))
160 allocate(tcs_racs2_flat(size(tcs_racs2)))
161 allocate(tmr_racs2_flat(size(tmr_racs2)))
162 allocate(tcr_sacr1_flat(size(tcr_sacr1)))
163 allocate(tms_sacr1_flat(size(tms_sacr1)))
164 allocate(tcr_sacr2_flat(size(tcr_sacr2)))
165 allocate(tms_sacr2_flat(size(tms_sacr2)))
166 allocate(tnr_racs1_flat(size(tnr_racs1)))
167 allocate(tnr_racs2_flat(size(tnr_racs2)))
168 allocate(tnr_sacr1_flat(size(tnr_sacr1)))
169 allocate(tnr_sacr2_flat(size(tnr_sacr2)))
170 endif
171
172 ! split over the last dimension, nrb_r
173 call get_index_for_rank(ntb_r, rank, num_proc, start_idx, end_idx)
174 local_dim_size = end_idx - start_idx + 1
175 local_flat_size = local_dim_size * ntb_s*ntb_t*ntb_r1
176
177 ! local arrays for MPI
178 allocate(tcs_racs1_(ntb_s,ntb_t,ntb_r1,local_dim_size))
179 allocate(tmr_racs1_(ntb_s,ntb_t,ntb_r1,local_dim_size))
180 allocate(tcs_racs2_(ntb_s,ntb_t,ntb_r1,local_dim_size))
181 allocate(tmr_racs2_(ntb_s,ntb_t,ntb_r1,local_dim_size))
182 allocate(tcr_sacr1_(ntb_s,ntb_t,ntb_r1,local_dim_size))
183 allocate(tms_sacr1_(ntb_s,ntb_t,ntb_r1,local_dim_size))
184 allocate(tcr_sacr2_(ntb_s,ntb_t,ntb_r1,local_dim_size))
185 allocate(tms_sacr2_(ntb_s,ntb_t,ntb_r1,local_dim_size))
186 allocate(tnr_racs1_(ntb_s,ntb_t,ntb_r1,local_dim_size))
187 allocate(tnr_racs2_(ntb_s,ntb_t,ntb_r1,local_dim_size))
188 allocate(tnr_sacr1_(ntb_s,ntb_t,ntb_r1,local_dim_size))
189 allocate(tnr_sacr2_(ntb_s,ntb_t,ntb_r1,local_dim_size))
190
191 allocate(sendcounts(num_proc), displacements(num_proc))
192 if (num_proc == 1) then
193 sendcounts(1) = local_flat_size
194 displacements(1) = 0 ! MPI displacements start at zero
195 endif
196
197#ifdef build_tables_with_mpi
198 call mpi_allgather(local_flat_size, 1, mpi_integer, sendcounts, 1, mpi_integer, mpi_comm_world, ierror)
199 ! MPI displacements start at zero, i.e., start_idx-1 below
200 call mpi_allgather((start_idx-1)*ntb_s*ntb_t*ntb_r1, 1, mpi_integer, displacements, 1, mpi_integer, mpi_comm_world, ierror)
201#endif
202
203#ifdef build_tables_with_mpi
204 timing_start = mpi_wtime()
205#else
206 call cpu_time(timing_start)
207#endif
208
209 call qr_acr_qs(start_idx, end_idx, &
210 tcs_racs1_, tmr_racs1_, tcs_racs2_, tmr_racs2_, &
211 tcr_sacr1_, tms_sacr1_, tcr_sacr2_, tms_sacr2_, &
212 tnr_racs1_, tnr_racs2_, tnr_sacr1_, tnr_sacr2_)
213
214#ifdef build_tables_with_mpi
215 timing_end = mpi_wtime()
216#else
217 call cpu_time(timing_end)
218#endif
219 ! if (rank == 0) write(*,'(A,I5,A)') 'build_table_qr_acr_qs() --- time to build table: ', int(timing_end - timing_start), ' s'
220
221#ifdef build_tables_with_mpi
222 call mpi_barrier(mpi_comm_world, ierror)
223 call gather(reshape(tcs_racs1_, (/local_flat_size/)), tcs_racs1_flat, sendcounts, displacements, ierror)
224 call gather(reshape(tmr_racs1_, (/local_flat_size/)), tmr_racs1_flat, sendcounts, displacements, ierror)
225 call gather(reshape(tcs_racs2_, (/local_flat_size/)), tcs_racs2_flat, sendcounts, displacements, ierror)
226 call gather(reshape(tmr_racs2_, (/local_flat_size/)), tmr_racs2_flat, sendcounts, displacements, ierror)
227 call gather(reshape(tcr_sacr1_, (/local_flat_size/)), tcr_sacr1_flat, sendcounts, displacements, ierror)
228 call gather(reshape(tms_sacr1_, (/local_flat_size/)), tms_sacr1_flat, sendcounts, displacements, ierror)
229 call gather(reshape(tcr_sacr2_, (/local_flat_size/)), tcr_sacr2_flat, sendcounts, displacements, ierror)
230 call gather(reshape(tms_sacr2_, (/local_flat_size/)), tms_sacr2_flat, sendcounts, displacements, ierror)
231 call gather(reshape(tnr_racs1_, (/local_flat_size/)), tnr_racs1_flat, sendcounts, displacements, ierror)
232 call gather(reshape(tnr_racs2_, (/local_flat_size/)), tnr_racs2_flat, sendcounts, displacements, ierror)
233 call gather(reshape(tnr_sacr1_, (/local_flat_size/)), tnr_sacr1_flat, sendcounts, displacements, ierror)
234 call gather(reshape(tnr_sacr2_, (/local_flat_size/)), tnr_sacr2_flat, sendcounts, displacements, ierror)
235
236 if (rank == 0) then
237 tcs_racs1 = reshape(tcs_racs1_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
238 tmr_racs1 = reshape(tmr_racs1_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
239 tcs_racs2 = reshape(tcs_racs2_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
240 tmr_racs2 = reshape(tmr_racs2_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
241 tcr_sacr1 = reshape(tcr_sacr1_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
242 tms_sacr1 = reshape(tms_sacr1_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
243 tcr_sacr2 = reshape(tcr_sacr2_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
244 tms_sacr2 = reshape(tms_sacr2_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
245 tnr_racs1 = reshape(tnr_racs1_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
246 tnr_racs2 = reshape(tnr_racs2_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
247 tnr_sacr1 = reshape(tnr_sacr1_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
248 tnr_sacr2 = reshape(tnr_sacr2_flat, (/ntb_s,ntb_t,ntb_r1,ntb_r/))
249 endif
250#else
251 tcs_racs1 = tcs_racs1_
252 tmr_racs1 = tmr_racs1_
253 tcs_racs2 = tcs_racs2_
254 tmr_racs2 = tmr_racs2_
255 tcr_sacr1 = tcr_sacr1_
256 tms_sacr1 = tms_sacr1_
257 tcr_sacr2 = tcr_sacr2_
258 tms_sacr2 = tms_sacr2_
259 tnr_racs1 = tnr_racs1_
260 tnr_racs2 = tnr_racs2_
261 tnr_sacr1 = tnr_sacr1_
262 tnr_sacr2 = tnr_sacr2_
263#endif
264
265#if build_tables_with_mpi
266 call mpi_barrier(mpi_comm_world, ierror)
267#endif
268 end subroutine build_table_qr_acr_qs
269
270
271 subroutine write_table_qr_acr_qs(filename, tempo_cfgs)
272 !! write data for rain-snow collection to a file
273 use module_mp_tempo_params, only : tcs_racs1, tmr_racs1, tcs_racs2, &
274 tmr_racs2, tcr_sacr1, tms_sacr1, tcr_sacr2, tms_sacr2, tnr_racs1, &
275 tnr_racs2, tnr_sacr1, tnr_sacr2
276
277 type(ty_tempo_cfgs), intent(in) :: tempo_cfgs
278 character(len=*), intent(in) :: filename
279 integer :: mp_unit, istat
280 logical :: fileexists
281
282 inquire(file=filename, exist=fileexists)
283 if (fileexists) then
284 if (tempo_cfgs%verbose) then
285 write(*,*) 'write_table_qr_acr_qs() --- please delete or move lookup table ', trim(filename), &
286 ' before attempted to create a new table'
287 ! error stop 'attempting to overwrite a table that already exists'
288 endif
289 endif
290
291 mp_unit = 11
292 open(unit=mp_unit, file=filename, form='unformatted', status='new', access='stream', &
293 iostat=istat &
294#ifndef TEMPO_IGNORE_CONVERT_ARG
295 , convert='big_endian' &
296#endif
297 )
298 write(mp_unit) tcs_racs1
299 write(mp_unit) tmr_racs1
300 write(mp_unit) tcs_racs2
301 write(mp_unit) tmr_racs2
302 write(mp_unit) tcr_sacr1
303 write(mp_unit) tms_sacr1
304 write(mp_unit) tcr_sacr2
305 write(mp_unit) tms_sacr2
306 write(mp_unit) tnr_racs1
307 write(mp_unit) tnr_racs2
308 write(mp_unit) tnr_sacr1
309 write(mp_unit) tnr_sacr2
310 close(unit=mp_unit)
311 end subroutine write_table_qr_acr_qs
312
313
314 subroutine build_table_qr_acr_qg(rank, num_proc)
315 !! build lookup table data for rain-graupel collection
316 use module_mp_tempo_params, only : table_dp, initialize_arrays_qr_acr_qg, &
317 tcg_racg, tmr_racg, tcr_gacr, tnr_racg, tnr_gacr, &
318 ntb_g1, ntb_g, nrhg, ntb_r1, ntb_r
319
320 integer, intent(in) :: rank, num_proc
321#ifdef build_tables_with_mpi
322 integer :: ierror
323#endif
324
325 real(wp) :: timing_start, timing_end
326 integer :: start_idx, end_idx, local_dim_size, local_flat_size
327 integer, allocatable, dimension(:) :: sendcounts, displacements
328 real(table_dp), allocatable, dimension(:) :: tcg_racg_flat, tmr_racg_flat, &
329 tcr_gacr_flat, tnr_racg_flat, tnr_gacr_flat
330 real(table_dp), allocatable, dimension(:,:,:,:,:) :: tcg_racg_, &
331 tmr_racg_, tcr_gacr_, tnr_racg_, tnr_gacr_
332
333 if (rank == 0) then
334 ! initialize lookup table arrays and flatten for MPI
335 call initialize_arrays_qr_acr_qg()
336 allocate(tcg_racg_flat(size(tcg_racg)))
337 allocate(tmr_racg_flat(size(tmr_racg)))
338 allocate(tcr_gacr_flat(size(tcr_gacr)))
339 allocate(tnr_racg_flat(size(tnr_racg)))
340 allocate(tnr_gacr_flat(size(tnr_gacr)))
341 endif
342
343 ! split over the last dimension, nrb_r
344 call get_index_for_rank(ntb_r, rank, num_proc, start_idx, end_idx)
345 local_dim_size = end_idx - start_idx + 1
346 local_flat_size = local_dim_size * ntb_g1*ntb_g*nrhg*ntb_r1
347
348 ! local arrays for MPI
349 allocate(tcg_racg_(ntb_g1,ntb_g,nrhg,ntb_r1,local_dim_size))
350 allocate(tmr_racg_(ntb_g1,ntb_g,nrhg,ntb_r1,local_dim_size))
351 allocate(tcr_gacr_(ntb_g1,ntb_g,nrhg,ntb_r1,local_dim_size))
352 allocate(tnr_racg_(ntb_g1,ntb_g,nrhg,ntb_r1,local_dim_size))
353 allocate(tnr_gacr_(ntb_g1,ntb_g,nrhg,ntb_r1,local_dim_size))
354
355 allocate(sendcounts(num_proc), displacements(num_proc))
356 if (num_proc == 1) then
357 sendcounts(1) = local_flat_size
358 displacements(1) = 0 ! MPI displacements start at zero
359 endif
360
361#ifdef build_tables_with_mpi
362 call mpi_allgather(local_flat_size, 1, mpi_integer, sendcounts, 1, mpi_integer, mpi_comm_world, ierror)
363 ! MPI displacements start at zero, i.e., start_idx-1 below
364 call mpi_allgather((start_idx-1)*ntb_g1*ntb_g*nrhg*ntb_r1, 1, mpi_integer, displacements, 1, mpi_integer, mpi_comm_world, ierror)
365#endif
366
367#ifdef build_tables_with_mpi
368 timing_start = mpi_wtime()
369#else
370 call cpu_time(timing_start)
371#endif
372
373 call qr_acr_qg(start_idx, end_idx, &
374 tcg_racg_, tmr_racg_, tcr_gacr_, tnr_racg_, tnr_gacr_)
375
376#ifdef build_tables_with_mpi
377 timing_end = mpi_wtime()
378#else
379 call cpu_time(timing_end)
380#endif
381 ! if (rank == 0) write(*,'(A,I5,A)') 'build_table_qr_acr_qg() --- time to build table: ', int(timing_end - timing_start), ' s'
382
383#ifdef build_tables_with_mpi
384 call mpi_barrier(mpi_comm_world, ierror)
385 call gather(reshape(tcg_racg_, (/local_flat_size/)), tcg_racg_flat, sendcounts, displacements, ierror)
386 call gather(reshape(tmr_racg_, (/local_flat_size/)), tmr_racg_flat, sendcounts, displacements, ierror)
387 call gather(reshape(tcr_gacr_, (/local_flat_size/)), tcr_gacr_flat, sendcounts, displacements, ierror)
388 call gather(reshape(tnr_racg_, (/local_flat_size/)), tnr_racg_flat, sendcounts, displacements, ierror)
389 call gather(reshape(tnr_gacr_, (/local_flat_size/)), tnr_gacr_flat, sendcounts, displacements, ierror)
390
391 if (rank == 0) then
392 tcg_racg = reshape(tcg_racg_flat, (/ntb_g1,ntb_g,nrhg,ntb_r1,ntb_r/))
393 tmr_racg = reshape(tmr_racg_flat, (/ntb_g1,ntb_g,nrhg,ntb_r1,ntb_r/))
394 tcr_gacr = reshape(tcr_gacr_flat, (/ntb_g1,ntb_g,nrhg,ntb_r1,ntb_r/))
395 tnr_racg = reshape(tnr_racg_flat, (/ntb_g1,ntb_g,nrhg,ntb_r1,ntb_r/))
396 tnr_gacr = reshape(tnr_gacr_flat, (/ntb_g1,ntb_g,nrhg,ntb_r1,ntb_r/))
397 endif
398#else
399 tcg_racg = tcg_racg_
400 tmr_racg = tmr_racg_
401 tcr_gacr = tcr_gacr_
402 tnr_racg = tnr_racg_
403 tnr_gacr = tnr_gacr_
404#endif
405
406#if build_tables_with_mpi
407 call mpi_barrier(mpi_comm_world, ierror)
408#endif
409 end subroutine build_table_qr_acr_qg
410
411
412 subroutine write_table_qr_acr_qg(filename, tempo_cfgs)
413 !! write data for rain-graupel collection to a file
414 use module_mp_tempo_params, only : tcg_racg, tmr_racg, &
415 tcr_gacr, tnr_racg, tnr_gacr
416
417 type(ty_tempo_cfgs), intent(in) :: tempo_cfgs
418 character(len=*), intent(in) :: filename
419 integer :: mp_unit, istat
420 logical :: fileexists
421
422 inquire(file=filename, exist=fileexists)
423 if (fileexists) then
424 if (tempo_cfgs%verbose) then
425 write(*,*) 'write_table_qr_acr_qg() --- please delete or move lookup table ', trim(filename), &
426 ' before attempted to create a new table'
427 ! error stop 'attempting to overwrite a table that already exists'
428 endif
429 endif
430
431 mp_unit = 11
432 open(unit=mp_unit, file=filename, form='unformatted', status='new', access='stream', &
433 iostat=istat &
434#ifndef TEMPO_IGNORE_CONVERT_ARG
435 , convert='big_endian' &
436#endif
437 )
438 write(mp_unit) tcg_racg
439 write(mp_unit) tmr_racg
440 write(mp_unit) tcr_gacr
441 write(mp_unit) tnr_racg
442 write(mp_unit) tnr_gacr
443 close(unit=mp_unit)
444 end subroutine write_table_qr_acr_qg
445
446#ifdef build_tables_with_mpi
447 subroutine gather(local_flat, global_flat, sendcounts, displacements, ierror)
448 !! wrapper to simplify MPI_Gatherv
449 use module_mp_tempo_params, only : table_dp
450
451 real(table_dp), dimension(:), intent(in) :: local_flat
452 real(table_dp), dimension(:), intent(out) :: global_flat
453 integer, intent(inout) :: ierror
454 integer, dimension(:), intent(in) :: sendcounts, displacements
455 integer :: local_size
456
457 local_size = size(local_flat)
458 call mpi_gatherv(local_flat, local_size, mpi_double_precision, &
459 global_flat, sendcounts, displacements, &
460 mpi_double_precision, 0, mpi_comm_world, ierror)
461 end subroutine gather
462#endif
463
464 subroutine get_index_for_rank(idx, rank, num_proc, start_idx, end_idx)
465 !! returns start and end index values for an array dimension
466 !! of size idx distributed over num_procs
467
468 integer, intent(in) :: idx, rank, num_proc
469 integer, intent(out) :: start_idx, end_idx
470 integer :: values_per_proc
471
472 ! if (num_proc > idx) then
473 ! write(*,'(A,I4,A,I4)') 'num_proc', num_proc, 'cannot be larger than idx', idx
474 ! error stop '--- reduce the number of processes'
475 ! endif
476
477 values_per_proc = idx/num_proc
478
479 if(rank < mod(idx, num_proc)) then
480 values_per_proc = values_per_proc + 1
481 endif
482
483 if(rank < mod(idx, num_proc)) then
484 start_idx = rank * values_per_proc + 1
485 end_idx = (rank+1) * values_per_proc
486 else
487 start_idx = mod(idx, num_proc) + rank*values_per_proc + 1
488 end_idx = mod(idx, num_proc) + (rank+1) * values_per_proc
489 endif
490 end subroutine get_index_for_rank
491
492
493 subroutine qr_acr_qs(local_start, local_end, &
494 ltcs_racs1, ltmr_racs1, ltcs_racs2, ltmr_racs2, ltcr_sacr1, ltms_sacr1, &
495 ltcr_sacr2, ltms_sacr2, ltnr_racs1, ltnr_racs2, ltnr_sacr1, ltnr_sacr2)
496 !! calculates rain collecting snow (and inverse)
497 use module_mp_tempo_params, only : table_dp, &
498 nbr, nbs, dr, av_s, bv_s, ds, fv_s, &
499 ntb_r, ntb_r1, n0r_exp, am_r, cre, crg, ore1, r_r, &
500 org1, org2, obmr, mu_r, dtr, ntb_t, ntb_s, r_s, &
501 sa, sb, tc, bm_s, mu_s, lam0, lam1, kap0, kap1, dts, &
502 bm_r, am_s, pi, ef_rs, table_dp
503
504 integer, intent(in) :: local_start, local_end
505 real(table_dp), intent(out), dimension(:,:,:,:) :: &
506 ltcs_racs1, ltmr_racs1, ltcs_racs2, ltmr_racs2, &
507 ltcr_sacr1, ltms_sacr1, ltcr_sacr2, ltms_sacr2, &
508 ltnr_racs1, ltnr_racs2, ltnr_sacr1, ltnr_sacr2
509
510 integer :: i, j, k, m, n, n2
511 real(dp), dimension(nbr) :: vr, d1, n_r
512 real(dp), dimension(nbs) :: vs, n_s
513 real(dp) :: m0, m2, m3, mrat, om3
514 real(dp) :: n0_r, lam_exp, lamr, slam1, slam2
515 real(dp) :: dvs, dvr, masss, massr
516 real(dp) :: t1, t2, t3, t4, z1, z2, z3, z4
517 real(dp) :: y1, y2, y3, y4
518
519 do n2 = 1, nbr
520 vr(n2) = -0.1021_dp + 4.932e3_dp*dr(n2) - 0.9551e6_dp*dr(n2)*dr(n2) &
521 + 0.07934e9_dp*dr(n2)*dr(n2)*dr(n2) &
522 - 0.002362e12_dp*dr(n2)*dr(n2)*dr(n2)*dr(n2)
523 d1(n2) = (vr(n2)/av_s)**(1._dp/bv_s)
524 enddo
525 do n = 1, nbs
526 vs(n) = 1.5_dp*av_s*ds(n)**bv_s * exp(real(-fv_s*ds(n), kind=dp))
527 enddo
528
529 do m = local_start, local_end
530 do k = 1, ntb_r1
531 lam_exp = (n0r_exp(k)*am_r*crg(1)/r_r(m))**ore1
532 lamr = lam_exp * (crg(3)*org2*org1)**obmr
533 n0_r = n0r_exp(k)/(crg(2)*lam_exp) * lamr**cre(2)
534 do n2 = 1, nbr
535 n_r(n2) = n0_r*dr(n2)**mu_r * exp(-lamr*dr(n2))*dtr(n2)
536 enddo
537
538 do j = 1, ntb_t
539 do i = 1, ntb_s
540 call snow_moments(rs=r_s(i), tc=tc(j), smob=m2, smoc=m3)
541
542 om3 = 1._wp/m3
543 mrat = m2*(m2*om3)*(m2*om3)*(m2*om3)
544 m0 = (m2*om3)**mu_s
545 slam1 = m2 * om3 * lam0
546 slam2 = m2 * om3 * lam1
547
548 do n = 1, nbs
549 n_s(n) = mrat*(kap0*exp(-slam1*ds(n)) &
550 + kap1*m0*ds(n)**mu_s * exp(-slam2*ds(n)))*dts(n)
551 enddo
552
553 t1 = 0._dp
554 t2 = 0._dp
555 t3 = 0._dp
556 t4 = 0._dp
557 z1 = 0._dp
558 z2 = 0._dp
559 z3 = 0._dp
560 z4 = 0._dp
561 y1 = 0._dp
562 y2 = 0._dp
563 y3 = 0._dp
564 y4 = 0._dp
565 do n2 = 1, nbr
566 massr = am_r * dr(n2)**bm_r
567 do n = 1, nbs
568 masss = am_s * ds(n)**bm_s
569
570 dvs = 0.5_dp*((vr(n2) - vs(n)) + abs(vr(n2)-vs(n)))
571 dvr = 0.5_dp*((vs(n) - vr(n2)) + abs(vs(n)-vr(n2)))
572 if (massr > 1.5*masss) then
573 t1 = t1+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
574 *dvs*masss * n_s(n)* n_r(n2)
575 z1 = z1+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
576 *dvs*massr * n_s(n)* n_r(n2)
577 y1 = y1+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
578 *dvs * n_s(n)* n_r(n2)
579 else
580 t3 = t3+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
581 *dvs*masss * n_s(n)* n_r(n2)
582 z3 = z3+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
583 *dvs*massr * n_s(n)* n_r(n2)
584 y3 = y3+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
585 *dvs * n_s(n)* n_r(n2)
586 endif
587
588 if (massr > 1.5_dp*masss) then
589 t2 = t2+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
590 *dvr*massr * n_s(n)* n_r(n2)
591 y2 = y2+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
592 *dvr * n_s(n)* n_r(n2)
593 z2 = z2+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
594 *dvr*masss * n_s(n)* n_r(n2)
595 else
596 t4 = t4+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
597 *dvr*massr * n_s(n)* n_r(n2)
598 y4 = y4+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
599 *dvr * n_s(n)* n_r(n2)
600 z4 = z4+ pi*.25_dp*ef_rs*(ds(n)+dr(n2))*(ds(n)+dr(n2)) &
601 *dvr*masss * n_s(n)* n_r(n2)
602 endif
603 enddo
604 enddo
605 ltcs_racs1(i,j,k,m-local_start+1) = t1
606 ltmr_racs1(i,j,k,m-local_start+1) = min(z1, real(r_r(m), kind=dp))
607 ltcs_racs2(i,j,k,m-local_start+1) = t3
608 ltmr_racs2(i,j,k,m-local_start+1) = z3
609 ltcr_sacr1(i,j,k,m-local_start+1) = t2
610 ltms_sacr1(i,j,k,m-local_start+1) = z2
611 ltcr_sacr2(i,j,k,m-local_start+1) = t4
612 ltms_sacr2(i,j,k,m-local_start+1) = z4
613 ltnr_racs1(i,j,k,m-local_start+1) = y1
614 ltnr_racs2(i,j,k,m-local_start+1) = y3
615 ltnr_sacr1(i,j,k,m-local_start+1) = y2
616 ltnr_sacr2(i,j,k,m-local_start+1) = y4
617 enddo
618 enddo
619 enddo
620 enddo
621 end subroutine qr_acr_qs
622
623
624 subroutine qr_acr_qg(local_start, local_end, &
625 ltcg_racg, ltmr_racg, ltcr_gacr, ltnr_racg, ltnr_gacr)
626 !! rain collecting graupel (and inverse) using explicit integration
627 use module_mp_tempo_params, only : table_dp, nrhg, nbg, nbr, dr, &
628 av_g, dg, bv_g, ntb_r, ntb_r1, &
629 n0r_exp, am_r, cre, crg, r_r, ore1, org1, org2, &
630 obmr, mu_r, dtr, ntb_g, ntb_g1, n0g_exp, am_g, cge, cgg, &
631 r_g, oge1, ogg1, ogg2, obmg, mu_g, dtg, bm_r, bm_g, pi, ef_rg
632
633 integer, intent(in) :: local_start, local_end
634 real(table_dp), intent(out), dimension(:,:,:,:,:) :: &
635 ltcg_racg, ltmr_racg, ltcr_gacr, ltnr_racg, ltnr_gacr
636
637 integer :: i, j, k, m, n, n2, n3
638 real(dp), dimension(nbg) :: n_g
639 real(dp), dimension(nbg, nrhg) :: vg
640 real(dp), dimension(nbr):: vr, n_r
641 real(dp) :: n0_r, n0_g, lam_exp, lamg, lamr
642 real(dp) :: massg, massr, dvg, dvr, t1, t2, z1, z2, y1, y2
643
644 do n2 = 1, nbr
645 vr(n2) = -0.1021_dp + 4.932e3_dp*dr(n2) - 0.9551e6_dp*dr(n2)*dr(n2) &
646 + 0.07934e9_dp*dr(n2)*dr(n2)*dr(n2) &
647 - 0.002362e12_dp*dr(n2)*dr(n2)*dr(n2)*dr(n2)
648 enddo
649 do n3 = 1, nrhg
650 do n = 1, nbg
651 vg(n,n3) = av_g(n3)*dg(n)**bv_g(n3)
652 enddo
653 enddo
654
655 do m = local_start, local_end
656 do k = 1, ntb_r1
657
658 lam_exp = (n0r_exp(k)*am_r*crg(1)/r_r(m))**ore1
659 lamr = lam_exp * (crg(3)*org2*org1)**obmr
660 n0_r = n0r_exp(k)/(crg(2)*lam_exp) * lamr**cre(2)
661 do n2 = 1, nbr
662 n_r(n2) = n0_r*dr(n2)**mu_r *exp(-lamr*dr(n2))*dtr(n2)
663 enddo
664
665 do n3 = 1, nrhg
666 do j = 1, ntb_g
667 do i = 1, ntb_g1
668 lam_exp = (n0g_exp(i)*am_g(n3)*cgg(1,1)/r_g(j))**oge1
669 lamg = lam_exp * (cgg(3,1)*ogg2*ogg1)**obmg
670 n0_g = n0g_exp(i)/(cgg(2,1)*lam_exp) * lamg**cge(2,1)
671 do n = 1, nbg
672 n_g(n) = n0_g*dg(n)**mu_g * exp(-lamg*dg(n))*dtg(n)
673 enddo
674
675 t1 = 0._dp
676 t2 = 0._dp
677 z1 = 0._dp
678 z2 = 0._dp
679 y1 = 0._dp
680 y2 = 0._dp
681 do n2 = 1, nbr
682 massr = am_r * dr(n2)**bm_r
683 do n = 1, nbg
684 massg = am_g(n3) * dg(n)**bm_g
685
686 dvg = 0.5_dp*((vr(n2) - vg(n,n3)) + abs(vr(n2)-vg(n,n3)))
687 dvr = 0.5_dp*((vg(n,n3) - vr(n2)) + abs(vg(n,n3)-vr(n2)))
688
689 t1 = t1+ pi*.25_wp*ef_rg*(dg(n)+dr(n2))*(dg(n)+dr(n2)) &
690 *dvg*massg * n_g(n)* n_r(n2)
691 z1 = z1+ pi*.25_wp*ef_rg*(dg(n)+dr(n2))*(dg(n)+dr(n2)) &
692 *dvg*massr * n_g(n)* n_r(n2)
693 y1 = y1+ pi*.25_wp*ef_rg*(dg(n)+dr(n2))*(dg(n)+dr(n2)) &
694 *dvg * n_g(n)* n_r(n2)
695
696 t2 = t2+ pi*.25_wp*ef_rg*(dg(n)+dr(n2))*(dg(n)+dr(n2)) &
697 *dvr*massr * n_g(n)* n_r(n2)
698 y2 = y2+ pi*.25_wp*ef_rg*(dg(n)+dr(n2))*(dg(n)+dr(n2)) &
699 *dvr * n_g(n)* n_r(n2)
700 z2 = z2+ pi*.25_wp*ef_rg*(dg(n)+dr(n2))*(dg(n)+dr(n2)) &
701 *dvr*massg * n_g(n)* n_r(n2)
702 enddo
703 enddo
704 ltcg_racg(i,j,n3,k,m-local_start+1) = t1
705 ltmr_racg(i,j,n3,k,m-local_start+1) = min(z1, real(r_r(m), kind=dp))
706 ltcr_gacr(i,j,n3,k,m-local_start+1) = t2
707 ltnr_racg(i,j,n3,k,m-local_start+1) = y1
708 ltnr_gacr(i,j,n3,k,m-local_start+1) = y2
709 enddo
710 enddo
711 enddo
712 enddo
713 enddo
714 end subroutine qr_acr_qg
715
716
717 subroutine freezewater()
718 !! calculates the probability of drops of a particular volume freezing
719 !! from Bigg (1953)
720 !! https://doi.org/10.1002/qj.49707934207
721 use module_mp_tempo_params, only : nbc, nbr, rho_w, &
722 am_r, dr, dtr, bm_r, dc, dtc, ntb_in, ntb_r1, ntb_r, nt_in, &
723 n0r_exp, cre, crg, r_r, ore1, org2, org1, obmr, mu_r, &
724 nu_c_scale, xm0g, t_nc, cce, ccg, ocg1, r_c, ntb_c, &
725 tpi_qrfz, tni_qrfz, tpg_qrfz, tnr_qrfz, tpi_qcfz, tni_qcfz ! data arrays
726
727 integer :: i, j, k, m, n, n2
728 real(dp) :: n_r, n_c
729 real(dp), dimension(nbr):: massr
730 real(dp), dimension(nbc):: massc
731 real(dp) :: sum1, sum2, sumn1, sumn2, &
732 prob, vol, texp, orho_w, &
733 lam_exp, lamr, n0_r, lamc, n0_c
734 integer :: nu_c
735 real(wp) :: t_adjust
736
737 orho_w = 1._wp/rho_w
738
739 do n2 = 1, nbr
740 massr(n2) = am_r*dr(n2)**bm_r
741 enddo
742 do n = 1, nbc
743 massc(n) = am_r*dc(n)**bm_r
744 enddo
745
746 ! the smallest drops become cloud ice, otherwise graupel
747 do m = 1, ntb_in
748 t_adjust = max(-3.0_wp, min(3.0_wp - log10(nt_in(m)), 3.0_wp))
749 do k = 1, 45
750 texp = exp(real(k, kind=dp) - real(t_adjust, kind=dp)) - 1.0_dp
751 do j = 1, ntb_r1
752 do i = 1, ntb_r
753 lam_exp = (n0r_exp(j)*am_r*crg(1)/r_r(i))**ore1
754 lamr = lam_exp * (crg(3)*org2*org1)**obmr
755 n0_r = n0r_exp(j)/(crg(2)*lam_exp) * lamr**cre(2)
756 sum1 = 0._dp
757 sum2 = 0._dp
758 sumn1 = 0._dp
759 sumn2 = 0._dp
760 do n2 = nbr, 1, -1
761 n_r = n0_r*dr(n2)**mu_r*exp(-lamr*dr(n2))*dtr(n2)
762 vol = massr(n2)*orho_w
763 prob = max(0.0_dp, 1.0_dp - exp(-120.0_dp*vol*5.2d-4 * texp))
768 if (massr(n2) < xm0g) then
769 sumn1 = sumn1 + prob*n_r
770 sum1 = sum1 + prob*n_r*massr(n2)
771 else
772 sumn2 = sumn2 + prob*n_r
773 sum2 = sum2 + prob*n_r*massr(n2)
774 endif
775 if ((sum1+sum2) >= r_r(i)) exit
776 enddo
777 tpi_qrfz(i,j,k,m) = sum1
778 tni_qrfz(i,j,k,m) = sumn1
779 tpg_qrfz(i,j,k,m) = sum2
780 tnr_qrfz(i,j,k,m) = sumn2
781 enddo
782 enddo
783
784 do j = 1, nbc
785 nu_c = min(15, nint(nu_c_scale/t_nc(j)) + 2)
786 do i = 1, ntb_c
787 lamc = (t_nc(j)*am_r* ccg(2,nu_c) * ocg1(nu_c) / r_c(i))**obmr
788 n0_c = t_nc(j)*ocg1(nu_c) * lamc**cce(1,nu_c)
789 sum1 = 0._dp
790 sumn2 = 0._dp
791 do n = nbc, 1, -1
792 vol = massc(n)*orho_w
793 prob = max(0.0_dp, 1.0_dp - exp(-120.0_dp*vol*5.2e-4_dp * texp))
794 n_c = n0_c*dc(n)**nu_c*exp(-lamc*dc(n))*dtc(n)
795 sumn2 = min(t_nc(j), sumn2 + prob*n_c)
796 sum1 = sum1 + prob*n_c*massc(n)
797 if (sum1 >= r_c(i)) exit
798 enddo
799 tpi_qcfz(i,j,k,m) = sum1
800 tni_qcfz(i,j,k,m) = sumn2
801 enddo
802 enddo
803 enddo
804 enddo
805 end subroutine freezewater
806
807end module module_mp_tempo_tables