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

Last change on this file since 4776 was 4671, checked in by pavelkrc, 4 years ago

Radiative transfer model RTM version 4.1

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