source: palm/trunk/SOURCE/poismg_mod.f90 @ 4801

Last change on this file since 4801 was 4649, checked in by raasch, 4 years ago

files re-formatted to follow the PALM coding standard

  • Property svn:keywords set to Id
File size: 94.3 KB
Line 
1!> @file poismg.f90
2!--------------------------------------------------------------------------------------------------!
3! This file is part of the PALM model system.
4!
5! PALM is free software: you can redistribute it and/or modify it under the terms of the GNU General
6! Public License as published by the Free Software Foundation, either version 3 of the License, or
7! (at your option) any later version.
8!
9! PALM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
10! implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11! Public License for more details.
12!
13! You should have received a copy of the GNU General Public License along with PALM. If not, see
14! <http://www.gnu.org/licenses/>.
15!
16! Copyright 1997-2020 Leibniz Universitaet Hannover
17!--------------------------------------------------------------------------------------------------!
18!
19!
20! Current revisions:
21! -----------------
22!
23!
24! Former revisions:
25! -----------------
26! $Id: poismg_mod.f90 4649 2020-08-25 12:11:17Z raasch $
27! File re-formatted to follow the PALM coding standard
28!
29!
30! 4457 2020-03-11 14:20:43Z raasch
31! Use statement for exchange horiz added
32!
33! 4432 2020-02-28 07:43:21Z raasch
34! Bugfix for previous revision (vector directive was changed by mistake)
35!
36! 4429 2020-02-27 15:24:30Z raasch
37! Statement added to avoid compile error due to unused dummy argument
38! Bugfix: cpp-directives added for serial mode
39!
40! 4360 2020-01-07 11:25:50Z suehring
41! Corrected "Former revisions" section
42!
43! 3725 2019-02-07 10:11:02Z raasch
44! Unused subroutine removed
45!
46! 3655 2019-01-07 16:51:22Z knoop
47! Unnecessary check eliminated
48!
49! Following optimisations have been made:
50! - Vectorisation (for Intel-CPUs) of the red-black algorithm by resorting array elements with even
51!   and odd indices
52! - Explicit boundary conditions for building walls removed (solver is running through the
53!   buildings)
54! - Reduced data transfer in case of ghost point exchange, because only "red" or "black" data points
55!   need to be exchanged. This is not applied for coarser grid levels, since for then the transfer
56!   time is latency bound
57!
58!
59!--------------------------------------------------------------------------------------------------!
60! Description:
61! ------------
62!> Solves the Poisson equation for the perturbation pressure with a multigrid V- or W-Cycle scheme.
63!>
64!> This multigrid method was originally developed for PALM by Joerg Uhlenbrock,
65!> September 2000 - July 2001. It has been optimised for speed by Klaus Ketelsen in November 2014.
66!>
67!> @attention Loop unrolling and cache optimization in SOR-Red/Black method still does not give the
68!             expected speedup!
69!>
70!> @todo Further work required.
71!--------------------------------------------------------------------------------------------------!
72 MODULE poismg_mod
73
74    USE control_parameters,                                                                        &
75        ONLY:  bc_dirichlet_l,                                                                     &
76               bc_dirichlet_n,                                                                     &
77               bc_dirichlet_r,                                                                     &
78               bc_dirichlet_s,                                                                     &
79               bc_radiation_l,                                                                     &
80               bc_radiation_n,                                                                     &
81               bc_radiation_r,                                                                     &
82               bc_radiation_s,                                                                     &
83               grid_level,                                                                         &
84               nesting_offline
85
86    USE cpulog,                                                                                    &
87        ONLY:  cpu_log,                                                                            &
88               log_point_s
89
90    USE exchange_horiz_mod,                                                                        &
91        ONLY:  exchange_horiz
92
93    USE kinds
94
95    USE pegrid
96
97    PRIVATE
98
99    INTEGER, SAVE                             ::  ind_even_odd    !< border index between even and odd k index
100
101    INTEGER, DIMENSION(:), SAVE, ALLOCATABLE  ::  even_odd_level  !< stores ind_even_odd for all MG levels
102
103    REAL(wp), DIMENSION(:,:), SAVE, ALLOCATABLE ::  f1_mg_b, f2_mg_b, f3_mg_b  !< blocked version of f1_mg ...
104
105    INTERFACE poismg
106       MODULE PROCEDURE poismg
107    END INTERFACE poismg
108
109    INTERFACE sort_k_to_even_odd_blocks
110       MODULE PROCEDURE sort_k_to_even_odd_blocks
111!       MODULE PROCEDURE sort_k_to_even_odd_blocks_int
112       MODULE PROCEDURE sort_k_to_even_odd_blocks_1d
113    END INTERFACE sort_k_to_even_odd_blocks
114
115    PUBLIC poismg
116
117 CONTAINS
118
119!--------------------------------------------------------------------------------------------------!
120! Description:
121! ------------
122!> Solves the Poisson equation for the perturbation pressure with a multigrid V- or W-Cycle scheme.
123!--------------------------------------------------------------------------------------------------!
124 SUBROUTINE poismg( r )
125
126    USE arrays_3d,                                                                                 &
127        ONLY:  d,                                                                                  &
128               p_loc
129
130    USE control_parameters,                                                                        &
131        ONLY:  bc_lr_cyc,                                                                          &
132               bc_ns_cyc,                                                                          &
133               gathered_size,                                                                      &
134               grid_level,                                                                         &
135               grid_level_count,                                                                   &
136               ibc_p_t,                                                                            &
137               maximum_grid_level,                                                                 &
138               message_string,                                                                     &
139               mgcycles,                                                                           &
140               mg_cycles,                                                                          &
141               mg_switch_to_pe0_level,                                                             &
142               residual_limit,                                                                     &
143               subdomain_size
144
145    USE cpulog,                                                                                    &
146        ONLY:  cpu_log,                                                                            &
147               log_point_s
148
149    USE indices,                                                                                   &
150        ONLY:  nxl,                                                                                &
151               nxlg,                                                                               &
152               nxl_mg,                                                                             &
153               nxr,                                                                                &
154               nxrg,                                                                               &
155               nxr_mg,                                                                             &
156               nys,                                                                                &
157               nysg,                                                                               &
158               nys_mg,                                                                             &
159               nyn,                                                                                &
160               nyng,                                                                               &
161               nyn_mg,                                                                             &
162               nzb,                                                                                &
163               nzt,                                                                                &
164               nzt_mg
165
166    IMPLICIT NONE
167
168    REAL(wp) ::  maxerror          !<
169    REAL(wp) ::  maximum_mgcycles  !<
170    REAL(wp) ::  residual_norm     !<
171
172    REAL(wp), DIMENSION(nzb:nzt+1,nys-1:nyn+1,nxl-1:nxr+1) ::  r  !<
173
174    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  p3  !<
175
176
177    CALL cpu_log( log_point_s(29), 'poismg', 'start' )
178!
179!-- Initialize arrays and variables used in this subroutine
180
181!-- If the number of grid points of the gathered grid, which is collected on PE0, is larger than the
182!-- number of grid points of a PE, than array p3 will be enlarged.
183    IF ( gathered_size > subdomain_size )  THEN
184       ALLOCATE( p3(nzb:nzt_mg(mg_switch_to_pe0_level)+1,nys_mg(                                   &
185                 mg_switch_to_pe0_level)-1:nyn_mg(mg_switch_to_pe0_level)+1,                       &
186                 nxl_mg(mg_switch_to_pe0_level)-1:nxr_mg(mg_switch_to_pe0_level)+1) )
187    ELSE
188       ALLOCATE ( p3(nzb:nzt+1,nysg:nyng,nxlg:nxrg) )
189    ENDIF
190
191    p3 = 0.0_wp
192
193
194!
195!-- Ghost boundaries have to be added to divergence array.
196!-- Exchange routine needs to know the grid level!
197    grid_level = maximum_grid_level
198    CALL exchange_horiz( d, 1)
199!
200!-- Set bottom and top boundary conditions
201    d(nzb,:,:) = d(nzb+1,:,:)
202    IF ( ibc_p_t == 1 )  d(nzt+1,:,: ) = d(nzt,:,:)
203!
204!-- Set lateral boundary conditions in non-cyclic case
205    IF ( .NOT. bc_lr_cyc )  THEN
206       IF ( bc_dirichlet_l  .OR.  bc_radiation_l )  d(:,:,nxl-1) = d(:,:,nxl)
207       IF ( bc_dirichlet_r  .OR.  bc_radiation_r )  d(:,:,nxr+1) = d(:,:,nxr)
208    ENDIF
209    IF ( .NOT. bc_ns_cyc )  THEN
210       IF ( bc_dirichlet_n  .OR.  bc_radiation_n )  d(:,nyn+1,:) = d(:,nyn,:)
211       IF ( bc_dirichlet_s  .OR.  bc_radiation_s )  d(:,nys-1,:) = d(:,nys,:)
212    ENDIF
213!
214!-- Initiation of the multigrid scheme. Does n cycles until the residual is smaller than the given
215!-- limit. The accuracy of the solution of the poisson equation will increase with the number of
216!-- cycles. If the number of cycles is preset by the user, this number will be carried out
217!-- regardless of the accuracy.
218    grid_level_count =  0
219    mgcycles         =  0
220    IF ( mg_cycles == -1 )  THEN
221       maximum_mgcycles = 0
222       residual_norm    = 1.0_wp
223    ELSE
224       maximum_mgcycles = mg_cycles
225       residual_norm    = 0.0_wp
226    ENDIF
227
228!
229!-- Initial settings for sorting k-dimension from sequential order (alternate even/odd) into blocks
230!-- of even and odd or vice versa
231    CALL init_even_odd_blocks
232
233!
234!-- Sort input arrays in even/odd blocks along k-dimension
235    CALL sort_k_to_even_odd_blocks( d, grid_level )
236    CALL sort_k_to_even_odd_blocks( p_loc, grid_level )
237
238!
239!-- The complete multigrid cycles are running in block mode, i.e. over seperate data blocks of even
240!-- and odd indices
241    DO WHILE ( residual_norm > residual_limit  .OR.  mgcycles < maximum_mgcycles )
242
243       CALL next_mg_level( d, p_loc, p3, r)
244
245!
246!--    Calculate the residual if the user has not preset the number of cycles to be performed
247       IF ( maximum_mgcycles == 0 )  THEN
248          CALL resid( d, p_loc, r )
249          maxerror = SUM( r(nzb+1:nzt,nys:nyn,nxl:nxr)**2 )
250
251#if defined( __parallel )
252          IF ( collective_wait )  CALL MPI_BARRIER( comm2d, ierr )
253             CALL MPI_ALLREDUCE( maxerror, residual_norm, 1, MPI_REAL, MPI_SUM, comm2d, ierr)
254#else
255             residual_norm = maxerror
256#endif
257          residual_norm = SQRT( residual_norm )
258       ENDIF
259
260       mgcycles = mgcycles + 1
261
262!
263!--    If the user has not limited the number of cycles, stop the run in case of insufficient
264!--    convergence
265       IF ( mgcycles > 1000  .AND.  mg_cycles == -1 )  THEN
266          message_string = 'no sufficient convergence within 1000 cycles'
267          CALL message( 'poismg', 'PA0283', 1, 2, 0, 6, 0 )
268       ENDIF
269
270    ENDDO
271
272    DEALLOCATE( p3 )
273!
274!-- Result has to be sorted back from even/odd blocks to sequential order
275    CALL sort_k_to_sequential( p_loc )
276!
277!-- Unset the grid level. Variable is used to determine the MPI datatypes for ghost point exchange
278    grid_level = 0
279
280    CALL cpu_log( log_point_s(29), 'poismg', 'stop' )
281
282 END SUBROUTINE poismg
283
284
285!--------------------------------------------------------------------------------------------------!
286! Description:
287! ------------
288!> Computes the residual of the perturbation pressure.
289!--------------------------------------------------------------------------------------------------!
290 SUBROUTINE resid( f_mg, p_mg, r )
291
292
293    USE arrays_3d,                                                                                 &
294        ONLY:  rho_air_mg
295
296    USE control_parameters,                                                                        &
297        ONLY:  bc_lr_cyc,                                                                          &
298               bc_ns_cyc,                                                                          &
299               ibc_p_b,                                                                            &
300               ibc_p_t
301
302    USE grid_variables,                                                                            &
303        ONLY:  ddx2_mg,                                                                            &
304               ddy2_mg
305
306    USE indices,                                                                                   &
307        ONLY:  nxl_mg,                                                                             &
308               nxr_mg,                                                                             &
309               nys_mg,                                                                             &
310               nyn_mg,                                                                             &
311               nzb,                                                                                &
312               nzt_mg
313
314    IMPLICIT NONE
315
316    INTEGER(iwp) ::  i    !< index variable along x
317    INTEGER(iwp) ::  j    !< index variable along y
318    INTEGER(iwp) ::  k    !< index variable along z
319    INTEGER(iwp) ::  l    !< index indicating grid level
320    INTEGER(iwp) ::  km1  !< index variable along z dimension (k-1)
321    INTEGER(iwp) ::  kp1  !< index variable along z dimension (k+1)
322
323    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
324                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  f_mg  !< velocity divergence
325    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
326                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  p_mg  !< perturbation pressure
327    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
328                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  r     !< residuum of perturbation pressure
329
330!
331!-- Calculate the residual
332    l = grid_level
333
334    CALL cpu_log( log_point_s(53), 'resid', 'start' )
335    !$OMP PARALLEL PRIVATE (i,j,k,km1,kp1)
336    !$OMP DO
337    DO  i = nxl_mg(l), nxr_mg(l)
338       DO  j = nys_mg(l), nyn_mg(l)
339             !DIR$ IVDEP
340          DO k = ind_even_odd+1, nzt_mg(l)
341             km1 = k-ind_even_odd-1
342             kp1 = k-ind_even_odd
343             r(k,j,i) = f_mg(k,j,i) - rho_air_mg(k,l) * ddx2_mg(l)                                 &
344                        * ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                                        &
345                        - rho_air_mg(k,l) * ddy2_mg(l) * ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )         &
346                        - f2_mg_b(k,l) * p_mg(kp1,j,i) - f3_mg_b(k,l) * p_mg(km1,j,i)              &
347                        + f1_mg_b(k,l) * p_mg(k,j,i)
348          ENDDO
349          !DIR$ IVDEP
350          DO k = nzb+1, ind_even_odd
351             km1 = k+ind_even_odd
352             kp1 = k+ind_even_odd+1
353             r(k,j,i) = f_mg(k,j,i) - rho_air_mg(k,l) * ddx2_mg(l)                                 &
354                        * ( p_mg(k,j,i+1) +  p_mg(k,j,i-1) ) - rho_air_mg(k,l) * ddy2_mg(l)        &
355                        * ( p_mg(k,j+1,i) +  p_mg(k,j-1,i) ) - f2_mg_b(k,l) * p_mg(kp1,j,i)        &
356                        - f3_mg_b(k,l) * p_mg(km1,j,i)       + f1_mg_b(k,l) * p_mg(k,j,i)
357          ENDDO
358       ENDDO
359    ENDDO
360    !$OMP END PARALLEL
361!
362!-- Horizontal boundary conditions
363    CALL exchange_horiz( r, 1)
364
365    IF ( .NOT. bc_lr_cyc )  THEN
366       IF ( bc_dirichlet_l  .OR.  bc_radiation_l )  THEN
367          r(:,:,nxl_mg(l)-1) = r(:,:,nxl_mg(l))
368       ENDIF
369       IF ( bc_dirichlet_r  .OR.  bc_radiation_r )  THEN
370          r(:,:,nxr_mg(l)+1) = r(:,:,nxr_mg(l))
371       ENDIF
372    ENDIF
373
374    IF ( .NOT. bc_ns_cyc )  THEN
375       IF ( bc_dirichlet_n  .OR.  bc_radiation_n )  THEN
376          r(:,nyn_mg(l)+1,:) = r(:,nyn_mg(l),:)
377       ENDIF
378       IF ( bc_dirichlet_s  .OR.  bc_radiation_s )  THEN
379          r(:,nys_mg(l)-1,:) = r(:,nys_mg(l),:)
380       ENDIF
381    ENDIF
382
383!
384!-- Boundary conditions at bottom and top of the domain. Points may be within buildings, but that
385!-- doesn't matter.
386    IF ( ibc_p_b == 1 )  THEN
387!
388!--    Equivalent to r(nzb,:,: ) = r(nzb+1,:,:)
389       r(nzb,:,: ) = r(ind_even_odd+1,:,:)
390    ELSE
391       r(nzb,:,: ) = 0.0_wp
392    ENDIF
393
394    IF ( ibc_p_t == 1 )  THEN
395!
396!--    Equivalent to r(nzt_mg(l)+1,:,: ) = r(nzt_mg(l),:,:)
397       r(nzt_mg(l)+1,:,: ) = r(ind_even_odd,:,:)
398    ELSE
399       r(nzt_mg(l)+1,:,: ) = 0.0_wp
400    ENDIF
401
402    CALL cpu_log( log_point_s(53), 'resid', 'stop' )
403
404 END SUBROUTINE resid
405
406
407!--------------------------------------------------------------------------------------------------!
408! Description:
409! ------------
410!> Interpolates the residual on the next coarser grid with "full weighting" scheme
411!--------------------------------------------------------------------------------------------------!
412 SUBROUTINE restrict( f_mg, r )
413
414
415    USE control_parameters,                                                                        &
416        ONLY:  bc_lr_cyc,                                                                          &
417               bc_ns_cyc,                                                                          &
418               ibc_p_b,                                                                            &
419               ibc_p_t
420
421    USE indices,                                                                                   &
422        ONLY:  nxl_mg,                                                                             &
423               nxr_mg,                                                                             &
424               nys_mg,                                                                             &
425               nyn_mg,                                                                             &
426               nzb,                                                                                &
427               nzt_mg
428
429    IMPLICIT NONE
430
431    INTEGER(iwp) ::  i    !< index variable along x on finer grid
432    INTEGER(iwp) ::  ic   !< index variable along x on coarser grid
433    INTEGER(iwp) ::  j    !< index variable along y on finer grid
434    INTEGER(iwp) ::  jc   !< index variable along y on coarser grid
435    INTEGER(iwp) ::  k    !< index variable along z on finer grid
436    INTEGER(iwp) ::  kc   !< index variable along z on coarser grid
437    INTEGER(iwp) ::  l    !< index indicating finer grid level
438    INTEGER(iwp) ::  km1  !< index variable along z dimension (k-1 on finer level)
439    INTEGER(iwp) ::  kp1  !< index variable along z dimension (k+1 on finer level)
440
441
442    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
443                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  f_mg  !< Residual on coarser grid level
444
445    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level+1)+1,nys_mg(grid_level+1)-1:nyn_mg(grid_level+1)+1,  &
446                        nxl_mg(grid_level+1)-1:nxr_mg(grid_level+1)+1) ::  r  !< Residual on finer grid level
447
448!
449!-- Interpolate the residual
450    l = grid_level
451
452    CALL cpu_log( log_point_s(54), 'restrict', 'start' )
453!
454!-- No wall treatment
455    !$OMP PARALLEL PRIVATE (i,j,k,ic,jc,kc,km1,kp1)
456    !$OMP DO SCHEDULE( STATIC )
457    DO  ic = nxl_mg(l), nxr_mg(l)
458       i = 2 * ic
459       DO  jc = nys_mg(l), nyn_mg(l)
460!
461!--       Calculation for the first point along k
462          j  = 2 * jc
463!
464!--       Calculation for the other points along k
465          !DIR$ IVDEP
466          DO  k = ind_even_odd+1, nzt_mg(l+1)    ! Fine grid at this point
467             km1 = k-ind_even_odd-1
468             kp1 = k-ind_even_odd
469             kc  = k-ind_even_odd               ! Coarse grid index
470
471             f_mg(kc,jc,ic) = 1.0_wp / 64.0_wp                                                     &
472                              * ( 8.0_wp * r(k,j,i) + 4.0_wp * ( r(k,j,i-1)     + r(k,j,i+1)       &
473                                                               + r(k,j+1,i)     + r(k,j-1,i)     ) &
474                                                    + 2.0_wp * ( r(k,j-1,i-1)   + r(k,j+1,i-1)     &
475                                                               + r(k,j-1,i+1)   + r(k,j+1,i+1)   ) &
476                                                    + 4.0_wp * r(km1,j,i)                          &
477                                                    + 2.0_wp * ( r(km1,j,i-1)   + r(km1,j,i+1)     &
478                                                               + r(km1,j+1,i)   + r(km1,j-1,i)   ) &
479                                                             + ( r(km1,j-1,i-1) + r(km1,j+1,i-1)   &
480                                                               + r(km1,j-1,i+1) + r(km1,j+1,i+1) ) &
481                                                    + 4.0_wp * r(kp1,j,i)                          &
482                                                    + 2.0_wp * ( r(kp1,j,i-1)   + r(kp1,j,i+1)     &
483                                                               + r(kp1,j+1,i)   + r(kp1,j-1,i)   ) &
484                                                             + ( r(kp1,j-1,i-1) + r(kp1,j+1,i-1)   &
485                                                               + r(kp1,j-1,i+1) + r(kp1,j+1,i+1) ) &
486                                )
487          ENDDO
488       ENDDO
489    ENDDO
490    !$OMP ENDDO
491    !$OMP END PARALLEL
492
493!
494!-- Ghost point exchange
495    CALL exchange_horiz( f_mg, 1)
496!
497!-- Horizontal boundary conditions
498    IF ( .NOT. bc_lr_cyc )  THEN
499       IF ( bc_dirichlet_l  .OR.  bc_radiation_l )  THEN
500          f_mg(:,:,nxl_mg(l)-1) = f_mg(:,:,nxl_mg(l))
501       ENDIF
502       IF ( bc_dirichlet_r  .OR.  bc_radiation_r )  THEN
503          f_mg(:,:,nxr_mg(l)+1) = f_mg(:,:,nxr_mg(l))
504       ENDIF
505    ENDIF
506
507    IF ( .NOT. bc_ns_cyc )  THEN
508       IF ( bc_dirichlet_n  .OR.  bc_radiation_n )  THEN
509          f_mg(:,nyn_mg(l)+1,:) = f_mg(:,nyn_mg(l),:)
510       ENDIF
511       IF ( bc_dirichlet_s  .OR.  bc_radiation_s )  THEN
512          f_mg(:,nys_mg(l)-1,:) = f_mg(:,nys_mg(l),:)
513       ENDIF
514    ENDIF
515
516!
517!-- Boundary conditions at bottom and top of the domain. These points are not handled by the above
518!-- loop. Points may be within buildings, but that doesn't matter. Remark: f_mg is ordered
519!-- sequentielly after interpolation on coarse grid (is ordered in odd-even blocks further below).
520    IF ( ibc_p_b == 1 )  THEN
521       f_mg(nzb,:,: ) = f_mg(nzb+1,:,:)
522    ELSE
523       f_mg(nzb,:,: ) = 0.0_wp
524    ENDIF
525
526    IF ( ibc_p_t == 1 )  THEN
527       f_mg(nzt_mg(l)+1,:,: ) = f_mg(nzt_mg(l),:,:)
528    ELSE
529       f_mg(nzt_mg(l)+1,:,: ) = 0.0_wp
530    ENDIF
531
532    CALL cpu_log( log_point_s(54), 'restrict', 'stop' )
533!
534!-- Since residual is in sequential order after interpolation, an additional sorting in odd-even
535!-- blocks along z dimension is required at this point.
536    CALL sort_k_to_even_odd_blocks( f_mg , l)
537
538 END SUBROUTINE restrict
539
540
541!--------------------------------------------------------------------------------------------------!
542! Description:
543! ------------
544!> Interpolates the correction of the perturbation pressure to the next finer grid.
545!--------------------------------------------------------------------------------------------------!
546 SUBROUTINE prolong( p, temp )
547
548
549    USE control_parameters,                                                                        &
550        ONLY:  bc_lr_cyc,                                                                          &
551               bc_ns_cyc,                                                                          &
552               ibc_p_b,                                                                            &
553               ibc_p_t
554    USE indices,                                                                                   &
555        ONLY:  nxl_mg,                                                                             &
556               nxr_mg,                                                                             &
557               nys_mg,                                                                             &
558               nyn_mg,                                                                             &
559               nzb,                                                                                &
560               nzt_mg
561
562    IMPLICIT NONE
563
564    INTEGER(iwp) ::  i   !< index variable along x on coarser grid level
565    INTEGER(iwp) ::  j   !< index variable along y on coarser grid level
566    INTEGER(iwp) ::  k   !< index variable along z on coarser grid level
567    INTEGER(iwp) ::  l   !< index indicating finer grid level
568    INTEGER(iwp) ::  kp1 !< index variable along z
569    INTEGER(iwp) ::  ke  !< index for prolog even
570    INTEGER(iwp) ::  ko  !< index for prolog odd
571
572    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level-1)+1,nys_mg(grid_level-1)-1:nyn_mg(grid_level-1)+1,  &
573                        nxl_mg(grid_level-1)-1:nxr_mg(grid_level-1)+1 ) ::  p  !< perturbation pressure on coarser grid level
574
575    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
576                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  temp  !< perturbation pressure on finer grid level
577
578
579    CALL cpu_log( log_point_s(55), 'prolong', 'start' )
580
581!
582!-- First, store elements of the coarser grid on the next finer grid
583    l = grid_level
584    ind_even_odd = even_odd_level(grid_level-1)
585
586    !$OMP PARALLEL PRIVATE (i,j,k,kp1,ke,ko)
587    !$OMP DO
588    DO  i = nxl_mg(l-1), nxr_mg(l-1)
589       DO  j = nys_mg(l-1), nyn_mg(l-1)
590
591          !DIR$ IVDEP
592          DO  k = ind_even_odd+1, nzt_mg(l-1)
593             kp1 = k - ind_even_odd
594             ke  = 2 * ( k-ind_even_odd - 1 ) + 1
595             ko  = 2 * k - 1
596!
597!--          Points of the coarse grid are directly stored on the next finer grid
598             temp(ko,2*j,2*i)   = p(k,j,i)
599!
600!--          Points between two coarse-grid points
601             temp(ko,2*j,2*i+1) = 0.5_wp * ( p(k,j,i) + p(k,j,i+1) )
602             temp(ko,2*j+1,2*i) = 0.5_wp * ( p(k,j,i) + p(k,j+1,i) )
603             temp(ke,2*j,2*i)   = 0.5_wp * ( p(k,j,i) + p(kp1,j,i) )
604!
605!--          Points in the center of the planes stretched by four points of the coarse grid cube
606             temp(ko,2*j+1,2*i+1) = 0.25_wp * ( p(k,j,i)   + p(k,j,i+1) +                          &
607                                                p(k,j+1,i) + p(k,j+1,i+1) )
608             temp(ke,2*j,2*i+1)   = 0.25_wp * ( p(k,j,i)   + p(k,j,i+1) +                          &
609                                                p(kp1,j,i) + p(kp1,j,i+1) )
610             temp(ke,2*j+1,2*i)   = 0.25_wp * ( p(k,j,i)   + p(k,j+1,i) +                          &
611                                                p(kp1,j,i) + p(kp1,j+1,i) )
612!
613!--          Points in the middle of coarse grid cube
614             temp(ke,2*j+1,2*i+1) = 0.125_wp * ( p(k,j,i)     + p(k,j,i+1) + p(k,j+1,i)            &
615                                               + p(k,j+1,i+1) + p(kp1,j,i) + p(kp1,j,i+1)          &
616                                               + p(kp1,j+1,i) + p(kp1,j+1,i+1) )
617
618          ENDDO
619
620          !DIR$ IVDEP
621          DO  k = nzb+1, ind_even_odd
622             kp1 = k + ind_even_odd + 1
623             ke  = 2 * k
624             ko  = 2 * ( k + ind_even_odd )
625!
626!--          Points of the coarse grid are directly stored on the next finer grid
627             temp(ko,2*j,2*i)   = p(k,j,i)
628!
629!--          Points between two coarse-grid points
630             temp(ko,2*j,2*i+1) = 0.5_wp * ( p(k,j,i) + p(k,j,i+1) )
631             temp(ko,2*j+1,2*i) = 0.5_wp * ( p(k,j,i) + p(k,j+1,i) )
632             temp(ke,2*j,2*i)   = 0.5_wp * ( p(k,j,i) + p(kp1,j,i) )
633!
634!--          Points in the center of the planes stretched by four points
635!--          of the coarse grid cube
636             temp(ko,2*j+1,2*i+1) = 0.25_wp * ( p(k,j,i)   + p(k,j,i+1) +                          &
637                                                p(k,j+1,i) + p(k,j+1,i+1) )
638             temp(ke,2*j,2*i+1)   = 0.25_wp * ( p(k,j,i)   + p(k,j,i+1) +                          &
639                                                p(kp1,j,i) + p(kp1,j,i+1) )
640             temp(ke,2*j+1,2*i)   = 0.25_wp * ( p(k,j,i)   + p(k,j+1,i) +                          &
641                                                p(kp1,j,i) + p(kp1,j+1,i) )
642!
643!--          Points in the middle of coarse grid cube
644             temp(ke,2*j+1,2*i+1) = 0.125_wp * ( p(k,j,i)     + p(k,j,i+1) + p(k,j+1,i)            &
645                                               + p(k,j+1,i+1) + p(kp1,j,i) + p(kp1,j,i+1)          &
646                                               + p(kp1,j+1,i) + p(kp1,j+1,i+1) )
647
648          ENDDO
649
650       ENDDO
651    ENDDO
652    !$OMP END PARALLEL
653
654    ind_even_odd = even_odd_level(grid_level)
655!
656!-- Horizontal boundary conditions
657    CALL exchange_horiz( temp, 1)
658
659    IF ( .NOT. bc_lr_cyc )  THEN
660       IF ( bc_dirichlet_l  .OR.  bc_radiation_l )  THEN
661          temp(:,:,nxl_mg(l)-1) = temp(:,:,nxl_mg(l))
662       ENDIF
663       IF ( bc_dirichlet_r  .OR.  bc_radiation_r )  THEN
664          temp(:,:,nxr_mg(l)+1) = temp(:,:,nxr_mg(l))
665       ENDIF
666    ENDIF
667
668    IF ( .NOT. bc_ns_cyc )  THEN
669       IF ( bc_dirichlet_n  .OR.  bc_radiation_n )  THEN
670          temp(:,nyn_mg(l)+1,:) = temp(:,nyn_mg(l),:)
671       ENDIF
672       IF ( bc_dirichlet_s  .OR.  bc_radiation_s )  THEN
673          temp(:,nys_mg(l)-1,:) = temp(:,nys_mg(l),:)
674       ENDIF
675    ENDIF
676
677!
678!-- Bottom and top boundary conditions
679    IF ( ibc_p_b == 1 )  THEN
680!
681!--    Equivalent to temp(nzb,:,: ) = temp(nzb+1,:,:)
682       temp(nzb,:,: ) = temp(ind_even_odd+1,:,:)
683    ELSE
684       temp(nzb,:,: ) = 0.0_wp
685    ENDIF
686
687    IF ( ibc_p_t == 1 )  THEN
688!
689!--    Equivalent to temp(nzt_mg(l)+1,:,: ) = temp(nzt_mg(l),:,:)
690       temp(nzt_mg(l)+1,:,: ) = temp(ind_even_odd,:,:)
691    ELSE
692       temp(nzt_mg(l)+1,:,: ) = 0.0_wp
693    ENDIF
694
695    CALL cpu_log( log_point_s(55), 'prolong', 'stop' )
696
697 END SUBROUTINE prolong
698
699
700!--------------------------------------------------------------------------------------------------!
701! Description:
702! ------------
703!> Relaxation method for the multigrid scheme. A Gauss-Seidel iteration with 3D-Red-Black
704!> decomposition (GS-RB) is used.
705!--------------------------------------------------------------------------------------------------!
706 SUBROUTINE redblack( f_mg, p_mg )
707
708
709    USE arrays_3d,                                                                                 &
710        ONLY:  rho_air_mg
711
712    USE control_parameters,                                                                        &
713        ONLY:  bc_lr_cyc,                                                                          &
714               bc_ns_cyc,                                                                          &
715               ibc_p_b,                                                                            &
716               ibc_p_t,                                                                            &
717               ngsrb
718
719    USE grid_variables,                                                                            &
720        ONLY:  ddx2_mg,                                                                            &
721               ddy2_mg
722
723    USE indices,                                                                                   &
724        ONLY:  nxl_mg,                                                                             &
725               nxr_mg,                                                                             &
726               nys_mg,                                                                             &
727               nyn_mg,                                                                             &
728               nzb,                                                                                &
729               nzt_mg
730
731    IMPLICIT NONE
732
733    INTEGER(iwp) ::  color  !< grid point color, either red or black
734    INTEGER(iwp) ::  i      !< index variable along x
735    INTEGER(iwp) ::  ic     !< index variable along x
736    INTEGER(iwp) ::  j      !< index variable along y
737    INTEGER(iwp) ::  jc     !< index variable along y
738    INTEGER(iwp) ::  jj     !< index variable along y
739    INTEGER(iwp) ::  k      !< index variable along z
740    INTEGER(iwp) ::  km1    !< index variable (k-1)
741    INTEGER(iwp) ::  kp1    !< index variable (k+1)
742    INTEGER(iwp) ::  l      !< grid level
743    INTEGER(iwp) ::  n      !< loop variable Gauß-Seidel iterations
744
745
746    LOGICAL ::  unroll  !< flag indicating whether loop unrolling is possible
747
748    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
749                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  f_mg  !< residual of perturbation pressure
750    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
751                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  p_mg  !< perturbation pressure
752
753    l = grid_level
754
755    unroll = ( MOD( nyn_mg(l)-nys_mg(l)+1, 4 ) == 0  .AND.  MOD( nxr_mg(l)-nxl_mg(l)+1, 2 ) == 0 )
756
757    DO  n = 1, ngsrb
758
759       DO  color = 1, 2
760
761          IF ( .NOT. unroll )  THEN
762
763             CALL cpu_log( log_point_s(36), 'redblack_no_unroll_f', 'start' )
764!
765!--          Without unrolling of loops, no cache optimization
766             !$OMP PARALLEL PRIVATE (i,j,k,km1,kp1)
767             !$OMP DO
768             DO  i = nxl_mg(l), nxr_mg(l), 2
769                DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
770                   !DIR$ IVDEP
771                   DO  k = ind_even_odd+1, nzt_mg(l)
772                      km1 = k-ind_even_odd-1
773                      kp1 = k-ind_even_odd
774                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l)                                          &
775                                    * ( rho_air_mg(k,l) * ddx2_mg(l) *                             &
776                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
777                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
778                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
779                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
780                                    + f3_mg_b(k,l) * p_mg(km1,j,i) - f_mg(k,j,i)                   &
781                                       )
782                   ENDDO
783                ENDDO
784             ENDDO
785
786             !$OMP DO
787             DO  i = nxl_mg(l)+1, nxr_mg(l), 2
788                DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
789                    !DIR$ IVDEP
790                    DO  k = ind_even_odd+1, nzt_mg(l)
791                      km1 = k-ind_even_odd-1
792                      kp1 = k-ind_even_odd
793                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
794                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
795                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
796                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
797                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
798                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
799                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
800                                    - f_mg(k,j,i)           )
801                   ENDDO
802                ENDDO
803             ENDDO
804
805             !$OMP DO
806             DO  i = nxl_mg(l), nxr_mg(l), 2
807                DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
808                   !DIR$ IVDEP
809                   DO  k = nzb+1, ind_even_odd
810                      km1 = k+ind_even_odd
811                      kp1 = k+ind_even_odd+1
812                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
813                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
814                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
815                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
816                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
817                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
818                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
819                                    - f_mg(k,j,i)           )
820                   ENDDO
821                ENDDO
822             ENDDO
823
824             !$OMP DO
825             DO  i = nxl_mg(l)+1, nxr_mg(l), 2
826                DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
827                   !DIR$ IVDEP
828                   DO  k = nzb+1, ind_even_odd
829                      km1 = k+ind_even_odd
830                      kp1 = k+ind_even_odd+1
831                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
832                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
833                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
834                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
835                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
836                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
837                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
838                                    - f_mg(k,j,i)           )
839                   ENDDO
840                ENDDO
841             ENDDO
842             !$OMP END PARALLEL
843
844             CALL cpu_log( log_point_s(36), 'redblack_no_unroll_f', 'stop' )
845
846          ELSE
847!
848!--          Loop unrolling along y, only one i loop for better cache use
849             CALL cpu_log( log_point_s(38), 'redblack_unroll_f', 'start' )
850
851             !$OMP PARALLEL PRIVATE (i,j,k,ic,jc,km1,kp1,jj)
852             !$OMP DO
853             DO  ic = nxl_mg(l), nxr_mg(l), 2
854                DO  jc = nys_mg(l), nyn_mg(l), 4
855                   i  = ic
856                   jj = jc+2-color
857                   !DIR$ IVDEP
858                   DO  k = ind_even_odd+1, nzt_mg(l)
859                      km1 = k-ind_even_odd-1
860                      kp1 = k-ind_even_odd
861                      j   = jj
862                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
863                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
864                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
865                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
866                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
867                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
868                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
869                                    - f_mg(k,j,i)           )
870
871                      j = jj+2
872                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
873                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
874                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
875                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
876                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
877                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
878                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
879                                    - f_mg(k,j,i)           )
880                   ENDDO
881
882                   i  = ic+1
883                   jj = jc+color-1
884                   !DIR$ IVDEP
885                   DO  k = ind_even_odd+1, nzt_mg(l)
886                      km1 = k-ind_even_odd-1
887                      kp1 = k-ind_even_odd
888                      j   = jj
889                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
890                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
891                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
892                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
893                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
894                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
895                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
896                                    - f_mg(k,j,i)           )
897
898                      j = jj+2
899                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
900                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
901                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
902                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
903                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
904                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
905                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
906                                    - f_mg(k,j,i)           )
907                   ENDDO
908
909                   i  = ic
910                   jj = jc+color-1
911                   !DIR$ IVDEP
912                   DO  k = nzb+1, ind_even_odd
913                      km1 = k+ind_even_odd
914                      kp1 = k+ind_even_odd+1
915                      j   = jj
916                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
917                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
918                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
919                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
920                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
921                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
922                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
923                                    - f_mg(k,j,i)           )
924
925                      j = jj+2
926                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
927                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
928                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
929                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
930                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
931                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
932                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
933                                    - f_mg(k,j,i)           )
934                   ENDDO
935
936                   i  = ic+1
937                   jj = jc+2-color
938                   !DIR$ IVDEP
939                   DO  k = nzb+1, ind_even_odd
940                      km1 = k+ind_even_odd
941                      kp1 = k+ind_even_odd+1
942                      j   = jj
943                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
944                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
945                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
946                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
947                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
948                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
949                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
950                                    - f_mg(k,j,i)           )
951
952                      j = jj+2
953                      p_mg(k,j,i) = 1.0_wp / f1_mg_b(k,l) * (                                      &
954                                      rho_air_mg(k,l) * ddx2_mg(l) *                               &
955                                    ( p_mg(k,j,i+1) + p_mg(k,j,i-1) )                              &
956                                    + rho_air_mg(k,l) * ddy2_mg(l) *                               &
957                                    ( p_mg(k,j+1,i) + p_mg(k,j-1,i) )                              &
958                                    + f2_mg_b(k,l) * p_mg(kp1,j,i)                                 &
959                                    + f3_mg_b(k,l) * p_mg(km1,j,i)                                 &
960                                    - f_mg(k,j,i)           )
961                   ENDDO
962
963                ENDDO
964             ENDDO
965             !$OMP END PARALLEL
966
967             CALL cpu_log( log_point_s(38), 'redblack_unroll_f', 'stop' )
968
969          ENDIF
970
971!
972!--       Horizontal boundary conditions
973          CALL special_exchange_horiz( p_mg, color )
974
975          IF ( .NOT. bc_lr_cyc )  THEN
976             IF ( bc_dirichlet_l  .OR.  bc_radiation_l )  THEN
977                p_mg(:,:,nxl_mg(l)-1) = p_mg(:,:,nxl_mg(l))
978             ENDIF
979             IF ( bc_dirichlet_r  .OR.  bc_radiation_r )  THEN
980                p_mg(:,:,nxr_mg(l)+1) = p_mg(:,:,nxr_mg(l))
981             ENDIF
982          ENDIF
983
984          IF ( .NOT. bc_ns_cyc )  THEN
985             IF ( bc_dirichlet_n  .OR.  bc_radiation_n )  THEN
986                p_mg(:,nyn_mg(l)+1,:) = p_mg(:,nyn_mg(l),:)
987             ENDIF
988             IF ( bc_dirichlet_s  .OR.  bc_radiation_s )  THEN
989                p_mg(:,nys_mg(l)-1,:) = p_mg(:,nys_mg(l),:)
990             ENDIF
991          ENDIF
992
993!
994!--       Bottom and top boundary conditions
995          IF ( ibc_p_b == 1 )  THEN
996!
997!--          Equivalent to p_mg(nzb,:,: ) = p_mg(nzb+1,:,:)
998             p_mg(nzb,:,: ) = p_mg(ind_even_odd+1,:,:)
999          ELSE
1000             p_mg(nzb,:,: ) = 0.0_wp
1001          ENDIF
1002
1003          IF ( ibc_p_t == 1 )  THEN
1004!
1005!--          Equivalent to p_mg(nzt_mg(l)+1,:,: ) = p_mg(nzt_mg(l),:,:)
1006             p_mg(nzt_mg(l)+1,:,: ) = p_mg(ind_even_odd,:,:)
1007          ELSE
1008             p_mg(nzt_mg(l)+1,:,: ) = 0.0_wp
1009          ENDIF
1010
1011       ENDDO
1012
1013    ENDDO
1014
1015 END SUBROUTINE redblack
1016
1017
1018!--------------------------------------------------------------------------------------------------!
1019! Description:
1020! ------------
1021!> Sort k-dimension from sequential into blocks of even and odd. This is required to vectorize the
1022!> red-black subroutine. Version for 3D-REAL arrays
1023!--------------------------------------------------------------------------------------------------!
1024 SUBROUTINE sort_k_to_even_odd_blocks( p_mg , glevel )
1025
1026
1027    USE indices,                                                                                   &
1028        ONLY:  nxl_mg,                                                                             &
1029               nxr_mg,                                                                             &
1030               nys_mg,                                                                             &
1031               nyn_mg,                                                                             &
1032               nzb,                                                                                &
1033               nzt_mg
1034
1035    IMPLICIT NONE
1036
1037    INTEGER(iwp), INTENT(IN) ::  glevel  !< grid level
1038
1039    REAL(wp), DIMENSION(nzb:nzt_mg(glevel)+1,nys_mg(glevel)-1:nyn_mg(glevel)+1,                    &
1040                        nxl_mg(glevel)-1:nxr_mg(glevel)+1) ::  p_mg  !< array to be sorted
1041!
1042!-- Local variables
1043    INTEGER(iwp) ::  i    !< index variable along x
1044    INTEGER(iwp) ::  ind  !< index variable along z
1045    INTEGER(iwp) ::  j    !< index variable along y
1046    INTEGER(iwp) ::  k    !< index variable along z
1047    INTEGER(iwp) ::  l    !< grid level
1048
1049    REAL(wp), DIMENSION(nzb:nzt_mg(glevel)+1) ::  tmp  !< odd-even sorted temporary array
1050
1051
1052    CALL cpu_log( log_point_s(52), 'sort_k_to_even_odd', 'start' )
1053
1054    l = glevel
1055    ind_even_odd = even_odd_level(l)
1056
1057    !$OMP PARALLEL PRIVATE (i,j,k,ind,tmp)
1058    !$OMP DO
1059    DO  i = nxl_mg(l)-1, nxr_mg(l)+1
1060       DO  j = nys_mg(l)-1, nyn_mg(l)+1
1061
1062!
1063!--       Sort the data with even k index
1064          ind = nzb-1
1065          DO  k = nzb, nzt_mg(l), 2
1066             ind = ind + 1
1067             tmp(ind) = p_mg(k,j,i)
1068          ENDDO
1069!
1070!--       Sort the data with odd k index
1071          DO  k = nzb+1, nzt_mg(l)+1, 2
1072             ind = ind + 1
1073             tmp(ind) = p_mg(k,j,i)
1074          ENDDO
1075
1076          p_mg(:,j,i) = tmp
1077
1078       ENDDO
1079    ENDDO
1080    !$OMP END PARALLEL
1081
1082    CALL cpu_log( log_point_s(52), 'sort_k_to_even_odd', 'stop' )
1083
1084 END SUBROUTINE sort_k_to_even_odd_blocks
1085
1086
1087!--------------------------------------------------------------------------------------------------!
1088! Description:
1089! ------------
1090!> Sort k-dimension from sequential into blocks of even and odd. This is required to vectorize the
1091!> red-black subroutine. Version for 1D-REAL arrays
1092!--------------------------------------------------------------------------------------------------!
1093 SUBROUTINE sort_k_to_even_odd_blocks_1d( f_mg, f_mg_b, glevel )
1094
1095
1096    USE indices,                                                                                   &
1097        ONLY:  nzb,                                                                                &
1098               nzt_mg
1099
1100    IMPLICIT NONE
1101
1102    INTEGER(iwp), INTENT(IN) ::  glevel  !< grid level
1103
1104    REAL(wp), DIMENSION(nzb+1:nzt_mg(glevel)) ::  f_mg    !< 1D input array
1105    REAL(wp), DIMENSION(nzb:nzt_mg(glevel)+1) ::  f_mg_b  !< 1D output array
1106
1107!
1108!-- Local variables
1109    INTEGER(iwp) ::  ind  !< index variable along z
1110    INTEGER(iwp) ::  k    !< index variable along z
1111
1112
1113    ind = nzb - 1
1114!
1115!-- Sort the data with even k index
1116    DO  k = nzb, nzt_mg(glevel), 2
1117       ind = ind + 1
1118       IF ( k >= nzb+1  .AND.  k <= nzt_mg(glevel) )  THEN
1119          f_mg_b(ind) = f_mg(k)
1120       ENDIF
1121    ENDDO
1122!
1123!-- Sort the data with odd k index
1124    DO  k = nzb+1, nzt_mg(glevel)+1, 2
1125       ind = ind + 1
1126       IF( k >= nzb+1  .AND.  k <= nzt_mg(glevel) )  THEN
1127          f_mg_b(ind) = f_mg(k)
1128       ENDIF
1129    ENDDO
1130
1131 END SUBROUTINE sort_k_to_even_odd_blocks_1d
1132
1133
1134!--------------------------------------------------------------------------------------------------!
1135! Description:
1136! ------------
1137!> Sort k-dimension from sequential into blocks of even and odd. This is required to vectorize the
1138!> red-black subroutine. Version for 2D-INTEGER arrays
1139!--------------------------------------------------------------------------------------------------!
1140! SUBROUTINE sort_k_to_even_odd_blocks_int( i_mg , glevel )
1141!
1142!
1143!    USE indices,                                                            &
1144!        ONLY:  nxl_mg, nxr_mg, nys_mg, nyn_mg, nzb, nzt_mg
1145!
1146!    IMPLICIT NONE
1147!
1148!    INTEGER(iwp), INTENT(IN) ::  glevel  !< grid level
1149!
1150!    INTEGER(iwp), DIMENSION(nzb:nzt_mg(glevel)+1,                           &
1151!                            nys_mg(glevel)-1:nyn_mg(glevel)+1,              &
1152!                            nxl_mg(glevel)-1:nxr_mg(glevel)+1) ::           &
1153!                                 i_mg    !< array to be sorted
1154!!
1155!!-- Local variables
1156!    INTEGER(iwp) :: i        !< index variabel along x
1157!    INTEGER(iwp) :: j        !< index variable along y
1158!    INTEGER(iwp) :: k        !< index variable along z
1159!    INTEGER(iwp) :: l        !< grid level
1160!    INTEGER(iwp) :: ind      !< index variable along z
1161!    INTEGER(iwp),DIMENSION(nzb:nzt_mg(glevel)+1) ::  tmp  !< temporary odd-even sorted array
1162!
1163!
1164!    CALL cpu_log( log_point_s(52), 'sort_k_to_even_odd', 'start' )
1165!
1166!    l = glevel
1167!    ind_even_odd = even_odd_level(l)
1168!
1169!    DO  i = nxl_mg(l)-1, nxr_mg(l)+1
1170!       DO  j = nys_mg(l)-1, nyn_mg(l)+1
1171!
1172!
1173!--       Sort the data with even k index
1174!          ind = nzb-1
1175!          DO  k = nzb, nzt_mg(l), 2
1176!             ind = ind + 1
1177!             tmp(ind) = i_mg(k,j,i)
1178!          ENDDO
1179!
1180!--       Sort the data with odd k index
1181!          DO  k = nzb+1, nzt_mg(l)+1, 2
1182!             ind = ind + 1
1183!             tmp(ind) = i_mg(k,j,i)
1184!          ENDDO
1185!
1186!          i_mg(:,j,i) = tmp
1187!
1188!       ENDDO
1189!    ENDDO
1190!
1191!    CALL cpu_log( log_point_s(52), 'sort_k_to_even_odd', 'stop' )
1192!
1193! END SUBROUTINE sort_k_to_even_odd_blocks_int
1194
1195
1196!--------------------------------------------------------------------------------------------------!
1197! Description:
1198! ------------
1199!> Sort k-dimension from blocks of even and odd into sequential
1200!--------------------------------------------------------------------------------------------------!
1201 SUBROUTINE sort_k_to_sequential( p_mg )
1202
1203
1204    USE control_parameters,                                                                        &
1205        ONLY:  grid_level
1206
1207    USE indices,                                                                                   &
1208        ONLY:  nxl_mg,                                                                             &
1209               nxr_mg,                                                                             &
1210               nys_mg,                                                                             &
1211               nyn_mg,                                                                             &
1212               nzb,                                                                                &
1213               nzt_mg
1214
1215    IMPLICIT NONE
1216
1217    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1218                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  p_mg  !< array to be sorted
1219!
1220!-- Local variables
1221    INTEGER(iwp) ::  i    !< index variable along x
1222    INTEGER(iwp) ::  j    !< index variable along y
1223    INTEGER(iwp) ::  k    !< index variable along z
1224    INTEGER(iwp) ::  l    !< grid level
1225    INTEGER(iwp) ::  ind  !< index variable along z
1226
1227    REAL(wp),DIMENSION(nzb:nzt_mg(grid_level)+1) ::  tmp  !<
1228
1229
1230    l = grid_level
1231
1232    !$OMP PARALLEL PRIVATE (i,j,k,ind,tmp)
1233    !$OMP DO
1234    DO  i = nxl_mg(l)-1, nxr_mg(l)+1
1235       DO  j = nys_mg(l)-1, nyn_mg(l)+1
1236
1237          ind = nzb - 1
1238          tmp = p_mg(:,j,i)
1239          DO  k = nzb, nzt_mg(l), 2
1240             ind = ind + 1
1241             p_mg(k,j,i) = tmp(ind)
1242          ENDDO
1243
1244          DO  k = nzb+1, nzt_mg(l)+1, 2
1245             ind = ind + 1
1246             p_mg(k,j,i) = tmp(ind)
1247          ENDDO
1248       ENDDO
1249    ENDDO
1250    !$OMP END PARALLEL
1251
1252 END SUBROUTINE sort_k_to_sequential
1253
1254
1255!--------------------------------------------------------------------------------------------------!
1256! Description:
1257! ------------
1258!> Gather subdomain data from all PEs.
1259!--------------------------------------------------------------------------------------------------!
1260#if defined( __parallel )
1261 SUBROUTINE mg_gather( f2, f2_sub )
1262
1263    USE control_parameters,                                                                        &
1264        ONLY:  grid_level
1265
1266    USE cpulog,                                                                                    &
1267        ONLY:  cpu_log,                                                                            &
1268               log_point_s
1269
1270    USE indices,                                                                                   &
1271        ONLY:  mg_loc_ind,                                                                         &
1272               nxl_mg,                                                                             &
1273               nxr_mg,                                                                             &
1274               nys_mg,                                                                             &
1275               nyn_mg,                                                                             &
1276               nzb,                                                                                &
1277               nzt_mg
1278
1279    IMPLICIT NONE
1280
1281    INTEGER(iwp) ::  i       !<
1282    INTEGER(iwp) ::  il      !<
1283    INTEGER(iwp) ::  ir      !<
1284    INTEGER(iwp) ::  j       !<
1285    INTEGER(iwp) ::  jn      !<
1286    INTEGER(iwp) ::  js      !<
1287    INTEGER(iwp) ::  k       !<
1288    INTEGER(iwp) ::  nwords  !<
1289
1290    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1291                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  f2  !<
1292    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1293                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  f2_l  !<
1294
1295    REAL(wp), DIMENSION(nzb:mg_loc_ind(5,myid)+1,mg_loc_ind(3,myid)-1:mg_loc_ind(4,myid)+1,        &
1296                        mg_loc_ind(1,myid)-1:mg_loc_ind(2,myid)+1) ::  f2_sub  !<
1297
1298
1299    CALL cpu_log( log_point_s(34), 'mg_gather', 'start' )
1300
1301    f2_l = 0.0_wp
1302
1303!
1304!-- Store the local subdomain array on the total array
1305    js = mg_loc_ind(3,myid)
1306    IF ( south_border_pe )  js = js - 1
1307    jn = mg_loc_ind(4,myid)
1308    IF ( north_border_pe )  jn = jn + 1
1309    il = mg_loc_ind(1,myid)
1310    IF ( left_border_pe )   il = il - 1
1311    ir = mg_loc_ind(2,myid)
1312    IF ( right_border_pe )  ir = ir + 1
1313    DO  i = il, ir
1314       DO  j = js, jn
1315          DO  k = nzb, nzt_mg(grid_level)+1
1316             f2_l(k,j,i) = f2_sub(k,j,i)
1317          ENDDO
1318       ENDDO
1319    ENDDO
1320
1321!
1322!-- Find out the number of array elements of the total array
1323    nwords = SIZE( f2 )
1324
1325!
1326!-- Gather subdomain data from all PEs
1327    IF ( collective_wait )  CALL MPI_BARRIER( comm2d, ierr )
1328    CALL MPI_ALLREDUCE( f2_l(nzb,nys_mg(grid_level)-1,nxl_mg(grid_level)-1),                       &
1329                        f2(nzb,nys_mg(grid_level)-1,nxl_mg(grid_level)-1), nwords, MPI_REAL,       &
1330                        MPI_SUM, comm2d, ierr )
1331
1332    CALL cpu_log( log_point_s(34), 'mg_gather', 'stop' )
1333
1334 END SUBROUTINE mg_gather
1335#endif
1336
1337
1338!--------------------------------------------------------------------------------------------------!
1339! Description:
1340! ------------
1341!> @todo It might be possible to improve the speed of this routine by using non-blocking
1342!>       communication
1343!--------------------------------------------------------------------------------------------------!
1344#if defined( __parallel )
1345 SUBROUTINE mg_scatter( p2, p2_sub )
1346
1347    USE control_parameters,                                                                        &
1348        ONLY:  grid_level
1349
1350    USE cpulog,                                                                                    &
1351        ONLY:  cpu_log,                                                                            &
1352               log_point_s
1353
1354    USE indices,                                                                                   &
1355        ONLY:  mg_loc_ind,                                                                         &
1356               nxl_mg,                                                                             &
1357               nxr_mg,                                                                             &
1358               nys_mg,                                                                             &
1359               nyn_mg,                                                                             &
1360               nzb,                                                                                &
1361               nzt_mg
1362
1363    IMPLICIT NONE
1364
1365    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level-1)+1,nys_mg(grid_level-1)-1:nyn_mg(grid_level-1)+1,  &
1366                        nxl_mg(grid_level-1)-1:nxr_mg(grid_level-1)+1) ::  p2  !<
1367
1368    REAL(wp), DIMENSION(nzb:mg_loc_ind(5,myid)+1,mg_loc_ind(3,myid)-1:mg_loc_ind(4,myid)+1,        &
1369                        mg_loc_ind(1,myid)-1:mg_loc_ind(2,myid)+1) ::  p2_sub  !<
1370
1371
1372    CALL cpu_log( log_point_s(35), 'mg_scatter', 'start' )
1373
1374    p2_sub = p2(:,mg_loc_ind(3,myid)-1:mg_loc_ind(4,myid)+1,                                       &
1375                  mg_loc_ind(1,myid)-1:mg_loc_ind(2,myid)+1)
1376
1377    CALL cpu_log( log_point_s(35), 'mg_scatter', 'stop' )
1378
1379 END SUBROUTINE mg_scatter
1380#endif
1381
1382!--------------------------------------------------------------------------------------------------!
1383! Description:
1384! ------------
1385!> This is where the multigrid technique takes place. V- and W- Cycle are implemented and steered by
1386!> the parameter "gamma". Parameter "nue" determines the convergence of the multigrid iterative
1387!> solution. There are nue times RB-GS iterations. It should be set to "1" or "2", considering the
1388!> time effort one would like to invest. Last choice shows a very good converging factor, but leads
1389!> to an increase in computing time.
1390!--------------------------------------------------------------------------------------------------!
1391 RECURSIVE SUBROUTINE next_mg_level( f_mg, p_mg, p3, r )
1392
1393    USE control_parameters,                                                                        &
1394        ONLY:  bc_lr_dirrad,                                                                       &
1395               bc_lr_raddir,                                                                       &
1396               bc_ns_dirrad,                                                                       &
1397               bc_ns_raddir,                                                                       &
1398               child_domain,                                                                       &
1399               gamma_mg,                                                                           &
1400               grid_level_count,                                                                   &
1401               maximum_grid_level,                                                                 &
1402               mg_switch_to_pe0_level,                                                             &
1403               mg_switch_to_pe0,                                                                   &
1404               ngsrb
1405
1406    USE indices,                                                                                   &
1407        ONLY:  mg_loc_ind,                                                                         &
1408               nxl,                                                                                &
1409               nxl_mg,                                                                             &
1410               nxr,                                                                                &
1411               nxr_mg,                                                                             &
1412               nys,                                                                                &
1413               nys_mg,                                                                             &
1414               nyn,                                                                                &
1415               nyn_mg,                                                                             &
1416               nzb,                                                                                &
1417               nzt,                                                                                &
1418               nzt_mg
1419
1420    IMPLICIT NONE
1421
1422    INTEGER(iwp) ::  i            !< index variable along x
1423    INTEGER(iwp) ::  j            !< index variable along y
1424    INTEGER(iwp) ::  k            !< index variable along z
1425    INTEGER(iwp) ::  nxl_mg_save  !<
1426    INTEGER(iwp) ::  nxr_mg_save  !<
1427    INTEGER(iwp) ::  nyn_mg_save  !<
1428    INTEGER(iwp) ::  nys_mg_save  !<
1429    INTEGER(iwp) ::  nzt_mg_save  !<
1430
1431    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1432                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) :: f_mg  !<
1433    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1434                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) :: p_mg  !<
1435    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1436                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) :: p3    !<
1437    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1438                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) :: r     !<
1439
1440    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level-1)+1,nys_mg(grid_level-1)-1:nyn_mg(grid_level-1)+1,  &
1441                        nxl_mg(grid_level-1)-1:nxr_mg(grid_level-1)+1) ::  f2  !<
1442    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level-1)+1,nys_mg(grid_level-1)-1:nyn_mg(grid_level-1)+1,  &
1443                        nxl_mg(grid_level-1)-1:nxr_mg(grid_level-1)+1) ::  p2  !<
1444
1445    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  f2_sub  !<
1446
1447#if defined( __parallel )
1448    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  p2_sub  !<
1449#endif
1450
1451!
1452!-- Restriction to the coarsest grid
1453 10 IF ( grid_level == 1 )  THEN
1454
1455!
1456!--    Solution on the coarsest grid. Double the number of Gauss-Seidel iterations in order to get a
1457!--    more accurate solution.
1458       ngsrb = 2 * ngsrb
1459
1460       ind_even_odd = even_odd_level(grid_level)
1461
1462       CALL redblack( f_mg, p_mg )
1463
1464       ngsrb = ngsrb / 2
1465
1466
1467    ELSEIF ( grid_level /= 1 )  THEN
1468
1469       grid_level_count(grid_level) = grid_level_count(grid_level) + 1
1470
1471!
1472!--    Solution on the actual grid level
1473       ind_even_odd = even_odd_level(grid_level)
1474
1475       CALL redblack( f_mg, p_mg )
1476
1477!
1478!--    Determination of the actual residual
1479       CALL resid( f_mg, p_mg, r )
1480
1481!--    Restriction of the residual (finer grid values!) to the next coarser grid. Therefore, the
1482!--    grid level has to be decremented now. nxl..nzt have to be set to the coarse grid values,
1483!--    because these variables are needed for the exchange of ghost points in routine exchange_horiz
1484       grid_level = grid_level - 1
1485
1486       nxl = nxl_mg(grid_level)
1487       nys = nys_mg(grid_level)
1488       nxr = nxr_mg(grid_level)
1489       nyn = nyn_mg(grid_level)
1490       nzt = nzt_mg(grid_level)
1491
1492       IF ( grid_level == mg_switch_to_pe0_level )  THEN
1493
1494!
1495!--       From this level on, calculations are done on PE0 only. First, carry out restriction on the
1496!--       subdomain. Therefore, indices of the level have to be changed to subdomain values in
1497!--       between (otherwise, the restrict routine would expect the gathered array).
1498
1499          nxl_mg_save = nxl_mg(grid_level)
1500          nxr_mg_save = nxr_mg(grid_level)
1501          nys_mg_save = nys_mg(grid_level)
1502          nyn_mg_save = nyn_mg(grid_level)
1503          nzt_mg_save = nzt_mg(grid_level)
1504          nxl_mg(grid_level) = mg_loc_ind(1,myid)
1505          nxr_mg(grid_level) = mg_loc_ind(2,myid)
1506          nys_mg(grid_level) = mg_loc_ind(3,myid)
1507          nyn_mg(grid_level) = mg_loc_ind(4,myid)
1508          nzt_mg(grid_level) = mg_loc_ind(5,myid)
1509          nxl = mg_loc_ind(1,myid)
1510          nxr = mg_loc_ind(2,myid)
1511          nys = mg_loc_ind(3,myid)
1512          nyn = mg_loc_ind(4,myid)
1513          nzt = mg_loc_ind(5,myid)
1514
1515          ALLOCATE( f2_sub(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,     &
1516                           nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) )
1517
1518          CALL restrict( f2_sub, r )
1519
1520!
1521!--       Restore the correct indices of this level
1522          nxl_mg(grid_level) = nxl_mg_save
1523          nxr_mg(grid_level) = nxr_mg_save
1524          nys_mg(grid_level) = nys_mg_save
1525          nyn_mg(grid_level) = nyn_mg_save
1526          nzt_mg(grid_level) = nzt_mg_save
1527          nxl = nxl_mg(grid_level)
1528          nxr = nxr_mg(grid_level)
1529          nys = nys_mg(grid_level)
1530          nyn = nyn_mg(grid_level)
1531          nzt = nzt_mg(grid_level)
1532!
1533!--       Gather all arrays from the subdomains on PE0
1534#if defined( __parallel )
1535          CALL mg_gather( f2, f2_sub )
1536#endif
1537
1538!
1539!--       Set switch for routine exchange_horiz, that no ghostpoint exchange has to be carried out
1540!--       from now on
1541          mg_switch_to_pe0 = .TRUE.
1542
1543!
1544!--       In case of non-cyclic lateral boundary conditions, both in- and outflow conditions have to
1545!--       be used on all PEs after the switch, because then they have the total domain.
1546          IF ( bc_lr_dirrad )  THEN
1547             bc_dirichlet_l  = .TRUE.
1548             bc_dirichlet_r  = .FALSE.
1549             bc_radiation_l  = .FALSE.
1550             bc_radiation_r  = .TRUE.
1551          ELSEIF ( bc_lr_raddir )  THEN
1552             bc_dirichlet_l  = .FALSE.
1553             bc_dirichlet_r  = .TRUE.
1554             bc_radiation_l  = .TRUE.
1555             bc_radiation_r  = .FALSE.
1556          ELSEIF ( child_domain  .OR.  nesting_offline )  THEN
1557             bc_dirichlet_l  = .TRUE.
1558             bc_dirichlet_r  = .TRUE.
1559          ENDIF
1560
1561          IF ( bc_ns_dirrad )  THEN
1562             bc_dirichlet_n  = .TRUE.
1563             bc_dirichlet_s  = .FALSE.
1564             bc_radiation_n  = .FALSE.
1565             bc_radiation_s  = .TRUE.
1566          ELSEIF ( bc_ns_raddir )  THEN
1567             bc_dirichlet_n  = .FALSE.
1568             bc_dirichlet_s  = .TRUE.
1569             bc_radiation_n  = .TRUE.
1570             bc_radiation_s  = .FALSE.
1571          ELSEIF ( child_domain  .OR.  nesting_offline)  THEN
1572             bc_dirichlet_s  = .TRUE.
1573             bc_dirichlet_n  = .TRUE.
1574          ENDIF
1575
1576          DEALLOCATE( f2_sub )
1577
1578       ELSE
1579
1580          CALL restrict( f2, r )
1581
1582          ind_even_odd = even_odd_level(grid_level)  ! Must be after restrict
1583
1584       ENDIF
1585
1586       p2 = 0.0_wp
1587
1588!
1589!--    Repeat the same procedure untill the coarsest grid is reached
1590       CALL next_mg_level( f2, p2, p3, r )
1591
1592    ENDIF
1593
1594!
1595!-- Now follows the prolongation
1596    IF ( grid_level >= 2 )  THEN
1597
1598!
1599!--    Prolongation of the new residual. The values are transferred from the coarse to the next
1600!--    finer grid.
1601       IF ( grid_level == mg_switch_to_pe0_level+1 )  THEN
1602
1603#if defined( __parallel )
1604!
1605!--       At this level, the new residual first has to be scattered from PE0 to the other PEs
1606          ALLOCATE( p2_sub(nzb:mg_loc_ind(5,myid)+1,mg_loc_ind(3,myid)-1:mg_loc_ind(4,myid)+1,     &
1607                                                    mg_loc_ind(1,myid)-1:mg_loc_ind(2,myid)+1) )
1608
1609          CALL mg_scatter( p2, p2_sub )
1610
1611!
1612!--       Therefore, indices of the previous level have to be changed to subdomain values in between
1613!--       (otherwise, the prolong routine would expect the gathered array).
1614          nxl_mg_save = nxl_mg(grid_level-1)
1615          nxr_mg_save = nxr_mg(grid_level-1)
1616          nys_mg_save = nys_mg(grid_level-1)
1617          nyn_mg_save = nyn_mg(grid_level-1)
1618          nzt_mg_save = nzt_mg(grid_level-1)
1619          nxl_mg(grid_level-1) = mg_loc_ind(1,myid)
1620          nxr_mg(grid_level-1) = mg_loc_ind(2,myid)
1621          nys_mg(grid_level-1) = mg_loc_ind(3,myid)
1622          nyn_mg(grid_level-1) = mg_loc_ind(4,myid)
1623          nzt_mg(grid_level-1) = mg_loc_ind(5,myid)
1624
1625!
1626!--       Set switch for routine exchange_horiz, that ghost point exchange has to be carried out
1627!--       again from now on
1628          mg_switch_to_pe0 = .FALSE.
1629
1630!
1631!--       For non-cyclic lateral boundary conditions and in case of nesting, restore the in-/outflow
1632!--       conditions.
1633          bc_dirichlet_l = .FALSE.;  bc_dirichlet_r = .FALSE.
1634          bc_dirichlet_n = .FALSE.;  bc_dirichlet_s = .FALSE.
1635          bc_radiation_l = .FALSE.;  bc_radiation_r = .FALSE.
1636          bc_radiation_n = .FALSE.;  bc_radiation_s = .FALSE.
1637
1638          IF ( pleft == MPI_PROC_NULL )  THEN
1639             IF ( bc_lr_dirrad  .OR.  child_domain  .OR.  nesting_offline )  THEN
1640                bc_dirichlet_l = .TRUE.
1641             ELSEIF ( bc_lr_raddir )  THEN
1642                bc_radiation_l = .TRUE.
1643             ENDIF
1644          ENDIF
1645
1646          IF ( pright == MPI_PROC_NULL )  THEN
1647             IF ( bc_lr_dirrad )  THEN
1648                bc_radiation_r = .TRUE.
1649             ELSEIF ( bc_lr_raddir  .OR.  child_domain  .OR.  nesting_offline )  THEN
1650                bc_dirichlet_r = .TRUE.
1651             ENDIF
1652          ENDIF
1653
1654          IF ( psouth == MPI_PROC_NULL )  THEN
1655             IF ( bc_ns_dirrad )  THEN
1656                bc_radiation_s = .TRUE.
1657             ELSEIF ( bc_ns_raddir  .OR.  child_domain  .OR.  nesting_offline )  THEN
1658                bc_dirichlet_s = .TRUE.
1659             ENDIF
1660          ENDIF
1661
1662          IF ( pnorth == MPI_PROC_NULL )  THEN
1663             IF ( bc_ns_dirrad  .OR.  child_domain  .OR.  nesting_offline )  THEN
1664                bc_dirichlet_n = .TRUE.
1665             ELSEIF ( bc_ns_raddir )  THEN
1666                bc_radiation_n = .TRUE.
1667             ENDIF
1668          ENDIF
1669
1670          CALL prolong( p2_sub, p3 )
1671
1672!
1673!--       Restore the correct indices of the previous level
1674          nxl_mg(grid_level-1) = nxl_mg_save
1675          nxr_mg(grid_level-1) = nxr_mg_save
1676          nys_mg(grid_level-1) = nys_mg_save
1677          nyn_mg(grid_level-1) = nyn_mg_save
1678          nzt_mg(grid_level-1) = nzt_mg_save
1679
1680          DEALLOCATE( p2_sub )
1681#endif
1682
1683       ELSE
1684
1685          CALL prolong( p2, p3 )
1686
1687       ENDIF
1688
1689!
1690!--    Computation of the new pressure correction. Therefore, values from prior grids are added up
1691!--    automatically stage by stage.
1692       DO  i = nxl_mg(grid_level)-1, nxr_mg(grid_level)+1
1693          DO  j = nys_mg(grid_level)-1, nyn_mg(grid_level)+1
1694             DO  k = nzb, nzt_mg(grid_level)+1
1695                p_mg(k,j,i) = p_mg(k,j,i) + p3(k,j,i)
1696             ENDDO
1697          ENDDO
1698       ENDDO
1699
1700!
1701!--    Relaxation of the new solution
1702       CALL redblack( f_mg, p_mg )
1703
1704    ENDIF
1705
1706
1707!
1708!-- The following few lines serve the steering of the multigrid scheme
1709    IF ( grid_level == maximum_grid_level )  THEN
1710
1711       GOTO 20
1712
1713    ELSEIF ( grid_level /= maximum_grid_level  .AND.  grid_level /= 1  .AND.                       &
1714             grid_level_count(grid_level) /= gamma_mg )  THEN
1715
1716       GOTO 10
1717
1718    ENDIF
1719
1720!
1721!-- Reset counter for the next call of poismg
1722    grid_level_count(grid_level) = 0
1723
1724!
1725!-- Continue with the next finer level. nxl..nzt have to be set to the finer grid values, because
1726!-- these variables are needed for the exchange of ghost points in routine exchange_horiz.
1727    grid_level = grid_level + 1
1728    ind_even_odd = even_odd_level(grid_level)
1729
1730    nxl = nxl_mg(grid_level)
1731    nxr = nxr_mg(grid_level)
1732    nys = nys_mg(grid_level)
1733    nyn = nyn_mg(grid_level)
1734    nzt = nzt_mg(grid_level)
1735
1736 20 CONTINUE
1737
1738 END SUBROUTINE next_mg_level
1739
1740
1741!--------------------------------------------------------------------------------------------------!
1742! Description:
1743! ------------
1744!> Initial settings for sorting k-dimension from sequential order (alternate even/odd) into blocks
1745!> of even and odd or vice versa
1746!--------------------------------------------------------------------------------------------------!
1747 SUBROUTINE init_even_odd_blocks
1748
1749
1750    USE arrays_3d,                                                                                 &
1751        ONLY:  f1_mg,                                                                              &
1752               f2_mg,                                                                              &
1753               f3_mg
1754
1755    USE control_parameters,                                                                        &
1756        ONLY:  grid_level,                                                                         &
1757               maximum_grid_level
1758
1759    USE indices,                                                                                   &
1760        ONLY:  nzb,                                                                                &
1761               nzt,                                                                                &
1762               nzt_mg
1763
1764    USE indices,                                                                                   &
1765        ONLY:  nzb,                                                                                &
1766               nzt_mg
1767
1768    IMPLICIT NONE
1769!
1770!-- Local variables
1771    INTEGER(iwp) ::  i  !<
1772    INTEGER(iwp) ::  l  !<
1773
1774    LOGICAL, SAVE ::  lfirst = .TRUE.  !<
1775
1776
1777    IF ( .NOT. lfirst )  RETURN
1778
1779    ALLOCATE( even_odd_level(maximum_grid_level) )
1780
1781    ALLOCATE( f1_mg_b(nzb:nzt+1,maximum_grid_level), f2_mg_b(nzb:nzt+1,maximum_grid_level),        &
1782              f3_mg_b(nzb:nzt+1,maximum_grid_level) )
1783
1784!
1785!-- Set border index between the even and odd block
1786    DO  i = maximum_grid_level, 1, -1
1787       even_odd_level(i) = nzt_mg(i) / 2
1788    ENDDO
1789
1790!
1791!-- Sort grid coefficients used in red/black scheme and for calculating the residual to block
1792!-- (even/odd) structure
1793    DO  l = maximum_grid_level, 1 , -1
1794       CALL sort_k_to_even_odd_blocks( f1_mg(nzb+1:nzt_mg(grid_level),l),                          &
1795                                       f1_mg_b(nzb:nzt_mg(grid_level)+1,l), l )
1796       CALL sort_k_to_even_odd_blocks( f2_mg(nzb+1:nzt_mg(grid_level),l),                          &
1797                                       f2_mg_b(nzb:nzt_mg(grid_level)+1,l), l )
1798       CALL sort_k_to_even_odd_blocks( f3_mg(nzb+1:nzt_mg(grid_level),l),                          &
1799                                       f3_mg_b(nzb:nzt_mg(grid_level)+1,l), l )
1800    ENDDO
1801
1802    lfirst = .FALSE.
1803
1804 END SUBROUTINE init_even_odd_blocks
1805
1806
1807!--------------------------------------------------------------------------------------------------!
1808! Description:
1809! ------------
1810!> Special exchange_horiz subroutine for use in redblack. Transfers only "red" or "black" data
1811!> points.
1812!--------------------------------------------------------------------------------------------------!
1813 SUBROUTINE special_exchange_horiz( p_mg, color )
1814
1815
1816    USE control_parameters,                                                                        &
1817        ONLY:  grid_level
1818
1819#if defined( __parallel )
1820    USE control_parameters,                                                                        &
1821        ONLY:  mg_switch_to_pe0_level,                                                             &
1822               synchronous_exchange
1823#endif
1824
1825    USE indices,                                                                                   &
1826        ONLY:  nxl_mg,                                                                             &
1827               nxr_mg,                                                                             &
1828               nys_mg,                                                                             &
1829               nyn_mg,                                                                             &
1830               nzb,                                                                                &
1831               nzt_mg
1832
1833#if defined( __parallel )
1834    USE indices,                                                                                   &
1835        ONLY:  nxl,                                                                                &
1836               nxr,                                                                                &
1837               nys,                                                                                &
1838               nyn,                                                                                &
1839               nzt
1840#endif
1841
1842    IMPLICIT NONE
1843
1844    INTEGER(iwp), INTENT(IN) ::  color  !< flag for grid point type (red or black)
1845
1846    REAL(wp), DIMENSION(nzb:nzt_mg(grid_level)+1,nys_mg(grid_level)-1:nyn_mg(grid_level)+1,        &
1847                        nxl_mg(grid_level)-1:nxr_mg(grid_level)+1) ::  p_mg   !< treated array
1848
1849
1850#if defined ( __parallel )
1851!
1852!-- Local variables
1853    INTEGER(iwp) ::  i    !< index variable along x
1854    INTEGER(iwp) ::  i1   !< index variable along x on coarse level
1855    INTEGER(iwp) ::  i2   !< index variable along x on coarse level
1856
1857    INTEGER(iwp) ::  j    !< index variable along y
1858    INTEGER(iwp) ::  j1   !< index variable along y on coarse level
1859    INTEGER(iwp) ::  j2   !< index variable along y on coarse level
1860    INTEGER(iwp) ::  k    !< index variable along z
1861    INTEGER(iwp) ::  l    !< short for grid level
1862    INTEGER(iwp) ::  jys  !< index for lower local PE boundary along y
1863    INTEGER(iwp) ::  jyn  !< index for upper local PE boundary along y
1864    INTEGER(iwp) ::  ixl  !< index for lower local PE boundary along x
1865    INTEGER(iwp) ::  ixr  !< index for upper local PE boundary along x
1866
1867    LOGICAL ::  synchronous_exchange_save  !< dummy to reset synchronous_exchange to prescribed value
1868
1869    REAL(wp), DIMENSION(:,:,:), ALLOCATABLE ::  temp  !< temporary array on next coarser grid level
1870
1871    synchronous_exchange_save = synchronous_exchange
1872    synchronous_exchange      = .FALSE.
1873
1874    l = grid_level
1875
1876    ind_even_odd = even_odd_level(grid_level)
1877
1878!
1879!-- Restricted transfer only on finer levels with enough data. Restricted transfer is not possible
1880!-- for levels smaller or equal to 'switch to PE0 levels', since array bounds do not fit.
1881!-- Moreover, it is not possible for the coarsest grid level, since the dimensions of temp are not
1882!-- defined. For such cases, normal exchange_horiz is called.
1883    IF ( l > 1 .AND. l > mg_switch_to_pe0_level + 1 .AND.                                          &
1884         ( ngp_xz(grid_level) >= 900 .OR. ngp_yz(grid_level) >= 900 ) )  THEN
1885
1886       jys = nys_mg(grid_level-1)
1887       jyn = nyn_mg(grid_level-1)
1888       ixl = nxl_mg(grid_level-1)
1889       ixr = nxr_mg(grid_level-1)
1890       ALLOCATE( temp(nzb:nzt_mg(l-1)+1,jys-1:jyn+1,ixl-1:ixr+1) )
1891!
1892!--    Handling the even k Values
1893!--    Collecting data for the north - south exchange
1894!--    Since only every second value has to be transfered, data are stored on the next coarser grid
1895!--    level, because the arrays on that level have just the required size
1896       i1 = nxl_mg(grid_level-1)
1897       i2 = nxl_mg(grid_level-1)
1898
1899       DO  i = nxl_mg(l), nxr_mg(l), 2
1900          DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
1901
1902             IF ( j == nys_mg(l) )  THEN
1903                !DIR$ IVDEP
1904                DO  k = ind_even_odd+1, nzt_mg(l)
1905                   temp(k-ind_even_odd,jys,i1) = p_mg(k,j,i)
1906                ENDDO
1907                i1 = i1 + 1
1908
1909             ENDIF
1910
1911             IF ( j == nyn_mg(l) )  THEN
1912                !DIR$ IVDEP
1913                DO  k = ind_even_odd+1, nzt_mg(l)
1914                   temp(k-ind_even_odd,jyn,i2) = p_mg(k,j,i)
1915                ENDDO
1916                i2 = i2 + 1
1917
1918             ENDIF
1919
1920          ENDDO
1921       ENDDO
1922
1923       DO  i = nxl_mg(l)+1, nxr_mg(l), 2
1924          DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
1925
1926             IF ( j == nys_mg(l) )  THEN
1927                !DIR$ IVDEP
1928                DO  k = ind_even_odd+1, nzt_mg(l)
1929                   temp(k-ind_even_odd,jys,i1) = p_mg(k,j,i)
1930                ENDDO
1931                i1 = i1 + 1
1932
1933             ENDIF
1934
1935             IF ( j == nyn_mg(l) )  THEN
1936                !DIR$ IVDEP
1937                DO  k = ind_even_odd+1, nzt_mg(l)
1938                   temp(k-ind_even_odd,jyn,i2) = p_mg(k,j,i)
1939                ENDDO
1940                i2 = i2 + 1
1941
1942             ENDIF
1943
1944          ENDDO
1945       ENDDO
1946
1947       grid_level = grid_level-1
1948
1949       nxl = nxl_mg(grid_level)
1950       nys = nys_mg(grid_level)
1951       nxr = nxr_mg(grid_level)
1952       nyn = nyn_mg(grid_level)
1953       nzt = nzt_mg(grid_level)
1954
1955       send_receive = 'ns'
1956       CALL exchange_horiz( temp, 1 )
1957
1958       grid_level = grid_level+1
1959
1960       i1 = nxl_mg(grid_level-1)
1961       i2 = nxl_mg(grid_level-1)
1962
1963       DO  i = nxl_mg(l), nxr_mg(l), 2
1964          DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
1965
1966             IF ( j == nys_mg(l) )  THEN
1967                !DIR$ IVDEP
1968                DO  k = ind_even_odd+1, nzt_mg(l)
1969                   p_mg(k,nyn_mg(l)+1,i) = temp(k-ind_even_odd,jyn+1,i1)
1970                ENDDO
1971                i1 = i1 + 1
1972
1973             ENDIF
1974
1975             IF ( j == nyn_mg(l) )  THEN
1976                !DIR$ IVDEP
1977                DO  k = ind_even_odd+1, nzt_mg(l)
1978                   p_mg(k,nys_mg(l)-1,i) = temp(k-ind_even_odd,jys-1,i2)
1979                ENDDO
1980                i2 = i2 + 1
1981
1982             ENDIF
1983
1984          ENDDO
1985       ENDDO
1986
1987       DO  i = nxl_mg(l)+1, nxr_mg(l), 2
1988          DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
1989
1990             IF ( j == nys_mg(l) )  THEN
1991                !DIR$ IVDEP
1992                DO  k = ind_even_odd+1, nzt_mg(l)
1993                   p_mg(k,nyn_mg(l)+1,i) = temp(k-ind_even_odd,jyn+1,i1)
1994                ENDDO
1995                i1 = i1 + 1
1996
1997             ENDIF
1998
1999             IF ( j == nyn_mg(l) )  THEN
2000                !DIR$ IVDEP
2001                DO  k = ind_even_odd+1, nzt_mg(l)
2002                   p_mg(k,nys_mg(l)-1,i) = temp(k-ind_even_odd,jys-1,i2)
2003                ENDDO
2004                i2 = i2 + 1
2005
2006             ENDIF
2007
2008          ENDDO
2009       ENDDO
2010
2011!
2012!--    Collecting data for the left - right exchange.
2013!--    Since only every second value has to be transfered, data are stored on the next coarser grid
2014!--    level, because the arrays on that level have just the required size.
2015       j1 = nys_mg(grid_level-1)
2016       j2 = nys_mg(grid_level-1)
2017
2018       DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
2019          DO  i = nxl_mg(l), nxr_mg(l), 2
2020
2021             IF ( i == nxl_mg(l) )  THEN
2022                !DIR$ IVDEP
2023                DO  k = ind_even_odd+1, nzt_mg(l)
2024                   temp(k-ind_even_odd,j1,ixl) = p_mg(k,j,i)
2025                ENDDO
2026                j1 = j1 + 1
2027
2028             ENDIF
2029
2030             IF ( i == nxr_mg(l) )  THEN
2031                !DIR$ IVDEP
2032                DO  k = ind_even_odd+1, nzt_mg(l)
2033                   temp(k-ind_even_odd,j2,ixr) = p_mg(k,j,i)
2034                ENDDO
2035                j2 = j2 + 1
2036
2037             ENDIF
2038
2039          ENDDO
2040       ENDDO
2041
2042       DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
2043          DO  i = nxl_mg(l)+1, nxr_mg(l), 2
2044
2045             IF ( i == nxl_mg(l) )  THEN
2046                !DIR$ IVDEP
2047                DO  k = ind_even_odd+1, nzt_mg(l)
2048                   temp(k-ind_even_odd,j1,ixl) = p_mg(k,j,i)
2049                ENDDO
2050                j1 = j1 + 1
2051
2052             ENDIF
2053
2054             IF ( i == nxr_mg(l) )  THEN
2055                !DIR$ IVDEP
2056                DO  k = ind_even_odd+1, nzt_mg(l)
2057                   temp(k-ind_even_odd,j2,ixr) = p_mg(k,j,i)
2058                ENDDO
2059                j2 = j2 + 1
2060
2061             ENDIF
2062
2063          ENDDO
2064       ENDDO
2065
2066       grid_level = grid_level-1
2067       send_receive = 'lr'
2068
2069       CALL exchange_horiz( temp, 1 )
2070
2071       grid_level = grid_level+1
2072
2073       j1 = nys_mg(grid_level-1)
2074       j2 = nys_mg(grid_level-1)
2075
2076       DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
2077          DO  i = nxl_mg(l), nxr_mg(l), 2
2078
2079             IF ( i == nxl_mg(l) )  THEN
2080                !DIR$ IVDEP
2081                DO  k = ind_even_odd+1, nzt_mg(l)
2082                   p_mg(k,j,nxr_mg(l)+1)  = temp(k-ind_even_odd,j1,ixr+1)
2083                ENDDO
2084                j1 = j1 + 1
2085
2086             ENDIF
2087
2088             IF ( i == nxr_mg(l) )  THEN
2089                !DIR$ IVDEP
2090                DO  k = ind_even_odd+1, nzt_mg(l)
2091                   p_mg(k,j,nxl_mg(l)-1)  = temp(k-ind_even_odd,j2,ixl-1)
2092                ENDDO
2093                j2 = j2 + 1
2094
2095             ENDIF
2096
2097          ENDDO
2098       ENDDO
2099
2100       DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
2101          DO  i = nxl_mg(l)+1, nxr_mg(l), 2
2102
2103             IF ( i == nxl_mg(l) )  THEN
2104                !DIR$ IVDEP
2105                DO  k = ind_even_odd+1, nzt_mg(l)
2106                   p_mg(k,j,nxr_mg(l)+1)  = temp(k-ind_even_odd,j1,ixr+1)
2107                ENDDO
2108                j1 = j1 + 1
2109
2110             ENDIF
2111
2112             IF ( i == nxr_mg(l) )  THEN
2113                !DIR$ IVDEP
2114                DO  k = ind_even_odd+1, nzt_mg(l)
2115                   p_mg(k,j,nxl_mg(l)-1)  = temp(k-ind_even_odd,j2,ixl-1)
2116                ENDDO
2117                j2 = j2 + 1
2118
2119             ENDIF
2120
2121          ENDDO
2122       ENDDO
2123
2124!
2125!--    Now handling the even k values
2126!--    Collecting data for the north - south exchange.
2127!--    Since only every second value has to be transfered, data are stored on the next coarser grid
2128!--    level, because the arrays on that level have just the required size.
2129       i1 = nxl_mg(grid_level-1)
2130       i2 = nxl_mg(grid_level-1)
2131
2132       DO  i = nxl_mg(l), nxr_mg(l), 2
2133          DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
2134
2135             IF ( j == nys_mg(l) )  THEN
2136                !DIR$ IVDEP
2137                DO  k = nzb+1, ind_even_odd
2138                   temp(k,jys,i1) = p_mg(k,j,i)
2139                ENDDO
2140                i1 = i1 + 1
2141
2142             ENDIF
2143
2144             IF ( j == nyn_mg(l) )  THEN
2145                !DIR$ IVDEP
2146                DO  k = nzb+1, ind_even_odd
2147                   temp(k,jyn,i2) = p_mg(k,j,i)
2148                ENDDO
2149                i2 = i2 + 1
2150
2151             ENDIF
2152
2153          ENDDO
2154       ENDDO
2155
2156       DO  i = nxl_mg(l)+1, nxr_mg(l), 2
2157          DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
2158
2159             IF ( j == nys_mg(l) )  THEN
2160                !DIR$ IVDEP
2161                DO  k = nzb+1, ind_even_odd
2162                   temp(k,jys,i1) = p_mg(k,j,i)
2163                ENDDO
2164                i1 = i1 + 1
2165
2166             ENDIF
2167
2168             IF ( j == nyn_mg(l) )  THEN
2169                !DIR$ IVDEP
2170                DO  k = nzb+1, ind_even_odd
2171                   temp(k,jyn,i2) = p_mg(k,j,i)
2172                ENDDO
2173                i2 = i2 + 1
2174
2175             ENDIF
2176
2177          ENDDO
2178       ENDDO
2179
2180       grid_level = grid_level-1
2181
2182       send_receive = 'ns'
2183       CALL exchange_horiz( temp, 1 )
2184
2185       grid_level = grid_level+1
2186
2187       i1 = nxl_mg(grid_level-1)
2188       i2 = nxl_mg(grid_level-1)
2189
2190       DO  i = nxl_mg(l), nxr_mg(l), 2
2191          DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
2192
2193             IF ( j == nys_mg(l) )  THEN
2194                !DIR$ IVDEP
2195                DO  k = nzb+1, ind_even_odd
2196                   p_mg(k,nyn_mg(l)+1,i) = temp(k,jyn+1,i1)
2197                ENDDO
2198                i1 = i1 + 1
2199
2200             ENDIF
2201
2202             IF ( j == nyn_mg(l) )  THEN
2203                !DIR$ IVDEP
2204                DO  k = nzb+1, ind_even_odd
2205                   p_mg(k,nys_mg(l)-1,i) = temp(k,jys-1,i2)
2206                ENDDO
2207                i2 = i2 + 1
2208
2209             ENDIF
2210
2211          ENDDO
2212       ENDDO
2213
2214       DO  i = nxl_mg(l)+1, nxr_mg(l), 2
2215          DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
2216
2217             IF ( j == nys_mg(l) )  THEN
2218                !DIR$ IVDEP
2219                DO  k = nzb+1, ind_even_odd
2220                   p_mg(k,nyn_mg(l)+1,i) = temp(k,jyn+1,i1)
2221                ENDDO
2222                i1 = i1 + 1
2223
2224             ENDIF
2225
2226             IF ( j == nyn_mg(l) )  THEN
2227                !DIR$ IVDEP
2228                DO  k = nzb+1, ind_even_odd
2229                   p_mg(k,nys_mg(l)-1,i) = temp(k,jys-1,i2)
2230                ENDDO
2231                i2 = i2 + 1
2232
2233             ENDIF
2234
2235          ENDDO
2236       ENDDO
2237
2238       j1 = nys_mg(grid_level-1)
2239       j2 = nys_mg(grid_level-1)
2240
2241       DO  i = nxl_mg(l), nxr_mg(l), 2
2242          DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
2243
2244             IF ( i == nxl_mg(l) )  THEN
2245                !DIR$ IVDEP
2246                DO  k = nzb+1, ind_even_odd
2247                   temp(k,j1,ixl) = p_mg(k,j,i)
2248                ENDDO
2249                j1 = j1 + 1
2250
2251             ENDIF
2252
2253             IF ( i == nxr_mg(l) )  THEN
2254                !DIR$ IVDEP
2255                DO  k = nzb+1, ind_even_odd
2256                   temp(k,j2,ixr) = p_mg(k,j,i)
2257                ENDDO
2258                j2 = j2 + 1
2259
2260             ENDIF
2261
2262          ENDDO
2263       ENDDO
2264
2265       DO  i = nxl_mg(l)+1, nxr_mg(l), 2
2266          DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
2267
2268             IF ( i == nxl_mg(l) )  THEN
2269                !DIR$ IVDEP
2270                DO  k = nzb+1, ind_even_odd
2271                   temp(k,j1,ixl) = p_mg(k,j,i)
2272                ENDDO
2273                j1 = j1 + 1
2274
2275             ENDIF
2276
2277             IF ( i == nxr_mg(l) )  THEN
2278                !DIR$ IVDEP
2279                DO  k = nzb+1, ind_even_odd
2280                   temp(k,j2,ixr) = p_mg(k,j,i)
2281                ENDDO
2282                j2 = j2 + 1
2283
2284             ENDIF
2285
2286          ENDDO
2287       ENDDO
2288
2289       grid_level = grid_level-1
2290
2291       send_receive = 'lr'
2292       CALL exchange_horiz( temp, 1 )
2293
2294       grid_level = grid_level+1
2295
2296       nxl = nxl_mg(grid_level)
2297       nys = nys_mg(grid_level)
2298       nxr = nxr_mg(grid_level)
2299       nyn = nyn_mg(grid_level)
2300       nzt = nzt_mg(grid_level)
2301
2302       j1 = nys_mg(grid_level-1)
2303       j2 = nys_mg(grid_level-1)
2304
2305       DO  i = nxl_mg(l), nxr_mg(l), 2
2306          DO  j = nys_mg(l) + (color-1), nyn_mg(l), 2
2307
2308             IF ( i == nxl_mg(l) )  THEN
2309                !DIR$ IVDEP
2310                DO  k = nzb+1, ind_even_odd
2311                   p_mg(k,j,nxr_mg(l)+1)  = temp(k,j1,ixr+1)
2312                ENDDO
2313                j1 = j1 + 1
2314
2315             ENDIF
2316
2317             IF ( i == nxr_mg(l) )  THEN
2318                !DIR$ IVDEP
2319                DO  k = nzb+1, ind_even_odd
2320                   p_mg(k,j,nxl_mg(l)-1)  = temp(k,j2,ixl-1)
2321                ENDDO
2322                j2 = j2 + 1
2323
2324             ENDIF
2325
2326          ENDDO
2327       ENDDO
2328
2329       DO  i = nxl_mg(l)+1, nxr_mg(l), 2
2330          DO  j = nys_mg(l) + 2 - color, nyn_mg(l), 2
2331
2332             IF ( i == nxl_mg(l) )  THEN
2333                !DIR$ IVDEP
2334                DO  k = nzb+1, ind_even_odd
2335                   p_mg(k,j,nxr_mg(l)+1)  = temp(k,j1,ixr+1)
2336                ENDDO
2337                j1 = j1 + 1
2338
2339             ENDIF
2340
2341             IF ( i == nxr_mg(l) )  THEN
2342                !DIR$ IVDEP
2343                DO  k = nzb+1, ind_even_odd
2344                   p_mg(k,j,nxl_mg(l)-1)  = temp(k,j2,ixl-1)
2345                ENDDO
2346                j2 = j2 + 1
2347
2348             ENDIF
2349
2350          ENDDO
2351       ENDDO
2352
2353       DEALLOCATE( temp )
2354
2355    ELSE
2356
2357!
2358!--    Standard horizontal ghost boundary exchange for small coarse grid levels, where the transfer
2359!--    time is latency bound
2360       CALL exchange_horiz( p_mg, 1 )
2361
2362    ENDIF
2363
2364!
2365!-- Reset values to default PALM setup
2366    synchronous_exchange   = synchronous_exchange_save
2367    send_receive = 'al'
2368#else
2369
2370!
2371!-- Next line is to avoid compiler error due to unused dummy argument
2372    IF ( color == 1234567 )  RETURN
2373!
2374!-- Standard horizontal ghost boundary exchange for small coarse grid levels, where the transfer
2375!-- time is latency bound.
2376    CALL exchange_horiz( p_mg, 1 )
2377#endif
2378
2379 END SUBROUTINE special_exchange_horiz
2380
2381 END MODULE poismg_mod
Note: See TracBrowser for help on using the repository browser.