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

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

Bugfix: bottom and top boundary condition

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