source: palm/trunk/SOURCE/synthetic_turbulence_generator_mod.f90 @ 4850

Last change on this file since 4850 was 4848, checked in by gronemeier, 3 years ago

bugfix: removed syn_turb_gen from restart files, replaced use_syn_turb_gen by syn_turb_gen

  • Property svn:keywords set to Id
File size: 112.9 KB
Line 
1!> @synthetic_turbulence_generator_mod.f90
2!--------------------------------------------------------------------------------------------------!
3! This file is part of the PALM model system.
4!
5! PALM is free software: you can redistribute it and/or modify it under the terms of the GNU General
6! Public License as published by the Free Software Foundation, either version 3 of the License, or
7! (at your option) any later version.
8!
9! PALM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
10! implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11! Public License for more details.
12!
13! You should have received a copy of the GNU General Public License along with PALM. If not, see
14! <http://www.gnu.org/licenses/>.
15!
16! Copyright 1997-2021 Leibniz Universitaet Hannover
17!--------------------------------------------------------------------------------------------------!
18!
19!
20! Current revisions:
21! -----------------
22!
23!
24! Former revisions:
25! -----------------
26! $Id: synthetic_turbulence_generator_mod.f90 4848 2021-01-21 15:51:51Z suehring $
27! replaced use_syn_turb_gen by syn_turb_gen
28!
29! 4843 2021-01-15 15:22:11Z raasch
30! local namelist parameter added to switch off the module although the respective module namelist
31! appears in the namelist file
32!
33! 4842 2021-01-14 10:42:28Z raasch
34! reading of namelist file and actions in case of namelist errors revised so that statement labels
35! and goto statements are not required any more
36!
37! 4828 2021-01-05 11:21:41Z Giersch
38! Implementation of downward facing USM and LSM surfaces
39!
40! 4647 2020-08-24 16:36:18Z suehring
41! Change default value of synthetic turbulence adjustment as well as compute_velocity_seeds_local
42! By default, the random-seed computation is now distributed among several cores. Especially for
43! large length scales this is significantly faster.
44!
45! 4640 2020-08-11 16:28:32Z suehring
46! - to avoid that the correction term in r11/r22 computation becomes unrealistically high, limit
47!   Obukhov length (term is not valid for near neutral conditions)
48! - to avoid unrealistically large perturbations, change computation of r21 so that this resembles
49!   the vertical transport of horizontal momentum
50!
51! 4629 2020-07-29 09:37:56Z raasch
52! support for MPI Fortran77 interface (mpif.h) removed
53!
54! 4603 2020-07-14 16:08:30Z suehring
55! Bugfix in initialization from ASCII file - x-length scales at the bottom boundary were not
56! initialized properly
57!
58! 4566 2020-06-16 10:11:51Z suehring
59! - revise parametrization for reynolds-stress components, turbulent length- and time scales
60! - revise computation of velocity disturbances to be consistent to Xie and Castro (2008)
61! - change default value of time interval to adjust turbulence parametrization
62! - bugfix in computation of amplitude-tensor (vertical flux of horizontal momentum)
63!
64! 4562 2020-06-12 08:38:47Z raasch
65! Parts of r4559 re-formatted
66!
67! 4559 2020-06-11 08:51:48Z raasch
68! File re-formatted to follow the PALM coding standard
69!
70! 4535 2020-05-15 12:07:23Z raasch
71! Bugfix for restart data format query
72!
73! 4495 2020-04-13 20:11:20Z raasch
74! Restart data handling with MPI-IO added
75!
76! 4481 2020-03-31 18:55:54Z maronga
77! Bugfix: cpp-directives for serial mode added, dummy statements to prevent compile errors added
78!
79! 4442 2020-03-04 19:21:13Z suehring
80! Set back turbulent length scale to 8 x grid spacing in the parametrized mode
81! (was accidantly changed).
82!
83! 4441 2020-03-04 19:20:35Z suehring
84! Correct misplaced preprocessor directive
85!
86! 4438 2020-03-03 20:49:28Z suehring
87! Performance optimizations in velocity-seed calculation:
88!  - Random number array is only defined and computed locally (except for normalization to zero mean
89!    and unit variance)
90!  - Parallel random number generator is applied independent on the 2D random numbers in other
91!    routines
92!  - Option to decide wheter velocity seeds are computed locally without any further communication
93!    or are computed by all processes along the communicator
94!
95! 4346 2019-12-18 11:55:56Z motisi
96! Introduction of wall_flags_total_0, which currently sets bits based on static topography
97! information used in wall_flags_static_0
98!
99! 4335 2019-12-12 16:39:05Z suehring
100! Commentation of last commit
101!
102! 4332 2019-12-10 19:44:12Z suehring
103! Limit initial velocity seeds in restart runs, if not the seed calculation may become unstable.
104! Further, minor bugfix in initial velocity seed calculation.
105!
106! 4329 2019-12-10 15:46:36Z motisi
107! Renamed wall_flags_0 to wall_flags_static_0
108!
109! 4309 2019-11-26 18:49:59Z suehring
110! Computation of velocity seeds optimized. This implies that random numbers are computed now using
111! the parallel random number generator. Random numbers are now only computed and normalized locally,
112! while distributed over all mpi ranks afterwards, instead of computing random numbers on a global
113! array.
114! Further, the number of calls for the time-consuming velocity-seed generation is reduced - now the
115! left and right, as well as the north and south boundary share the same velocity-seed matrices.
116!
117! 4182 2019-08-22 15:20:23Z scharf
118! Corrected "Former revisions" section
119!
120! 4148 2019-08-08 11:26:00Z suehring
121! Remove unused variable
122!
123! 4144 2019-08-06 09:11:47Z raasch
124! Relational operators .EQ., .NE., etc. replaced by ==, /=, etc.
125!
126! 4071 2019-07-03 20:02:00Z suehring
127! Bugfix, initialize mean_inflow_profiles in case turbulence and inflow information is not read from
128! file.
129!
130! 4022 2019-06-12 11:52:39Z suehring
131! Several bugfixes and improvements
132! - Revise bias correction of the imposed perturbations (correction via volume flow can create
133!   instabilities in case the mean volume flow is close to zero)
134! - Introduce lower limits in calculation of coefficient matrix, else the calculation may become
135!   numerically unstable
136! - Impose perturbations every timestep, even though no new set of perturbations is generated in
137!   case dt_stg_call /= dt_3d
138! - Implement a gradual decrease of Reynolds stress and length scales above ABL height (within 1
139!   length scale above ABL depth to 1/10) rather than a discontinuous decrease
140! - Bugfix in non-nested case: use ABL height for parametrized turbulence
141!
142! 3987 2019-05-22 09:52:13Z kanani
143! Introduce alternative switch for debug output during timestepping
144!
145! 3938 2019-04-29 16:06:25Z suehring
146! Remove unused variables
147!
148! 3937 2019-04-29 15:09:07Z suehring
149! Minor bugfix in case of a very early restart where mc_factor is sill not present.
150! Some modification and fixing of potential bugs in the calculation of scaling parameters used for
151! synthetic turbulence parametrization.
152!
153! 3909 2019-04-17 09:13:25Z suehring
154! Minor bugfix for last commit
155!
156! 3900 2019-04-16 15:17:43Z suehring
157! Missing re-calculation of perturbation seeds in case of restarts
158!
159! 3891 2019-04-12 17:52:01Z suehring
160! Bugfix in initialization in case of restart runs.
161!
162! 3885 2019-04-11 11:29:34Z kanani
163! Changes related to global restructuring of location messages and introduction of additional debug
164! messages
165!
166!
167! Removed unused variables
168!
169! 3719 2019-02-06 13:10:18Z kanani
170! Removed log_point measurement from stg_init, since this part is counted to log_point(2)
171! 'initialization' already. Moved other log_points to calls of the subroutines in time_integration
172! for better overview.
173!
174! 2259 2017-06-08 09:09:11Z gronemeier
175! Initial revision
176!
177! Authors:
178! --------
179! @author Tobias Gronemeier, Matthias Suehring, Atsushi Inagaki, Micha Gryschka, Christoph Knigge
180!
181!
182! Description:
183! ------------
184!> The module generates turbulence at the inflow boundary based on a method by Xie and Castro (2008)
185!> utilizing a Lund rotation (Lund, 1998) and a mass-flux correction by Kim et al. (2013).
186!> The turbulence is correlated based on length scales in y- and z-direction and a time scale for
187!> each velocity component. The profiles of length and time scales, mean u, v, w, e and pt, and all
188!> components of the Reynolds stress tensor can be either read from file STG_PROFILES, or will be
189!> parametrized within the boundary layer.
190!>
191!> @todo Enable cyclic_fill
192!>       Implement turbulence generation for e and pt
193!> @note <Enter notes on the module>
194!> @bug  Height information from input file is not used. Profiles from input must match with current
195!>       PALM grid.
196!>       In case of restart, velocity seeds differ from precursor run if a11, a22, or a33 are zero.
197!--------------------------------------------------------------------------------------------------!
198 MODULE synthetic_turbulence_generator_mod
199
200
201    USE arrays_3d,                                                                                 &
202        ONLY:  dzw,                                                                                &
203               ddzw,                                                                               &
204               drho_air,                                                                           &
205               mean_inflow_profiles,                                                               &
206               pt,                                                                                 &
207               pt_init,                                                                            &
208               q,                                                                                  &
209               q_init,                                                                             &
210               u,                                                                                  &
211               u_init,                                                                             &
212               v,                                                                                  &
213               v_init,                                                                             &
214               w,                                                                                  &
215               zu,                                                                                 &
216               zw
217
218    USE basic_constants_and_equations_mod,                                                         &
219        ONLY:  g,                                                                                  &
220               kappa,                                                                              &
221               pi
222
223    USE control_parameters,                                                                        &
224        ONLY:  bc_lr,                                                                              &
225               bc_ns,                                                                              &
226               child_domain,                                                                       &
227               coupling_char,                                                                      &
228               debug_output_timestep,                                                              &
229               dt_3d,                                                                              &
230               e_init,                                                                             &
231               humidity,                                                                           &
232               initializing_actions,                                                               &
233               intermediate_timestep_count,                                                        &
234               intermediate_timestep_count_max,                                                    &
235               length,                                                                             &
236               message_string,                                                                     &
237               nesting_offline,                                                                    &
238               neutral,                                                                            &
239               num_mean_inflow_profiles,                                                           &
240               random_generator,                                                                   &
241               rans_mode,                                                                          &
242               restart_data_format_output,                                                         &
243               restart_string,                                                                     &
244               syn_turb_gen,                                                                       &
245               time_since_reference_point,                                                         &
246               turbulent_inflow
247
248    USE cpulog,                                                                                    &
249        ONLY:  cpu_log,                                                                            &
250               log_point_s
251
252    USE grid_variables,                                                                            &
253        ONLY:  ddx,                                                                                &
254               ddy,                                                                                &
255               dx,                                                                                 &
256               dy
257
258    USE indices,                                                                                   &
259        ONLY:  nbgp,                                                                               &
260               nz,                                                                                 &
261               nzb,                                                                                &
262               nzt,                                                                                &
263               nx,                                                                                 &
264               nxl,                                                                                &
265               nxlu,                                                                               &
266               nxr,                                                                                &
267               ny,                                                                                 &
268               nys,                                                                                &
269               nysv,                                                                               &
270               nyn,                                                                                &
271               wall_flags_total_0
272
273    USE kinds
274
275#if defined( __parallel )
276    USE MPI
277#endif
278
279    USE nesting_offl_mod,                                                                          &
280        ONLY:  nesting_offl_calc_zi,                                                               &
281               zi_ribulk
282
283    USE pegrid,                                                                                    &
284        ONLY:  comm1dx,                                                                            &
285               comm1dy,                                                                            &
286               comm2d,                                                                             &
287               ierr,                                                                               &
288               myidx,                                                                              &
289               myidy,                                                                              &
290               pdims
291
292    USE pmc_interface,                                                                             &
293        ONLY : rans_mode_parent
294
295    USE random_generator_parallel,                                                                 &
296        ONLY:  init_parallel_random_generator,                                                     &
297               random_dummy,                                                                       &
298               random_number_parallel,                                                             &
299               random_seed_parallel
300
301    USE restart_data_mpi_io_mod,                                                                   &
302        ONLY:  rrd_mpi_io,                                                                         &
303               wrd_mpi_io
304
305    USE transpose_indices,                                                                         &
306        ONLY:  nzb_x,                                                                              &
307               nzt_x
308
309    USE surface_mod,                                                                               &
310        ONLY:  surf_def_h,                                                                         &
311               surf_lsm_h,                                                                         &
312               surf_usm_h
313
314    IMPLICIT NONE
315
316    INTEGER(iwp) ::  id_stg_left        !< left lateral boundary core id in case of turbulence generator
317    INTEGER(iwp) ::  id_stg_north       !< north lateral boundary core id in case of turbulence generator
318    INTEGER(iwp) ::  id_stg_right       !< right lateral boundary core id in case of turbulence generator
319    INTEGER(iwp) ::  id_stg_south       !< south lateral boundary core id in case of turbulence generator
320    INTEGER(iwp) ::  k_zi               !< vertical index of boundary-layer top
321    INTEGER(iwp) ::  mergp_limit = 1000 !< maximum length scale (in gp)
322    INTEGER(iwp) ::  mergp_x            !< maximum length scale in x (in gp)
323    INTEGER(iwp) ::  mergp_xy           !< maximum horizontal length scale (in gp)
324    INTEGER(iwp) ::  mergp_y            !< maximum length scale in y (in gp)
325    INTEGER(iwp) ::  mergp_z            !< maximum length scale in z (in gp)
326    INTEGER(iwp) ::  nzb_x_stg          !< lower bound of z coordinate (required for transposing z on PEs along x)
327    INTEGER(iwp) ::  nzt_x_stg          !< upper bound of z coordinate (required for transposing z on PEs along x)
328    INTEGER(iwp) ::  nzb_y_stg          !< lower bound of z coordinate (required for transposing z on PEs along y)
329    INTEGER(iwp) ::  nzt_y_stg          !< upper bound of z coordinate (required for transposing z on PEs along y)
330#if defined( __parallel )
331    INTEGER(iwp) ::  stg_type_xz        !< MPI type for full z range
332    INTEGER(iwp) ::  stg_type_xz_small  !< MPI type for small z range
333    INTEGER(iwp) ::  stg_type_yz        !< MPI type for full z range
334    INTEGER(iwp) ::  stg_type_yz_small  !< MPI type for small z range
335#endif
336
337    INTEGER(iwp), DIMENSION(3) ::  nr_non_topo_xz = 0  !< number of non-topography grid points at xz cross-sections,
338                                                       !< required for bias correction of imposed perturbations
339    INTEGER(iwp), DIMENSION(3) ::  nr_non_topo_yz = 0  !< number of non-topography grid points at yz cross-sections,
340                                                       !< required for bias correction of imposed perturbations
341
342#if defined( __parallel )
343    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  displs_xz      !< displacement for MPI_GATHERV
344    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  recv_count_xz  !< receive count for MPI_GATHERV
345    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  displs_yz      !< displacement for MPI_GATHERV
346    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  recv_count_yz  !< receive count for MPI_GATHERV
347#endif
348    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nux            !< length scale of u in x direction (in gp)
349    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nuy            !< length scale of u in y direction (in gp)
350    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nuz            !< length scale of u in z direction (in gp)
351    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nvx            !< length scale of v in x direction (in gp)
352    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nvy            !< length scale of v in y direction (in gp)
353    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nvz            !< length scale of v in z direction (in gp)
354    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nwx            !< length scale of w in x direction (in gp)
355    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nwy            !< length scale of w in y direction (in gp)
356    INTEGER(iwp), DIMENSION(:), ALLOCATABLE ::  nwz            !< length scale of w in z direction (in gp)
357
358    INTEGER(isp), DIMENSION(:), ALLOCATABLE   ::  id_rand_xz   !< initial random IDs at xz inflow boundary
359    INTEGER(isp), DIMENSION(:), ALLOCATABLE   ::  id_rand_yz   !< initial random IDs at yz inflow boundary
360    INTEGER(isp), DIMENSION(:,:), ALLOCATABLE ::  seq_rand_xz  !< initial random seeds at xz inflow boundary
361    INTEGER(isp), DIMENSION(:,:), ALLOCATABLE ::  seq_rand_yz  !< initial random seeds at yz inflow boundary
362
363
364    LOGICAL ::  adjustment_step               = .FALSE.  !< control flag indicating that time and lenght scales have been updated and
365                                                         !< no time correlation to the timestep before should be considered
366    LOGICAL ::  compute_velocity_seeds_local  = .FALSE.   !< switch to decide whether velocity seeds are computed locally
367                                                         !< or if computation is distributed over several processes
368    LOGICAL ::  parametrize_inflow_turbulence = .FALSE.  !< flag indicating that inflow turbulence is either read from file
369                                                         !< (.FALSE.) or if it parametrized
370    LOGICAL ::  velocity_seed_initialized     = .FALSE.  !< true after first call of stg_main
371
372
373    REAL(wp) ::  blend                     !< value to create gradually and smooth blending of Reynolds stress and length
374                                           !< scales above the boundary layer
375    REAL(wp) ::  blend_coeff = -9.3_wp     !< coefficient used to ensure that blending functions decreases to 1/10 after
376                                           !< one length scale above ABL top
377    REAL(wp) ::  d_l                       !< blend_coeff/length_scale
378    REAL(wp) ::  d_nxy                     !< inverse of the total number of xy-grid points
379    REAL(wp) ::  dt_stg_adjust = 1800.0_wp !< time interval for adjusting turbulence statistics
380    REAL(wp) ::  dt_stg_call = 0.0_wp      !< time interval for calling synthetic turbulence generator
381    REAL(wp) ::  scale_l                   !< scaling parameter used for turbulence parametrization - Obukhov length
382    REAL(wp) ::  scale_us                  !< scaling parameter used for turbulence parametrization - friction velocity
383    REAL(wp) ::  scale_wm                  !< scaling parameter used for turbulence parametrization - momentum scale
384    REAL(wp) ::  time_stg_adjust = 0.0_wp  !< time counter for adjusting turbulence information
385    REAL(wp) ::  time_stg_call = 0.0_wp    !< time counter for calling generator
386
387    REAL(wp), DIMENSION(3) ::  mc_factor = 1.0_wp  !< correction factor for the u,v,w-components to maintain original mass flux
388
389
390    REAL(wp),DIMENSION(:), ALLOCATABLE ::  r11  !< Reynolds parameter
391    REAL(wp),DIMENSION(:), ALLOCATABLE ::  r21  !< Reynolds parameter
392    REAL(wp),DIMENSION(:), ALLOCATABLE ::  r22  !< Reynolds parameter
393    REAL(wp),DIMENSION(:), ALLOCATABLE ::  r31  !< Reynolds parameter
394    REAL(wp),DIMENSION(:), ALLOCATABLE ::  r32  !< Reynolds parameter
395    REAL(wp),DIMENSION(:), ALLOCATABLE ::  r33  !< Reynolds parameter
396
397    REAL(wp), DIMENSION(:), ALLOCATABLE ::  a11  !< coefficient for Lund rotation
398    REAL(wp), DIMENSION(:), ALLOCATABLE ::  a21  !< coefficient for Lund rotation
399    REAL(wp), DIMENSION(:), ALLOCATABLE ::  a22  !< coefficient for Lund rotation
400    REAL(wp), DIMENSION(:), ALLOCATABLE ::  a31  !< coefficient for Lund rotation
401    REAL(wp), DIMENSION(:), ALLOCATABLE ::  a32  !< coefficient for Lund rotation
402    REAL(wp), DIMENSION(:), ALLOCATABLE ::  a33  !< coefficient for Lund rotation
403    REAL(wp), DIMENSION(:), ALLOCATABLE ::  tu   !< Lagrangian time scale of u
404    REAL(wp), DIMENSION(:), ALLOCATABLE ::  tv   !< Lagrangian time scale of v
405    REAL(wp), DIMENSION(:), ALLOCATABLE ::  tw   !< Lagrangian time scale of w
406
407    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bux     !< filter function for u in x direction
408    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  buy     !< filter function for u in y direction
409    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  buz     !< filter function for u in z direction
410    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bvx     !< filter function for v in x direction
411    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bvy     !< filter function for v in y direction
412    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bvz     !< filter function for v in z direction
413    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bwx     !< filter function for w in y direction
414    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bwy     !< filter function for w in y direction
415    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  bwz     !< filter function for w in z direction
416    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fu_xz   !< velocity seed for u at xz plane
417    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fuo_xz  !< velocity seed for u at xz plane with new random number
418    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fu_yz   !< velocity seed for u at yz plane
419    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fuo_yz  !< velocity seed for u at yz plane with new random number
420    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fv_xz   !< velocity seed for v at xz plane
421    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fvo_xz  !< velocity seed for v at xz plane with new random number
422    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fv_yz   !< velocity seed for v at yz plane
423    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fvo_yz  !< velocity seed for v at yz plane with new random number
424    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fw_xz   !< velocity seed for w at xz plane
425    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fwo_xz  !< velocity seed for w at xz plane with new random number
426    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fw_yz   !< velocity seed for w at yz plane
427    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  fwo_yz  !< velocity seed for w at yz plane with new random number
428
429    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  dist_xz !< disturbances for parallel/crosswind/vertical component at north/south boundary
430    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  dist_yz !< disturbances for parallel/crosswind/vertical component  at north/south boundary
431
432!
433!-- PALM interfaces:
434!-- Adjust time and lenght scales, Reynolds stress, and filter functions
435    INTERFACE stg_adjust
436       MODULE PROCEDURE stg_adjust
437    END INTERFACE stg_adjust
438!
439!-- Input parameter checks to be done in check_parameters
440    INTERFACE stg_check_parameters
441       MODULE PROCEDURE stg_check_parameters
442    END INTERFACE stg_check_parameters
443
444!
445!-- Calculate filter functions
446    INTERFACE stg_filter_func
447       MODULE PROCEDURE stg_filter_func
448    END INTERFACE stg_filter_func
449
450!
451!-- Generate velocity seeds at south and north domain boundary
452    INTERFACE stg_generate_seed_xz
453       MODULE PROCEDURE stg_generate_seed_xz
454    END INTERFACE stg_generate_seed_xz
455!
456!-- Generate velocity seeds at left and/or right domain boundary
457    INTERFACE stg_generate_seed_yz
458       MODULE PROCEDURE stg_generate_seed_yz
459    END INTERFACE stg_generate_seed_yz
460
461!
462!-- Output of information to the header file
463    INTERFACE stg_header
464       MODULE PROCEDURE stg_header
465    END INTERFACE stg_header
466
467!
468!-- Initialization actions
469    INTERFACE stg_init
470       MODULE PROCEDURE stg_init
471    END INTERFACE stg_init
472
473!
474!-- Main procedure of synth. turb. gen.
475    INTERFACE stg_main
476       MODULE PROCEDURE stg_main
477    END INTERFACE stg_main
478
479!
480!-- Reading of NAMELIST parameters
481    INTERFACE stg_parin
482       MODULE PROCEDURE stg_parin
483    END INTERFACE stg_parin
484
485!
486!-- Reading of parameters for restart runs
487    INTERFACE stg_rrd_global
488       MODULE PROCEDURE stg_rrd_global_ftn
489       MODULE PROCEDURE stg_rrd_global_mpi
490    END INTERFACE stg_rrd_global
491
492!
493!-- Writing of binary output for restart runs
494    INTERFACE stg_wrd_global
495       MODULE PROCEDURE stg_wrd_global
496    END INTERFACE stg_wrd_global
497
498    SAVE
499
500    PRIVATE
501
502!
503!-- Public interfaces
504    PUBLIC  stg_adjust,                                                                            &
505            stg_check_parameters,                                                                  &
506            stg_header,                                                                            &
507            stg_init,                                                                              &
508            stg_main,                                                                              &
509            stg_parin,                                                                             &
510            stg_rrd_global,                                                                        &
511            stg_wrd_global
512
513!
514!-- Public variables
515    PUBLIC  dt_stg_call,                                                                           &
516            dt_stg_adjust,                                                                         &
517            id_stg_left,                                                                           &
518            id_stg_north,                                                                          &
519            id_stg_right,                                                                          &
520            id_stg_south,                                                                          &
521            parametrize_inflow_turbulence,                                                         &
522            time_stg_adjust,                                                                       &
523            time_stg_call
524
525
526 CONTAINS
527
528
529!--------------------------------------------------------------------------------------------------!
530! Description:
531! ------------
532!> Check parameters routine for synthetic turbulence generator
533!--------------------------------------------------------------------------------------------------!
534 SUBROUTINE stg_check_parameters
535
536    IF ( .NOT. syn_turb_gen  .AND.  .NOT. rans_mode  .AND.                                     &
537          nesting_offline )  THEN
538       message_string = 'Synthetic turbulence generator is required ' //                           &
539                        'if offline nesting is applied and PALM operates in LES mode.'
540       CALL message( 'stg_check_parameters', 'PA0520', 0, 0, 0, 6, 0 )
541    ENDIF
542
543    IF ( .NOT. syn_turb_gen  .AND.  child_domain                                               &
544         .AND. rans_mode_parent  .AND.  .NOT. rans_mode )  THEN
545       message_string = 'Synthetic turbulence generator is required when nesting is applied ' //   &
546                        'and parent operates in RANS-mode but current child in LES mode.'
547       CALL message( 'stg_check_parameters', 'PA0524', 1, 2, 0, 6, 0 )
548    ENDIF
549
550    IF ( syn_turb_gen )  THEN
551
552       IF ( child_domain  .AND.  .NOT. rans_mode  .AND.  .NOT. rans_mode_parent )  THEN
553          message_string = 'Using synthetic turbulence generator is not allowed in LES-LES nesting.'
554          CALL message( 'stg_check_parameters', 'PA0620', 1, 2, 0, 6, 0 )
555
556       ENDIF
557
558       IF ( child_domain  .AND.  rans_mode  .AND.  rans_mode_parent )  THEN
559          message_string = 'Using synthetic turbulence generator is not allowed in RANS-RANS nesting.'
560          CALL message( 'stg_check_parameters', 'PA0621', 1, 2, 0, 6, 0 )
561
562       ENDIF
563
564       IF ( .NOT. nesting_offline  .AND.  .NOT. child_domain )  THEN
565
566          IF ( INDEX( initializing_actions, 'set_constant_profiles' ) == 0                         &
567          .AND.  INDEX( initializing_actions, 'read_restart_data' ) == 0 )  THEN
568             message_string = 'Using synthetic turbulence generator requires ' //                  &
569                              '%initializing_actions = "set_constant_profiles" or ' //             &
570                              ' "read_restart_data", if not offline nesting is applied.'
571             CALL message( 'stg_check_parameters', 'PA0015', 1, 2, 0, 6, 0 )
572          ENDIF
573
574          IF ( bc_lr /= 'dirichlet/radiation' )  THEN
575             message_string = 'Using synthetic turbulence generator requires &bc_lr = ' //         &
576                              ' "dirichlet/radiation", if not offline nesting is applied.'
577             CALL message( 'stg_check_parameters', 'PA0035', 1, 2, 0, 6, 0 )
578          ENDIF
579          IF ( bc_ns /= 'cyclic' )  THEN
580             message_string = 'Using synthetic turbulence generator requires &bc_ns = ' //         &
581                              ' "cyclic", if not offline nesting is applied.'
582             CALL message( 'stg_check_parameters', 'PA0037', 1, 2, 0, 6, 0 )
583          ENDIF
584
585       ENDIF
586
587       IF ( turbulent_inflow )  THEN
588          message_string = 'Using synthetic turbulence generator in combination ' //               &
589                           '&with turbulent_inflow = .T. is not allowed'
590          CALL message( 'stg_check_parameters', 'PA0039', 1, 2, 0, 6, 0 )
591       ENDIF
592!
593!--    Synthetic turbulence generator requires the parallel random generator
594       IF ( random_generator /= 'random-parallel' )  THEN
595          message_string = 'Using synthetic turbulence generator requires random_generator = ' //  &
596                           'random-parallel.'
597          CALL message( 'stg_check_parameters', 'PA0421', 1, 2, 0, 6, 0 )
598       ENDIF
599
600    ENDIF
601
602 END SUBROUTINE stg_check_parameters
603
604
605!--------------------------------------------------------------------------------------------------!
606! Description:
607! ------------
608!> Header output for synthetic turbulence generator
609!--------------------------------------------------------------------------------------------------!
610 SUBROUTINE stg_header ( io )
611
612    INTEGER(iwp), INTENT(IN) ::  io  !< Unit of the output file
613
614!
615!-- Write synthetic turbulence generator Header
616    IF ( syn_turb_gen )  THEN
617       WRITE( io, 1 )
618       IF ( parametrize_inflow_turbulence )  THEN
619          WRITE( io, 4 ) dt_stg_adjust
620       ELSE
621          WRITE( io, 5 )
622       ENDIF
623    ENDIF
624
6251   FORMAT (//' Synthetic turbulence generator information:'/                                      &
626              ' ------------------------------------------'/)
6274   FORMAT ('    imposed turbulence statistics are parametrized and ajdusted to boundary-layer development each ', F8.2, ' s' )
6285   FORMAT ('    imposed turbulence is read from file' )
629
630 END SUBROUTINE stg_header
631
632
633!--------------------------------------------------------------------------------------------------!
634! Description:
635! ------------
636!> Initialization of the synthetic turbulence generator
637!--------------------------------------------------------------------------------------------------!
638 SUBROUTINE stg_init
639
640#if defined( __parallel )
641    INTEGER(KIND=MPI_ADDRESS_KIND) :: extent   !< extent of new MPI type
642    INTEGER(KIND=MPI_ADDRESS_KIND) :: tob = 0  !< dummy variable
643#endif
644
645    INTEGER(iwp) :: i         !> grid index in x-direction
646    INTEGER(iwp) :: j         !> loop index
647    INTEGER(iwp) :: k         !< index
648#if defined( __parallel )
649    INTEGER(iwp) :: newtype   !< dummy MPI type
650    INTEGER(iwp) :: realsize  !< size of REAL variables
651#endif
652
653    INTEGER(iwp), DIMENSION(3) ::  nr_non_topo_xz_l = 0 !< number of non-topography grid points at xz-cross-section on subdomain
654    INTEGER(iwp), DIMENSION(3) ::  nr_non_topo_yz_l = 0 !< number of non-topography grid points at yz-cross-section on subdomain
655
656
657    LOGICAL ::  file_stg_exist = .FALSE.  !< flag indicating whether parameter file for Reynolds stress and length scales exist
658
659!
660!-- Dummy variables used for reading profiles
661    REAL(wp) :: d1   !< u profile
662    REAL(wp) :: d2   !< v profile
663    REAL(wp) :: d3   !< w profile
664    REAL(wp) :: d5   !< e profile
665    REAL(wp) :: luy  !< length scale for u in y direction
666    REAL(wp) :: luz  !< length scale for u in z direction
667    REAL(wp) :: lvy  !< length scale for v in y direction
668    REAL(wp) :: lvz  !< length scale for v in z direction
669    REAL(wp) :: lwy  !< length scale for w in y direction
670    REAL(wp) :: lwz  !< length scale for w in z direction
671#if defined( __parallel )
672    REAL(wp) :: nnz  !< increment used to determine processor decomposition of z-axis along x and y direction
673#endif
674    REAL(wp) :: zz   !< height
675
676
677#if defined( __parallel )
678    CALL MPI_BARRIER( comm2d, ierr )
679#endif
680!
681!-- Create mpi-datatypes for exchange in case of non-local but distributed computation of the
682!-- velocity seeds. This option is useful in case large turbulent length scales are present, where
683!-- the computational effort becomes large and needs to be parallelized. For parameterized turbulence
684!-- the length scales are small and computing the velocity seeds locally is faster (no overhead by
685!-- communication).
686    IF ( .NOT. compute_velocity_seeds_local )  THEN
687#if defined( __parallel )
688!
689!--    Determine processor decomposition of z-axis along x- and y-direction
690       nnz = nz / pdims(1)
691       nzb_x_stg = 1 + myidx * INT( nnz )
692       nzt_x_stg = ( myidx + 1 ) * INT( nnz )
693
694       IF ( MOD( nz , pdims(1) ) /= 0  .AND.  myidx == id_stg_right )                              &
695          nzt_x_stg = nzt_x_stg + myidx * ( nnz - INT( nnz ) )
696
697       IF ( nesting_offline   .OR.  ( child_domain  .AND.  rans_mode_parent                        &
698                               .AND.  .NOT.  rans_mode ) )  THEN
699          nnz = nz / pdims(2)
700          nzb_y_stg = 1 + myidy * INT( nnz )
701          nzt_y_stg = ( myidy + 1 ) * INT( nnz )
702
703          IF ( MOD( nz , pdims(2) ) /= 0  .AND.  myidy == id_stg_north )                           &
704             nzt_y_stg = nzt_y_stg + myidy * ( nnz - INT( nnz ) )
705       ENDIF
706
707!
708!--    Define MPI type used in stg_generate_seed_yz to gather vertical splitted velocity seeds
709       CALL MPI_TYPE_SIZE( MPI_REAL, realsize, ierr )
710       extent = 1 * realsize
711!
712!--    Set-up MPI datatyp to involve all cores for turbulence generation at yz layer
713!--    stg_type_yz: yz-slice with vertical bounds nzb:nzt+1
714       CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt-nzb+2,nyn-nys+1],                                    &
715               [1,nyn-nys+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
716       CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_yz, ierr )
717       CALL MPI_TYPE_COMMIT( stg_type_yz, ierr )
718       CALL MPI_TYPE_FREE( newtype, ierr )
719
720       ! stg_type_yz_small: yz-slice with vertical bounds nzb_x_stg:nzt_x_stg+1
721       CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt_x_stg-nzb_x_stg+2,nyn-nys+1],                        &
722               [1,nyn-nys+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
723       CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_yz_small, ierr )
724       CALL MPI_TYPE_COMMIT( stg_type_yz_small, ierr )
725       CALL MPI_TYPE_FREE( newtype, ierr )
726
727       ! Receive count and displacement for MPI_GATHERV in stg_generate_seed_yz
728       ALLOCATE( recv_count_yz(pdims(1)), displs_yz(pdims(1)) )
729
730       recv_count_yz           = nzt_x_stg-nzb_x_stg + 1
731       recv_count_yz(pdims(1)) = recv_count_yz(pdims(1)) + 1
732
733       DO  j = 1, pdims(1)
734          displs_yz(j) = 0 + (nzt_x_stg-nzb_x_stg+1) * (j-1)
735       ENDDO
736!
737!--    Set-up MPI datatyp to involve all cores for turbulence generation at xz layer
738!--    stg_type_xz: xz-slice with vertical bounds nzb:nzt+1
739       IF ( nesting_offline  .OR.  ( child_domain .AND.  rans_mode_parent      &
740                              .AND.  .NOT.  rans_mode ) )  THEN
741          CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt-nzb+2,nxr-nxl+1],             &
742                  [1,nxr-nxl+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
743          CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_xz, ierr )
744          CALL MPI_TYPE_COMMIT( stg_type_xz, ierr )
745          CALL MPI_TYPE_FREE( newtype, ierr )
746
747          ! stg_type_yz_small: xz-slice with vertical bounds nzb_x_stg:nzt_x_stg+1
748          CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt_y_stg-nzb_y_stg+2,nxr-nxl+1], &
749                  [1,nxr-nxl+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
750          CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_xz_small, ierr )
751          CALL MPI_TYPE_COMMIT( stg_type_xz_small, ierr )
752          CALL MPI_TYPE_FREE( newtype, ierr )
753
754          ! Receive count and displacement for MPI_GATHERV in stg_generate_seed_yz
755          ALLOCATE( recv_count_xz(pdims(2)), displs_xz(pdims(2)) )
756
757          recv_count_xz           = nzt_y_stg-nzb_y_stg + 1
758          recv_count_xz(pdims(2)) = recv_count_xz(pdims(2)) + 1
759
760          DO  j = 1, pdims(2)
761             displs_xz(j) = 0 + (nzt_y_stg-nzb_y_stg+1) * (j-1)
762          ENDDO
763
764       ENDIF
765#endif
766    ENDIF
767!
768!-- Allocate required arrays.
769!-- In case no offline nesting or self nesting is used, the arrary mean_inflow profiles is required.
770!-- Check if it is already allocated, else allocate and initialize it appropriately. Note, in case
771!-- turbulence and inflow information is read from file, mean_inflow_profiles is already allocated
772!-- and initialized appropriately.
773    IF ( .NOT. nesting_offline  .AND.  .NOT.  child_domain )  THEN
774       IF ( .NOT. ALLOCATED( mean_inflow_profiles ) )  THEN
775          ALLOCATE( mean_inflow_profiles(nzb:nzt+1,1:num_mean_inflow_profiles) )
776          mean_inflow_profiles = 0.0_wp
777          mean_inflow_profiles(:,1) = u_init
778          mean_inflow_profiles(:,2) = v_init
779!
780!--       Even though potential temperature and humidity are not perturbed, they need to be
781!--       initialized appropriately.
782          IF ( .NOT. neutral )                                                                     &
783             mean_inflow_profiles(:,4) = pt_init
784          IF ( humidity )                                                                          &
785             mean_inflow_profiles(:,6) = q_init
786       ENDIF
787    ENDIF
788!
789!-- Assign initial profiles. Note, this is only required if turbulent inflow from the left is
790!-- desired, not in case of any of the nesting (offline or self nesting) approaches.
791    IF ( .NOT. nesting_offline  .AND.  .NOT.  child_domain )  THEN
792       u_init = mean_inflow_profiles(:,1)
793       v_init = mean_inflow_profiles(:,2)
794       e_init = MAXVAL( mean_inflow_profiles(:,5) )
795    ENDIF
796
797    ALLOCATE ( a11(nzb:nzt+1), a21(nzb:nzt+1), a22(nzb:nzt+1),                                     &
798               a31(nzb:nzt+1), a32(nzb:nzt+1), a33(nzb:nzt+1),                                     &
799               nux(nzb:nzt+1), nuy(nzb:nzt+1), nuz(nzb:nzt+1),                                     &
800               nvx(nzb:nzt+1), nvy(nzb:nzt+1), nvz(nzb:nzt+1),                                     &
801               nwx(nzb:nzt+1), nwy(nzb:nzt+1), nwz(nzb:nzt+1),                                     &
802               r11(nzb:nzt+1), r21(nzb:nzt+1), r22(nzb:nzt+1),                                     &
803               r31(nzb:nzt+1), r32(nzb:nzt+1), r33(nzb:nzt+1),                                     &
804               tu(nzb:nzt+1),  tv(nzb:nzt+1),  tw(nzb:nzt+1) )
805
806    r11 = 0.0_wp
807    r21 = 0.0_wp
808    r22 = 0.0_wp
809    r31 = 0.0_wp
810    r32 = 0.0_wp
811    r33 = 0.0_wp
812    tu  = 0.0_wp
813    tv  = 0.0_wp
814    tw  = 0.0_wp
815
816    ALLOCATE ( dist_xz(nzb:nzt+1,nxl:nxr,3) )
817    ALLOCATE ( dist_yz(nzb:nzt+1,nys:nyn,3) )
818    dist_xz = 0.0_wp
819    dist_yz = 0.0_wp
820!
821!-- Read inflow profile
822!-- Height levels of profiles in input profile is as follows:
823!-- zu: luy, luz, tu, lvy, lvz, tv, r11, r21, r22, d1, d2, d5 zw: lwy, lwz, tw, r31, r32, r33, d3
824!-- WARNING: zz is not used at the moment
825    INQUIRE( FILE = 'STG_PROFILES' // TRIM( coupling_char ), EXIST = file_stg_exist  )
826
827    IF ( file_stg_exist )  THEN
828
829       OPEN( 90, FILE = 'STG_PROFILES' // TRIM( coupling_char ), STATUS = 'OLD', FORM = 'FORMATTED' )
830!
831!--    Skip header
832       READ( 90, * )
833
834       DO  k = nzb, nzt
835          READ( 90, * ) zz, luy, luz, tu(k), lvy, lvz, tv(k), lwy, lwz, tw(k), r11(k), r21(k),     &
836                        r22(k), r31(k), r32(k), r33(k), d1, d2, d3, d5
837
838!
839!--       Convert length scales from meter to number of grid points.
840          IF ( k /= nzb )  THEN
841             nuz(k) = INT( luz * ddzw(k) )
842             nvz(k) = INT( lvz * ddzw(k) )
843             nwz(k) = INT( lwz * ddzw(k) )
844          ELSE
845             nuz(k) = INT( luz * ddzw(k+1) )
846             nvz(k) = INT( lvz * ddzw(k+1) )
847             nwz(k) = INT( lwz * ddzw(k+1) )
848          ENDIF
849
850          nuy(k) = INT( luy * ddy )
851          nvy(k) = INT( lvy * ddy )
852          nwy(k) = INT( lwy * ddy )
853!
854!--       Set length scales in x-direction. As a workaround assume isotropic turbulence in x- and
855!--       y-direction.
856          nwx(k) = nwy(k)
857          nvx(k) = nvy(k)
858          nux(k) = nuy(k)
859!
860!--       Save Mean inflow profiles
861          IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN
862             mean_inflow_profiles(k,1) = d1
863             mean_inflow_profiles(k,2) = d2
864            !  mean_inflow_profiles(k,4) = d4
865             mean_inflow_profiles(k,5) = d5
866          ENDIF
867       ENDDO
868!
869!--    Set length scales at the surface and top boundary. At the surface the lengths scales are
870!--    simply overwritten.
871       nwx(nzb) = nwy(nzb+1)
872       nvx(nzb) = nvy(nzb+1)
873       nux(nzb) = nuy(nzb+1)
874       nuy(nzb) = nuy(nzb+1)
875       nuz(nzb) = nuz(nzb+1)
876       nvy(nzb) = nvy(nzb+1)
877       nvz(nzb) = nvz(nzb+1)
878       nwy(nzb) = nwy(nzb+1)
879       nwz(nzb) = nwz(nzb+1)
880
881       nwx(nzt+1) = nwy(nzt)
882       nvx(nzt+1) = nvy(nzt)
883       nux(nzt+1) = nuy(nzt)
884       nuy(nzt+1) = nuy(nzt)
885       nuz(nzt+1) = nuz(nzt)
886       nvy(nzt+1) = nvy(nzt)
887       nvz(nzt+1) = nvz(nzt)
888       nwy(nzt+1) = nwy(nzt)
889       nwz(nzt+1) = nwz(nzt)
890
891       CLOSE( 90 )
892!
893!--    Calculate coefficient matrix from Reynolds stress tensor (Lund rotation)
894       CALL calc_coeff_matrix
895!
896!-- No information about turbulence and its length scales are available. Instead, parametrize
897!-- turbulence which is imposed at the boundaries. Set flag which indicates that turbulence is
898!-- parametrized, which is done later when energy-balance models are already initialized. This is
899!-- because the STG needs information about surface properties such as roughness to build
900!-- 'realistic' turbulence profiles.
901    ELSE
902!
903!--    Precalulate the inversion number of xy-grid points - later used for mass conservation
904       d_nxy = 1.0_wp / REAL( ( nx + 1 ) * ( ny + 1 ), KIND = wp )
905!
906!--    Set flag indicating that turbulence is parametrized
907       parametrize_inflow_turbulence = .TRUE.
908!
909!--    In case of dirichlet inflow boundary conditions only at one lateral boundary, i.e. in the
910!--    case no offline or self nesting is applied but synthetic turbulence shall be parametrized
911!--    nevertheless, the boundary-layer depth needs to be determined first.
912       IF ( .NOT. nesting_offline  .AND.  .NOT.  child_domain )                                    &
913          CALL nesting_offl_calc_zi
914!
915!--    Determine boundary-layer depth, which is used to initialize lenght scales
916       CALL calc_scaling_variables
917!
918!--    Parametrize Reynolds-stress tensor, diagonal elements as well as r21 (v'u'), r31 (w'u'),
919!--    r32 (w'v'). Parametrization follows Rotach et al. (1996) and is based on boundary-layer depth,
920!--    friction velocity and velocity scale.
921       CALL parametrize_turbulence
922!
923!--    Calculate coefficient matrix from Reynolds stress tensor (Lund rotation)
924       CALL calc_coeff_matrix
925
926    ENDIF
927!
928!-- Initial filter functions
929    CALL stg_setup_filter_function
930!
931!-- Allocate velocity seeds for turbulence at xz-layer
932    ALLOCATE ( fu_xz(nzb:nzt+1,nxl:nxr), fuo_xz(nzb:nzt+1,nxl:nxr),                                &
933               fv_xz(nzb:nzt+1,nxl:nxr), fvo_xz(nzb:nzt+1,nxl:nxr),                                &
934               fw_xz(nzb:nzt+1,nxl:nxr), fwo_xz(nzb:nzt+1,nxl:nxr) )
935
936!
937!-- Allocate velocity seeds for turbulence at yz-layer
938    ALLOCATE ( fu_yz(nzb:nzt+1,nys:nyn), fuo_yz(nzb:nzt+1,nys:nyn),                                &
939               fv_yz(nzb:nzt+1,nys:nyn), fvo_yz(nzb:nzt+1,nys:nyn),                                &
940               fw_yz(nzb:nzt+1,nys:nyn), fwo_yz(nzb:nzt+1,nys:nyn) )
941
942    fu_xz  = 0.0_wp
943    fuo_xz = 0.0_wp
944    fv_xz  = 0.0_wp
945    fvo_xz = 0.0_wp
946    fw_xz  = 0.0_wp
947    fwo_xz = 0.0_wp
948
949    fu_yz  = 0.0_wp
950    fuo_yz = 0.0_wp
951    fv_yz  = 0.0_wp
952    fvo_yz = 0.0_wp
953    fw_yz  = 0.0_wp
954    fwo_yz = 0.0_wp
955
956#if defined( __parallel )
957    CALL MPI_BARRIER( comm2d, ierr )
958#endif
959
960!
961!-- In case of restart, calculate velocity seeds fu, fv, fw from former time step.
962!   Bug: fu, fv, fw are different in those heights where a11, a22, a33 are 0 compared to the prerun.
963!-- This is mostly for k=nzt+1.
964    IF ( TRIM( initializing_actions ) == 'read_restart_data' )  THEN
965       IF ( myidx == id_stg_left  .OR.  myidx == id_stg_right )  THEN
966
967          IF ( myidx == id_stg_left  )  i = -1
968          IF ( myidx == id_stg_right )  i = nxr+1
969
970          DO  j = nys, nyn
971             DO  k = nzb, nzt+1
972                IF  ( a11(k) > 10E-8_wp )  THEN
973                   fu_yz(k,j) = ( u(k,j,i) - u_init(k) ) / a11(k)
974                ELSE
975                   fu_yz(k,j) = 10E-8_wp
976                ENDIF
977
978                IF  ( a22(k) > 10E-8_wp )  THEN
979                   fv_yz(k,j) = ( v(k,j,i) - a21(k) * fu_yz(k,j) - v_init(k) ) / a22(k)
980                ELSE
981                   fv_yz(k,j) = 10E-8_wp
982                ENDIF
983
984                IF  ( a33(k) > 10E-8_wp )  THEN
985                   fw_yz(k,j) = ( w(k,j,i) - a31(k) * fu_yz(k,j) - a32(k) * fv_yz(k,j) ) / a33(k)
986                ELSE
987                   fw_yz(k,j) = 10E-8_wp
988                ENDIF
989             ENDDO
990          ENDDO
991       ENDIF
992
993       IF ( myidy == id_stg_south  .OR.  myidy == id_stg_north )  THEN
994
995          IF ( myidy == id_stg_south )  j = -1
996          IF ( myidy == id_stg_north )  j = nyn+1
997
998          DO  i = nxl, nxr
999             DO  k = nzb, nzt+1
1000!
1001!--             In case the correlation coefficients are very small, the velocity seeds may become
1002!--             very large finally creating numerical instabilities in the synthetic turbulence
1003!--             generator. Empirically, a value of 10E-8 seems to be sufficient.
1004                IF  ( a11(k) > 10E-8_wp )  THEN
1005                   fu_xz(k,i) = ( u(k,j,i) - u_init(k) ) / a11(k)
1006                ELSE
1007                   fu_xz(k,i) = 10E-8_wp
1008                ENDIF
1009
1010                IF  ( a22(k) > 10E-8_wp )  THEN
1011                   fv_xz(k,i) = ( v(k,j,i) - a21(k) * fu_xz(k,i) - v_init(k) ) / a22(k)
1012                ELSE
1013                   fv_xz(k,i) = 10E-8_wp
1014                ENDIF
1015
1016                IF  ( a33(k) > 10E-8_wp )  THEN
1017                   fw_xz(k,i) = ( w(k,j,i) - a31(k) * fu_xz(k,i) - a32(k) * fv_xz(k,i) ) / a33(k)
1018                ELSE
1019                   fw_xz(k,i) = 10E-8_wp
1020                ENDIF
1021
1022             ENDDO
1023          ENDDO
1024       ENDIF
1025    ENDIF
1026!
1027!-- Count the number of non-topography grid points at the boundaries where perturbations are imposed.
1028!-- This number is later used for bias corrections of the perturbations, i.e. to force their mean to
1029!-- be zero. Please note, due to the asymetry of u and v along x and y direction, respectively,
1030!-- different cases must be distinguished.
1031    IF ( myidx == id_stg_left  .OR.  myidx == id_stg_right )  THEN
1032!
1033!--    Number of grid points where perturbations are imposed on u
1034       IF ( myidx == id_stg_left  )  i = nxl
1035       IF ( myidx == id_stg_right )  i = nxr+1
1036
1037       nr_non_topo_yz_l(1) = SUM( MERGE( 1, 0, BTEST( wall_flags_total_0(nzb:nzt,nys:nyn,i), 1 ) ) )
1038!
1039!--    Number of grid points where perturbations are imposed on v and w
1040       IF ( myidx == id_stg_left  )  i = nxl-1
1041       IF ( myidx == id_stg_right )  i = nxr+1
1042
1043       nr_non_topo_yz_l(2) = SUM( MERGE( 1, 0, BTEST( wall_flags_total_0(nzb:nzt,nysv:nyn,i), 2 ) ) )
1044       nr_non_topo_yz_l(3) = SUM( MERGE( 1, 0, BTEST( wall_flags_total_0(nzb:nzt,nys:nyn,i), 3 ) ) )
1045
1046#if defined( __parallel )
1047       CALL MPI_ALLREDUCE( nr_non_topo_yz_l, nr_non_topo_yz, 3, MPI_INTEGER, MPI_SUM, comm1dy, ierr )
1048#else
1049       nr_non_topo_yz = nr_non_topo_yz_l
1050#endif
1051    ENDIF
1052
1053    IF ( myidy == id_stg_south  .OR.  myidy == id_stg_north )  THEN
1054!
1055!--    Number of grid points where perturbations are imposed on v
1056       IF ( myidy == id_stg_south )  j = nys
1057       IF ( myidy == id_stg_north )  j = nyn+1
1058
1059       nr_non_topo_xz_l(2) = SUM( MERGE( 1, 0, BTEST( wall_flags_total_0(nzb:nzt,j,nxl:nxr), 2 ) ) )
1060!
1061!--    Number of grid points where perturbations are imposed on u and w
1062       IF ( myidy == id_stg_south )  j = nys-1
1063       IF ( myidy == id_stg_north )  j = nyn+1
1064
1065       nr_non_topo_xz_l(1) = SUM( MERGE( 1, 0, BTEST( wall_flags_total_0(nzb:nzt,j,nxlu:nxr), 1 ) ) )
1066       nr_non_topo_xz_l(3) = SUM( MERGE( 1, 0, BTEST( wall_flags_total_0(nzb:nzt,j,nxl:nxr), 3 ) ) )
1067
1068#if defined( __parallel )
1069       CALL MPI_ALLREDUCE( nr_non_topo_xz_l, nr_non_topo_xz, 3, MPI_INTEGER, MPI_SUM, comm1dx, ierr )
1070#else
1071       nr_non_topo_xz = nr_non_topo_xz_l
1072#endif
1073    ENDIF
1074!
1075!-- Initialize random number generator at xz- and yz-layers. Random numbers are initialized at each
1076!-- core. In case there is only inflow from the left, it is sufficient to generate only random
1077!-- numbers for the yz-layer, else random numbers for the xz-layer are also required.
1078    ALLOCATE ( id_rand_yz(-mergp_limit+nys:nyn+mergp_limit) )
1079    ALLOCATE ( seq_rand_yz(5,-mergp_limit+nys:nyn+mergp_limit) )
1080    id_rand_yz  = 0
1081    seq_rand_yz = 0
1082
1083    CALL init_parallel_random_generator( ny, -mergp_limit+nys, nyn+mergp_limit, id_rand_yz, seq_rand_yz )
1084
1085    IF ( nesting_offline  .OR.  ( child_domain .AND.  rans_mode_parent                             &
1086         .AND.  .NOT.  rans_mode ) )  THEN
1087       ALLOCATE ( id_rand_xz(-mergp_limit+nxl:nxr+mergp_limit) )
1088       ALLOCATE ( seq_rand_xz(5,-mergp_limit+nxl:nxr+mergp_limit) )
1089       id_rand_xz  = 0
1090       seq_rand_xz = 0
1091
1092       CALL init_parallel_random_generator( nx, -mergp_limit+nxl, nxr+mergp_limit, id_rand_xz, seq_rand_xz )
1093    ENDIF
1094
1095 END SUBROUTINE stg_init
1096
1097
1098!--------------------------------------------------------------------------------------------------!
1099! Description:
1100! ------------
1101!> Calculate filter function bxx from length scale nxx following Eg.9 and 10 (Xie and Castro, 2008)
1102!--------------------------------------------------------------------------------------------------!
1103 SUBROUTINE stg_filter_func( nxx, bxx, mergp )
1104
1105    INTEGER(iwp) ::  k     !< loop index
1106    INTEGER(iwp) ::  mergp !< passed length scale in grid points
1107    INTEGER(iwp) ::  n_k   !< length scale nXX in height k
1108    INTEGER(iwp) ::  nf    !< index for length scales
1109
1110    INTEGER(iwp), DIMENSION(nzb:nzt+1) ::  nxx  !< length scale (in gp)
1111
1112    REAL(wp) :: bdenom        !< denominator for filter functions bXX
1113    REAL(wp) :: qsi = 1.0_wp  !< minimization factor
1114
1115    REAL(wp), DIMENSION(-mergp:mergp,nzb:nzt+1) ::  bxx  !< filter function
1116
1117
1118    bxx = 0.0_wp
1119
1120    DO  k = nzb, nzt+1
1121       bdenom = 0.0_wp
1122       n_k    = nxx(k)
1123       IF ( n_k /= 0 )  THEN
1124
1125!
1126!--       ( Eq.10 )^2
1127          DO  nf = -n_k, n_k
1128             bdenom = bdenom + EXP( -qsi * pi * ABS( nf ) / n_k )**2
1129          ENDDO
1130
1131!
1132!--       ( Eq.9 )
1133          bdenom = SQRT( bdenom )
1134          DO  nf = -n_k, n_k
1135             bxx(nf,k) = EXP( -qsi * pi * ABS( nf ) / n_k ) / bdenom
1136          ENDDO
1137       ENDIF
1138    ENDDO
1139
1140 END SUBROUTINE stg_filter_func
1141
1142
1143!------------------------------------------------------------------------------!
1144! Description:
1145! ------------
1146!> Calculate filter function bxx from length scale nxx following Eg.9 and 10
1147!> (Xie and Castro, 2008)
1148!------------------------------------------------------------------------------!
1149 SUBROUTINE stg_setup_filter_function
1150
1151    INTEGER(iwp) :: j  !< dummy value to calculate maximum length scale index
1152    INTEGER(iwp) :: k  !< loop index along vertical direction
1153!
1154!-- Define the size of the filter functions and allocate them.
1155    mergp_x = 0
1156    mergp_y = 0
1157    mergp_z = 0
1158
1159    DO  k = nzb, nzt+1
1160       j = MAX( ABS(nux(k)), ABS(nvx(k)), ABS(nwx(k)) )
1161       IF ( j > mergp_x )  mergp_x = j
1162    ENDDO
1163    DO  k = nzb, nzt+1
1164       j = MAX( ABS(nuy(k)), ABS(nvy(k)), ABS(nwy(k)) )
1165       IF ( j > mergp_y )  mergp_y = j
1166    ENDDO
1167    DO  k = nzb, nzt+1
1168       j = MAX( ABS(nuz(k)), ABS(nvz(k)), ABS(nwz(k)) )
1169       IF ( j > mergp_z )  mergp_z = j
1170    ENDDO
1171
1172    mergp_xy = MAX( mergp_x, mergp_y )
1173
1174    IF ( ALLOCATED( bux ) )  DEALLOCATE( bux )
1175    IF ( ALLOCATED( bvx ) )  DEALLOCATE( bvx )
1176    IF ( ALLOCATED( bwx ) )  DEALLOCATE( bwx )
1177    IF ( ALLOCATED( buy ) )  DEALLOCATE( buy )
1178    IF ( ALLOCATED( bvy ) )  DEALLOCATE( bvy )
1179    IF ( ALLOCATED( bwy ) )  DEALLOCATE( bwy )
1180    IF ( ALLOCATED( buz ) )  DEALLOCATE( buz )
1181    IF ( ALLOCATED( bvz ) )  DEALLOCATE( bvz )
1182    IF ( ALLOCATED( bwz ) )  DEALLOCATE( bwz )
1183
1184    ALLOCATE ( bux(-mergp_x:mergp_x,nzb:nzt+1),                                                    &
1185               buy(-mergp_y:mergp_y,nzb:nzt+1),                                                    &
1186               buz(-mergp_z:mergp_z,nzb:nzt+1),                                                    &
1187               bvx(-mergp_x:mergp_x,nzb:nzt+1),                                                    &
1188               bvy(-mergp_y:mergp_y,nzb:nzt+1),                                                    &
1189               bvz(-mergp_z:mergp_z,nzb:nzt+1),                                                    &
1190               bwx(-mergp_x:mergp_x,nzb:nzt+1),                                                    &
1191               bwy(-mergp_y:mergp_y,nzb:nzt+1),                                                    &
1192               bwz(-mergp_z:mergp_z,nzb:nzt+1) )
1193!
1194!-- Create filter functions
1195    CALL stg_filter_func( nux, bux, mergp_x ) !filter ux
1196    CALL stg_filter_func( nuy, buy, mergp_y ) !filter uy
1197    CALL stg_filter_func( nuz, buz, mergp_z ) !filter uz
1198    CALL stg_filter_func( nvx, bvx, mergp_x ) !filter vx
1199    CALL stg_filter_func( nvy, bvy, mergp_y ) !filter vy
1200    CALL stg_filter_func( nvz, bvz, mergp_z ) !filter vz
1201    CALL stg_filter_func( nwx, bwx, mergp_x ) !filter wx
1202    CALL stg_filter_func( nwy, bwy, mergp_y ) !filter wy
1203    CALL stg_filter_func( nwz, bwz, mergp_z ) !filter wz
1204
1205 END SUBROUTINE stg_setup_filter_function
1206
1207!--------------------------------------------------------------------------------------------------!
1208! Description:
1209! ------------
1210!> Parin for &stg_par for synthetic turbulence generator
1211!--------------------------------------------------------------------------------------------------!
1212 SUBROUTINE stg_parin
1213
1214    CHARACTER(LEN=100) ::  line  !< dummy string that contains the current line of the parameter file
1215
1216    INTEGER(iwp) ::  io_status   !< status after reading the namelist file
1217
1218    LOGICAL ::  switch_off_module = .FALSE.  !< local namelist parameter to switch off the module
1219                                             !< although the respective module namelist appears in
1220                                             !< the namelist file
1221
1222    NAMELIST /stg_par/  compute_velocity_seeds_local,                                              &
1223                        dt_stg_adjust,                                                             &
1224                        dt_stg_call,                                                               &
1225                        switch_off_module
1226
1227
1228!
1229!-- Move to the beginning of the namelist file and try to find and read the namelist.
1230    REWIND( 11 )
1231    READ( 11, stg_par, IOSTAT=io_status )
1232
1233!
1234!-- Action depending on the READ status
1235    IF ( io_status == 0 )  THEN
1236!
1237!--    stg_par namelist was found and read correctly. Set flag that indicates that the synthetic
1238!--    turbulence generator is switched on.
1239       IF ( .NOT. switch_off_module )  syn_turb_gen = .TRUE.
1240
1241    ELSEIF ( io_status > 0 )  THEN
1242!
1243!--    stg_par namelist was found but contained errors. Print an error message including the line
1244!--    that caused the problem.
1245       BACKSPACE( 11 )
1246       READ( 11 , '(A)') line
1247       CALL parin_fail_message( 'stg_par', line )
1248
1249    ENDIF
1250
1251 END SUBROUTINE stg_parin
1252
1253
1254!--------------------------------------------------------------------------------------------------!
1255! Description:
1256! ------------
1257!> Read module-specific global restart data (Fortran binary format).
1258!--------------------------------------------------------------------------------------------------!
1259 SUBROUTINE stg_rrd_global_ftn( found )
1260
1261    LOGICAL, INTENT(OUT) ::  found !< flag indicating if variable was found
1262
1263    found = .TRUE.
1264
1265
1266    SELECT CASE ( restart_string(1:length) )
1267
1268       CASE ( 'time_stg_adjust' )
1269          READ ( 13 )  time_stg_adjust
1270
1271       CASE ( 'time_stg_call' )
1272          READ ( 13 )  time_stg_call
1273
1274       CASE DEFAULT
1275
1276          found = .FALSE.
1277
1278    END SELECT
1279
1280
1281 END SUBROUTINE stg_rrd_global_ftn
1282
1283
1284!--------------------------------------------------------------------------------------------------!
1285! Description:
1286! ------------
1287!> Read module-specific global restart data (MPI-IO).
1288!--------------------------------------------------------------------------------------------------!
1289 SUBROUTINE stg_rrd_global_mpi
1290
1291    CALL rrd_mpi_io( 'time_stg_adjust', time_stg_adjust )
1292    CALL rrd_mpi_io( 'time_stg_call', time_stg_call )
1293
1294 END SUBROUTINE stg_rrd_global_mpi
1295
1296
1297!--------------------------------------------------------------------------------------------------!
1298! Description:
1299! ------------
1300!> This routine writes the respective restart data.
1301!--------------------------------------------------------------------------------------------------!
1302 SUBROUTINE stg_wrd_global
1303
1304    IF ( TRIM( restart_data_format_output ) == 'fortran_binary' )  THEN
1305
1306      CALL wrd_write_string( 'time_stg_adjust' )
1307       WRITE ( 14 )  time_stg_adjust
1308
1309       CALL wrd_write_string( 'time_stg_call' )
1310       WRITE ( 14 )  time_stg_call
1311
1312    ELSEIF ( restart_data_format_output(1:3) == 'mpi' )  THEN
1313
1314       CALL wrd_mpi_io( 'time_stg_adjust', time_stg_adjust )
1315       CALL wrd_mpi_io( 'time_stg_call', time_stg_call )
1316
1317    ENDIF
1318
1319 END SUBROUTINE stg_wrd_global
1320
1321
1322!--------------------------------------------------------------------------------------------------!
1323! Description:
1324! ------------
1325!> Create turbulent inflow fields for u, v, w with prescribed length scales and Reynolds stress
1326!> tensor after a method of Xie and Castro (2008), modified following suggestions of Kim et al.
1327!> (2013), and using a Lund rotation (Lund, 1998).
1328!--------------------------------------------------------------------------------------------------!
1329 SUBROUTINE stg_main
1330
1331    USE exchange_horiz_mod,                                                                        &
1332        ONLY:  exchange_horiz
1333
1334    INTEGER(iwp) ::  i  !< grid index in x-direction
1335    INTEGER(iwp) ::  j  !< loop index in y-direction
1336    INTEGER(iwp) ::  k  !< loop index in z-direction
1337
1338    LOGICAL  ::  stg_call = .FALSE.  !< control flag indicating whether turbulence was updated or only restored from last call
1339
1340    REAL(wp) ::  dt_stg  !< time interval the STG is called
1341
1342    REAL(wp), DIMENSION(3) ::  mc_factor_l  !< local mass flux correction factor
1343
1344    IF ( debug_output_timestep )  CALL debug_message( 'stg_main', 'start' )
1345!
1346!-- Calculate time step which is needed for filter functions
1347    dt_stg = MAX( dt_3d, dt_stg_call )
1348!
1349!-- Check if synthetic turbulence generator needs to be called and new perturbations need to be
1350!-- created or if old disturbances can be imposed again.
1351    IF ( time_stg_call >= dt_stg_call  .AND.                                                       &
1352         intermediate_timestep_count == intermediate_timestep_count_max  )  THEN
1353       stg_call = .TRUE.
1354    ELSE
1355       stg_call = .FALSE.
1356    ENDIF
1357!
1358!-- Initial value of fu, fv, fw
1359    IF ( time_since_reference_point == 0.0_wp .AND. .NOT. velocity_seed_initialized )  THEN
1360!
1361!--    Generate turbulence at the left and right boundary. Random numbers for the yz-planes at the
1362!--    left/right boundary are generated by the left-sided mpi ranks only. After random numbers are
1363!--    calculated, they are distributed to all other mpi ranks in the model, so that the velocity
1364!--    seed matrices are available on all mpi ranks (i.e. also on the right-sided boundary mpi ranks).
1365!--    In case of offline nesting, this implies, that the left- and the right-sided lateral boundary
1366!--    have the same initial seeds.
1367!--    Note, in case of inflow from the right only, only turbulence at the left boundary is required.
1368       IF ( .NOT. ( nesting_offline  .OR.  ( child_domain .AND.  rans_mode_parent                  &
1369            .AND.  .NOT.  rans_mode ) ) )  THEN
1370          CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fu_yz, id_stg_left )
1371          CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fv_yz, id_stg_left )
1372          CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fw_yz, id_stg_left )
1373       ELSE
1374          CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fu_yz, id_stg_left, id_stg_right )
1375          CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fv_yz, id_stg_left, id_stg_right )
1376          CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fw_yz, id_stg_left, id_stg_right )
1377!
1378!--       Generate turbulence at the south and north boundary. Random numbers for the xz-planes at
1379!--       the south/north boundary are generated by the south-sided mpi ranks only. Please see also
1380!--       comment above.
1381          CALL stg_generate_seed_xz( nux, nuz, bux, buz, fu_xz, id_stg_south, id_stg_north )
1382          CALL stg_generate_seed_xz( nvx, nvz, bvx, bvz, fv_xz, id_stg_south, id_stg_north )
1383          CALL stg_generate_seed_xz( nwx, nwz, bwx, bwz, fw_xz, id_stg_south, id_stg_north )
1384       ENDIF
1385       velocity_seed_initialized = .TRUE.
1386    ENDIF
1387!
1388!-- New set of fu, fv, fw. Note, for inflow from the left side only, velocity seeds are only
1389!-- required at the left boundary, while in case of offline nesting or RANS-LES nesting velocity
1390!-- seeds are required also at the right, south and north boundaries.
1391    IF ( stg_call )  THEN
1392       IF ( .NOT. ( nesting_offline  .OR.                                                          &
1393                  ( child_domain .AND.  rans_mode_parent                                           &
1394                                 .AND.  .NOT.  rans_mode ) ) )  THEN
1395          CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fuo_yz, id_stg_left )
1396          CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fvo_yz, id_stg_left )
1397          CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fwo_yz, id_stg_left )
1398
1399       ELSE
1400          CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fuo_yz, id_stg_left, id_stg_right )
1401          CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fvo_yz, id_stg_left, id_stg_right )
1402          CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fwo_yz, id_stg_left, id_stg_right )
1403
1404          CALL stg_generate_seed_xz( nux, nuz, bux, buz, fuo_xz, id_stg_south, id_stg_north )
1405          CALL stg_generate_seed_xz( nvx, nvz, bvx, bvz, fvo_xz, id_stg_south, id_stg_north )
1406          CALL stg_generate_seed_xz( nwx, nwz, bwx, bwz, fwo_xz, id_stg_south, id_stg_north )
1407       ENDIF
1408    ENDIF
1409
1410!
1411!-- Turbulence generation at left and/or right boundary
1412    IF ( myidx == id_stg_left  .OR.  myidx == id_stg_right )  THEN
1413!
1414!--    Calculate new set of perturbations. Do this only at last RK3-substep and when dt_stg_call is
1415!--    exceeded. Else the old set of perturbations is imposed
1416       IF ( stg_call )  THEN
1417
1418          DO  j = nys, nyn
1419             DO  k = nzb, nzt + 1
1420!
1421!--             Update fu, fv, fw following Eq. 14 of Xie and Castro (2008)
1422                IF ( tu(k) == 0.0_wp  .OR.  adjustment_step )  THEN
1423                   fu_yz(k,j) = fuo_yz(k,j)
1424                ELSE
1425                   fu_yz(k,j) = fu_yz(k,j) * EXP( -pi * dt_stg * 0.5_wp / tu(k) ) +                &
1426                                fuo_yz(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tu(k) ) )
1427                ENDIF
1428
1429                IF ( tv(k) == 0.0_wp  .OR.  adjustment_step )  THEN
1430                   fv_yz(k,j) = fvo_yz(k,j)
1431                ELSE
1432                   fv_yz(k,j) = fv_yz(k,j) * EXP( -pi * dt_stg * 0.5_wp / tv(k) ) +                &
1433                                fvo_yz(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tv(k) ) )
1434                ENDIF
1435
1436                IF ( tw(k) == 0.0_wp  .OR.  adjustment_step )  THEN
1437                   fw_yz(k,j) = fwo_yz(k,j)
1438                ELSE
1439                   fw_yz(k,j) = fw_yz(k,j) * EXP( -pi * dt_stg * 0.5_wp / tw(k) ) +                &
1440                                fwo_yz(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tw(k) ) )
1441                ENDIF
1442             ENDDO
1443          ENDDO
1444
1445          dist_yz(nzb,:,1) = 0.0_wp
1446          dist_yz(nzb,:,2) = 0.0_wp
1447          dist_yz(nzb,:,3) = 0.0_wp
1448
1449          IF ( myidx == id_stg_left  )  i = nxl
1450          IF ( myidx == id_stg_right )  i = nxr+1
1451          DO  j = nys, nyn
1452             DO  k = nzb+1, nzt + 1
1453!
1454!--             Lund rotation following Eq. 17 in Xie and Castro (2008).
1455                dist_yz(k,j,1) = a11(k) * fu_yz(k,j) *                                             &
1456                                 MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,i), 1 ) )
1457
1458             ENDDO
1459          ENDDO
1460
1461          IF ( myidx == id_stg_left  )  i = nxl-1
1462          IF ( myidx == id_stg_right )  i = nxr+1
1463          DO  j = nys, nyn
1464             DO  k = nzb+1, nzt + 1
1465!
1466!--             Lund rotation following Eq. 17 in Xie and Castro (2008).
1467!--             Additional factors are added to improve the variance of v and w experimental test
1468!--             of 1.2
1469                dist_yz(k,j,2) = ( a21(k) * fu_yz(k,j) + a22(k) * fv_yz(k,j) ) *                   &
1470                                 MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,i), 2 ) )
1471                dist_yz(k,j,3) = ( a31(k) * fu_yz(k,j) + a32(k) * fv_yz(k,j) +                     &
1472                                   a33(k) * fw_yz(k,j) ) *                                         &
1473                                 MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,i), 3 ) )
1474
1475             ENDDO
1476          ENDDO
1477       ENDIF
1478!
1479!--    Mass flux correction following Kim et al. (2013)
1480!--    This correction factor ensures that the mass flux is preserved at the inflow boundary. First,
1481!--    calculate mean value of the imposed perturbations at yz boundary. Note, this needs to be done
1482!--    only after the last RK3-substep, else the boundary values won't be accessed.
1483       IF ( intermediate_timestep_count == intermediate_timestep_count_max )  THEN
1484          mc_factor_l = 0.0_wp
1485          mc_factor   = 0.0_wp
1486!
1487!--       Sum up the original volume flows (with and without perturbations).
1488!--       Note, for non-normal components (here v and w) it is actually no volume flow.
1489          IF ( myidx == id_stg_left  )  i = nxl
1490          IF ( myidx == id_stg_right )  i = nxr+1
1491
1492          mc_factor_l(1) = SUM( dist_yz(nzb:nzt,nys:nyn,1) *                                       &
1493                       MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(nzb:nzt,nys:nyn,i), 1 ) ) )
1494
1495          IF ( myidx == id_stg_left  )  i = nxl-1
1496          IF ( myidx == id_stg_right )  i = nxr+1
1497
1498          mc_factor_l(2) = SUM( dist_yz(nzb:nzt,nysv:nyn,2) *                                      &
1499                       MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(nzb:nzt,nysv:nyn,i), 2 ) ) )
1500          mc_factor_l(3) = SUM( dist_yz(nzb:nzt,nys:nyn,3) *                                       &
1501                       MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(nzb:nzt,nys:nyn,i), 3 ) ) )
1502
1503#if defined( __parallel )
1504          CALL MPI_ALLREDUCE( mc_factor_l, mc_factor, 3, MPI_REAL, MPI_SUM, comm1dy, ierr )
1505#else
1506          mc_factor   = mc_factor_l
1507#endif
1508!
1509!--       Calculate correction factor and force zero mean perturbations.
1510          mc_factor = mc_factor / REAL( nr_non_topo_yz, KIND = wp )
1511
1512          IF ( myidx == id_stg_left  )  i = nxl
1513          IF ( myidx == id_stg_right )  i = nxr+1
1514
1515          dist_yz(:,nys:nyn,1) = ( dist_yz(:,nys:nyn,1) - mc_factor(1) ) *                         &
1516                                MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(:,nys:nyn,i), 1 ) )
1517
1518
1519          IF ( myidx == id_stg_left  )  i = nxl-1
1520          IF ( myidx == id_stg_right )  i = nxr+1
1521
1522          dist_yz(:,nys:nyn,2) = ( dist_yz(:,nys:nyn,2) - mc_factor(2) ) *                         &
1523                                MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(:,nys:nyn,i), 2 ) )
1524
1525          dist_yz(:,nys:nyn,3) = ( dist_yz(:,nys:nyn,3) - mc_factor(3) ) *                         &
1526                                MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(:,nys:nyn,i), 3 ) )
1527!
1528!--       Add disturbances
1529          IF ( myidx == id_stg_left  )  THEN
1530!
1531!--          For the left boundary distinguish between mesoscale offline / self nesting and
1532!--          turbulent inflow at the left boundary only. In the latter case turbulence is imposed on
1533!--          the mean inflow profiles.
1534             IF ( .NOT. nesting_offline  .AND.  .NOT. child_domain )  THEN
1535!
1536!--             Add disturbance at the inflow
1537                DO  j = nys, nyn
1538                   DO  k = nzb, nzt+1
1539                      u(k,j,-nbgp+1:0) = ( mean_inflow_profiles(k,1) + dist_yz(k,j,1) ) *          &
1540                                     MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,0), 1 ) )
1541                      v(k,j,-nbgp:-1)  = ( mean_inflow_profiles(k,2) + dist_yz(k,j,2) ) *          &
1542                                     MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,-1), 2 ) )
1543                      w(k,j,-nbgp:-1)  = dist_yz(k,j,3) *                                          &
1544                                     MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,-1), 3 ) )
1545                   ENDDO
1546                ENDDO
1547             ELSE
1548
1549                DO  j = nys, nyn
1550                   DO  k = nzb+1, nzt
1551                      u(k,j,0)   = ( u(k,j,0)  + dist_yz(k,j,1) ) *                                &
1552                                   MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,0), 1 ) )
1553                      u(k,j,-1)  = u(k,j,0)
1554                      v(k,j,-1)  = ( v(k,j,-1) + dist_yz(k,j,2) ) *                                &
1555                                   MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,-1), 2 ) )
1556                      w(k,j,-1)  = ( w(k,j,-1) + dist_yz(k,j,3) ) *                                &
1557                                   MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,-1), 3 ) )
1558                   ENDDO
1559                ENDDO
1560             ENDIF
1561          ENDIF
1562          IF ( myidx == id_stg_right  )  THEN
1563             DO  j = nys, nyn
1564                DO  k = nzb+1, nzt
1565                   u(k,j,nxr+1) = ( u(k,j,nxr+1) + dist_yz(k,j,1) ) *                              &
1566                                  MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,nxr+1), 1 ) )
1567                   v(k,j,nxr+1) = ( v(k,j,nxr+1) + dist_yz(k,j,2) ) *                              &
1568                                  MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,nxr+1), 2 ) )
1569                   w(k,j,nxr+1) = ( w(k,j,nxr+1) + dist_yz(k,j,3) ) *                              &
1570                                  MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,nxr+1), 3 ) )
1571                ENDDO
1572             ENDDO
1573          ENDIF
1574       ENDIF
1575    ENDIF
1576!
1577!-- Turbulence generation at north and south boundary
1578    IF ( myidy == id_stg_north  .OR.  myidy == id_stg_south )  THEN
1579!
1580!--    Calculate new set of perturbations. Do this only at last RK3-substep and when dt_stg_call is
1581!--    exceeded. Else the old set of perturbations is imposed
1582       IF ( stg_call )  THEN
1583          DO  i = nxl, nxr
1584             DO  k = nzb, nzt + 1
1585!
1586!--             Update fu, fv, fw following Eq. 14 of Xie and Castro (2008)
1587                IF ( tu(k) == 0.0_wp  .OR.  adjustment_step )  THEN
1588                   fu_xz(k,i) = fuo_xz(k,i)
1589                ELSE
1590                   fu_xz(k,i) = fu_xz(k,i) * EXP( -pi * dt_stg * 0.5_wp / tu(k) ) +                &
1591                                fuo_xz(k,i) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tu(k) ) )
1592                ENDIF
1593
1594                IF ( tv(k) == 0.0_wp  .OR.  adjustment_step )  THEN
1595                   fv_xz(k,i) = fvo_xz(k,i)
1596                ELSE
1597                   fv_xz(k,i) = fv_xz(k,i) * EXP( -pi * dt_stg * 0.5_wp / tv(k) ) +                &
1598                                fvo_xz(k,i) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tv(k) ) )
1599                ENDIF
1600
1601                IF ( tw(k) == 0.0_wp  .OR.  adjustment_step )  THEN
1602                   fw_xz(k,i) = fwo_xz(k,i)
1603                ELSE
1604                   fw_xz(k,i) = fw_xz(k,i) * EXP( -pi * dt_stg * 0.5_wp / tw(k) ) +                &
1605                                fwo_xz(k,i) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tw(k) ) )
1606                ENDIF
1607             ENDDO
1608          ENDDO
1609
1610
1611          dist_xz(nzb,:,1) = 0.0_wp
1612          dist_xz(nzb,:,2) = 0.0_wp
1613          dist_xz(nzb,:,3) = 0.0_wp
1614
1615          IF ( myidy == id_stg_south  ) j = nys
1616          IF ( myidy == id_stg_north )  j = nyn+1
1617          DO  i = nxl, nxr
1618             DO  k = nzb+1, nzt + 1
1619!
1620!--             Lund rotation following Eq. 17 in Xie and Castro (2008).
1621!--             Additional factors are added to improve the variance of v and w
1622                !experimental test of 1.2
1623                dist_xz(k,i,2) = ( a21(k) * fu_xz(k,i) + a22(k) * fv_xz(k,i) ) *                   &
1624                                 MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,i), 2 ) )
1625             ENDDO
1626          ENDDO
1627
1628          IF ( myidy == id_stg_south  ) j = nys-1
1629          IF ( myidy == id_stg_north )  j = nyn+1
1630          DO  i = nxl, nxr
1631             DO  k = nzb+1, nzt + 1
1632!
1633!--             Lund rotation following Eq. 17 in Xie and Castro (2008).
1634!--             Additional factors are added to improve the variance of v and w
1635                dist_xz(k,i,1) = a11(k) * fu_xz(k,i) *                                             &
1636                                 MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,i), 1 ) )
1637
1638                dist_xz(k,i,3) = ( a31(k) * fu_xz(k,i) + a32(k) * fv_xz(k,i) +                     &
1639                                   a33(k) * fw_xz(k,i) ) *                                         &
1640                                 MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,j,i), 3 ) )
1641             ENDDO
1642          ENDDO
1643       ENDIF
1644
1645!
1646!--    Mass flux correction following Kim et al. (2013). This correction factor ensures that the
1647!--    mass flux is preserved at the inflow boundary. First, calculate mean value of the imposed
1648!--    perturbations at yz boundary. Note, this needs to be done only after the last RK3-substep,
1649!--    else the boundary values won't be accessed.
1650       IF ( intermediate_timestep_count == intermediate_timestep_count_max )  THEN
1651          mc_factor_l = 0.0_wp
1652          mc_factor   = 0.0_wp
1653
1654          IF ( myidy == id_stg_south  ) j = nys
1655          IF ( myidy == id_stg_north )  j = nyn+1
1656
1657          mc_factor_l(2) = SUM( dist_xz(nzb:nzt,nxl:nxr,2) *                                       &
1658                       MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(nzb:nzt,j,nxl:nxr), 2 ) ) )
1659
1660          IF ( myidy == id_stg_south ) j = nys-1
1661          IF ( myidy == id_stg_north ) j = nyn+1
1662
1663          mc_factor_l(1) = SUM( dist_xz(nzb:nzt,nxlu:nxr,1) *                                      &
1664                       MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(nzb:nzt,j,nxlu:nxr), 1 ) ) )
1665          mc_factor_l(3) = SUM( dist_xz(nzb:nzt,nxl:nxr,3) *                                       &
1666                       MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(nzb:nzt,j,nxl:nxr), 3 ) ) )
1667
1668#if defined( __parallel )
1669          CALL MPI_ALLREDUCE( mc_factor_l, mc_factor, 3, MPI_REAL, MPI_SUM, comm1dx, ierr )
1670#else
1671          mc_factor   = mc_factor_l
1672#endif
1673
1674          mc_factor = mc_factor / REAL( nr_non_topo_xz, KIND = wp )
1675
1676          IF ( myidy == id_stg_south ) j = nys
1677          IF ( myidy == id_stg_north ) j = nyn+1
1678
1679          dist_xz(:,nxl:nxr,2) = ( dist_xz(:,nxl:nxr,2) - mc_factor(2) ) *                         &
1680                                MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(:,j,nxl:nxr), 2 ) )
1681
1682
1683          IF ( myidy == id_stg_south ) j = nys-1
1684          IF ( myidy == id_stg_north ) j = nyn+1
1685
1686          dist_xz(:,nxl:nxr,1) = ( dist_xz(:,nxl:nxr,1) - mc_factor(1) ) *                         &
1687                                MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(:,j,nxl:nxr), 1 ) )
1688
1689          dist_xz(:,nxl:nxr,3) = ( dist_xz(:,nxl:nxr,3) - mc_factor(3) ) *                         &
1690                                MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(:,j,nxl:nxr), 3 ) )
1691!
1692!--       Add disturbances
1693          IF ( myidy == id_stg_south )  THEN
1694             DO  i = nxl, nxr
1695                DO  k = nzb+1, nzt
1696                   u(k,-1,i) = ( u(k,-1,i) + dist_xz(k,i,1) )                                      &
1697                               * MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,-1,i), 1 ) )
1698                   v(k,0,i)  = ( v(k,0,i)  + dist_xz(k,i,2) )                                      &
1699                               * MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,0,i), 2 ) )
1700                   v(k,-1,i) = v(k,0,i)
1701                   w(k,-1,i) = ( w(k,-1,i) + dist_xz(k,i,3) )                                      &
1702                               * MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,-1,i), 3 ) )
1703                ENDDO
1704             ENDDO
1705          ENDIF
1706          IF ( myidy == id_stg_north  )  THEN
1707
1708             DO  i = nxl, nxr
1709                DO  k = nzb+1, nzt
1710                   u(k,nyn+1,i) = ( u(k,nyn+1,i) + dist_xz(k,i,1) ) *                              &
1711                                  MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,nyn+1,i), 1 ) )
1712                   v(k,nyn+1,i) = ( v(k,nyn+1,i) + dist_xz(k,i,2) ) *                              &
1713                                  MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,nyn+1,i), 2 ) )
1714                   w(k,nyn+1,i) = ( w(k,nyn+1,i) + dist_xz(k,i,3) ) *                              &
1715                                  MERGE( 1.0_wp, 0.0_wp, BTEST( wall_flags_total_0(k,nyn+1,i), 3 ) )
1716                ENDDO
1717             ENDDO
1718          ENDIF
1719       ENDIF
1720    ENDIF
1721!
1722!-- Exchange ghost points.
1723    CALL exchange_horiz( u, nbgp )
1724    CALL exchange_horiz( v, nbgp )
1725    CALL exchange_horiz( w, nbgp )
1726!
1727!-- Finally, set time counter for calling STG to zero
1728    IF ( stg_call )  time_stg_call = 0.0_wp
1729!
1730!-- Set adjustment step to False to indicate that time correlation can be
1731!-- switched-on again.
1732    adjustment_step = .FALSE.
1733
1734    IF ( debug_output_timestep )  CALL debug_message( 'stg_main', 'end' )
1735
1736 END SUBROUTINE stg_main
1737
1738!--------------------------------------------------------------------------------------------------!
1739! Description:
1740! ------------
1741!> Generate a set of random number rand_it wich is equal on each PE and calculate the velocity seed
1742!> f_n. f_n is splitted in vertical direction by the number of PEs in x-direction and each PE
1743!> calculates a vertical subsection of f_n. At the the end, all parts are collected to form the full
1744!> array.
1745!--------------------------------------------------------------------------------------------------!
1746 SUBROUTINE stg_generate_seed_yz( n_y, n_z, b_y, b_z, f_n, id_left, id_right )
1747
1748    INTEGER(iwp)           ::  id_left     !< core ids at respective boundaries
1749    INTEGER(iwp), OPTIONAL ::  id_right    !< core ids at respective boundaries
1750    INTEGER(iwp)           ::  j           !< loop index in y-direction
1751    INTEGER(iwp)           ::  jj          !< loop index in y-direction
1752    INTEGER(iwp)           ::  k           !< loop index in z-direction
1753    INTEGER(iwp)           ::  kk          !< loop index in z-direction
1754    INTEGER(iwp)           ::  send_count  !< send count for MPI_GATHERV
1755
1756    INTEGER(iwp), DIMENSION(nzb:nzt+1) ::  n_y  !< length scale in y-direction
1757    INTEGER(iwp), DIMENSION(nzb:nzt+1) ::  n_z  !< length scale in z-direction
1758
1759    REAL(wp) ::  nyz_inv         !< inverse of number of grid points in yz-slice
1760    REAL(wp) ::  rand_av         !< average of random number
1761    REAL(wp) ::  rand_sigma_inv  !< inverse of stdev of random number
1762
1763    REAL(wp), DIMENSION(-mergp_y:mergp_y,nzb:nzt+1) :: b_y     !< filter function in y-direction
1764    REAL(wp), DIMENSION(-mergp_z:mergp_z,nzb:nzt+1) :: b_z     !< filter function in z-direction
1765
1766    REAL(wp), DIMENSION(nzb_x_stg:nzt_x_stg+1,nys:nyn) ::  f_n_l  !<  local velocity seed
1767    REAL(wp), DIMENSION(nzb:nzt+1,nys:nyn)             ::  f_n    !<  velocity seed
1768
1769    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  rand_it  !< global array of random numbers
1770!
1771!-- Generate random numbers using the parallel random generator. The set of random numbers are
1772!-- modified to have an average of 0 and unit variance. Note, at the end the random number array
1773!-- must be defined globally in order to compute the correlation matrices. However, the calculation
1774!-- and normalization of random numbers is done locally, while the result is later distributed to
1775!-- all processes. Further, please note, a set of random numbers is only calculated for the west
1776!-- boundary, while the east boundary uses the same random numbers and thus also computes the same
1777!-- correlation matrix.
1778    ALLOCATE( rand_it(nzb-mergp_z:nzt+1+mergp_z,-mergp_y+nys:nyn+mergp_y) )
1779    rand_it = 0.0_wp
1780
1781    rand_av        = 0.0_wp
1782    rand_sigma_inv = 0.0_wp
1783    nyz_inv        = 1.0_wp / REAL( ( nzt + 1 + mergp_z - ( nzb - mergp_z ) + 1 )                  &
1784                     * ( ny + mergp_y - ( 0 - mergp_y ) + 1 ), KIND = wp )
1785!
1786!-- Compute and normalize random numbers.
1787    DO  j = nys - mergp_y, nyn + mergp_y
1788!
1789!--    Put the random seeds at grid point j
1790       CALL random_seed_parallel( put=seq_rand_yz(:,j) )
1791       DO  k = nzb - mergp_z, nzt + 1 + mergp_z
1792          CALL random_number_parallel( random_dummy )
1793          rand_it(k,j) = random_dummy
1794       ENDDO
1795!
1796!--    Get the new random seeds from last call at grid point j
1797       CALL random_seed_parallel( get=seq_rand_yz(:,j) )
1798    ENDDO
1799!
1800!-- For normalization to zero mean, sum-up the global random numers. To normalize the global set of
1801!-- random numbers, the inner ghost layers mergp must not be summed-up, else the random numbers on
1802!-- the ghost layers will be stronger weighted as they also occur on the inner subdomains.
1803    DO  j = MERGE( nys, nys - mergp_y, nys /= 0 ), MERGE( nyn, nyn + mergp_y, nyn /= ny )
1804       DO  k = nzb - mergp_z, nzt + 1 + mergp_z
1805          rand_av = rand_av + rand_it(k,j)
1806       ENDDO
1807    ENDDO
1808
1809#if defined( __parallel )
1810!
1811!-- Sum-up the local averages of the random numbers
1812    CALL MPI_ALLREDUCE( MPI_IN_PLACE, rand_av, 1, MPI_REAL, MPI_SUM, comm1dy, ierr )
1813#endif
1814    rand_av = rand_av * nyz_inv
1815!
1816!-- Obtain zero mean
1817    rand_it= rand_it - rand_av
1818!
1819!-- Now, compute the variance
1820    DO  j = MERGE( nys, nys - mergp_y, nys /= 0 ), MERGE( nyn, nyn + mergp_y, nyn /= ny )
1821       DO  k = nzb - mergp_z, nzt + 1 + mergp_z
1822          rand_sigma_inv = rand_sigma_inv + rand_it(k,j)**2
1823       ENDDO
1824    ENDDO
1825
1826#if defined( __parallel )
1827!
1828!-- Sum-up the local quadratic averages of the random numbers
1829    CALL MPI_ALLREDUCE( MPI_IN_PLACE, rand_sigma_inv, 1, MPI_REAL, MPI_SUM, comm1dy, ierr )
1830#endif
1831!
1832!-- Compute standard deviation
1833    IF ( rand_sigma_inv /= 0.0_wp )  THEN
1834       rand_sigma_inv = 1.0_wp / SQRT( rand_sigma_inv * nyz_inv )
1835    ELSE
1836       rand_sigma_inv = 1.0_wp
1837    ENDIF
1838!
1839!-- Normalize with standard deviation to obtain unit variance
1840    rand_it = rand_it * rand_sigma_inv
1841
1842    CALL cpu_log( log_point_s(31), 'STG f_n factors', 'start' )
1843!
1844!-- Generate velocity seed following Eq.6 of Xie and Castro (2008). There are two options. In the
1845!-- first one, the computation of the seeds is distributed to all processes along the communicator
1846!-- comm1dy and gathered on the leftmost and, if necessary, on the rightmost process. For huge
1847!-- length scales the computational effort can become quite huge (it scales with the turbulent
1848!-- length scales), so that gain by parallelization exceeds the costs by the subsequent
1849!-- communication. In the second option, which performs better when the turbulent length scales
1850!-- are parametrized and thus the loops are smaller, the seeds are computed locally and no
1851!-- communication is necessary.
1852    IF ( compute_velocity_seeds_local )  THEN
1853
1854       f_n  = 0.0_wp
1855       DO  j = nys, nyn
1856          DO  k = nzb, nzt+1
1857             DO  jj = -n_y(k), n_y(k)
1858                DO  kk = -n_z(k), n_z(k)
1859                   f_n(k,j) = f_n(k,j) + b_y(jj,k) * b_z(kk,k) * rand_it(k+kk,j+jj)
1860                ENDDO
1861             ENDDO
1862          ENDDO
1863       ENDDO
1864
1865    ELSE
1866
1867       f_n_l  = 0.0_wp
1868       DO  j = nys, nyn
1869          DO  k = nzb_x_stg, nzt_x_stg+1
1870             DO  jj = -n_y(k), n_y(k)
1871                DO  kk = -n_z(k), n_z(k)
1872                   f_n_l(k,j) = f_n_l(k,j) + b_y(jj,k) * b_z(kk,k) * rand_it(k+kk,j+jj)
1873                ENDDO
1874             ENDDO
1875          ENDDO
1876       ENDDO
1877!
1878!--    Gather velocity seeds of full subdomain
1879       send_count = nzt_x_stg - nzb_x_stg + 1
1880       IF ( nzt_x_stg == nzt )  send_count = send_count + 1
1881
1882#if defined( __parallel )
1883!
1884!--    Gather the velocity seed matrix on left boundary mpi ranks.
1885       CALL MPI_GATHERV( f_n_l(nzb_x_stg,nys), send_count, stg_type_yz_small, f_n(nzb+1,nys),      &
1886                         recv_count_yz, displs_yz, stg_type_yz, id_left, comm1dx, ierr )
1887!
1888!--    If required, gather the same velocity seed matrix on right boundary mpi ranks (in offline
1889!--    nesting for example).
1890       IF ( PRESENT( id_right ) )  THEN
1891          CALL MPI_GATHERV( f_n_l(nzb_x_stg,nys), send_count, stg_type_yz_small, f_n(nzb+1,nys),   &
1892                            recv_count_yz, displs_yz, stg_type_yz, id_right, comm1dx, ierr )
1893       ENDIF
1894#else
1895       f_n(nzb+1:nzt+1,nys:nyn) = f_n_l(nzb_x_stg:nzt_x_stg+1,nys:nyn)
1896!
1897!--    Next line required to avoid compile errors because of unused dummy arguments
1898       IF ( id_left == 0 )  id_right = 0
1899#endif
1900
1901    ENDIF
1902
1903    DEALLOCATE( rand_it )
1904
1905    CALL cpu_log( log_point_s(31), 'STG f_n factors', 'stop' )
1906
1907 END SUBROUTINE stg_generate_seed_yz
1908
1909
1910!--------------------------------------------------------------------------------------------------!
1911! Description:
1912! ------------
1913!> Generate a set of random number rand_it wich is equal on each PE and calculate the velocity seed
1914!> f_n.
1915!> f_n is splitted in vertical direction by the number of PEs in y-direction and and each PE
1916!> calculates a vertical subsection of f_n. At the the end, all parts are collected to form the
1917!> full array.
1918!--------------------------------------------------------------------------------------------------!
1919 SUBROUTINE stg_generate_seed_xz( n_x, n_z, b_x, b_z, f_n, id_south, id_north )
1920
1921    INTEGER(iwp) :: i           !< loop index in x-direction
1922    INTEGER(iwp) :: id_north    !< core ids at respective boundaries
1923    INTEGER(iwp) :: id_south    !< core ids at respective boundaries
1924    INTEGER(iwp) :: ii          !< loop index in x-direction
1925    INTEGER(iwp) :: k           !< loop index in z-direction
1926    INTEGER(iwp) :: kk          !< loop index in z-direction
1927    INTEGER(iwp) :: send_count  !< send count for MPI_GATHERV
1928
1929    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_x    !< length scale in x-direction
1930    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z    !< length scale in z-direction
1931
1932    REAL(wp) :: nxz_inv         !< inverse of number of grid points in xz-slice
1933    REAL(wp) :: rand_av         !< average of random number
1934    REAL(wp) :: rand_sigma_inv  !< inverse of stdev of random number
1935
1936    REAL(wp), DIMENSION(-mergp_x:mergp_x,nzb:nzt+1) :: b_x     !< filter function in x-direction
1937    REAL(wp), DIMENSION(-mergp_z:mergp_z,nzb:nzt+1) :: b_z     !< filter function in z-direction
1938
1939    REAL(wp), DIMENSION(nzb_y_stg:nzt_y_stg+1,nxl:nxr) :: f_n_l   !<  local velocity seed
1940    REAL(wp), DIMENSION(nzb:nzt+1,nxl:nxr)             :: f_n     !<  velocity seed
1941
1942    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  rand_it   !< global array of random numbers
1943
1944!
1945!-- Generate random numbers using the parallel random generator. The set of random numbers are
1946!-- modified to have an average of 0 and unit variance. Note, at the end the random number array
1947!-- must be defined globally in order to compute the correlation matrices. However, the calculation
1948!-- and normalization of random numbers is done locally, while the result is later distributed to
1949!-- all processes. Further, please note, a set of random numbers is only calculated for the south
1950!-- boundary, while the north boundary uses the same random numbers and thus also computes the same
1951!-- correlation matrix.
1952    ALLOCATE( rand_it(nzb-mergp_z:nzt+1+mergp_z,-mergp_x+nxl:nxr+mergp_x) )
1953    rand_it = 0.0_wp
1954
1955    rand_av        = 0.0_wp
1956    rand_sigma_inv = 0.0_wp
1957    nxz_inv        = 1.0_wp / REAL( ( nzt + 1 + mergp_z - ( nzb - mergp_z ) + 1 )                  &
1958                     * ( nx + mergp_x - ( 0 - mergp_x ) +1 ), KIND = wp )
1959!
1960!-- Compute and normalize random numbers.
1961    DO  i = nxl - mergp_x, nxr + mergp_x
1962!
1963!--    Put the random seeds at grid point ii
1964       CALL random_seed_parallel( put=seq_rand_xz(:,i) )
1965       DO  k = nzb - mergp_z, nzt + 1 + mergp_z
1966          CALL random_number_parallel( random_dummy )
1967          rand_it(k,i) = random_dummy
1968       ENDDO
1969!
1970!--    Get the new random seeds from last call at grid point ii
1971       CALL random_seed_parallel( get=seq_rand_xz(:,i) )
1972    ENDDO
1973!
1974!-- For normalization to zero mean, sum-up the global random numers.
1975!-- To normalize the global set of random numbers, the inner ghost layers mergp must not be
1976!-- summed-up, else the random numbers on the ghost layers will be stronger weighted as they
1977!-- also occur on the inner subdomains.
1978    DO  i = MERGE( nxl, nxl - mergp_x, nxl /= 0 ), MERGE( nxr, nxr + mergp_x, nxr /= nx )
1979       DO  k = nzb - mergp_z, nzt + 1 + mergp_z
1980          rand_av = rand_av + rand_it(k,i)
1981       ENDDO
1982    ENDDO
1983
1984#if defined( __parallel )
1985!
1986!-- Sum-up the local averages of the random numbers
1987    CALL MPI_ALLREDUCE( MPI_IN_PLACE, rand_av, 1, MPI_REAL, MPI_SUM, comm1dx, ierr )
1988#endif
1989    rand_av = rand_av * nxz_inv
1990!
1991!-- Obtain zero mean
1992    rand_it= rand_it - rand_av
1993!
1994!-- Now, compute the variance
1995    DO  i = MERGE( nxl, nxl - mergp_x, nxl /= 0 ), MERGE( nxr, nxr + mergp_x, nxr /= nx )
1996       DO  k = nzb - mergp_z, nzt + 1 + mergp_z
1997          rand_sigma_inv = rand_sigma_inv + rand_it(k,i)**2
1998       ENDDO
1999    ENDDO
2000
2001#if defined( __parallel )
2002!
2003!-- Sum-up the local quadratic averages of the random numbers
2004    CALL MPI_ALLREDUCE( MPI_IN_PLACE, rand_sigma_inv, 1, MPI_REAL, MPI_SUM, comm1dx, ierr )
2005#endif
2006!
2007!-- Compute standard deviation
2008    IF ( rand_sigma_inv /= 0.0_wp )  THEN
2009       rand_sigma_inv = 1.0_wp / SQRT( rand_sigma_inv * nxz_inv )
2010    ELSE
2011       rand_sigma_inv = 1.0_wp
2012    ENDIF
2013!
2014!-- Normalize with standard deviation to obtain unit variance
2015    rand_it = rand_it * rand_sigma_inv
2016
2017    CALL cpu_log( log_point_s(31), 'STG f_n factors', 'start' )
2018!
2019!-- Generate velocity seed following Eq.6 of Xie and Castro (2008). There are two options. In the
2020!-- first one, the computation of the seeds is distributed to all processes along the communicator
2021!-- comm1dx and gathered on the southmost and, if necessary, on the northmost process. For huge
2022!-- length scales the computational effort can become quite huge (it scales with the turbulent
2023!-- length scales), so that gain by parallelization exceeds the costs by the subsequent communication.
2024!-- In the second option, which performs better when the turbulent length scales are parametrized
2025!-- and thus the loops are smaller, the seeds are computed locally and no communication is necessary.
2026    IF ( compute_velocity_seeds_local )  THEN
2027
2028       f_n  = 0.0_wp
2029       DO  i = nxl, nxr
2030          DO  k = nzb, nzt+1
2031             DO  ii = -n_x(k), n_x(k)
2032                DO  kk = -n_z(k), n_z(k)
2033                   f_n(k,i) = f_n(k,i) + b_x(ii,k) * b_z(kk,k) * rand_it(k+kk,i+ii)
2034                ENDDO
2035             ENDDO
2036          ENDDO
2037       ENDDO
2038
2039    ELSE
2040
2041       f_n_l  = 0.0_wp
2042       DO  i = nxl, nxr
2043          DO  k = nzb_y_stg, nzt_y_stg+1
2044             DO  ii = -n_x(k), n_x(k)
2045                DO  kk = -n_z(k), n_z(k)
2046                   f_n_l(k,i) = f_n_l(k,i) + b_x(ii,k) * b_z(kk,k) * rand_it(k+kk,i+ii)
2047                ENDDO
2048             ENDDO
2049          ENDDO
2050       ENDDO
2051!
2052!--    Gather velocity seeds of full subdomain
2053       send_count = nzt_y_stg - nzb_y_stg + 1
2054       IF ( nzt_y_stg == nzt )  send_count = send_count + 1
2055
2056#if defined( __parallel )
2057!
2058!--    Gather the processed velocity seed on south boundary mpi ranks.
2059       CALL MPI_GATHERV( f_n_l(nzb_y_stg,nxl), send_count, stg_type_xz_small, f_n(nzb+1,nxl),      &
2060                         recv_count_xz, displs_xz, stg_type_xz, id_south, comm1dy, ierr )
2061!
2062!--    Gather the processed velocity seed on north boundary mpi ranks.
2063       CALL MPI_GATHERV( f_n_l(nzb_y_stg,nxl), send_count, stg_type_xz_small, f_n(nzb+1,nxl),      &
2064                         recv_count_xz, displs_xz, stg_type_xz, id_north, comm1dy, ierr )
2065#else
2066       f_n(nzb+1:nzt+1,nxl:nxr) = f_n_l(nzb_y_stg:nzt_y_stg+1,nxl:nxr)
2067!
2068!--    Next line required to avoid compile errors because of unused dummy arguments
2069       IF ( id_north == 0 )  id_south = 0
2070#endif
2071
2072    ENDIF
2073
2074    DEALLOCATE( rand_it )
2075
2076    CALL cpu_log( log_point_s(31), 'STG f_n factors', 'stop' )
2077
2078 END SUBROUTINE stg_generate_seed_xz
2079
2080!--------------------------------------------------------------------------------------------------!
2081! Description:
2082! ------------
2083!> Parametrization of the Reynolds-stress componentes, turbulent length- and time scales. The
2084!> parametrization follows Brost et al. (1982) with modifications described in Rotach et al. (1996),
2085!> which is applied in state-of-the-art dispserion modelling.
2086!--------------------------------------------------------------------------------------------------!
2087  SUBROUTINE parametrize_turbulence
2088
2089    INTEGER(iwp) :: k                 !< loop index in z-direction
2090
2091    REAL(wp) ::  corr_term_uh         !< correction term in parametrization of horizontal variances for unstable stratification
2092    REAL(wp) ::  d_zi                 !< inverse boundary-layer depth
2093    REAL(wp) ::  length_scale_lon     !< length scale in flow direction
2094    REAL(wp) ::  length_scale_lon_zi  !< length scale in flow direction at boundary-layer top
2095    REAL(wp) ::  length_scale_lat     !< length scale in crosswind direction
2096    REAL(wp) ::  length_scale_lat_zi  !< length scale in crosswind direction at boundary-layer top
2097    REAL(wp) ::  length_scale_vert    !< length scale in vertical direction
2098    REAL(wp) ::  length_scale_vert_zi !< length scale in vertical direction at boundary-layer top
2099    REAL(wp) ::  time_scale_zi        !< time scale at boundary-layer top
2100    REAL(wp) ::  r11_zi               !< longitudinal variance at boundary-layer top
2101    REAL(wp) ::  r22_zi               !< crosswind variance at boundary-layer top
2102    REAL(wp) ::  r33_zi               !< vertical variance at boundary-layer top
2103    REAL(wp) ::  r31_zi               !< r31 at boundary-layer top
2104    REAL(wp) ::  r32_zi               !< r32 at boundary-layer top
2105    REAL(wp) ::  rlat1                !< first dummy argument for crosswind compoment of reynolds stress
2106    REAL(wp) ::  rlat2                !< second dummy argument for crosswind compoment of reynolds stress
2107    REAL(wp) ::  rlon1                !< first dummy argument for longitudinal compoment of reynolds stress
2108    REAL(wp) ::  rlon2                !< second dummy argument for longitudinal compoment of reynolds stress
2109    REAL(wp) ::  zzi                  !< ratio of z/zi
2110
2111    REAL(wp), DIMENSION(nzb+1:nzt+1) ::  cos_phi    !< cosine of angle between mean flow direction and x-axis
2112    REAL(wp), DIMENSION(nzb+1:nzt+1) ::  phi        !< angle between mean flow direction and x-axis
2113    REAL(wp), DIMENSION(nzb+1:nzt+1) ::  sin_phi    !< sine of angle between mean flow direction and x-axis
2114
2115!
2116!-- Calculate the boundary-layer top index. Boundary-layer top is calculated by Richardson-bulk
2117!-- criterion according to Heinze et al. (2017).
2118    k_zi = MAX( 1, MINLOC( ABS( zu - zi_ribulk ), DIM = 1 ) )
2119    IF ( zu(k_zi) > zi_ribulk )  k_zi = k_zi - 1
2120    k_zi = MIN( k_zi, nzt )
2121!
2122!-- Calculate angle between flow direction and x-axis.
2123    DO  k = nzb+1, nzt + 1
2124       IF ( u_init(k) /= 0.0_wp )  THEN
2125          phi(k) = ATAN( v_init(k) / u_init(k) )
2126       ELSE
2127          phi(k) = 0.5 * pi
2128       ENDIF
2129!
2130!--    Pre-calculate sine and cosine.
2131       cos_phi(k) = COS( phi(k) )
2132       sin_phi(k) = SIN( phi(k) )
2133    ENDDO
2134!
2135!-- Parametrize Reynolds-stress components. Please note, parametrization is formulated for the
2136!-- stream- and spanwise components, while stream- and spanwise direction do not necessarily
2137!-- coincide with the grid axis. Hence, components are rotated after computation.
2138    d_zi = 1.0_wp / zi_ribulk
2139    DO  k = nzb+1, k_zi
2140
2141       corr_term_uh = MERGE( 0.35_wp * ABS(                                                        &
2142                        - zi_ribulk / ( kappa * scale_l - 10E-4_wp )                               &
2143                                       )**( 2.0_wp / 3.0_wp ),                                     &
2144                          0.0_wp,                                                                  &
2145                          scale_l < -5.0_wp )
2146!
2147!--    Determine normalized height coordinate
2148       zzi = zu(k) * d_zi
2149!
2150!--    Compute longitudinal and crosswind component of reynolds stress. Rotate these components by
2151!--    the wind direction to map onto the u- and v-component. Note, since reynolds stress for
2152!--    variances cannot become negative, take the absolute values.
2153       rlon1 = scale_us**2 * ( corr_term_uh + 5.0_wp - 4.0_wp * zzi )
2154       rlat1 = scale_us**2 * ( corr_term_uh + 2.0_wp - zzi )
2155
2156       r11(k) = ABS(   cos_phi(k) * rlon1 + sin_phi(k) * rlat1 )
2157       r22(k) = ABS( - sin_phi(k) * rlon1 + cos_phi(k) * rlat1 )
2158!
2159!--    w'w'
2160       r33(k) = scale_wm**2 * (                                                                    &
2161                   1.5_wp * zzi**( 2.0_wp / 3.0_wp ) * EXP( -2.0_wp * zzi )                        &
2162                 + ( 1.7_wp - zzi ) * ( scale_us / scale_wm )**2                                   &
2163                              )
2164!
2165!--    u'w' and v'w'. After calculation of the longitudinal and crosswind component
2166!--    these are projected along the x- and y-direction. Note, it is assumed that
2167!--    the flux within the boundary points opposite to the vertical gradient.
2168       rlon2 = scale_us**2 * ( zzi - 1.0_wp )
2169       rlat2 = scale_us**2 * ( 0.4 * zzi * ( 1.0_wp - zzi ) )
2170
2171       r31(k) = SIGN( ABS(   cos_phi(k) * rlon2 + sin_phi(k) * rlat2 ),                            &
2172                   - ( u_init(k+1) - u_init(k-1) ) )
2173       r32(k) = SIGN( ABS( - sin_phi(k) * rlon2 + cos_phi(k) * rlat2 ),                            &
2174                   - ( v_init(k+1) - v_init(k-1) ) )
2175!
2176!--    For u'v' no parametrization exist so far. For simplicity assume a similar profile as
2177!--    for the vertical transport.
2178       r21(k) = 0.5_wp * ( r31(k) + r32(k) )
2179!
2180!--    Compute turbulent time scales according to Brost et al. (1982). Note, time scales are
2181!--    limited to the adjustment time scales.
2182       tu(k)  = MIN( dt_stg_adjust,                                                                &
2183                     3.33_wp * zzi * ( 1.0 - 0.67_wp * zzi ) / scale_wm * zi_ribulk )
2184
2185       tv(k)  = tu(k)
2186       tw(k)  = tu(k)
2187
2188       length_scale_lon  = MIN( SQRT( r11(k) ) * tu(k), zi_ribulk )
2189       length_scale_lat  = MIN( SQRT( r22(k) ) * tv(k), zi_ribulk )
2190       length_scale_vert = MIN( SQRT( r33(k) ) * tw(k), zi_ribulk )
2191!
2192!--    Assume isotropic turbulence length scales
2193       nux(k) = MAX( INT( length_scale_lon  * ddx     ), 1 )
2194       nuy(k) = MAX( INT( length_scale_lat  * ddy     ), 1 )
2195       nvx(k) = MAX( INT( length_scale_lon  * ddx     ), 1 )
2196       nvy(k) = MAX( INT( length_scale_lat  * ddy     ), 1 )
2197       nwx(k) = MAX( INT( length_scale_lon  * ddx     ), 1 )
2198       nwy(k) = MAX( INT( length_scale_lat  * ddy     ), 1 )
2199       nuz(k) = MAX( INT( length_scale_vert * ddzw(k) ), 1 )
2200       nvz(k) = MAX( INT( length_scale_vert * ddzw(k) ), 1 )
2201       nwz(k) = MAX( INT( length_scale_vert * ddzw(k) ), 1 )
2202
2203    ENDDO
2204!
2205!-- Above boundary-layer top length- and timescales as well as reynolds-stress components are
2206!-- reduced to zero by a blending function.
2207    length_scale_lon_zi  = SQRT( r11(k_zi) ) * tu(k_zi)
2208    length_scale_lat_zi  = SQRT( r22(k_zi) ) * tv(k_zi)
2209    length_scale_vert_zi = SQRT( r33(k_zi) ) * tu(k_zi)
2210
2211    time_scale_zi        = tu(k_zi)
2212    r11_zi               = r11(k_zi)
2213    r22_zi               = r22(k_zi)
2214    r33_zi               = r33(k_zi)
2215    r31_zi               = r31(k_zi)
2216    r32_zi               = r32(k_zi)
2217
2218    d_l = blend_coeff / MAX( length_scale_vert_zi, dx, dy, MINVAL( dzw ) )
2219
2220    DO  k = k_zi+1, nzt+1
2221!
2222!--    Calculate function to gradually decrease Reynolds stress above ABL top.
2223       blend = MIN( 1.0_wp, EXP( d_l * zu(k) - d_l * zi_ribulk ) )
2224!
2225!--    u'u' and v'v'. Assume isotropy. Note, add a small negative number to the denominator, else
2226!--    the mergpe-function can crash if scale_l is zero.
2227       r11(k) = r11_zi * blend
2228       r22(k) = r22_zi * blend
2229       r33(k) = r33_zi * blend
2230       r31(k) = r31_zi * blend
2231       r32(k) = r32_zi * blend
2232       r21(k) = 0.5_wp * ( r31(k) + r32(k) )
2233
2234!
2235!--    Compute turbulent time scales according to Brost et al. (1982).
2236!--    Note, time scales are limited to the adjustment time scales.
2237       tu(k)  = time_scale_zi * blend
2238       tv(k)  = time_scale_zi * blend
2239       tw(k)  = time_scale_zi * blend
2240
2241       length_scale_lon  = length_scale_lon_zi  * blend
2242       length_scale_lat  = length_scale_lat_zi  * blend
2243       length_scale_vert = length_scale_vert_zi * blend
2244!
2245!--    Assume isotropic turbulence length scales
2246       nux(k) = MAX( INT( length_scale_lon  * ddx ),     1 )
2247       nuy(k) = MAX( INT( length_scale_lat  * ddy ),     1 )
2248       nvx(k) = MAX( INT( length_scale_lon  * ddx ),     1 )
2249       nvy(k) = MAX( INT( length_scale_lat  * ddy ),     1 )
2250       nwx(k) = MAX( INT( length_scale_lon  * ddx ),     1 )
2251       nwy(k) = MAX( INT( length_scale_lat  * ddy ),     1 )
2252       nuz(k) = MAX( INT( length_scale_vert * ddzw(k) ), 1 )
2253       nvz(k) = MAX( INT( length_scale_vert * ddzw(k) ), 1 )
2254       nwz(k) = MAX( INT( length_scale_vert * ddzw(k) ), 1 )
2255    ENDDO
2256!
2257!-- Set bottom boundary condition for reynolds stresses
2258    r11(nzb) = r11(nzb+1)
2259    r22(nzb) = r22(nzb+1)
2260    r33(nzb) = r33(nzb+1)
2261
2262    r21(nzb) = r11(nzb+1)
2263    r31(nzb) = r31(nzb+1)
2264    r32(nzb) = r32(nzb+1)
2265
2266!
2267!-- Set bottom boundary condition for the length and time scales
2268    nux(nzb) = nux(nzb+1)
2269    nuy(nzb) = nuy(nzb+1)
2270    nuz(nzb) = nuz(nzb+1)
2271    nvx(nzb) = nvx(nzb+1)
2272    nvy(nzb) = nvy(nzb+1)
2273    nvz(nzb) = nvz(nzb+1)
2274    nwx(nzb) = nwx(nzb+1)
2275    nwy(nzb) = nwy(nzb+1)
2276    nwz(nzb) = nwz(nzb+1)
2277
2278    tu(nzb)  = tu(nzb+1)
2279    tv(nzb)  = tv(nzb+1)
2280    tw(nzb)  = tw(nzb+1)
2281
2282    adjustment_step = .TRUE.
2283
2284 END SUBROUTINE parametrize_turbulence
2285
2286!--------------------------------------------------------------------------------------------------!
2287! Description:
2288! ------------
2289!> Calculate the coefficient matrix from the Lund rotation.
2290!--------------------------------------------------------------------------------------------------!
2291 SUBROUTINE calc_coeff_matrix
2292
2293    INTEGER(iwp) ::  k  !< loop index in z-direction
2294
2295!
2296!-- Calculate coefficient matrix. Split loops to allow for loop vectorization.
2297    DO  k = nzb+1, nzt+1
2298       IF ( r11(k) > 10E-6_wp )  THEN
2299          a11(k) = SQRT( r11(k) )
2300          a21(k) = r21(k) / a11(k)
2301          a31(k) = r31(k) / a11(k)
2302       ELSE
2303          a11(k) = 10E-8_wp
2304          a21(k) = 10E-8_wp
2305          a31(k) = 10E-8_wp
2306       ENDIF
2307    ENDDO
2308    DO  k = nzb+1, nzt+1
2309       a22(k) = r22(k) - a21(k)**2
2310       IF ( a22(k) > 10E-6_wp )  THEN
2311          a22(k) = SQRT( a22(k) )
2312          a32(k) = ( r32(k) - a21(k) * a31(k) ) / a22(k)
2313       ELSE
2314          a22(k) = 10E-8_wp
2315          a32(k) = 10E-8_wp
2316       ENDIF
2317    ENDDO
2318    DO  k = nzb+1, nzt+1
2319       a33(k) = r33(k) - a31(k)**2 - a32(k)**2
2320       IF ( a33(k) > 10E-6_wp )  THEN
2321          a33(k) =  SQRT( a33(k) )
2322       ELSE
2323          a33(k) = 10E-8_wp
2324       ENDIF
2325    ENDDO
2326!
2327!-- Set bottom boundary condition
2328    a11(nzb) = a11(nzb+1)
2329    a22(nzb) = a22(nzb+1)
2330    a21(nzb) = a21(nzb+1)
2331    a33(nzb) = a33(nzb+1)
2332    a31(nzb) = a31(nzb+1)
2333    a32(nzb) = a32(nzb+1)
2334
2335 END SUBROUTINE calc_coeff_matrix
2336
2337!--------------------------------------------------------------------------------------------------!
2338! Description:
2339! ------------
2340!> This routine controls the re-adjustment of the turbulence statistics used for generating
2341!> turbulence at the lateral boundaries.
2342!--------------------------------------------------------------------------------------------------!
2343 SUBROUTINE stg_adjust
2344
2345    IF ( debug_output_timestep )  CALL debug_message( 'stg_adjust', 'start' )
2346!
2347!-- In case of dirichlet inflow boundary conditions only at one lateral boundary, i.e. in the case
2348!-- no offline or self nesting is applied but synthetic turbulence shall be parametrized
2349!-- nevertheless, the boundary-layer depth need to determined first.
2350    IF ( .NOT. nesting_offline  .AND.  .NOT.  child_domain )                                       &
2351       CALL nesting_offl_calc_zi
2352!
2353!-- Compute scaling parameters (domain-averaged), such as friction velocity are calculated.
2354    CALL calc_scaling_variables
2355!
2356!-- Parametrize Reynolds-stress tensor. Parametrization follows Brost et al. (1982) with
2357!-- modifications described in Rotach et al. (1996) and is based on boundary-layer depth, friction
2358!-- velocity and velocity scale.
2359    CALL parametrize_turbulence
2360!
2361!-- Calculate coefficient matrix from Reynolds stress tensor
2362!-- (Lund rotation)
2363    CALL calc_coeff_matrix
2364!
2365!-- Setup filter functions according to updated length scales.
2366    CALL stg_setup_filter_function
2367!
2368!-- Reset time counter for controlling next adjustment to zero
2369    time_stg_adjust = 0.0_wp
2370
2371    IF ( debug_output_timestep )  CALL debug_message( 'stg_adjust', 'end' )
2372
2373 END SUBROUTINE stg_adjust
2374
2375
2376!--------------------------------------------------------------------------------------------------!
2377! Description:
2378! ------------
2379!> Calculate scaling variables which are used for turbulence parametrization according to Rotach
2380!> et al. (1996). Scaling variables are: friction velocity, boundary-layer depth, momentum velocity
2381!> scale, and Obukhov length.
2382!--------------------------------------------------------------------------------------------------!
2383 SUBROUTINE calc_scaling_variables
2384
2385    INTEGER(iwp) ::  i  !< loop index in x-direction
2386    INTEGER(iwp) ::  j  !< loop index in y-direction
2387    INTEGER(iwp) ::  k  !< loop index in z-direction
2388    INTEGER(iwp) ::  m  !< surface element index
2389
2390    REAL(wp) ::  friction_vel_l  !< mean friction veloctiy on subdomain
2391    REAL(wp) ::  pt_surf_mean    !< mean near surface temperature (at 1st grid point)
2392    REAL(wp) ::  pt_surf_mean_l  !< mean near surface temperature (at 1st grid point) on subdomain
2393    REAL(wp) ::  scale_l_l       !< mean Obukhov lenght on subdomain
2394    REAL(wp) ::  shf_mean        !< mean surface sensible heat flux
2395    REAL(wp) ::  shf_mean_l      !< mean surface sensible heat flux on subdomain
2396    REAL(wp) ::  w_convective    !< convective velocity scale
2397
2398!
2399!-- Calculate mean friction velocity, velocity scale, heat flux and near-surface temperature in the
2400!-- model domain.
2401    pt_surf_mean_l = 0.0_wp
2402    shf_mean_l     = 0.0_wp
2403    scale_l_l      = 0.0_wp
2404    friction_vel_l = 0.0_wp
2405    DO  m = 1, surf_def_h(0)%ns
2406       i = surf_def_h(0)%i(m)
2407       j = surf_def_h(0)%j(m)
2408       k = surf_def_h(0)%k(m)
2409       friction_vel_l = friction_vel_l  + surf_def_h(0)%us(m)
2410       shf_mean_l     = shf_mean_l      + surf_def_h(0)%shf(m) * drho_air(k)
2411       scale_l_l      = scale_l_l       + surf_def_h(0)%ol(m)
2412       pt_surf_mean_l = pt_surf_mean_l  + pt(k,j,i)
2413    ENDDO
2414    DO  m = 1, surf_lsm_h(0)%ns
2415       i = surf_lsm_h(0)%i(m)
2416       j = surf_lsm_h(0)%j(m)
2417       k = surf_lsm_h(0)%k(m)
2418       friction_vel_l = friction_vel_l  + surf_lsm_h(0)%us(m)
2419       shf_mean_l     = shf_mean_l      + surf_lsm_h(0)%shf(m) * drho_air(k)
2420       scale_l_l      = scale_l_l       + surf_lsm_h(0)%ol(m)
2421       pt_surf_mean_l = pt_surf_mean_l  + pt(k,j,i)
2422    ENDDO
2423    DO  m = 1, surf_usm_h(0)%ns
2424       i = surf_usm_h(0)%i(m)
2425       j = surf_usm_h(0)%j(m)
2426       k = surf_usm_h(0)%k(m)
2427       friction_vel_l = friction_vel_l  + surf_usm_h(0)%us(m)
2428       shf_mean_l     = shf_mean_l      + surf_usm_h(0)%shf(m) * drho_air(k)
2429       scale_l_l      = scale_l_l       + surf_usm_h(0)%ol(m)
2430       pt_surf_mean_l = pt_surf_mean_l  + pt(k,j,i)
2431    ENDDO
2432
2433#if defined( __parallel )
2434    CALL MPI_ALLREDUCE( friction_vel_l, scale_us,     1, MPI_REAL, MPI_SUM, comm2d, ierr )
2435    CALL MPI_ALLREDUCE( shf_mean_l, shf_mean,         1, MPI_REAL, MPI_SUM, comm2d, ierr )
2436    CALL MPI_ALLREDUCE( scale_l_l, scale_l,           1, MPI_REAL, MPI_SUM, comm2d, ierr )
2437    CALL MPI_ALLREDUCE( pt_surf_mean_l, pt_surf_mean, 1, MPI_REAL, MPI_SUM, comm2d, ierr )
2438#else
2439    scale_us     = friction_vel_l
2440    shf_mean     = shf_mean_l
2441    scale_l      = scale_l_l
2442    pt_surf_mean = pt_surf_mean_l
2443#endif
2444
2445    scale_us     = scale_us     * d_nxy
2446    shf_mean     = shf_mean     * d_nxy
2447    scale_l      = scale_l      * d_nxy
2448    pt_surf_mean = pt_surf_mean * d_nxy
2449!
2450!-- Compute mean convective velocity scale. Note, in case the mean heat flux is negative, set
2451!-- convective velocity scale to zero.
2452    IF ( shf_mean > 0.0_wp )  THEN
2453       w_convective = ( g * shf_mean * zi_ribulk / pt_surf_mean )**( 1.0_wp / 3.0_wp )
2454    ELSE
2455       w_convective = 0.0_wp
2456    ENDIF
2457!
2458!-- At the initial run the friction velocity is initialized close to zero, leading to almost zero
2459!-- disturbances at the boundaries. In order to obtain disturbances nevertheless, set a minium
2460!-- value of friction velocity for the reynolds-stress parametrization.
2461    IF ( time_since_reference_point <= 0.0_wp )  scale_us = MAX( scale_us, 0.05_wp )
2462!
2463!-- Finally, in order to consider also neutral or stable stratification, compute momentum velocity
2464!-- scale from u* and convective velocity scale, according to Rotach et al. (1996).
2465    scale_wm = ( scale_us**3 + 0.6_wp * w_convective**3 )**( 1.0_wp / 3.0_wp )
2466
2467 END SUBROUTINE calc_scaling_variables
2468
2469 END MODULE synthetic_turbulence_generator_mod
Note: See TracBrowser for help on using the repository browser.