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

Last change on this file since 2836 was 2836, checked in by Giersch, 3 years ago

Bugfix in interpolation of lift and drag coefficients during initialization, default value of dt_dopr_listing is set to zero to allow header output

  • Property svn:keywords set to Id
File size: 35.9 KB
Line 
1!> @synthetic_turbulence_generator_mod.f90
2!------------------------------------------------------------------------------!
3! This file is part of the PALM model system.
4!
5! PALM is free software: you can redistribute it and/or modify it under the
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!
10! PALM is distributed in the hope that it will be useful, but WITHOUT ANY
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!
23!
24! Former revisions:
25! -----------------
26! $Id: synthetic_turbulence_generator_mod.f90 2836 2018-02-26 13:40:05Z Giersch $
27! The variables synthetic_turbulence_generator and
28! use_synthetic_turbulence_generator have been abbreviated + syn_turb_gen_prerun
29! flag is used to define if module related parameters were outputted as restart
30! data
31!
32! 2716 2017-12-29 16:35:59Z kanani
33! Corrected "Former revisions" section
34!
35! 2696 2017-12-14 17:12:51Z kanani
36! Change in file header (GPL part)
37!
38! 2669 2017-12-06 16:03:27Z raasch
39! unit number for file containing turbulence generator data changed to 90
40! bugfix: preprocessor directives added for MPI specific code
41!
42! 2576 2017-10-24 13:49:46Z Giersch
43! Definition of a new function called stg_skip_var_list to skip module
44! parameters during reading restart data
45!
46! 2563 2017-10-19 15:36:10Z Giersch
47! stg_read_restart_data is called in stg_parin in the case of a restart run
48!
49! 2259 2017-06-08 09:09:11Z gronemeier
50! Initial revision
51!
52!
53!
54! Authors:
55! --------
56! @author Tobias Gronemeier, Atsushi Inagaki, Micha Gryschka, Christoph Knigge
57!
58!
59! Description:
60! ------------
61!> The module generates turbulence at the inflow boundary based on a method by
62!> Xie and Castro (2008) utilizing a Lund rotation (Lund, 1998) and a mass-flux
63!> correction by Kim et al. (2013).
64!> The turbulence is correlated based on length scales in y- and z-direction and
65!> a time scale for each velocity component. The profiles of length and time
66!> scales, mean u, v, w, e and pt, and all components of the Reynolds stress
67!> tensor are read from file STG_PROFILES.
68!>
69!> @todo test restart
70!>       enable cyclic_fill
71!>       implement turbulence generation for e and pt
72!> @note <Enter notes on the module>
73!> @bug  Height information from input file is not used. Profiles from input
74!>       must match with current PALM grid.
75!>       Transformation of length scales to number of gridpoints does not
76!>       consider grid stretching.
77!>       In case of restart, velocity seeds differ from precursor run if a11,
78!>       a22, or a33 are zero.
79!------------------------------------------------------------------------------!
80 MODULE synthetic_turbulence_generator_mod
81
82
83    USE arrays_3d,                                                             &
84        ONLY:  mean_inflow_profiles, u, v, w
85
86    USE constants,                                                             &
87        ONLY:  pi
88
89    USE control_parameters,                                                    &
90        ONLY:  initializing_actions, message_string,                           &
91               syn_turb_gen, syn_turb_gen_prerun
92
93    USE cpulog,                                                                &
94        ONLY:  cpu_log, log_point, log_point_s
95
96    USE indices,                                                               &
97        ONLY:  nbgp, nzb, nzt, nyng, nysg
98
99    USE kinds
100
101    USE MPI
102
103    USE pegrid,                                                                &
104        ONLY:  comm1dx, comm1dy, comm2d, id_inflow, ierr, myidx, pdims
105
106    USE transpose_indices,                                                     &
107        ONLY: nzb_x, nzt_x
108
109
110    IMPLICIT NONE
111
112    LOGICAL :: velocity_seed_initialized = .FALSE.  !< true after first call of stg_main
113    LOGICAL :: use_syn_turb_gen = .FALSE.           !< switch to use synthetic turbulence generator
114
115    INTEGER(iwp) :: stg_type_yz        !< MPI type for full z range
116    INTEGER(iwp) :: stg_type_yz_small  !< MPI type for small z range
117    INTEGER(iwp) :: merg               !< maximum length scale (in gp)
118    INTEGER(iwp) :: mergp              !< merg + nbgp
119
120    REAL(wp) :: mc_factor    !< mass flux correction factor
121
122    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: displs      !< displacement for MPI_GATHERV
123    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: recv_count  !< receive count for MPI_GATHERV
124    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nuy         !< length scale of u in y direction (in gp)
125    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nuz         !< length scale of u in z direction (in gp)
126    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nvy         !< length scale of v in y direction (in gp)
127    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nvz         !< length scale of v in z direction (in gp)
128    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nwy         !< length scale of w in y direction (in gp)
129    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: nwz         !< length scale of w in z direction (in gp)
130
131    INTEGER(iwp), DIMENSION(:), ALLOCATABLE :: seed        !< seed of random number for rn-generator
132
133    REAL(wp), DIMENSION(:), ALLOCATABLE :: a11             !< coefficient for Lund rotation
134    REAL(wp), DIMENSION(:), ALLOCATABLE :: a21             !< coefficient for Lund rotation
135    REAL(wp), DIMENSION(:), ALLOCATABLE :: a22             !< coefficient for Lund rotation
136    REAL(wp), DIMENSION(:), ALLOCATABLE :: a31             !< coefficient for Lund rotation
137    REAL(wp), DIMENSION(:), ALLOCATABLE :: a32             !< coefficient for Lund rotation
138    REAL(wp), DIMENSION(:), ALLOCATABLE :: a33             !< coefficient for Lund rotation
139    REAL(wp), DIMENSION(:), ALLOCATABLE :: tu              !< Lagrangian time scale of u
140    REAL(wp), DIMENSION(:), ALLOCATABLE :: tv              !< Lagrangian time scale of v
141    REAL(wp), DIMENSION(:), ALLOCATABLE :: tw              !< Lagrangian time scale of w
142
143    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: buy           !< filter function for u in y direction
144    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: buz           !< filter function for u in z direction
145    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bvy           !< filter function for v in y direction
146    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bvz           !< filter function for v in z direction
147    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bwy           !< filter function for w in y direction
148    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: bwz           !< filter function for w in z direction
149    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fu            !< velocity seed for u
150    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fuo           !< velocity seed for u with new random number
151    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fv            !< velocity seed for v
152    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fvo           !< velocity seed for v with new random number
153    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fw            !< velocity seed for w
154    REAL(wp), DIMENSION(:,:), ALLOCATABLE :: fwo           !< velocity seed for w with new random number
155
156
157!
158!-- PALM interfaces:
159!-- Input parameter checks to be done in check_parameters
160    INTERFACE stg_check_parameters
161       MODULE PROCEDURE stg_check_parameters
162    END INTERFACE stg_check_parameters
163
164!
165!-- Calculate filter functions
166    INTERFACE stg_filter_func
167       MODULE PROCEDURE stg_filter_func
168    END INTERFACE stg_filter_func
169
170!
171!-- Generate velocity seeds
172    INTERFACE stg_generate_seed_yz
173       MODULE PROCEDURE stg_generate_seed_yz
174    END INTERFACE stg_generate_seed_yz
175
176!
177!-- Output of information to the header file
178    INTERFACE stg_header
179       MODULE PROCEDURE stg_header
180    END INTERFACE stg_header
181
182!
183!-- Initialization actions
184    INTERFACE stg_init
185       MODULE PROCEDURE stg_init
186    END INTERFACE stg_init
187
188!
189!-- Main procedure of synth. turb. gen.
190    INTERFACE stg_main
191       MODULE PROCEDURE stg_main
192    END INTERFACE stg_main
193
194!
195!-- Reading of NAMELIST parameters
196    INTERFACE stg_parin
197       MODULE PROCEDURE stg_parin
198    END INTERFACE stg_parin
199
200!
201!-- Skipping of parameters for restart runs
202    INTERFACE stg_skip_var_list
203       MODULE PROCEDURE stg_skip_var_list
204    END INTERFACE stg_skip_var_list
205
206!
207!-- Reading of parameters for restart runs
208    INTERFACE stg_read_restart_data
209       MODULE PROCEDURE stg_read_restart_data
210    END INTERFACE stg_read_restart_data
211
212!
213!-- Writing of binary output for restart runs
214    INTERFACE stg_write_restart_data
215       MODULE PROCEDURE stg_write_restart_data
216    END INTERFACE stg_write_restart_data
217
218    SAVE
219
220    PRIVATE
221
222!
223!-- Public interfaces
224    PUBLIC  stg_check_parameters, stg_header, stg_init, stg_main, stg_parin,   &
225            stg_write_restart_data, stg_skip_var_list
226
227!
228!-- Public variables
229    PUBLIC  use_syn_turb_gen
230
231
232 CONTAINS
233
234
235!------------------------------------------------------------------------------!
236! Description:
237! ------------
238!> Check parameters routine for synthetic turbulence generator
239!------------------------------------------------------------------------------!
240 SUBROUTINE stg_check_parameters
241
242
243    USE control_parameters,                                                    &
244        ONLY:  bc_lr, bc_ns, turbulent_inflow
245
246
247    IMPLICIT NONE
248
249    IF ( use_syn_turb_gen )  THEN
250
251       IF ( INDEX( initializing_actions, 'set_constant_profiles' ) == 0  .AND. &
252            INDEX( initializing_actions, 'read_restart_data' ) == 0 )  THEN
253          message_string = 'Using synthetic turbulence generator ' //          &
254                           'requires &initializing_actions = '            //   &
255                           '"set_constant_profiles" or "read_restart_data"'
256          CALL message( 'stg_check_parameters', 'PA0015', 1, 2, 0, 6, 0 )
257       ENDIF
258
259       IF ( bc_lr /= 'dirichlet/radiation' )  THEN
260          message_string = 'Using synthetic turbulence generator ' //          &
261                           'requires &bc_lr = "dirichlet/radiation"'
262          CALL message( 'stg_check_parameters', 'PA0035', 1, 2, 0, 6, 0 )
263       ENDIF
264       IF ( bc_ns /= 'cyclic' )  THEN
265          message_string = 'Using synthetic turbulence generator ' //          &
266                           'requires &bc_ns = "cyclic"'
267          CALL message( 'stg_check_parameters', 'PA0037', 1, 2, 0, 6, 0 )
268       ENDIF
269       IF ( turbulent_inflow )  THEN
270          message_string = 'Using synthetic turbulence generator ' //          &
271                           'in combination &with turbulent_inflow = .T. ' //   &
272                           'is not allowed'
273          CALL message( 'stg_check_parameters', 'PA0039', 1, 2, 0, 6, 0 )
274       ENDIF
275
276    ENDIF
277
278 END SUBROUTINE stg_check_parameters
279
280
281!------------------------------------------------------------------------------!
282! Description:
283! ------------
284!> Header output for synthetic turbulence generator
285!------------------------------------------------------------------------------!
286 SUBROUTINE stg_header ( io )
287
288
289    IMPLICIT NONE
290
291    INTEGER(iwp), INTENT(IN) ::  io   !< Unit of the output file
292
293!
294!-- Write synthetic turbulence generator Header
295    WRITE( io, 1 )
296    IF ( use_syn_turb_gen )  THEN
297       WRITE( io, 2 )
298    ELSE
299       WRITE( io, 3 )
300    ENDIF
301
3021   FORMAT (//' Synthetic turbulence generator information:'/                  &
303              ' ------------------------------------------'/)
3042   FORMAT ('    synthetic turbulence generator switched on')
3053   FORMAT ('    synthetic turbulence generator switched off')
306
307 END SUBROUTINE stg_header
308
309
310!------------------------------------------------------------------------------!
311! Description:
312! ------------
313!> Initialization of the synthetic turbulence generator
314!------------------------------------------------------------------------------!
315 SUBROUTINE stg_init
316
317
318    USE arrays_3d,                                                             &
319        ONLY:  u_init, v_init
320
321    USE control_parameters,                                                    &
322        ONLY:  coupling_char, dz, e_init
323
324    USE grid_variables,                                                        &
325        ONLY:  ddy
326
327
328    IMPLICIT NONE
329
330#if defined( __parallel )
331    INTEGER(KIND=MPI_ADDRESS_KIND) :: extent !< extent of new MPI type
332    INTEGER(KIND=MPI_ADDRESS_KIND) :: tob=0  !< dummy variable
333#endif
334
335    INTEGER(iwp) :: j                        !> loop index
336    INTEGER(iwp) :: k                        !< index
337    INTEGER(iwp) :: newtype                  !< dummy MPI type
338    INTEGER(iwp) :: realsize                 !< size of REAL variables
339    INTEGER(iwp) :: nseed                    !< dimension of random number seed
340    INTEGER(iwp) :: startseed = 1234567890   !< start seed for random number generator
341
342!
343!-- Dummy variables used for reading profiles
344    REAL(wp) :: d1      !< u profile
345    REAL(wp) :: d2      !< v profile
346    REAL(wp) :: d3      !< w profile
347    REAL(wp) :: d5      !< e profile
348    REAL(wp) :: d11     !< vertical interpolation for a11
349    REAL(wp) :: d21     !< vertical interpolation for a21
350    REAL(wp) :: d22     !< vertical interpolation for a22
351    REAL(wp) :: luy     !< length scale for u in y direction
352    REAL(wp) :: luz     !< length scale for u in z direction
353    REAL(wp) :: lvy     !< length scale for v in y direction
354    REAL(wp) :: lvz     !< length scale for v in z direction
355    REAL(wp) :: lwy     !< length scale for w in y direction
356    REAL(wp) :: lwz     !< length scale for w in z direction
357    REAL(wp) :: zz      !< height
358
359    REAL(wp),DIMENSION(nzb:nzt+1) :: r11  !< Reynolds parameter
360    REAL(wp),DIMENSION(nzb:nzt+1) :: r21  !< Reynolds parameter
361    REAL(wp),DIMENSION(nzb:nzt+1) :: r22  !< Reynolds parameter
362    REAL(wp),DIMENSION(nzb:nzt+1) :: r31  !< Reynolds parameter
363    REAL(wp),DIMENSION(nzb:nzt+1) :: r32  !< Reynolds parameter
364    REAL(wp),DIMENSION(nzb:nzt+1) :: r33  !< Reynolds parameter
365
366
367#if defined( __parallel )
368    CALL MPI_BARRIER( comm2d, ierr )
369#endif
370
371    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'start' )
372
373    IF ( .NOT. ALLOCATED( mean_inflow_profiles ) )                             &
374       ALLOCATE( mean_inflow_profiles(nzb:nzt+1,5) )
375
376    ALLOCATE ( a11(nzb:nzt+1), a21(nzb:nzt+1), a22(nzb:nzt+1),                 &
377               a31(nzb:nzt+1), a32(nzb:nzt+1), a33(nzb:nzt+1),                 &
378               nuy(nzb:nzt+1), nuz(nzb:nzt+1), nvy(nzb:nzt+1),                 &
379               nvz(nzb:nzt+1), nwy(nzb:nzt+1), nwz(nzb:nzt+1),                 &
380               tu(nzb:nzt+1),  tv(nzb:nzt+1),  tw(nzb:nzt+1)   )
381
382#if defined( __parallel )
383!
384!-- Define MPI type used in stg_generate_seed_yz to gather vertical splitted
385!-- velocity seeds
386    CALL MPI_TYPE_SIZE( MPI_REAL, realsize, ierr )
387    extent = 1 * realsize
388
389    ! stg_type_yz: yz-slice with vertical bounds nzb:nzt+1
390    CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt-nzb+2,nyng-nysg+1],                 &
391            [1,nyng-nysg+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
392    CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_yz, ierr )
393    CALL MPI_TYPE_COMMIT( stg_type_yz, ierr )
394    CALL MPI_TYPE_FREE( newtype, ierr )
395
396    ! stg_type_yz_small: yz-slice with vertical bounds nzb_x:nzt_x+1
397    CALL MPI_TYPE_CREATE_SUBARRAY( 2, [nzt_x-nzb_x+2,nyng-nysg+1],             &
398            [1,nyng-nysg+1], [0,0], MPI_ORDER_FORTRAN, MPI_REAL, newtype, ierr )
399    CALL MPI_TYPE_CREATE_RESIZED( newtype, tob, extent, stg_type_yz_small, ierr )
400    CALL MPI_TYPE_COMMIT( stg_type_yz_small, ierr )
401    CALL MPI_TYPE_FREE( newtype, ierr )
402
403    ! receive count and displacement for MPI_GATHERV in stg_generate_seed_yz
404    ALLOCATE( recv_count(pdims(1)), displs(pdims(1)) )
405
406    recv_count           = nzt_x-nzb_x + 1
407    recv_count(pdims(1)) = recv_count(pdims(1)) + 1
408
409    DO  j = 1, pdims(1)
410       displs(j) = 0 + (nzt_x-nzb_x+1) * (j-1)
411    ENDDO
412#endif
413
414!
415!-- Define seed of random number
416    CALL RANDOM_SEED()
417    CALL RANDOM_SEED( size=nseed )
418    ALLOCATE( seed(1:nseed) )
419    DO  j = 1, nseed
420       seed(j) = startseed + j
421    ENDDO
422    CALL RANDOM_SEED(put=seed)
423
424!
425!-- Read inflow profile
426!-- Height levels of profiles in input profile is as follows:
427!-- zu: luy, luz, tu, lvy, lvz, tv, r11, r21, r22, d1, d2, d5
428!-- zw: lwy, lwz, tw, r31, r32, r33, d3
429!-- WARNING: zz is not used at the moment
430    OPEN( 90, FILE='STG_PROFILES'//TRIM( coupling_char ), STATUS='OLD',        &
431                   FORM='FORMATTED')
432
433    ! Skip header
434    READ( 90, * )
435
436    DO  k = nzb, nzt+1
437       READ( 90, * ) zz, luy, luz, tu(k), lvy, lvz, tv(k), lwy, lwz, tw(k),    &
438                     r11(k), r21(k), r22(k), r31(k), r32(k), r33(k),           &
439                     d1, d2, d3, d5
440
441!
442!--    Convert length scales from meter to number of grid points
443       nuy(k) = INT( luy * ddy )
444       nuz(k) = INT( luz / dz  )
445       nvy(k) = INT( lvy * ddy )
446       nvz(k) = INT( lvz / dz  )
447       nwy(k) = INT( lwy * ddy )
448       nwz(k) = INT( lwz / dz  )
449
450!
451!--    Save Mean inflow profiles
452       IF ( TRIM( initializing_actions ) /= 'read_restart_data' ) THEN
453          mean_inflow_profiles(k,1) = d1
454          mean_inflow_profiles(k,2) = d2
455         !  mean_inflow_profiles(k,4) = d4
456          mean_inflow_profiles(k,5) = d5
457       ENDIF
458    ENDDO
459
460    CLOSE( 90 )
461
462!
463!--    Assign initial profiles
464    u_init = mean_inflow_profiles(:,1)
465    v_init = mean_inflow_profiles(:,2)
466   !  pt_init = mean_inflow_profiles(:,4)
467    e_init = MAXVAL( mean_inflow_profiles(:,5) )
468
469!
470!-- Calculate coefficient matrix from Reynolds stress tensor (Lund rotation)
471    DO  k = nzb, nzt+1
472       IF ( r11(k) > 0.0_wp )  THEN
473          a11(k) = SQRT( r11(k) )
474          a21(k) = r21(k) / a11(k)
475       ELSE
476          a11(k) = 0.0_wp
477          a21(k) = 0.0_wp
478       ENDIF
479
480       a22(k) = r22(k) - a21(k)**2
481       IF ( a22(k) > 0.0_wp )  THEN
482          a22(k) = SQRT( a22(k) )
483          a32(k) = ( r32(k) - a21(k) * a31(k) ) / a22(k)
484       ELSE
485          a22(k) = 0.0_wp
486          a32(k) = 0.0_wp
487       ENDIF
488
489!
490!--    a31, a32, a33 must be calculated with interpolated a11, a21, a22 (d11,
491!--    d21, d22) because of different vertical grid
492       IF ( k .le. nzt )  THEN
493          d11 = 0.5_wp * ( r11(k) + r11(k+1) )
494          IF ( d11 > 0.0_wp )  THEN
495             d11 = SQRT( d11 )
496             d21 = ( 0.5_wp * ( r21(k) + r21(k+1) ) ) / d11
497             a31(k) = r31(k) / d11
498          ELSE
499             d21 = 0.0_wp
500             a31(k) = 0.0_wp
501          ENDIF
502
503          d22 = 0.5_wp * ( r22(k) + r22(k+1) ) - d21 ** 2
504          IF ( d22 > 0.0_wp )  THEN
505             a32(k) = ( r32(k) - d21 * a31(k) ) / SQRT( d22 )
506          ELSE
507             a32(k) = 0.0_wp
508          ENDIF
509
510          a33(k) = r33(k) - a31(k) ** 2 - a32(k) ** 2
511          IF ( a33(k) > 0.0_wp )  THEN
512             a33(k) = SQRT( a33(k) )
513          ELSE
514             a33(k) = 0.0_wp
515          ENDIF
516       ELSE
517          a31(k) = a31(k-1)
518          a32(k) = a32(k-1)
519          a33(k) = a33(k-1)
520       ENDIF
521
522    ENDDO
523
524!
525!-- Define the size of the filter functions and allocate them.
526    merg = 0
527
528    ! arrays must be large enough to cover the largest length scale
529    DO  k = nzb, nzt+1
530       j = MAX( ABS(nuy(k)), ABS(nuz(k)), &
531                ABS(nvy(k)), ABS(nvz(k)), &
532                ABS(nwy(k)), ABS(nwz(k))  )
533       IF ( j > merg )  merg = j
534    ENDDO
535
536    merg  = 2 * merg
537    mergp = merg + nbgp
538
539    ALLOCATE ( buy(-merg:merg,nzb:nzt+1), buz(-merg:merg,nzb:nzt+1), &
540               bvy(-merg:merg,nzb:nzt+1), bvz(-merg:merg,nzb:nzt+1), &
541               bwy(-merg:merg,nzb:nzt+1), bwz(-merg:merg,nzb:nzt+1)  )
542
543!
544!-- Allocate velocity seeds
545    ALLOCATE ( fu( nzb:nzt+1,nysg:nyng), fuo(nzb:nzt+1,nysg:nyng), &
546               fv( nzb:nzt+1,nysg:nyng), fvo(nzb:nzt+1,nysg:nyng), &
547               fw( nzb:nzt+1,nysg:nyng), fwo(nzb:nzt+1,nysg:nyng)  )
548
549    fu  = 0._wp
550    fuo = 0._wp
551    fv  = 0._wp
552    fvo = 0._wp
553    fw  = 0._wp
554    fwo = 0._wp
555
556!
557!-- Create filter functions
558    CALL stg_filter_func( nuy, buy ) !filter uy
559    CALL stg_filter_func( nuz, buz ) !filter uz
560    CALL stg_filter_func( nvy, bvy ) !filter vy
561    CALL stg_filter_func( nvz, bvz ) !filter vz
562    CALL stg_filter_func( nwy, bwy ) !filter wy
563    CALL stg_filter_func( nwz, bwz ) !filter wz
564
565#if defined( __parallel )
566    CALL MPI_BARRIER( comm2d, ierr )
567#endif
568
569!
570!--    In case of restart, calculate velocity seeds fu, fv, fw from former
571!      time step.
572!      Bug: fu, fv, fw are different in those heights where a11, a22, a33
573!           are 0 compared to the prerun. This is mostly for k=nzt+1.
574    IF ( TRIM( initializing_actions ) == 'read_restart_data' )  THEN
575       IF ( myidx == id_inflow )  THEN
576          DO  j = nysg, nyng
577             DO  k = nzb, nzt+1
578
579                IF  ( a11(k) .NE. 0._wp ) THEN
580                fu(k,j) = ( u(k,j,-1) / mc_factor -                    &
581                            mean_inflow_profiles(k,1) ) / a11(k)
582                ELSE
583                   fu(k,j) = 0._wp
584                ENDIF
585
586                IF  ( a22(k) .NE. 0._wp ) THEN
587                fv(k,j) = ( v(k,j,-1) / mc_factor - a21(k) * fu(k,j) - &
588                            mean_inflow_profiles(k,2) ) / a22(k)
589                ELSE
590                   fv(k,j) = 0._wp
591                ENDIF
592
593                IF  ( a33(k) .NE. 0._wp ) THEN
594                fw(k,j) = ( w(k,j,-1) / mc_factor - a31(k) * fu(k,j) - &
595                            a32(k) * fv(k,j) ) / a33(k)
596                ELSE
597                   fw = 0._wp
598                ENDIF
599
600             ENDDO
601          ENDDO
602       ENDIF
603    ENDIF
604
605    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'stop' )
606
607 END SUBROUTINE stg_init
608
609
610!------------------------------------------------------------------------------!
611! Description:
612! ------------
613!> Calculate filter function bxx from length scale nxx following Eg.9 and 10
614!> (Xie and Castro, 2008)
615!------------------------------------------------------------------------------!
616 SUBROUTINE stg_filter_func( nxx, bxx )
617
618
619    IMPLICIT NONE
620
621    INTEGER(iwp) :: k         !< loop index
622    INTEGER(iwp) :: n_k       !< length scale nXX in height k
623    INTEGER(iwp) :: n_k2      !< n_k * 2
624    INTEGER(iwp) :: nf        !< index for length scales
625
626    REAL(wp) :: bdenom        !< denominator for filter functions bXX
627    REAL(wp) :: qsi = 1.0_wp  !< minimization factor
628
629    INTEGER(iwp), DIMENSION(:) :: nxx(nzb:nzt+1)           !< length scale (in gp)
630
631    REAL(wp), DIMENSION(:,:) :: bxx(-merg:merg,nzb:nzt+1)  !< filter function
632
633
634    bxx = 0.0_wp
635
636    DO  k = nzb, nzt+1
637       bdenom = 0.0_wp
638       n_k    = nxx(k)
639       IF ( n_k /= 0 )  THEN
640          n_k2 = n_k * 2
641
642!
643!--       ( Eq.10 )^2
644          DO  nf = -n_k2, n_k2
645             bdenom = bdenom + EXP( -qsi * pi * ABS(nf) / n_k )**2
646          ENDDO
647
648!
649!--       ( Eq.9 )
650          bdenom = SQRT( bdenom )
651          DO  nf = -n_k2, n_k2
652             bxx(nf,k) = EXP( -qsi * pi * ABS(nf) / n_k ) / bdenom
653          ENDDO
654       ENDIF
655    ENDDO
656
657END SUBROUTINE stg_filter_func
658
659
660!------------------------------------------------------------------------------!
661! Description:
662! ------------
663!> Parin for &stg_par for synthetic turbulence generator
664!------------------------------------------------------------------------------!
665 SUBROUTINE stg_parin
666
667
668    IMPLICIT NONE
669
670    CHARACTER (LEN=80) ::  line   !< dummy string that contains the current line of the parameter file
671
672
673    NAMELIST /stg_par/   use_syn_turb_gen
674
675    line = ' '
676
677!
678!-- Try to find stg package
679    REWIND ( 11 )
680    line = ' '
681    DO WHILE ( INDEX( line, '&stg_par' ) == 0 )
682       READ ( 11, '(A)', END=10 )  line
683    ENDDO
684    BACKSPACE ( 11 )
685
686!
687!-- Read namelist
688    READ ( 11, stg_par )
689
690!
691!-- Set flag that indicates that the synthetic turbulence generator is switched
692!-- on
693    syn_turb_gen = .TRUE.
694
695    IF ( TRIM( initializing_actions ) == 'read_restart_data' ) THEN
696       CALL stg_read_restart_data
697    ENDIF
698
699 10 CONTINUE
700
701 END SUBROUTINE stg_parin
702
703
704!------------------------------------------------------------------------------!
705! Description:
706! ------------
707!> Skipping the stg variables from restart-file (binary format).
708!------------------------------------------------------------------------------!
709   SUBROUTINE stg_skip_var_list
710       
711      IMPLICIT NONE
712           
713      CHARACTER (LEN=1)  ::  cdum
714      CHARACTER (LEN=30) ::  variable_chr
715           
716      READ ( 13 )  variable_chr
717
718      DO  WHILE ( TRIM( variable_chr ) /= '*** end stg module ***' )
719
720         READ ( 13 )  cdum
721         READ ( 13 )  variable_chr
722
723      ENDDO   
724           
725   END SUBROUTINE stg_skip_var_list
726
727
728!------------------------------------------------------------------------------!
729! Description:
730! ------------
731!> This routine reads the respective restart data.
732!------------------------------------------------------------------------------!
733 SUBROUTINE stg_read_restart_data
734
735
736    IMPLICIT NONE
737
738    CHARACTER (LEN=30) ::  variable_chr  !< dummy variable to read string
739
740
741    READ ( 13 )  variable_chr
742    DO  WHILE ( TRIM( variable_chr ) /= '*** end stg module ***' )
743
744       SELECT CASE ( TRIM( variable_chr ) )
745
746          CASE ( 'use_syn_turb_gen' )
747             READ ( 13 )  use_syn_turb_gen
748          CASE ( 'mc_factor' )
749             READ ( 13 )  mc_factor
750          CASE ( 'syn_turb_gen_prerun' )
751             READ ( 13 )  syn_turb_gen_prerun
752
753       END SELECT
754
755       READ ( 13 )  variable_chr
756
757    ENDDO
758
759 END SUBROUTINE stg_read_restart_data
760
761
762!------------------------------------------------------------------------------!
763! Description:
764! ------------
765!> This routine writes the respective restart data.
766!------------------------------------------------------------------------------!
767 SUBROUTINE stg_write_restart_data
768
769
770    IMPLICIT NONE
771
772    syn_turb_gen_prerun = .TRUE.
773
774    WRITE ( 14 )  'use_syn_turb_gen              '
775    WRITE ( 14 )  use_syn_turb_gen
776    WRITE ( 14 )  'mc_factor                     '
777    WRITE ( 14 )  mc_factor
778    WRITE ( 14 )  'syn_turb_gen_prerun           '
779    WRITE ( 14 )  syn_turb_gen_prerun
780
781    WRITE ( 14 )  '*** end stg module ***        '
782
783END SUBROUTINE stg_write_restart_data
784
785
786!------------------------------------------------------------------------------!
787! Description:
788! ------------
789!> Create turbulent inflow fields for u, v, w with prescribed length scales and
790!> Reynolds stress tensor after a method of Xie and Castro (2008), modified
791!> following suggestions of Kim et al. (2013), and using a Lund rotation
792!> (Lund, 1998).
793!------------------------------------------------------------------------------!
794 SUBROUTINE stg_main
795
796
797    USE arrays_3d,                                                             &
798        ONLY:  dzw
799
800    USE control_parameters,                                                    &
801        ONLY:  dt_3d, intermediate_timestep_count, simulated_time,             &
802               volume_flow_initial
803
804    USE indices,                                                               &
805        ONLY:  nyn, nys
806
807    USE statistics,                                                            &
808        ONLY:  weight_substep
809
810
811    IMPLICIT NONE
812
813    INTEGER(iwp) :: j           !< loop index in y-direction
814    INTEGER(iwp) :: k           !< loop index in z-direction
815
816    REAL(wp) :: dt_stg          !< wheighted subtimestep
817    REAL(wp) :: mc_factor_l     !< local mass flux correction factor
818
819    REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng,5,nbgp) :: inflow_dist !< disturbance for inflow profiles
820
821
822    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'start' )
823
824!
825!-- Calculate time step which is needed for filter functions
826    dt_stg = dt_3d * weight_substep(intermediate_timestep_count)
827
828!
829!-- Initial value of fu, fv, fw
830    IF ( simulated_time == 0.0_wp .AND. .NOT. velocity_seed_initialized )  THEN
831       CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fu )
832       CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fv )
833       CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fw )
834       velocity_seed_initialized = .TRUE.
835    ENDIF
836!
837!-- New set of fu, fv, fw
838    CALL stg_generate_seed_yz( nuy, nuz, buy, buz, fuo )
839    CALL stg_generate_seed_yz( nvy, nvz, bvy, bvz, fvo )
840    CALL stg_generate_seed_yz( nwy, nwz, bwy, bwz, fwo )
841
842    IF ( myidx == id_inflow )  THEN
843
844       DO  j = nysg, nyng
845          DO  k = nzb, nzt + 1
846!
847!--          Update fu, fv, fw following Eq. 14 of Xie and Castro (2008)
848             IF ( tu(k) == 0.0_wp )  THEN
849                fu(k,j) = fuo(k,j)
850             ELSE
851                fu(k,j) = fu(k,j) * EXP( -pi * dt_stg * 0.5_wp / tu(k) ) +     &
852                         fuo(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tu(k) ) )
853             ENDIF
854
855             IF ( tv(k) == 0.0_wp )  THEN
856                fv(k,j) = fvo(k,j)
857             ELSE
858                fv(k,j) = fv(k,j) * EXP( -pi * dt_stg * 0.5_wp / tv(k) ) +     &
859                         fvo(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tv(k) ) )
860             ENDIF
861
862             IF ( tw(k) == 0.0_wp )  THEN
863                fw(k,j) = fwo(k,j)
864             ELSE
865                fw(k,j) = fw(k,j) * EXP( -pi * dt_stg * 0.5_wp / tw(k) ) +     &
866                         fwo(k,j) * SQRT( 1.0_wp - EXP( -pi * dt_stg / tw(k) ) )
867             ENDIF
868!
869!--          Lund rotation following Eq. 17 in Xie and Castro (2008).
870!--          Additional factors are added to improve the variance of v and w
871             IF( k == 0 )  THEN
872                inflow_dist(k,j,1,1) = 0.0_wp
873                inflow_dist(k,j,2,1) = 0.0_wp
874                inflow_dist(k,j,3,1) = 0.0_wp
875                inflow_dist(k,j,4,1) = 0.0_wp
876                inflow_dist(k,j,5,1) = 0.0_wp
877             ELSE
878                inflow_dist(k,j,1,1) = a11(k) * fu(k,j)
879                !experimental test of 1.2
880                inflow_dist(k,j,2,1) = ( SQRT( a22(k) / MAXVAL(a22) )          &
881                                         * 1.2_wp )                            &
882                                       * (   a21(k) * fu(k,j)                  &
883                                           + a22(k) * fv(k,j) )
884                inflow_dist(k,j,3,1) = ( SQRT(a33(k) / MAXVAL(a33) )           &
885                                         * 1.3_wp )                            &
886                                       * (   a31(k) * fu(k,j)                  &
887                                           + a32(k) * fv(k,j)                  &
888                                           + a33(k) * fw(k,j) )
889                ! Calculation for pt and e not yet implemented
890                inflow_dist(k,j,4,1) = 0.0_wp
891                inflow_dist(k,j,5,1) = 0.0_wp
892             ENDIF
893
894          ENDDO
895       ENDDO
896
897!
898!--    Mass flux correction following Kim et al. (2013)
899!--    This correction factor insures that the mass flux is preserved at the
900!--    inflow boundary
901       mc_factor_l = 0.0_wp
902       mc_factor   = 0.0_wp
903       DO  j = nys, nyn
904          DO  k = nzb+1, nzt
905             mc_factor_l = mc_factor_l + dzw(k)  *                             &
906                           ( mean_inflow_profiles(k,1) + inflow_dist(k,j,1,1) )
907          ENDDO
908       ENDDO
909
910#if defined( __parallel )
911       CALL MPI_ALLREDUCE( mc_factor_l, mc_factor,  &
912                           1, MPI_REAL, MPI_SUM, comm1dy, ierr )
913#else
914       mc_factor = mc_factor_l
915#endif
916
917       mc_factor = volume_flow_initial(1) / mc_factor
918
919!
920!--    Add disturbance at the inflow
921       DO  j = nysg, nyng
922          DO  k = nzb, nzt+1
923              u(k,j,-nbgp+1:0) = ( mean_inflow_profiles(k,1) +                 &
924                                   inflow_dist(k,j,1,1)      ) * mc_factor
925              v(k,j,-nbgp:-1)  = ( mean_inflow_profiles(k,2) +                 &
926                                   inflow_dist(k,j,2,1)      ) * mc_factor
927              w(k,j,-nbgp:-1)  =   inflow_dist(k,j,3,1)        * mc_factor
928          ENDDO
929       ENDDO
930
931    ENDIF
932
933    CALL  cpu_log( log_point(57), 'synthetic_turbulence_gen', 'stop' )
934
935 END SUBROUTINE stg_main
936
937
938!------------------------------------------------------------------------------!
939! Description:
940! ------------
941!> Generate a set of random number rand_it wich is equal on each PE
942!> and calculate the velocity seed f_n.
943!> f_n is splitted in vertical direction by the number of PEs in x-direction and
944!> and each PE calculates a vertical subsection of f_n. At the the end, all
945!> parts are collected to form the full array.
946!------------------------------------------------------------------------------!
947 SUBROUTINE stg_generate_seed_yz( n_y, n_z, b_y, b_z, f_n )
948
949
950    USE indices,                                                               &
951        ONLY: ny
952
953
954    IMPLICIT NONE
955
956    INTEGER(iwp) :: j           !< loop index in y-direction
957    INTEGER(iwp) :: jj          !< loop index in y-direction
958    INTEGER(iwp) :: k           !< loop index in z-direction
959    INTEGER(iwp) :: kk          !< loop index in z-direction
960    INTEGER(iwp) :: send_count  !< send count for MPI_GATHERV
961
962    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_y    !< length scale in y-direction
963    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z    !< length scale in z-direction
964    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_y2   !< n_y*2
965    INTEGER(iwp), DIMENSION(nzb:nzt+1) :: n_z2   !< n_z*2
966
967    REAL(wp) :: nyz_inv         !< inverse of number of grid points in yz-slice
968    REAL(wp) :: rand_av         !< average of random number
969    REAL(wp) :: rand_sigma_inv  !< inverse of stdev of random number
970
971    REAL(wp), DIMENSION(-merg:merg,nzb:nzt+1)    :: b_y     !< filter func in y-dir
972    REAL(wp), DIMENSION(-merg:merg,nzb:nzt+1)    :: b_z     !< filter func in z-dir
973    REAL(wp), DIMENSION(nzb_x:nzt_x+1,nysg:nyng) :: f_n_l   !<  local velocity seed
974    REAL(wp), DIMENSION(nzb:nzt+1,nysg:nyng)     :: f_n     !<  velocity seed
975    REAL(wp), DIMENSION(:,:), ALLOCATABLE        :: rand_it !<  random number
976
977
978!
979!-- Generate random numbers using a seed generated in stg_init.
980!-- The set of random numbers are modified to have an average of 0 and
981!-- unit variance.
982    ALLOCATE( rand_it(nzb-mergp:nzt+1+mergp,-mergp:ny+mergp) )
983
984    rand_av        = 0.0_wp
985    rand_sigma_inv = 0.0_wp
986    nyz_inv        = 1.0_wp / REAL( ( nzt+1 - nzb+1 ) * ( ny+1 ), KIND=wp )
987
988    DO  j = 0, ny
989       DO  k = nzb, nzt+1
990          CALL RANDOM_NUMBER( rand_it(k,j) )
991          rand_av = rand_av + rand_it(k,j)
992       ENDDO
993    ENDDO
994
995    rand_av = rand_av * nyz_inv
996
997    DO  j = 0, ny
998       DO  k = nzb, nzt+1
999          rand_it(k,j)   = rand_it(k,j) - rand_av
1000          rand_sigma_inv = rand_sigma_inv + rand_it(k,j) ** 2
1001       ENDDO
1002    ENDDO
1003
1004    rand_sigma_inv = 1.0_wp / SQRT(rand_sigma_inv * nyz_inv)
1005
1006    DO  j = 0, ny
1007       DO  k = nzb, nzt+1
1008          rand_it(k,j) = rand_it(k,j) * rand_sigma_inv
1009       ENDDO
1010    ENDDO
1011
1012!
1013!-- Periodic fill of random number in space
1014    DO  j = 0, ny
1015       DO  k = 1, mergp
1016          rand_it(nzb  -k,j) = rand_it(nzt+2-k,j)    ! bottom margin
1017          rand_it(nzt+1+k,j) = rand_it(nzb+k-1,j)    ! top margin
1018       ENDDO
1019    ENDDO
1020    DO  j = 1, mergp
1021       DO  k = nzb-mergp, nzt+1+mergp
1022          rand_it(k,  -j) = rand_it(k,ny-j+1)        ! south margin
1023          rand_it(k,ny+j) = rand_it(k,   j-1)        ! north margin
1024       ENDDO
1025    ENDDO
1026
1027!
1028!-- Generate velocity seed following Eq.6 of Xie and Castro (2008)
1029    n_y2 = n_y * 2
1030    n_z2 = n_z * 2
1031    f_n_l  = 0.0_wp
1032
1033    DO  j = nysg, nyng
1034       DO  k = nzb_x, nzt_x+1
1035          DO  jj = -n_y2(k), n_y2(k)
1036             DO  kk = -n_z2(k), n_z2(k)
1037                f_n_l(k,j) = f_n_l(k,j)                                        &
1038                           + b_y(jj,k) * b_z(kk,k) * rand_it(k+kk,j+jj)
1039             ENDDO
1040          ENDDO
1041       ENDDO
1042    ENDDO
1043
1044    DEALLOCATE( rand_it )
1045
1046!
1047!-- Gather velocity seeds of full subdomain
1048    send_count = nzt_x - nzb_x + 1
1049    IF ( nzt_x == nzt )  send_count = send_count + 1
1050
1051#if defined( __parallel )
1052    CALL MPI_GATHERV( f_n_l(nzb_x,nysg), send_count, stg_type_yz_small,        &
1053                      f_n(nzb+1,nysg), recv_count, displs, stg_type_yz,        &
1054                      id_inflow, comm1dx, ierr )
1055#else
1056    f_n(nzb+1:nzt+1,nysg:nyng) = f_n_l(nzb_x:nzt_x+1,nysg:nyng)
1057#endif
1058
1059
1060 END SUBROUTINE stg_generate_seed_yz
1061
1062 END MODULE synthetic_turbulence_generator_mod
Note: See TracBrowser for help on using the repository browser.