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

Last change on this file since 4650 was 4647, checked in by suehring, 4 years ago

Change default value of synthetic turbulence adjustment as well as compute_velocity_seeds_local. By default, the random-seed computation is now distributed among several cores. Especially for large length scales this is significantly faster.

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