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

Last change on this file since 3053 was 3051, checked in by suehring, 6 years ago

Speed-up NetCDF input; Revise NetCDF-input routines and remove input via io-blocks; Temporarily revoke renaming of input variables in dynamic driver; More detailed error messages created; Bugfix in mapping 3D buildings; Bugfix in land-surface model at pavement surfaces; Bugfix in initialization with inifor

  • Property svn:keywords set to Id
File size: 62.0 KB
RevLine 
[2259]1!> @synthetic_turbulence_generator_mod.f90
2!------------------------------------------------------------------------------!
[2696]3! This file is part of the PALM model system.
[2259]4!
[2696]5! PALM is free software: you can redistribute it and/or modify it under the
[2259]6! terms of the GNU General Public License as published by the Free Software
7! Foundation, either version 3 of the License, or (at your option) any later
8! version.
9!
[2696]10! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
[2259]11! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12! A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13!
14! You should have received a copy of the GNU General Public License along with
15! PALM. If not, see <http://www.gnu.org/licenses/>.
16!
17! Copyright 2017 Leibniz Universitaet Hannover
18!------------------------------------------------------------------------------!
19!
20! Current revisions:
21! -----------------
22!
[3049]23!
[2259]24! Former revisions:
25! -----------------
26! $Id: synthetic_turbulence_generator_mod.f90 3051 2018-05-30 17:43:55Z suehring $
[3051]27! Bugfix in calculation of initial Reynolds-stress tensor.
[3049]28!
29! 3045 2018-05-28 07:55:41Z Giersch
[3051]30! Error messages revised
[3045]31!
32! 3044 2018-05-25 10:59:41Z gronemeier
[3044]33! Add missing variable descriptions
34!
35! 3038 2018-05-24 10:54:00Z gronemeier
[3038]36! updated variable descriptions
37!
38! 2967 2018-04-13 11:22:08Z raasch
[2967]39! bugfix: missing parallel cpp-directives added
[3038]40!
[2967]41! 2946 2018-04-04 17:01:23Z suehring
[2946]42! Remove unused module load
[3038]43!
[2946]44! 2945 2018-04-04 16:27:14Z suehring
[3038]45! - Bugfix in parallelization of synthetic turbulence generator in case the
46!   z-dimension is not an integral divisor of the number of processors along
[2945]47!   the x- and y-dimension
[3038]48! - Revision in control mimic in case of RAN-LES nesting
49!
[2945]50! 2938 2018-03-27 15:52:42Z suehring
[3038]51! Apply turbulence generator at all non-cyclic lateral boundaries in case of
52! realistic Inifor large-scale forcing or RANS-LES nesting
53!
[2938]54! 2936 2018-03-27 14:49:27Z suehring
[3038]55! variable named found has been introduced for checking if restart data was found,
56! reading of restart strings has been moved completely to read_restart_data_mod,
57! redundant skipping function has been removed, stg_read/write_restart_data
58! have been renamed to stg_r/wrd_global, stg_rrd_global is called in
[2894]59! read_restart_data_mod now, flag syn_turb_gen_prerun and marker *** end stg
[3038]60! *** have been removed (Giersch), strings and their respective lengths are
61! written out and read now in case of restart runs to get rid of prescribed
62! character lengths (Giersch), CASE DEFAULT was added if restart data is read
63!
[2894]64! 2841 2018-02-27 15:02:57Z suehring
[2841]65! Bugfix: wrong placement of include 'mpif.h' corrected
[3038]66!
[2841]67! 2836 2018-02-26 13:40:05Z Giersch
[3038]68! The variables synthetic_turbulence_generator and
[2836]69! use_synthetic_turbulence_generator have been abbreviated + syn_turb_gen_prerun
70! flag is used to define if module related parameters were outputted as restart
[3038]71! data
72!
[2776]73! 2716 2017-12-29 16:35:59Z kanani
[2716]74! Corrected "Former revisions" section
[3038]75!
[2716]76! 2696 2017-12-14 17:12:51Z kanani
77! Change in file header (GPL part)
78!
79! 2669 2017-12-06 16:03:27Z raasch
[2669]80! unit number for file containing turbulence generator data changed to 90
81! bugfix: preprocessor directives added for MPI specific code
[3038]82!
[2669]83! 2576 2017-10-24 13:49:46Z Giersch
[3038]84! Definition of a new function called stg_skip_global to skip module
[2576]85! parameters during reading restart data
[3038]86!
[2576]87! 2563 2017-10-19 15:36:10Z Giersch
[2563]88! stg_read_restart_data is called in stg_parin in the case of a restart run
[3038]89!
[2563]90! 2259 2017-06-08 09:09:11Z gronemeier
[2259]91! Initial revision
92!
93!
[3038]94!
[2259]95! Authors:
96! --------
97! @author Tobias Gronemeier, Atsushi Inagaki, Micha Gryschka, Christoph Knigge
98!
99!
100! Description:
101! ------------
102!> The module generates turbulence at the inflow boundary based on a method by
103!> Xie and Castro (2008) utilizing a Lund rotation (Lund, 1998) and a mass-flux
104!> correction by Kim et al. (2013).
105!> The turbulence is correlated based on length scales in y- and z-direction and
106!> a time scale for each velocity component. The profiles of length and time
107!> scales, mean u, v, w, e and pt, and all components of the Reynolds stress
108!> tensor are read from file STG_PROFILES.
109!>
110!> @todo test restart
111!>       enable cyclic_fill
112!>       implement turbulence generation for e and pt
[2945]113!> @todo Input of height-constant length scales via namelist
[2259]114!> @note <Enter notes on the module>
115!> @bug  Height information from input file is not used. Profiles from input
116!>       must match with current PALM grid.
117!>       Transformation of length scales to number of gridpoints does not
118!>       consider grid stretching.
119!>       In case of restart, velocity seeds differ from precursor run if a11,
120!>       a22, or a33 are zero.
121!------------------------------------------------------------------------------!
122 MODULE synthetic_turbulence_generator_mod
123
124
125    USE arrays_3d,                                                             &
126        ONLY:  mean_inflow_profiles, u, v, w
127
128    USE constants,                                                             &
129        ONLY:  pi
130
131    USE control_parameters,                                                    &
[2938]132        ONLY:  initializing_actions, message_string, syn_turb_gen
[2259]133
134    USE cpulog,                                                                &
135        ONLY:  cpu_log, log_point, log_point_s
136
137    USE indices,                                                               &
[2938]138        ONLY:  nbgp, nzb, nzt, nxl, nxlg, nxr, nxrg, nys, nyn, nyng, nysg
[2259]139
140    USE kinds
141
[2967]142#if defined( __parallel )  &&  !defined( __mpifh )
[2259]143    USE MPI
[2841]144#endif
[2259]145
146    USE pegrid,                                                                &
[2938]147        ONLY:  comm1dx, comm1dy, comm2d, ierr, myidx, myidy, pdims
[2259]148
149    USE transpose_indices,                                                     &
150        ONLY: nzb_x, nzt_x
151
152
153    IMPLICIT NONE
154
[2967]155#if defined( __parallel )  &&  defined( __mpifh )
[2841]156    INCLUDE "mpif.h"
157#endif
158
[2776]159    LOGICAL :: velocity_seed_initialized = .FALSE.  !< true after first call of stg_main
160    LOGICAL :: use_syn_turb_gen = .FALSE.           !< switch to use synthetic turbulence generator
[2259]161
[3038]162    INTEGER(iwp) ::  id_stg_left        !< left lateral boundary core id in case of turbulence generator
163    INTEGER(iwp) ::  id_stg_north       !< north lateral boundary core id in case of turbulence generator
164    INTEGER(iwp) ::  id_stg_right       !< right lateral boundary core id in case of turbulence generator
165    INTEGER(iwp) ::  id_stg_south       !< south lateral boundary core id in case of turbulence generator
[2938]166    INTEGER(iwp) ::  stg_type_xz        !< MPI type for full z range
167    INTEGER(iwp) ::  stg_type_xz_small  !< MPI type for small z range
168    INTEGER(iwp) ::  stg_type_yz        !< MPI type for full z range
169    INTEGER(iwp) ::  stg_type_yz_small  !< MPI type for small z range
170    INTEGER(iwp) ::  merg               !< maximum length scale (in gp)
171    INTEGER(iwp) ::  mergp              !< merg + nbgp
[3038]172    INTEGER(iwp) ::  nzb_x_stg          !< lower bound of z coordinate (required for transposing z on PEs along x)
173    INTEGER(iwp) ::  nzt_x_stg          !< upper bound of z coordinate (required for transposing z on PEs along x)
174    INTEGER(iwp) ::  nzb_y_stg          !< lower bound of z coordinate (required for transposing z on PEs along y)
175    INTEGER(iwp) ::  nzt_y_stg          !< upper bound of z coordinate (required for transposing z on PEs along y)
[2259]176
177    REAL(wp) :: mc_factor    !< mass flux correction factor
178
[2938]179    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: displs_xz      !< displacement for MPI_GATHERV
180    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: recv_count_xz  !< receive count for MPI_GATHERV
181    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: displs_yz      !< displacement for MPI_GATHERV
182    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: recv_count_yz  !< receive count for MPI_GATHERV
183    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nux            !< length scale of u in x direction (in gp)
184    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nuy            !< length scale of u in y direction (in gp)
185    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nuz            !< length scale of u in z direction (in gp)
186    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nvx            !< length scale of v in x direction (in gp)
187    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nvy            !< length scale of v in y direction (in gp)
188    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nvz            !< length scale of v in z direction (in gp)
189    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nwx            !< length scale of w in x direction (in gp)
190    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nwy            !< length scale of w in y direction (in gp)
191    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nwz            !< length scale of w in z direction (in gp)
[2259]192
193    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: seed        !< seed of random number for rn-generator
194
195    REAL(wp), DIMENSION(:), ALLOCATABLE :: a11             !< coefficient for Lund rotation
196    REAL(wp), DIMENSION(:), ALLOCATABLE :: a21             !< coefficient for Lund rotation
197    REAL(wp), DIMENSION(:), ALLOCATABLE :: a22             !< coefficient for Lund rotation
198    REAL(wp), DIMENSION(:), ALLOCATABLE :: a31             !< coefficient for Lund rotation
199    REAL(wp), DIMENSION(:), ALLOCATABLE :: a32             !< coefficient for Lund rotation
200    REAL(wp), DIMENSION(:), ALLOCATABLE :: a33             !< coefficient for Lund rotation
201    REAL(wp), DIMENSION(:), ALLOCATABLE :: tu              !< Lagrangian time scale of u
202    REAL(wp), DIMENSION(:), ALLOCATABLE :: tv              !< Lagrangian time scale of v
203    REAL(wp), DIMENSION(:), ALLOCATABLE :: tw              !< Lagrangian time scale of w
204
[2938]205    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bux           !< filter function for u in x direction
[2259]206    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: buy           !< filter function for u in y direction
207    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: buz           !< filter function for u in z direction
[2938]208    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bvx           !< filter function for v in x direction
[2259]209    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bvy           !< filter function for v in y direction
210    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bvz           !< filter function for v in z direction
[2938]211    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bwx           !< filter function for w in y direction
[2259]212    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bwy           !< filter function for w in y direction
213    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bwz           !< filter function for w in z direction
[2938]214    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fu_xz         !< velocity seed for u at xz plane
215    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fuo_xz        !< velocity seed for u at xz plane with new random number
216    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fu_yz         !< velocity seed for u at yz plane
217    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fuo_yz        !< velocity seed for u at yz plane with new random number
218    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fv_xz         !< velocity seed for v at xz plane
219    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fvo_xz        !< velocity seed for v at xz plane with new random number
220    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fv_yz         !< velocity seed for v at yz plane
221    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fvo_yz        !< velocity seed for v at yz plane with new random number
222    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fw_xz         !< velocity seed for w at xz plane
223    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fwo_xz        !< velocity seed for w at xz plane with new random number
224    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fw_yz         !< velocity seed for w at yz plane
225    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fwo_yz        !< velocity seed for w at yz plane with new random number
[2259]226
227
228!
229!-- PALM interfaces:
230!-- Input parameter checks to be done in check_parameters
231    INTERFACE stg_check_parameters
232       MODULE PROCEDURE stg_check_parameters
233    END INTERFACE stg_check_parameters
234
235!
236!-- Calculate filter functions
237    INTERFACE stg_filter_func
238       MODULE PROCEDURE stg_filter_func
239    END INTERFACE stg_filter_func
240
241!
[2938]242!-- Generate velocity seeds at south and north domain boundary
243    INTERFACE stg_generate_seed_xz
244       MODULE PROCEDURE stg_generate_seed_xz
245    END INTERFACE stg_generate_seed_xz
246!
247!-- Generate velocity seeds at left and/or right domain boundary
[2259]248    INTERFACE stg_generate_seed_yz
249       MODULE PROCEDURE stg_generate_seed_yz
250    END INTERFACE stg_generate_seed_yz
251
252!
253!-- Output of information to the header file
254    INTERFACE stg_header
255       MODULE PROCEDURE stg_header
256    END INTERFACE stg_header
257
258!
259!-- Initialization actions
260    INTERFACE stg_init
261       MODULE PROCEDURE stg_init
262    END INTERFACE stg_init
263
264!
265!-- Main procedure of synth. turb. gen.
266    INTERFACE stg_main
267       MODULE PROCEDURE stg_main
268    END INTERFACE stg_main
269
270!
271!-- Reading of NAMELIST parameters
272    INTERFACE stg_parin
273       MODULE PROCEDURE stg_parin
274    END INTERFACE stg_parin
275
276!
277!-- Reading of parameters for restart runs
[2894]278    INTERFACE stg_rrd_global
279       MODULE PROCEDURE stg_rrd_global
280    END INTERFACE stg_rrd_global
[2259]281
282!
283!-- Writing of binary output for restart runs
[2894]284    INTERFACE stg_wrd_global
285       MODULE PROCEDURE stg_wrd_global
286    END INTERFACE stg_wrd_global
[2259]287
288    SAVE
289
290    PRIVATE
291
292!
293!-- Public interfaces
294    PUBLIC  stg_check_parameters, stg_header, stg_init, stg_main, stg_parin,   &
[2894]295            stg_wrd_global, stg_rrd_global
[2259]296
297!
298!-- Public variables
[2938]299    PUBLIC  id_stg_left, id_stg_north, id_stg_right, id_stg_south,             &
300            use_syn_turb_gen
[2259]301
302
303 CONTAINS
304
305
306!------------------------------------------------------------------------------!
307! Description:
308! ------------
309!> Check parameters routine for synthetic turbulence generator
310!------------------------------------------------------------------------------!
311 SUBROUTINE stg_check_parameters
312
313
314    USE control_parameters,                                                    &
[2938]315        ONLY:  bc_lr, bc_ns, forcing, nest_domain, rans_mode, turbulent_inflow
[2259]316
[2938]317    USE pmc_interface,                                                         &
318        ONLY : rans_mode_parent
[2259]319
[2938]320
[2259]321    IMPLICIT NONE
322
[2938]323    IF ( .NOT. use_syn_turb_gen  .AND.  .NOT. rans_mode  .AND.  forcing )  THEN
324       message_string = 'Synthetic turbulence generator has to be applied ' // &
325                        'when forcing is used and model operates in LES mode.'
326       CALL message( 'stg_check_parameters', 'PA0000', 1, 2, 0, 6, 0 )
327    ENDIF
328
329    IF ( .NOT. use_syn_turb_gen  .AND.  nest_domain                            &
330         .AND. rans_mode_parent  .AND.  .NOT. rans_mode )  THEN
331       message_string = 'Synthetic turbulence generator has to be applied ' // &
332                        'when nesting is applied and parent operates in '  //  &
333                        'RANS-mode but current child in LES mode.'
334       CALL message( 'stg_check_parameters', 'PA0000', 1, 2, 0, 6, 0 )
335    ENDIF
336
[2776]337    IF ( use_syn_turb_gen )  THEN
[2259]338
[3038]339       IF ( .NOT. forcing  .AND.  .NOT. nest_domain )  THEN
[2938]340
341          IF ( INDEX( initializing_actions, 'set_constant_profiles' ) == 0     &
342        .AND.  INDEX( initializing_actions, 'read_restart_data' ) == 0 )  THEN
343             message_string = 'Using synthetic turbulence generator ' //       &
[3046]344                              'requires %initializing_actions = '         //   &
[2938]345                              '"set_constant_profiles" or "read_restart_data"'
346             CALL message( 'stg_check_parameters', 'PA0015', 1, 2, 0, 6, 0 )
347          ENDIF
348
349          IF ( bc_lr /= 'dirichlet/radiation' )  THEN
350             message_string = 'Using synthetic turbulence generator ' //       &
[3046]351                              'requires &bc_lr = "dirichlet/radiation"'
[2938]352             CALL message( 'stg_check_parameters', 'PA0035', 1, 2, 0, 6, 0 )
353          ENDIF
354          IF ( bc_ns /= 'cyclic' )  THEN
355             message_string = 'Using synthetic turbulence generator ' //       &
[3046]356                              'requires &bc_ns = "cyclic"'
[2938]357             CALL message( 'stg_check_parameters', 'PA0037', 1, 2, 0, 6, 0 )
358          ENDIF
359
[2259]360       ENDIF
361
362       IF ( turbulent_inflow )  THEN
363          message_string = 'Using synthetic turbulence generator ' //          &
[2938]364                           'in combination &with turbulent_inflow = .T. '//    &
365                              'is not allowed'
[2259]366          CALL message( 'stg_check_parameters', 'PA0039', 1, 2, 0, 6, 0 )
367       ENDIF
368
369    ENDIF
370
371 END SUBROUTINE stg_check_parameters
372
373
374!------------------------------------------------------------------------------!
375! Description:
376! ------------
377!> Header output for synthetic turbulence generator
378!------------------------------------------------------------------------------!
379 SUBROUTINE stg_header ( io )
380
381
382    IMPLICIT NONE
383
384    INTEGER(iwp), INTENT(IN) ::  io   !< Unit of the output file
385
386!
387!-- Write synthetic turbulence generator Header
388    WRITE( io, 1 )
[2776]389    IF ( use_syn_turb_gen )  THEN
[2259]390       WRITE( io, 2 )
391    ELSE
392       WRITE( io, 3 )
393    ENDIF
394
3951   FORMAT (//' Synthetic turbulence generator information:'/                  &
396              ' ------------------------------------------'/)
3972   FORMAT ('    synthetic turbulence generator switched on')
3983   FORMAT ('    synthetic turbulence generator switched off')
399
400 END SUBROUTINE stg_header
401
402
403!------------------------------------------------------------------------------!
404! Description:
405! ------------
406!> Initialization of the synthetic turbulence generator
407!------------------------------------------------------------------------------!
408 SUBROUTINE stg_init
409
410
411    USE arrays_3d,                                                             &
[2938]412        ONLY:  ddzw, u_init, v_init, zu
[2259]413
414    USE control_parameters,                                                    &
[2945]415        ONLY:  coupling_char, dz, e_init, forcing, nest_domain, rans_mode
[2259]416
417    USE grid_variables,                                                        &
[2938]418        ONLY:  ddx, ddy
[2259]419
[2938]420    USE indices,                                                               &
421        ONLY:  nz
[2259]422
[2945]423    USE pmc_interface,                                                         &
424        ONLY : rans_mode_parent
[2938]425
[2945]426
[2259]427    IMPLICIT NONE
428
[2938]429    LOGICAL ::  file_stg_exist = .FALSE. !< flag indication whether parameter file for Reynolds stress and length scales exist
430
[2669]431#if defined( __parallel )
[2259]432    INTEGER(KIND=MPI_ADDRESS_KIND) :: extent !< extent of new MPI type
433    INTEGER(KIND=MPI_ADDRESS_KIND) :: tob=0  !< dummy variable
[2669]434#endif
[2259]435
[2938]436    INTEGER(iwp) :: i                        !> grid index in x-direction
[2259]437    INTEGER(iwp) :: j                        !> loop index
438    INTEGER(iwp) :: k                        !< index
439    INTEGER(iwp) :: newtype                  !< dummy MPI type
440    INTEGER(iwp) :: realsize                 !< size of REAL variables
441    INTEGER(iwp) :: nseed                    !< dimension of random number seed
442    INTEGER(iwp) :: startseed = 1234567890   !< start seed for random number generator
443
444!
445!-- Dummy variables used for reading profiles
446    REAL(wp) :: d1      !< u profile
447    REAL(wp) :: d2      !< v profile
448    REAL(wp) :: d3      !< w profile
449    REAL(wp) :: d5      !< e profile
450    REAL(wp) :: d11     !< vertical interpolation for a11
451    REAL(wp) :: d21     !< vertical interpolation for a21
452    REAL(wp) :: d22     !< vertical interpolation for a22
[2938]453    REAL(wp) :: dum_exp !< dummy variable used for exponential vertical decrease of turbulent length scales
[2259]454    REAL(wp) :: luy     !< length scale for u in y direction
455    REAL(wp) :: luz     !< length scale for u in z direction
456    REAL(wp) :: lvy     !< length scale for v in y direction
457    REAL(wp) :: lvz     !< length scale for v in z direction
458    REAL(wp) :: lwy     !< length scale for w in y direction
459    REAL(wp) :: lwz     !< length scale for w in z direction
[3038]460    REAL(wp) :: nnz     !< increment used to determine processor decomposition of z-axis along x and y direction
[2259]461    REAL(wp) :: zz      !< height
462
[3044]463    REAL(wp) :: length_scale_surface !< typical length scale
464    REAL(wp) :: r_ii_0               !< correction factor
465    REAL(wp) :: time_scale           !< typical time scale
466    REAL(wp) :: length_scale_z       !< typical length scale
[2938]467
[2259]468    REAL(wp),DIMENSION(nzb:nzt+1) :: r11  !< Reynolds parameter
469    REAL(wp),DIMENSION(nzb:nzt+1) :: r21  !< Reynolds parameter
470    REAL(wp),DIMENSION(nzb:nzt+1) :: r22  !< Reynolds parameter
471    REAL(wp),DIMENSION(nzb:nzt+1) :: r31  !< Reynolds parameter
472    REAL(wp),DIMENSION(nzb:nzt+1) :: r32  !< Reynolds parameter
473    REAL(wp),DIMENSION(nzb:nzt+1) :: r33  !< Reynolds parameter
474
475
476#if defined( __parallel )
477    CALL MPI_BARRIER( comm2d, ierr )
478#endif
479
480    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'start' )
481
482    IF ( .NOT. ALLOCATED( mean_inflow_profiles ) )                             &
483       ALLOCATE( mean_inflow_profiles(nzb:nzt+1,5) )
484
485    ALLOCATE ( a11(nzb:nzt+1), a21(nzb:nzt+1), a22(nzb:nzt+1),                 &
486               a31(nzb:nzt+1), a32(nzb:nzt+1), a33(nzb:nzt+1),                 &
[2938]487               nux(nzb:nzt+1), nuy(nzb:nzt+1), nuz(nzb:nzt+1),                 &
488               nvx(nzb:nzt+1), nvy(nzb:nzt+1), nvz(nzb:nzt+1),                 &
489               nwx(nzb:nzt+1), nwy(nzb:nzt+1), nwz(nzb:nzt+1),                 &
[2259]490               tu(nzb:nzt+1),  tv(nzb:nzt+1),  tw(nzb:nzt+1)   )
491
[2669]492#if defined( __parallel )
[2259]493!
[2938]494!-- Determine processor decomposition of z-axis along x- and y-direction
495    nnz = nz / pdims(1)
[2945]496    nzb_x_stg = 1 + myidx * INT( nnz )
497    nzt_x_stg = ( myidx + 1 ) * INT( nnz )
[2938]498
[3038]499    IF ( MOD( nz , pdims(1) ) /= 0  .AND.  myidx == id_stg_right )             &
[2945]500       nzt_x_stg = nzt_x_stg + myidx * ( nnz - INT( nnz ) )
501!        nzt_x_stg = myidx * nnz + MOD( nz , pdims(1) )
[2938]502
[2945]503    IF ( forcing  .OR.  ( nest_domain .AND.  rans_mode_parent  .AND.           &
504                   .NOT.  rans_mode ) )  THEN
[2938]505       nnz = nz / pdims(2)
[2945]506       nzb_y_stg = 1 + myidy * INT( nnz )
507       nzt_y_stg = ( myidy + 1 ) * INT( nnz )
[2938]508
[2945]509       IF ( MOD( nz , pdims(2) ) /= 0  .AND.  myidy == id_stg_north )          &
[3038]510          nzt_y_stg = nzt_y_stg + myidy * ( nnz - INT( nnz ) )
[2945]511!           nzt_y_stg = myidy * nnz + MOD( nz , pdims(2) )
[2938]512    ENDIF
513
514!
[2259]515!-- Define MPI type used in stg_generate_seed_yz to gather vertical splitted
516!-- velocity seeds
517    CALL MPI_TYPE_SIZE( MPI_REAL, realsize, ierr )
518    extent = 1 * realsize
[2938]519!
[3038]520!-- Set-up MPI datatyp to involve all cores for turbulence generation at yz
521!-- layer
[2938]522!-- stg_type_yz: yz-slice with vertical bounds nzb:nzt+1
[2259]523    CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt-nzb+2,nyng-nysg+1],                 &
524            [1,nyng-nysg+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
525    CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_yz, ierr )
526    CALL MPI_TYPE_COMMIT( stg_type_yz, ierr )
527    CALL MPI_TYPE_FREE( newtype, ierr )
528
[2938]529    ! stg_type_yz_small: yz-slice with vertical bounds nzb_x_stg:nzt_x_stg+1
[2945]530    CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt_x_stg-nzb_x_stg+2,nyng-nysg+1],     &
[2259]531            [1,nyng-nysg+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
532    CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_yz_small, ierr )
533    CALL MPI_TYPE_COMMIT( stg_type_yz_small, ierr )
534    CALL MPI_TYPE_FREE( newtype, ierr )
535
536    ! receive count and displacement for MPI_GATHERV in stg_generate_seed_yz
[2938]537    ALLOCATE( recv_count_yz(pdims(1)), displs_yz(pdims(1)) )
[2259]538
[2938]539    recv_count_yz           = nzt_x_stg-nzb_x_stg + 1
540    recv_count_yz(pdims(1)) = recv_count_yz(pdims(1)) + 1
[2259]541
542    DO  j = 1, pdims(1)
[2938]543       displs_yz(j) = 0 + (nzt_x_stg-nzb_x_stg+1) * (j-1)
[2259]544    ENDDO
[2938]545!
[3038]546!-- Set-up MPI datatyp to involve all cores for turbulence generation at xz
547!-- layer
[2938]548!-- stg_type_xz: xz-slice with vertical bounds nzb:nzt+1
[2945]549    IF ( forcing  .OR.  ( nest_domain .AND.  rans_mode_parent  .AND.           &
550                   .NOT.  rans_mode ) )  THEN
551       CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt-nzb+2,nxrg-nxlg+1],              &
[2938]552               [1,nxrg-nxlg+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
553       CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_xz, ierr )
554       CALL MPI_TYPE_COMMIT( stg_type_xz, ierr )
555       CALL MPI_TYPE_FREE( newtype, ierr )
556
557       ! stg_type_yz_small: xz-slice with vertical bounds nzb_x_stg:nzt_x_stg+1
[2945]558       CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt_y_stg-nzb_y_stg+2,nxrg-nxlg+1],  &
[2938]559               [1,nxrg-nxlg+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
560       CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_xz_small, ierr )
561       CALL MPI_TYPE_COMMIT( stg_type_xz_small, ierr )
562       CALL MPI_TYPE_FREE( newtype, ierr )
563
564       ! receive count and displacement for MPI_GATHERV in stg_generate_seed_yz
565       ALLOCATE( recv_count_xz(pdims(2)), displs_xz(pdims(2)) )
566
567       recv_count_xz           = nzt_y_stg-nzb_y_stg + 1
568       recv_count_xz(pdims(2)) = recv_count_xz(pdims(2)) + 1
569
570       DO  j = 1, pdims(2)
571          displs_xz(j) = 0 + (nzt_y_stg-nzb_y_stg+1) * (j-1)
572       ENDDO
573
574    ENDIF
575
[2669]576#endif
[2259]577!
578!-- Define seed of random number
579    CALL RANDOM_SEED()
580    CALL RANDOM_SEED( size=nseed )
581    ALLOCATE( seed(1:nseed) )
582    DO  j = 1, nseed
583       seed(j) = startseed + j
584    ENDDO
585    CALL RANDOM_SEED(put=seed)
586
587!-- Read inflow profile
588!-- Height levels of profiles in input profile is as follows:
589!-- zu: luy, luz, tu, lvy, lvz, tv, r11, r21, r22, d1, d2, d5
590!-- zw: lwy, lwz, tw, r31, r32, r33, d3
591!-- WARNING: zz is not used at the moment
[2938]592    INQUIRE( FILE = 'STG_PROFILES' // TRIM( coupling_char ),                   &
593             EXIST = file_stg_exist  )
[2259]594
[2938]595    IF ( file_stg_exist )  THEN
[2259]596
[2938]597       OPEN( 90, FILE='STG_PROFILES'//TRIM( coupling_char ), STATUS='OLD',     &
598                      FORM='FORMATTED')
599!
600!--    Skip header
601       READ( 90, * )
[2259]602
[2938]603       DO  k = nzb, nzt+1
604          READ( 90, * ) zz, luy, luz, tu(k), lvy, lvz, tv(k), lwy, lwz, tw(k), &
605                        r11(k), r21(k), r22(k), r31(k), r32(k), r33(k),        &
606                        d1, d2, d3, d5
607
[2259]608!
[2938]609!--       Convert length scales from meter to number of grid points
610          nuy(k) = INT( luy * ddy )
611          nuz(k) = INT( luz / dz  )
612          nvy(k) = INT( lvy * ddy )
613          nvz(k) = INT( lvz / dz  )
614          nwy(k) = INT( lwy * ddy )
615          nwz(k) = INT( lwz / dz  )
616!
617!--       Workaround, assume isotropic turbulence
618          nwx(k) = nwy(k)
619          nvx(k) = nvy(k)
620          nux(k) = nuy(k)
621!
622!--       Save Mean inflow profiles
623          IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN
624             mean_inflow_profiles(k,1) = d1
625             mean_inflow_profiles(k,2) = d2
626            !  mean_inflow_profiles(k,4) = d4
627             mean_inflow_profiles(k,5) = d5
628          ENDIF
629       ENDDO
[2259]630
[2938]631       CLOSE( 90 )
[3038]632
[2938]633    ELSE
[2259]634!
[3038]635!--    Set-up defaul length scales. Assume exponentially decreasing length
636!--    scales and isotropic turbulence.
637!--    Typical length (time) scales of 100 m (s) should be a good compromise
638!--    between all stratrifications. Near-surface variances are fixed to
[2938]639!--    0.1 m2/s2, vertical fluxes are one order of magnitude smaller.
[3038]640!--    Vertical fluxes
[2938]641       length_scale_surface = 100.0_wp
642       r_ii_0               = 0.1_wp
643       time_scale           = 100.0_wp
644       DO  k = nzb+1, nzt+1
645          dum_exp        = MERGE( -zu(k) / ( 0.3* zu(nzt) ),                   &
646                                  0.0_wp,                                      &
647                                  zu(k) > 0.3 * zu(nzt)                        &
648                                )
649          length_scale_z = length_scale_surface * EXP( dum_exp )
[2259]650
[2938]651          nux(k) = MAX( INT( length_scale_z * ddx     ), 1 )
652          nuy(k) = MAX( INT( length_scale_z * ddy     ), 1 )
653          nuz(k) = MAX( INT( length_scale_z * ddzw(k) ), 1 )
654          nvx(k) = MAX( INT( length_scale_z * ddx     ), 1 )
655          nvy(k) = MAX( INT( length_scale_z * ddy     ), 1 )
656          nvz(k) = MAX( INT( length_scale_z * ddzw(k) ), 1 )
657          nwx(k) = MAX( INT( length_scale_z * ddx     ), 1 )
658          nwy(k) = MAX( INT( length_scale_z * ddy     ), 1 )
659          nwz(k) = MAX( INT( length_scale_z * ddzw(k) ), 1 )
[2259]660
[2938]661          r11(k) = r_ii_0 * EXP( dum_exp )
662          r22(k) = r_ii_0 * EXP( dum_exp )
663          r33(k) = r_ii_0 * EXP( dum_exp )
[2259]664
[2938]665          r21(k) = 0.1_wp * r_ii_0 * EXP( dum_exp )
666          r31(k) = 0.1_wp * r_ii_0 * EXP( dum_exp )
667          r32(k) = 0.1_wp * r_ii_0 * EXP( dum_exp )
668
669          tu(k)  = time_scale
670          tv(k)  = time_scale
671          tw(k)  = time_scale
672
673       ENDDO
674       nux(nzb) = nux(nzb+1)
675       nuy(nzb) = nuy(nzb+1)
676       nuz(nzb) = nuz(nzb+1)
677       nvx(nzb) = nvx(nzb+1)
678       nvy(nzb) = nvy(nzb+1)
679       nvz(nzb) = nvz(nzb+1)
680       nwx(nzb) = nwx(nzb+1)
681       nwy(nzb) = nwy(nzb+1)
682       nwz(nzb) = nwz(nzb+1)
683
684       r11(nzb) = r11(nzb+1)
685       r22(nzb) = r22(nzb+1)
686       r33(nzb) = r33(nzb+1)
687
688       r21(nzb) = r11(nzb+1)
689       r31(nzb) = r31(nzb+1)
690       r32(nzb) = r32(nzb+1)
691
692       tu(nzb)  = time_scale
693       tv(nzb)  = time_scale
694       tw(nzb)  = time_scale
695
696    ENDIF
697
[2259]698!
[2938]699!-- Assign initial profiles
[3038]700    IF ( .NOT. forcing  .AND.  .NOT.  nest_domain )  THEN
[2938]701       u_init = mean_inflow_profiles(:,1)
702       v_init = mean_inflow_profiles(:,2)
703      !pt_init = mean_inflow_profiles(:,4)
704       e_init = MAXVAL( mean_inflow_profiles(:,5) )
705    ENDIF
706!
[2259]707!-- Calculate coefficient matrix from Reynolds stress tensor (Lund rotation)
708    DO  k = nzb, nzt+1
709       IF ( r11(k) > 0.0_wp )  THEN
710          a11(k) = SQRT( r11(k) )
711          a21(k) = r21(k) / a11(k)
712       ELSE
713          a11(k) = 0.0_wp
714          a21(k) = 0.0_wp
715       ENDIF
716
717       a22(k) = r22(k) - a21(k)**2
718       IF ( a22(k) > 0.0_wp )  THEN
719          a22(k) = SQRT( a22(k) )
720       ELSE
721          a22(k) = 0.0_wp
722       ENDIF
723
724!
725!--    a31, a32, a33 must be calculated with interpolated a11, a21, a22 (d11,
726!--    d21, d22) because of different vertical grid
727       IF ( k .le. nzt )  THEN
728          d11 = 0.5_wp * ( r11(k) + r11(k+1) )
729          IF ( d11 > 0.0_wp )  THEN
730             d11 = SQRT( d11 )
731             d21 = ( 0.5_wp * ( r21(k) + r21(k+1) ) ) / d11
732             a31(k) = r31(k) / d11
733          ELSE
734             d21 = 0.0_wp
735             a31(k) = 0.0_wp
736          ENDIF
737
738          d22 = 0.5_wp * ( r22(k) + r22(k+1) ) - d21 ** 2
739          IF ( d22 > 0.0_wp )  THEN
740             a32(k) = ( r32(k) - d21 * a31(k) ) / SQRT( d22 )
741          ELSE
742             a32(k) = 0.0_wp
743          ENDIF
744
745          a33(k) = r33(k) - a31(k) ** 2 - a32(k) ** 2
746          IF ( a33(k) > 0.0_wp )  THEN
747             a33(k) = SQRT( a33(k) )
748          ELSE
749             a33(k) = 0.0_wp
750          ENDIF
751       ELSE
752          a31(k) = a31(k-1)
753          a32(k) = a32(k-1)
754          a33(k) = a33(k-1)
755       ENDIF
756
757    ENDDO
758!
759!-- Define the size of the filter functions and allocate them.
760    merg = 0
761
762    ! arrays must be large enough to cover the largest length scale
763    DO  k = nzb, nzt+1
[2938]764       j = MAX( ABS(nux(k)), ABS(nuy(k)), ABS(nuz(k)), &
765                ABS(nvx(k)), ABS(nvy(k)), ABS(nvz(k)), &
766                ABS(nwx(k)), ABS(nwy(k)), ABS(nwz(k))  )
[2259]767       IF ( j > merg )  merg = j
768    ENDDO
769
770    merg  = 2 * merg
771    mergp = merg + nbgp
772
[2938]773    ALLOCATE ( bux(-merg:merg,nzb:nzt+1),                                      &
774               buy(-merg:merg,nzb:nzt+1),                                      &
775               buz(-merg:merg,nzb:nzt+1),                                      &
776               bvx(-merg:merg,nzb:nzt+1),                                      &
777               bvy(-merg:merg,nzb:nzt+1),                                      &
778               bvz(-merg:merg,nzb:nzt+1),                                      &
779               bwx(-merg:merg,nzb:nzt+1),                                      &
780               bwy(-merg:merg,nzb:nzt+1),                                      &
781               bwz(-merg:merg,nzb:nzt+1)  )
[2259]782
783!
[2938]784!-- Allocate velocity seeds for turbulence at xz-layer
785    ALLOCATE ( fu_xz( nzb:nzt+1,nxlg:nxrg), fuo_xz(nzb:nzt+1,nxlg:nxrg),       &
786               fv_xz( nzb:nzt+1,nxlg:nxrg), fvo_xz(nzb:nzt+1,nxlg:nxrg),       &
787               fw_xz( nzb:nzt+1,nxlg:nxrg), fwo_xz(nzb:nzt+1,nxlg:nxrg)  )
[2259]788
[2938]789!
790!-- Allocate velocity seeds for turbulence at yz-layer
791    ALLOCATE ( fu_yz( nzb:nzt+1,nysg:nyng), fuo_yz(nzb:nzt+1,nysg:nyng),       &
792               fv_yz( nzb:nzt+1,nysg:nyng), fvo_yz(nzb:nzt+1,nysg:nyng),       &
793               fw_yz( nzb:nzt+1,nysg:nyng), fwo_yz(nzb:nzt+1,nysg:nyng)  )
[2259]794
[2938]795    fu_xz  = 0.0_wp
796    fuo_xz = 0.0_wp
797    fv_xz  = 0.0_wp
798    fvo_xz = 0.0_wp
799    fw_xz  = 0.0_wp
800    fwo_xz = 0.0_wp
801
802    fu_yz  = 0.0_wp
803    fuo_yz = 0.0_wp
804    fv_yz  = 0.0_wp
805    fvo_yz = 0.0_wp
806    fw_yz  = 0.0_wp
807    fwo_yz = 0.0_wp
808
[2259]809!
810!-- Create filter functions
[2938]811    CALL stg_filter_func( nux, bux ) !filter ux
[2259]812    CALL stg_filter_func( nuy, buy ) !filter uy
813    CALL stg_filter_func( nuz, buz ) !filter uz
[2938]814    CALL stg_filter_func( nvx, bvx ) !filter vx
[2259]815    CALL stg_filter_func( nvy, bvy ) !filter vy
816    CALL stg_filter_func( nvz, bvz ) !filter vz
[2938]817    CALL stg_filter_func( nwx, bwx ) !filter wx
[2259]818    CALL stg_filter_func( nwy, bwy ) !filter wy
819    CALL stg_filter_func( nwz, bwz ) !filter wz
820
821#if defined( __parallel )
822    CALL MPI_BARRIER( comm2d, ierr )
823#endif
824
825!
[2938]826!-- In case of restart, calculate velocity seeds fu, fv, fw from former
827!   time step.
828!   Bug: fu, fv, fw are different in those heights where a11, a22, a33
829!        are 0 compared to the prerun. This is mostly for k=nzt+1.
[2259]830    IF ( TRIM( initializing_actions ) == 'read_restart_data' )  THEN
[2938]831       IF ( myidx == id_stg_left  .OR.  myidx == id_stg_right )  THEN
832
833          IF ( myidx == id_stg_left  )  i = -1
834          IF ( myidx == id_stg_right )  i = nxr+1
835
[2259]836          DO  j = nysg, nyng
837             DO  k = nzb, nzt+1
838
839                IF  ( a11(k) .NE. 0._wp ) THEN
[2938]840                   fu_yz(k,j) = ( u(k,j,i) / mc_factor - u_init(k) ) / a11(k)
[2259]841                ELSE
[2938]842                   fu_yz(k,j) = 0._wp
[2259]843                ENDIF
844
845                IF  ( a22(k) .NE. 0._wp ) THEN
[2938]846                   fv_yz(k,j) = ( v(k,j,i) / mc_factor - a21(k) * fu_yz(k,j) - &
847                               v_init(k) ) / a22(k)
[2259]848                ELSE
[2938]849                   fv_yz(k,j) = 0._wp
[2259]850                ENDIF
851
852                IF  ( a33(k) .NE. 0._wp ) THEN
[2938]853                   fw_yz(k,j) = ( w(k,j,i) / mc_factor - a31(k) * fu_yz(k,j) - &
854                               a32(k) * fv_yz(k,j) ) / a33(k)
[2259]855                ELSE
[2938]856                   fw_yz = 0._wp
[2259]857                ENDIF
858
859             ENDDO
860          ENDDO
861       ENDIF
862    ENDIF
863
864    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'stop' )
865
866 END SUBROUTINE stg_init
867
868
869!------------------------------------------------------------------------------!
870! Description:
871! ------------
872!> Calculate filter function bxx from length scale nxx following Eg.9 and 10
873!> (Xie and Castro, 2008)
874!------------------------------------------------------------------------------!
875 SUBROUTINE stg_filter_func( nxx, bxx )
876
877
878    IMPLICIT NONE
879
880    INTEGER(iwp) :: k         !< loop index
881    INTEGER(iwp) :: n_k       !< length scale nXX in height k
882    INTEGER(iwp) :: n_k2      !< n_k * 2
883    INTEGER(iwp) :: nf        !< index for length scales
884
885    REAL(wp) :: bdenom        !< denominator for filter functions bXX
886    REAL(wp) :: qsi = 1.0_wp  !< minimization factor
887
888    INTEGER(iwp), DIMENSION(:) :: nxx(nzb:nzt+1)           !< length scale (in gp)
889
890    REAL(wp), DIMENSION(:,:) :: bxx(-merg:merg,nzb:nzt+1)  !< filter function
891
892
893    bxx = 0.0_wp
894
895    DO  k = nzb, nzt+1
896       bdenom = 0.0_wp
897       n_k    = nxx(k)
898       IF ( n_k /= 0 )  THEN
899          n_k2 = n_k * 2
900
901!
902!--       ( Eq.10 )^2
903          DO  nf = -n_k2, n_k2
904             bdenom = bdenom + EXP( -qsi * pi * ABS(nf) / n_k )**2
905          ENDDO
906
907!
908!--       ( Eq.9 )
909          bdenom = SQRT( bdenom )
910          DO  nf = -n_k2, n_k2
911             bxx(nf,k) = EXP( -qsi * pi * ABS(nf) / n_k ) / bdenom
912          ENDDO
913       ENDIF
914    ENDDO
915
916END SUBROUTINE stg_filter_func
917
918
919!------------------------------------------------------------------------------!
920! Description:
921! ------------
922!> Parin for &stg_par for synthetic turbulence generator
923!------------------------------------------------------------------------------!
924 SUBROUTINE stg_parin
925
926
927    IMPLICIT NONE
928
929    CHARACTER (LEN=80) ::  line   !< dummy string that contains the current line of the parameter file
930
931
[2776]932    NAMELIST /stg_par/   use_syn_turb_gen
[2259]933
934    line = ' '
935
936!
937!-- Try to find stg package
938    REWIND ( 11 )
939    line = ' '
940    DO WHILE ( INDEX( line, '&stg_par' ) == 0 )
941       READ ( 11, '(A)', END=10 )  line
942    ENDDO
943    BACKSPACE ( 11 )
944
945!
946!-- Read namelist
947    READ ( 11, stg_par )
948
949!
950!-- Set flag that indicates that the synthetic turbulence generator is switched
951!-- on
[2776]952    syn_turb_gen = .TRUE.
[2259]953
[2563]954
[2259]955 10 CONTINUE
956
957 END SUBROUTINE stg_parin
958
959
960!------------------------------------------------------------------------------!
961! Description:
962! ------------
[2894]963!> This routine reads the respective restart data.
[2576]964!------------------------------------------------------------------------------!
[2894]965 SUBROUTINE stg_rrd_global( found )
[2576]966
967
[2894]968    USE control_parameters,                                                    &
969        ONLY: length, restart_string
[2576]970
971
[2894]972    IMPLICIT NONE
[2576]973
[3044]974    LOGICAL, INTENT(OUT)  ::  found !< flag indicating if variable was found
[2259]975
976
[2894]977    found = .TRUE.
[2259]978
[3038]979
[2894]980    SELECT CASE ( restart_string(1:length) )
[2259]981
[2894]982       CASE ( 'mc_factor' )
983          READ ( 13 )  mc_factor
984       CASE ( 'use_syn_turb_gen' )
985          READ ( 13 )  use_syn_turb_gen
[2259]986
[2894]987       CASE DEFAULT
[2259]988
[3038]989          found = .FALSE.
[2259]990
[2894]991    END SELECT
[2259]992
993
[2894]994 END SUBROUTINE stg_rrd_global
[2259]995
996
997!------------------------------------------------------------------------------!
998! Description:
999! ------------
1000!> This routine writes the respective restart data.
1001!------------------------------------------------------------------------------!
[2894]1002 SUBROUTINE stg_wrd_global
[2259]1003
1004
1005    IMPLICIT NONE
1006
[2894]1007    CALL wrd_write_string( 'mc_factor' )
[2259]1008    WRITE ( 14 )  mc_factor
1009
[2894]1010    CALL wrd_write_string( 'use_syn_turb_gen' )
1011    WRITE ( 14 )  use_syn_turb_gen
[2259]1012
1013
[2894]1014 END SUBROUTINE stg_wrd_global
[2259]1015
[2894]1016
[2259]1017!------------------------------------------------------------------------------!
1018! Description:
1019! ------------
1020!> Create turbulent inflow fields for u, v, w with prescribed length scales and
1021!> Reynolds stress tensor after a method of Xie and Castro (2008), modified
1022!> following suggestions of Kim et al. (2013), and using a Lund rotation
1023!> (Lund, 1998).
1024!------------------------------------------------------------------------------!
1025 SUBROUTINE stg_main
1026
1027
1028    USE arrays_3d,                                                             &
1029        ONLY:  dzw
1030
1031    USE control_parameters,                                                    &
[2938]1032        ONLY:  dt_3d, forcing, intermediate_timestep_count,  nest_domain,      &
[2945]1033               rans_mode, simulated_time, volume_flow_initial
[2259]1034
[2938]1035    USE grid_variables,                                                        &
1036        ONLY:  dx, dy
1037
[2259]1038    USE indices,                                                               &
[2938]1039        ONLY:  wall_flags_0
[2259]1040
1041    USE statistics,                                                            &
1042        ONLY:  weight_substep
1043
[2945]1044    USE pmc_interface,                                                         &
1045        ONLY : rans_mode_parent
[2259]1046
[2945]1047
[2259]1048    IMPLICIT NONE
1049
[2938]1050    INTEGER(iwp) :: i           !< grid index in x-direction
[2259]1051    INTEGER(iwp) :: j           !< loop index in y-direction
1052    INTEGER(iwp) :: k           !< loop index in z-direction
1053
1054    REAL(wp) :: dt_stg          !< wheighted subtimestep
1055    REAL(wp) :: mc_factor_l     !< local mass flux correction factor
[2938]1056    REAL(wp) :: volume_flow     !< mass flux through lateral boundary
1057    REAL(wp) :: volume_flow_l   !< local mass flux through lateral boundary
[2259]1058
[2938]1059    REAL(wp), DIMENSION(nzb:nzt+1,nxlg:nxrg,5) :: dist_xz !< imposed disturbances at north/south boundary
1060    REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng,5) :: dist_yz !< imposed disturbances at left/right boundary
[2259]1061
1062
1063    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'start' )
1064
1065!
1066!-- Calculate time step which is needed for filter functions
1067    dt_stg = dt_3d * weight_substep(intermediate_timestep_count)
1068
1069!
1070!-- Initial value of fu, fv, fw
1071    IF ( simulated_time == 0.0_wp .AND. .NOT. velocity_seed_initialized )  THEN
[2938]1072       CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fu_yz, id_stg_left )
1073       CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fv_yz, id_stg_left )
1074       CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fw_yz, id_stg_left )
1075
[2945]1076       IF ( forcing  .OR.  ( nest_domain .AND.  rans_mode_parent  .AND.        &
1077                      .NOT.  rans_mode ) )  THEN
[2938]1078!
1079!--       Generate turbulence at right boundary
1080          CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fu_yz, id_stg_right )
1081          CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fv_yz, id_stg_right )
1082          CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fw_yz, id_stg_right )
1083!
1084!--       Generate turbulence at north boundary
1085          CALL stg_generate_seed_xz( nux, nuz, bux, buz, fu_xz, id_stg_north )
1086          CALL stg_generate_seed_xz( nvx, nvz, bvx, bvz, fv_xz, id_stg_north )
1087          CALL stg_generate_seed_xz( nwx, nwz, bwx, bwz, fw_xz, id_stg_north )
1088!
1089!--       Generate turbulence at south boundary
1090          CALL stg_generate_seed_xz( nux, nuz, bux, buz, fu_xz, id_stg_south )
1091          CALL stg_generate_seed_xz( nvx, nvz, bvx, bvz, fv_xz, id_stg_south )
1092          CALL stg_generate_seed_xz( nwx, nwz, bwx, bwz, fw_xz, id_stg_south )
1093       ENDIF
[2259]1094       velocity_seed_initialized = .TRUE.
1095    ENDIF
1096!
1097!-- New set of fu, fv, fw
[2938]1098    CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fuo_yz, id_stg_left )
1099    CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fvo_yz, id_stg_left )
1100    CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fwo_yz, id_stg_left )
[2259]1101
[2945]1102    IF ( forcing  .OR.  ( nest_domain .AND.  rans_mode_parent  .AND.           &
1103                   .NOT.  rans_mode ) )  THEN
[2938]1104!
1105!--       Generate turbulence at right boundary
1106          CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fuo_yz, id_stg_right )
1107          CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fvo_yz, id_stg_right )
1108          CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fwo_yz, id_stg_right )
1109!
1110!--       Generate turbulence at north boundary
1111          CALL stg_generate_seed_xz( nux, nuz, bux, buz, fuo_xz, id_stg_north )
1112          CALL stg_generate_seed_xz( nvx, nvz, bvx, bvz, fvo_xz, id_stg_north )
1113          CALL stg_generate_seed_xz( nwx, nwz, bwx, bwz, fwo_xz, id_stg_north )
1114!
1115!--       Generate turbulence at south boundary
1116          CALL stg_generate_seed_xz( nux, nuz, bux, buz, fuo_xz, id_stg_south )
1117          CALL stg_generate_seed_xz( nvx, nvz, bvx, bvz, fvo_xz, id_stg_south )
1118          CALL stg_generate_seed_xz( nwx, nwz, bwx, bwz, fwo_xz, id_stg_south )
1119    ENDIF
1120!
1121!-- Turbulence generation at left and or right boundary
1122    IF ( myidx == id_stg_left  .OR.  myidx == id_stg_right )  THEN
[2259]1123
1124       DO  j = nysg, nyng
1125          DO  k = nzb, nzt + 1
1126!
1127!--          Update fu, fv, fw following Eq. 14 of Xie and Castro (2008)
1128             IF ( tu(k) == 0.0_wp )  THEN
[2938]1129                fu_yz(k,j) = fuo_yz(k,j)
[2259]1130             ELSE
[2938]1131                fu_yz(k,j) = fu_yz(k,j) * EXP( -pi * dt_stg * 0.5_wp / tu(k) ) +     &
1132                         fuo_yz(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tu(k) ) )
[2259]1133             ENDIF
1134
1135             IF ( tv(k) == 0.0_wp )  THEN
[2938]1136                fv_yz(k,j) = fvo_yz(k,j)
[2259]1137             ELSE
[2938]1138                fv_yz(k,j) = fv_yz(k,j) * EXP( -pi * dt_stg * 0.5_wp / tv(k) ) +     &
1139                         fvo_yz(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tv(k) ) )
[2259]1140             ENDIF
1141
1142             IF ( tw(k) == 0.0_wp )  THEN
[2938]1143                fw_yz(k,j) = fwo_yz(k,j)
[2259]1144             ELSE
[2938]1145                fw_yz(k,j) = fw_yz(k,j) * EXP( -pi * dt_stg * 0.5_wp / tw(k) ) +     &
1146                         fwo_yz(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tw(k) ) )
[2259]1147             ENDIF
1148!
1149!--          Lund rotation following Eq. 17 in Xie and Castro (2008).
1150!--          Additional factors are added to improve the variance of v and w
1151             IF( k == 0 )  THEN
[2938]1152                dist_yz(k,j,1) = 0.0_wp
1153                dist_yz(k,j,2) = 0.0_wp
1154                dist_yz(k,j,3) = 0.0_wp
1155!                 dist_yz(k,j,4) = 0.0_wp
1156!                 dist_yz(k,j,5) = 0.0_wp
[2259]1157             ELSE
[2938]1158                dist_yz(k,j,1) = a11(k) * fu_yz(k,j)
[2259]1159                !experimental test of 1.2
[2945]1160                dist_yz(k,j,2) = ( SQRT( a22(k) / MAXVAL(a22) )                &
[2259]1161                                         * 1.2_wp )                            &
[2945]1162                                       * (   a21(k) * fu_yz(k,j)               &
[2938]1163                                           + a22(k) * fv_yz(k,j) )
[2945]1164                dist_yz(k,j,3) = ( SQRT(a33(k) / MAXVAL(a33) )                 &
[2259]1165                                         * 1.3_wp )                            &
[2945]1166                                       * (   a31(k) * fu_yz(k,j)               &
1167                                           + a32(k) * fv_yz(k,j)               &
[2938]1168                                           + a33(k) * fw_yz(k,j) )
[2259]1169                ! Calculation for pt and e not yet implemented
[2938]1170!                 dist_yz(k,j,4) = 0.0_wp
1171!                 dist_yz(k,j,5) = 0.0_wp
[2259]1172             ENDIF
1173
1174          ENDDO
1175       ENDDO
1176
1177!
1178!--    Mass flux correction following Kim et al. (2013)
1179!--    This correction factor insures that the mass flux is preserved at the
1180!--    inflow boundary
[3038]1181       IF ( .NOT. forcing  .AND.  .NOT. nest_domain )  THEN
[2938]1182          mc_factor_l = 0.0_wp
1183          mc_factor   = 0.0_wp
1184          DO  j = nys, nyn
1185             DO  k = nzb+1, nzt
1186                mc_factor_l = mc_factor_l + dzw(k)  *                          &
1187                              ( mean_inflow_profiles(k,1) + dist_yz(k,j,1) )
1188             ENDDO
[2259]1189          ENDDO
1190
1191#if defined( __parallel )
[2938]1192          CALL MPI_ALLREDUCE( mc_factor_l, mc_factor,  &
1193                              1, MPI_REAL, MPI_SUM, comm1dy, ierr )
[2259]1194#else
[2938]1195          mc_factor = mc_factor_l
[2259]1196#endif
1197
[2938]1198          mc_factor = volume_flow_initial(1) / mc_factor
[2259]1199
1200!
[2938]1201!--       Add disturbance at the inflow
1202          DO  j = nysg, nyng
1203             DO  k = nzb, nzt+1
1204                 u(k,j,-nbgp+1:0) = ( mean_inflow_profiles(k,1) +              &
1205                                      dist_yz(k,j,1)             ) * mc_factor
1206                 v(k,j,-nbgp:-1)  = ( mean_inflow_profiles(k,2) +              &
1207                                      dist_yz(k,j,2)             ) * mc_factor
1208                 w(k,j,-nbgp:-1)  =   dist_yz(k,j,3)               * mc_factor
1209             ENDDO
[2259]1210          ENDDO
[2938]1211
1212       ELSE
1213!
1214!--       First, calculate volume flow at yz boundary
1215          IF ( myidx == id_stg_left  )  i = nxl
1216          IF ( myidx == id_stg_right )  i = nxr+1
1217
1218          volume_flow_l = 0.0_wp
1219          volume_flow   = 0.0_wp
1220          mc_factor_l   = 0.0_wp
1221          mc_factor     = 0.0_wp
1222          DO  j = nys, nyn
1223             DO  k = nzb+1, nzt
1224                volume_flow_l = volume_flow_l + u(k,j,i) * dzw(k) * dy         &
[3038]1225                                     * MERGE( 1.0_wp, 0.0_wp,                  &
[2938]1226                                              BTEST( wall_flags_0(k,j,i), 1 ) )
1227
1228                mc_factor_l = mc_factor_l     + ( u(k,j,i) + dist_yz(k,j,1) )  &
1229                                                         * dzw(k) * dy         &
[3038]1230                                     * MERGE( 1.0_wp, 0.0_wp,                  &
[2938]1231                                              BTEST( wall_flags_0(k,j,i), 1 ) )
1232             ENDDO
1233          ENDDO
1234#if defined( __parallel )
1235          CALL MPI_ALLREDUCE( volume_flow_l, volume_flow,                      &
1236                              1, MPI_REAL, MPI_SUM, comm1dy, ierr )
1237          CALL MPI_ALLREDUCE( mc_factor_l, mc_factor,                          &
1238                              1, MPI_REAL, MPI_SUM, comm1dy, ierr )
1239#else
1240          volume_flow = volume_flow_l
1241          mc_factor   = mc_factor_l
1242#endif
1243
1244          mc_factor = volume_flow / mc_factor
1245
1246!
1247!--       Add disturbances
1248          IF ( myidx == id_stg_left  )  THEN
1249
1250             DO  j = nysg, nyng
1251                DO  k = nzb, nzt+1
1252                   u(k,j,-nbgp+1:0) = ( u(k,j,-nbgp+1:0) + dist_yz(k,j,1) )    &
1253                                        * mc_factor
1254                   v(k,j,-nbgp:-1)  = ( v(k,j,-nbgp:-1)  + dist_yz(k,j,2)  )   &
1255                                        * mc_factor
1256                   w(k,j,-nbgp:-1)  = ( w(k,j,-nbgp:-1)  + dist_yz(k,j,3)  )   &
1257                                        * mc_factor
1258                ENDDO
1259             ENDDO
1260          ENDIF
1261          IF ( myidx == id_stg_right  )  THEN
1262
1263             DO  j = nysg, nyng
1264                DO  k = nzb, nzt+1
1265                   u(k,j,nxr+1:nxr+nbgp) = ( u(k,j,nxr+1:nxr+nbgp) +           &
1266                                             dist_yz(k,j,1) ) * mc_factor
1267                   v(k,j,nxr+1:nxr+nbgp) = ( v(k,j,nxr+1:nxr+nbgp) +           &
1268                                             dist_yz(k,j,2) ) * mc_factor
1269                   w(k,j,nxr+1:nxr+nbgp) = ( w(k,j,nxr+1:nxr+nbgp) +           &
1270                                             dist_yz(k,j,3) ) * mc_factor
1271                ENDDO
1272             ENDDO
1273          ENDIF
1274       ENDIF
1275
1276    ENDIF
1277!
1278!-- Turbulence generation at north and south boundary
1279    IF ( myidy == id_stg_north  .OR.  myidy == id_stg_south )  THEN
1280
1281       DO  i = nxlg, nxrg
1282          DO  k = nzb, nzt + 1
1283!
1284!--          Update fu, fv, fw following Eq. 14 of Xie and Castro (2008)
1285             IF ( tu(k) == 0.0_wp )  THEN
1286                fu_xz(k,i) = fuo_xz(k,i)
1287             ELSE
1288                fu_xz(k,i) = fu_xz(k,i) * EXP( -pi * dt_stg * 0.5_wp / tu(k) ) +     &
1289                         fuo_xz(k,i) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tu(k) ) )
1290             ENDIF
1291
1292             IF ( tv(k) == 0.0_wp )  THEN
1293                fv_xz(k,i) = fvo_xz(k,i)
1294             ELSE
1295                fv_xz(k,i) = fv_xz(k,i) * EXP( -pi * dt_stg * 0.5_wp / tv(k) ) +     &
1296                         fvo_xz(k,i) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tv(k) ) )
1297             ENDIF
1298
1299             IF ( tw(k) == 0.0_wp )  THEN
1300                fw_xz(k,i) = fwo_xz(k,i)
1301             ELSE
1302                fw_xz(k,i) = fw_xz(k,i) * EXP( -pi * dt_stg * 0.5_wp / tw(k) ) +     &
1303                         fwo_xz(k,i) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tw(k) ) )
1304             ENDIF
1305!
1306!--          Lund rotation following Eq. 17 in Xie and Castro (2008).
1307!--          Additional factors are added to improve the variance of v and w
1308             IF( k == 0 )  THEN
1309                dist_xz(k,i,1) = 0.0_wp
1310                dist_xz(k,i,2) = 0.0_wp
1311                dist_xz(k,i,3) = 0.0_wp
1312
1313             ELSE
1314                dist_xz(k,i,1) = a11(k) * fu_xz(k,i)
1315                !experimental test of 1.2
1316                dist_xz(k,i,2) = ( SQRT( a22(k) / MAXVAL(a22) )                &
1317                                         * 1.2_wp )                            &
1318                                       * (   a21(k) * fu_xz(k,i)               &
1319                                           + a22(k) * fv_xz(k,i) )
1320                dist_xz(k,i,3) = ( SQRT(a33(k) / MAXVAL(a33) )                 &
1321                                         * 1.3_wp )                            &
1322                                       * (   a31(k) * fu_xz(k,i)               &
1323                                           + a32(k) * fv_xz(k,i)               &
1324                                           + a33(k) * fw_xz(k,i) )
1325             ENDIF
1326
1327          ENDDO
[2259]1328       ENDDO
[2938]1329!
1330!--    Mass flux correction following Kim et al. (2013)
1331!--    This correction factor insures that the mass flux is preserved at the
1332!--    inflow boundary.
1333!--    First, calculate volume flow at xz boundary
1334       IF ( myidy == id_stg_south  ) j = nys
1335       IF ( myidy == id_stg_north )  j = nyn+1
[2259]1336
[2938]1337       volume_flow_l = 0.0_wp
1338       volume_flow   = 0.0_wp
1339       mc_factor_l   = 0.0_wp
1340       mc_factor     = 0.0_wp
1341       DO  i = nxl, nxr
1342          DO  k = nzb+1, nzt
[2945]1343             volume_flow_l = volume_flow_l + v(k,j,i) * dzw(k) * dx            &
[3038]1344                                  * MERGE( 1.0_wp, 0.0_wp,                     &
[2938]1345                                           BTEST( wall_flags_0(k,j,i), 2 ) )
1346
[2945]1347             mc_factor_l = mc_factor_l     + ( v(k,j,i) + dist_xz(k,i,2) )     &
1348                                                      * dzw(k) * dx            &
[3038]1349                                  * MERGE( 1.0_wp, 0.0_wp,                     &
[2938]1350                                           BTEST( wall_flags_0(k,j,i), 2 ) )
1351          ENDDO
1352       ENDDO
1353#if defined( __parallel )
[2945]1354       CALL MPI_ALLREDUCE( volume_flow_l, volume_flow,                         &
[2938]1355                           1, MPI_REAL, MPI_SUM, comm1dx, ierr )
[2945]1356       CALL MPI_ALLREDUCE( mc_factor_l, mc_factor,                             &
[2938]1357                           1, MPI_REAL, MPI_SUM, comm1dx, ierr )
1358#else
1359       volume_flow = volume_flow_l
1360       mc_factor   = mc_factor_l
1361#endif
1362
1363       mc_factor = volume_flow / mc_factor
1364
1365!
1366!--    Add disturbances
1367       IF ( myidy == id_stg_south  )  THEN
1368
1369          DO  i = nxlg, nxrg
1370             DO  k = nzb, nzt+1
1371                u(k,-nbgp:-1,i) = ( u(k,-nbgp:-1,i) + dist_xz(k,i,1) )         &
1372                                     * mc_factor
1373                v(k,-nbgp:0,i)  = ( v(k,-nbgp:0,i)  + dist_xz(k,i,2)  )        &
1374                                     * mc_factor
1375                w(k,-nbgp:-1,i) = ( w(k,-nbgp:-1,i) + dist_xz(k,i,3)  )        &
1376                                     * mc_factor
1377             ENDDO
1378          ENDDO
1379       ENDIF
1380       IF ( myidy == id_stg_north  )  THEN
1381
1382          DO  i = nxlg, nxrg
1383             DO  k = nzb, nzt+1
1384                u(k,nyn+1:nyn+nbgp,i) = ( u(k,nyn+1:nyn+nbgp,i) +              &
1385                                          dist_xz(k,i,1) ) * mc_factor
1386                v(k,nyn+1:nyn+nbgp,i) = ( v(k,nyn+1:nyn+nbgp,i) +              &
1387                                          dist_xz(k,i,2) ) * mc_factor
1388                w(k,nyn+1:nyn+nbgp,i) = ( w(k,nyn+1:nyn+nbgp,i) +              &
1389                                          dist_xz(k,i,3) ) * mc_factor
1390             ENDDO
1391          ENDDO
1392       ENDIF
[2259]1393    ENDIF
1394
1395    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'stop' )
1396
1397 END SUBROUTINE stg_main
1398
1399!------------------------------------------------------------------------------!
1400! Description:
1401! ------------
1402!> Generate a set of random number rand_it wich is equal on each PE
1403!> and calculate the velocity seed f_n.
1404!> f_n is splitted in vertical direction by the number of PEs in x-direction and
1405!> and each PE calculates a vertical subsection of f_n. At the the end, all
1406!> parts are collected to form the full array.
1407!------------------------------------------------------------------------------!
[2938]1408 SUBROUTINE stg_generate_seed_yz( n_y, n_z, b_y, b_z, f_n, id )
[2259]1409
1410
1411    USE indices,                                                               &
1412        ONLY: ny
1413
1414    IMPLICIT NONE
1415
[2938]1416    INTEGER(iwp) :: id          !< core ids at respective boundaries
[2259]1417    INTEGER(iwp) :: j           !< loop index in y-direction
1418    INTEGER(iwp) :: jj          !< loop index in y-direction
1419    INTEGER(iwp) :: k           !< loop index in z-direction
1420    INTEGER(iwp) :: kk          !< loop index in z-direction
1421    INTEGER(iwp) :: send_count  !< send count for MPI_GATHERV
1422
1423    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_y    !< length scale in y-direction
1424    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z    !< length scale in z-direction
1425    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_y2   !< n_y*2
1426    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z2   !< n_z*2
1427
1428    REAL(wp) :: nyz_inv         !< inverse of number of grid points in yz-slice
1429    REAL(wp) :: rand_av         !< average of random number
1430    REAL(wp) :: rand_sigma_inv  !< inverse of stdev of random number
1431
1432    REAL(wp), DIMENSION(-merg:merg,nzb:nzt+1)    :: b_y     !< filter func in y-dir
1433    REAL(wp), DIMENSION(-merg:merg,nzb:nzt+1)    :: b_z     !< filter func in z-dir
[2938]1434    REAL(wp), DIMENSION(nzb_x_stg:nzt_x_stg+1,nysg:nyng) :: f_n_l   !<  local velocity seed
[2259]1435    REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng)     :: f_n     !<  velocity seed
1436    REAL(wp), DIMENSION(:,:), ALLOCATABLE        :: rand_it !<  random number
1437
1438
1439!
1440!-- Generate random numbers using a seed generated in stg_init.
1441!-- The set of random numbers are modified to have an average of 0 and
1442!-- unit variance.
1443    ALLOCATE( rand_it(nzb-mergp:nzt+1+mergp,-mergp:ny+mergp) )
1444
1445    rand_av        = 0.0_wp
1446    rand_sigma_inv = 0.0_wp
1447    nyz_inv        = 1.0_wp / REAL( ( nzt+1 - nzb+1 ) * ( ny+1 ), KIND=wp )
1448
1449    DO  j = 0, ny
1450       DO  k = nzb, nzt+1
1451          CALL RANDOM_NUMBER( rand_it(k,j) )
1452          rand_av = rand_av + rand_it(k,j)
1453       ENDDO
1454    ENDDO
1455
1456    rand_av = rand_av * nyz_inv
1457
1458    DO  j = 0, ny
1459       DO  k = nzb, nzt+1
1460          rand_it(k,j)   = rand_it(k,j) - rand_av
1461          rand_sigma_inv = rand_sigma_inv + rand_it(k,j) ** 2
1462       ENDDO
1463    ENDDO
1464
1465    rand_sigma_inv = 1.0_wp / SQRT(rand_sigma_inv * nyz_inv)
1466
1467    DO  j = 0, ny
1468       DO  k = nzb, nzt+1
1469          rand_it(k,j) = rand_it(k,j) * rand_sigma_inv
1470       ENDDO
1471    ENDDO
1472
1473!
1474!-- Periodic fill of random number in space
1475    DO  j = 0, ny
1476       DO  k = 1, mergp
1477          rand_it(nzb  -k,j) = rand_it(nzt+2-k,j)    ! bottom margin
1478          rand_it(nzt+1+k,j) = rand_it(nzb+k-1,j)    ! top margin
1479       ENDDO
1480    ENDDO
1481    DO  j = 1, mergp
1482       DO  k = nzb-mergp, nzt+1+mergp
1483          rand_it(k,  -j) = rand_it(k,ny-j+1)        ! south margin
1484          rand_it(k,ny+j) = rand_it(k,   j-1)        ! north margin
1485       ENDDO
1486    ENDDO
1487
1488!
1489!-- Generate velocity seed following Eq.6 of Xie and Castro (2008)
1490    n_y2 = n_y * 2
1491    n_z2 = n_z * 2
1492    f_n_l  = 0.0_wp
1493
1494    DO  j = nysg, nyng
[2938]1495       DO  k = nzb_x_stg, nzt_x_stg+1
[2259]1496          DO  jj = -n_y2(k), n_y2(k)
1497             DO  kk = -n_z2(k), n_z2(k)
1498                f_n_l(k,j) = f_n_l(k,j)                                        &
1499                           + b_y(jj,k) * b_z(kk,k) * rand_it(k+kk,j+jj)
1500             ENDDO
1501          ENDDO
1502       ENDDO
1503    ENDDO
1504
1505    DEALLOCATE( rand_it )
1506!
1507!-- Gather velocity seeds of full subdomain
[2938]1508    send_count = nzt_x_stg - nzb_x_stg + 1
1509    IF ( nzt_x_stg == nzt )  send_count = send_count + 1
[2259]1510
1511#if defined( __parallel )
[2945]1512    CALL MPI_GATHERV( f_n_l(nzb_x_stg,nysg), send_count, stg_type_yz_small,    &
1513                      f_n(nzb+1,nysg), recv_count_yz, displs_yz, stg_type_yz,  &
[2938]1514                      id, comm1dx, ierr )
[2259]1515#else
[2938]1516    f_n(nzb+1:nzt+1,nysg:nyng) = f_n_l(nzb_x_stg:nzt_x_stg+1,nysg:nyng)
[2259]1517#endif
1518
1519
1520 END SUBROUTINE stg_generate_seed_yz
1521
[2938]1522
1523
1524
1525!------------------------------------------------------------------------------!
1526! Description:
1527! ------------
1528!> Generate a set of random number rand_it wich is equal on each PE
1529!> and calculate the velocity seed f_n.
1530!> f_n is splitted in vertical direction by the number of PEs in y-direction and
1531!> and each PE calculates a vertical subsection of f_n. At the the end, all
1532!> parts are collected to form the full array.
1533!------------------------------------------------------------------------------!
1534 SUBROUTINE stg_generate_seed_xz( n_x, n_z, b_x, b_z, f_n, id )
1535
1536
1537    USE indices,                                                               &
1538        ONLY: nx
1539
1540
1541    IMPLICIT NONE
1542
1543    INTEGER(iwp) :: id          !< core ids at respective boundaries
1544    INTEGER(iwp) :: i           !< loop index in x-direction
1545    INTEGER(iwp) :: ii          !< loop index in x-direction
1546    INTEGER(iwp) :: k           !< loop index in z-direction
1547    INTEGER(iwp) :: kk          !< loop index in z-direction
1548    INTEGER(iwp) :: send_count  !< send count for MPI_GATHERV
1549
1550    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_x    !< length scale in x-direction
1551    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z    !< length scale in z-direction
1552    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_x2   !< n_y*2
1553    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z2   !< n_z*2
1554
1555    REAL(wp) :: nxz_inv         !< inverse of number of grid points in xz-slice
1556    REAL(wp) :: rand_av         !< average of random number
1557    REAL(wp) :: rand_sigma_inv  !< inverse of stdev of random number
1558
1559    REAL(wp), DIMENSION(-merg:merg,nzb:nzt+1)    :: b_x     !< filter func in y-dir
1560    REAL(wp), DIMENSION(-merg:merg,nzb:nzt+1)    :: b_z     !< filter func in z-dir
1561    REAL(wp), DIMENSION(nzb_y_stg:nzt_y_stg+1,nxlg:nxrg) :: f_n_l   !<  local velocity seed
1562    REAL(wp), DIMENSION(nzb:nzt+1,nxlg:nxrg)     :: f_n     !<  velocity seed
1563    REAL(wp), DIMENSION(:,:), ALLOCATABLE        :: rand_it !<  random number
1564
1565
1566!
1567!-- Generate random numbers using a seed generated in stg_init.
1568!-- The set of random numbers are modified to have an average of 0 and
1569!-- unit variance.
1570    ALLOCATE( rand_it(nzb-mergp:nzt+1+mergp,-mergp:nx+mergp) )
1571
1572    rand_av        = 0.0_wp
1573    rand_sigma_inv = 0.0_wp
1574    nxz_inv        = 1.0_wp / REAL( ( nzt+1 - nzb+1 ) * ( nx+1 ), KIND=wp )
1575
1576    DO  i = 0, nx
1577       DO  k = nzb, nzt+1
1578          CALL RANDOM_NUMBER( rand_it(k,i) )
1579          rand_av = rand_av + rand_it(k,i)
1580       ENDDO
1581    ENDDO
1582
1583    rand_av = rand_av * nxz_inv
1584
1585    DO  i = 0, nx
1586       DO  k = nzb, nzt+1
1587          rand_it(k,i)   = rand_it(k,i) - rand_av
1588          rand_sigma_inv = rand_sigma_inv + rand_it(k,i) ** 2
1589       ENDDO
1590    ENDDO
1591
1592    rand_sigma_inv = 1.0_wp / SQRT(rand_sigma_inv * nxz_inv)
1593
1594    DO  i = 0, nx
1595       DO  k = nzb, nzt+1
1596          rand_it(k,i) = rand_it(k,i) * rand_sigma_inv
1597       ENDDO
1598    ENDDO
1599
1600!
1601!-- Periodic fill of random number in space
1602    DO  i = 0, nx
1603       DO  k = 1, mergp
1604          rand_it(nzb-k,i)   = rand_it(nzt+2-k,i)    ! bottom margin
1605          rand_it(nzt+1+k,i) = rand_it(nzb+k-1,i)    ! top margin
1606       ENDDO
1607    ENDDO
1608    DO  i = 1, mergp
1609       DO  k = nzb-mergp, nzt+1+mergp
1610          rand_it(k,-i)   = rand_it(k,nx-i+1)        ! left margin
1611          rand_it(k,nx+i) = rand_it(k,i-1)           ! right margin
1612       ENDDO
1613    ENDDO
1614
1615!
1616!-- Generate velocity seed following Eq.6 of Xie and Castro (2008)
1617    n_x2 = n_x * 2
1618    n_z2 = n_z * 2
1619    f_n_l  = 0.0_wp
1620
1621    DO  i = nxlg, nxrg
1622       DO  k = nzb_y_stg, nzt_y_stg+1
1623          DO  ii = -n_x2(k), n_x2(k)
1624             DO  kk = -n_z2(k), n_z2(k)
1625                f_n_l(k,i) = f_n_l(k,i)                                        &
1626                           + b_x(ii,k) * b_z(kk,k) * rand_it(k+kk,i+ii)
1627             ENDDO
1628          ENDDO
1629       ENDDO
1630    ENDDO
1631
1632    DEALLOCATE( rand_it )
1633
1634!
1635!-- Gather velocity seeds of full subdomain
1636    send_count = nzt_y_stg - nzb_y_stg + 1
1637    IF ( nzt_y_stg == nzt )  send_count = send_count + 1
1638
1639
1640#if defined( __parallel )
[2945]1641    CALL MPI_GATHERV( f_n_l(nzb_y_stg,nxlg), send_count, stg_type_xz_small,    &
[2938]1642                      f_n(nzb+1,nxlg), recv_count_xz, displs_xz, stg_type_xz,  &
1643                      id, comm1dy, ierr )
1644#else
1645    f_n(nzb+1:nzt+1,nxlg:nxrg) = f_n_l(nzb_y_stg:nzt_y_stg+1,nxlg:nxrg)
1646#endif
1647
1648
1649 END SUBROUTINE stg_generate_seed_xz
1650
[2259]1651 END MODULE synthetic_turbulence_generator_mod
Note: See TracBrowser for help on using the repository browser.