source: palm/trunk/SOURCE/poismg_fast_mod.f90 @ 1901

Last change on this file since 1901 was 1899, checked in by suehring, 8 years ago

last commit documented

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