source: palm/trunk/SOURCE/tridia_solver.f90 @ 1815

Last change on this file since 1815 was 1815, checked in by raasch, 9 years ago

cpp-switches removed + cpp-bugfixes + zero-settings for velocities inside topography re-activated

  • Property svn:keywords set to Id
File size: 22.2 KB
Line 
1!> @file tridia_solver.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-2014 Leibniz Universitaet Hannover
17!--------------------------------------------------------------------------------!
18!
19! Current revisions:
20! ------------------
21! cpp-switch intel11 removed
22!
23! Former revisions:
24! -----------------
25! $Id: tridia_solver.f90 1815 2016-04-06 13:49:59Z raasch $
26!
27! 1808 2016-04-05 19:44:00Z raasch
28! test output removed
29!
30! 1804 2016-04-05 16:30:18Z maronga
31! Removed code for parameter file check (__check)
32!
33! 1682 2015-10-07 23:56:08Z knoop
34! Code annotations made doxygen readable
35!
36! 1406 2014-05-16 13:47:01Z raasch
37! bugfix for pgi 14.4: declare create moved after array declaration
38!
39! 1342 2014-03-26 17:04:47Z kanani
40! REAL constants defined as wp-kind
41!
42! 1322 2014-03-20 16:38:49Z raasch
43! REAL functions provided with KIND-attribute
44!
45! 1320 2014-03-20 08:40:49Z raasch
46! ONLY-attribute added to USE-statements,
47! kind-parameters added to all INTEGER and REAL declaration statements,
48! kinds are defined in new module kinds,
49! old module precision_kind is removed,
50! revision history before 2012 removed,
51! comment fields (!:) to be used for variable explanations added to
52! all variable declaration statements
53!
54! 1257 2013-11-08 15:18:40Z raasch
55! openacc loop and loop vector clauses removed, declare create moved after
56! the FORTRAN declaration statement
57!
58! 1221 2013-09-10 08:59:13Z raasch
59! dummy argument tri in 1d-routines replaced by tri_for_1d because of name
60! conflict with arry tri in module arrays_3d
61!
62! 1216 2013-08-26 09:31:42Z raasch
63! +tridia_substi_overlap for handling overlapping fft / transposition
64!
65! 1212 2013-08-15 08:46:27Z raasch
66! Initial revision.
67! Routines have been moved to seperate module from former file poisfft to here.
68! The tridiagonal matrix coefficients of array tri are calculated only once at
69! the beginning, i.e. routine split is called within tridia_init.
70!
71!
72! Description:
73! ------------
74!> solves the linear system of equations:
75!>
76!> -(4 pi^2(i^2/(dx^2*nnx^2)+j^2/(dy^2*nny^2))+
77!>   1/(dzu(k)*dzw(k))+1/(dzu(k-1)*dzw(k)))*p(i,j,k)+
78!> 1/(dzu(k)*dzw(k))*p(i,j,k+1)+1/(dzu(k-1)*dzw(k))*p(i,j,k-1)=d(i,j,k)
79!>
80!> by using the Thomas algorithm
81!------------------------------------------------------------------------------!
82 MODULE tridia_solver
83 
84
85    USE indices,                                                               &
86        ONLY:  nx, ny, nz
87
88    USE kinds
89
90    USE transpose_indices,                                                     &
91        ONLY:  nxl_z, nyn_z, nxr_z, nys_z
92
93    IMPLICIT NONE
94
95    REAL(wp), DIMENSION(:,:), ALLOCATABLE ::  ddzuw !<
96
97    PRIVATE
98
99    INTERFACE tridia_substi
100       MODULE PROCEDURE tridia_substi
101    END INTERFACE tridia_substi
102
103    INTERFACE tridia_substi_overlap
104       MODULE PROCEDURE tridia_substi_overlap
105    END INTERFACE tridia_substi_overlap
106
107    PUBLIC  tridia_substi, tridia_substi_overlap, tridia_init, tridia_1dd
108
109 CONTAINS
110
111
112!------------------------------------------------------------------------------!
113! Description:
114! ------------
115!> @todo Missing subroutine description.
116!------------------------------------------------------------------------------!
117    SUBROUTINE tridia_init
118
119       USE arrays_3d,                                                          &
120           ONLY:  ddzu_pres, ddzw
121
122       USE kinds
123
124       IMPLICIT NONE
125
126       INTEGER(iwp) ::  k !<
127
128       ALLOCATE( ddzuw(0:nz-1,3) )
129
130       DO  k = 0, nz-1
131          ddzuw(k,1) = ddzu_pres(k+1) * ddzw(k+1)
132          ddzuw(k,2) = ddzu_pres(k+2) * ddzw(k+1)
133          ddzuw(k,3) = -1.0_wp * &
134                       ( ddzu_pres(k+2) * ddzw(k+1) + ddzu_pres(k+1) * ddzw(k+1) )
135       ENDDO
136!
137!--    Calculate constant coefficients of the tridiagonal matrix
138       CALL maketri
139       CALL split
140
141    END SUBROUTINE tridia_init
142
143
144!------------------------------------------------------------------------------!
145! Description:
146! ------------
147!> Computes the i- and j-dependent component of the matrix
148!> Provide the constant coefficients of the tridiagonal matrix for solution
149!> of the Poisson equation in Fourier space.
150!> The coefficients are computed following the method of
151!> Schmidt et al. (DFVLR-Mitteilung 84-15), which departs from Stephan
152!> Siano's original version by discretizing the Poisson equation,
153!> before it is Fourier-transformed.
154!------------------------------------------------------------------------------!
155    SUBROUTINE maketri
156
157
158          USE arrays_3d,                                                       &
159              ONLY:  tric
160
161          USE constants,                                                       &
162              ONLY:  pi
163
164          USE control_parameters,                                              &
165              ONLY:  ibc_p_b, ibc_p_t
166
167          USE grid_variables,                                                  &
168              ONLY:  dx, dy
169
170
171          USE kinds
172
173          IMPLICIT NONE
174
175          INTEGER(iwp) ::  i    !<
176          INTEGER(iwp) ::  j    !<
177          INTEGER(iwp) ::  k    !<
178          INTEGER(iwp) ::  nnxh !<
179          INTEGER(iwp) ::  nnyh !<
180
181          REAL(wp)    ::  ll(nxl_z:nxr_z,nys_z:nyn_z) !<
182          !$acc declare create( ll )
183
184
185          nnxh = ( nx + 1 ) / 2
186          nnyh = ( ny + 1 ) / 2
187
188          !$acc kernels present( tric )
189          DO  j = nys_z, nyn_z
190             DO  i = nxl_z, nxr_z
191                IF ( j >= 0  .AND.  j <= nnyh )  THEN
192                   IF ( i >= 0  .AND.  i <= nnxh )  THEN
193                      ll(i,j) = 2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * i ) / &
194                                            REAL( nx+1, KIND=wp ) ) ) / ( dx * dx ) + &
195                                2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * j ) / &
196                                            REAL( ny+1, KIND=wp ) ) ) / ( dy * dy )
197                   ELSE
198                      ll(i,j) = 2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * ( nx+1-i ) ) / &
199                                            REAL( nx+1, KIND=wp ) ) ) / ( dx * dx ) + &
200                                2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * j ) / &
201                                            REAL( ny+1, KIND=wp ) ) ) / ( dy * dy )
202                   ENDIF
203                ELSE
204                   IF ( i >= 0  .AND.  i <= nnxh )  THEN
205                      ll(i,j) = 2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * i ) / &
206                                            REAL( nx+1, KIND=wp ) ) ) / ( dx * dx ) + &
207                                2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * ( ny+1-j ) ) / &
208                                            REAL( ny+1, KIND=wp ) ) ) / ( dy * dy )
209                   ELSE
210                      ll(i,j) = 2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * ( nx+1-i ) ) / &
211                                            REAL( nx+1, KIND=wp ) ) ) / ( dx * dx ) + &
212                                2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * ( ny+1-j ) ) / &
213                                            REAL( ny+1, KIND=wp ) ) ) / ( dy * dy )
214                   ENDIF
215                ENDIF
216             ENDDO
217          ENDDO
218
219          DO  k = 0, nz-1
220             DO  j = nys_z, nyn_z
221                DO  i = nxl_z, nxr_z
222                   tric(i,j,k) = ddzuw(k,3) - ll(i,j)
223                ENDDO
224             ENDDO
225          ENDDO
226          !$acc end kernels
227
228          IF ( ibc_p_b == 1 )  THEN
229             !$acc kernels present( tric )
230             DO  j = nys_z, nyn_z
231                DO  i = nxl_z, nxr_z
232                   tric(i,j,0) = tric(i,j,0) + ddzuw(0,1)
233                ENDDO
234             ENDDO
235             !$acc end kernels
236          ENDIF
237          IF ( ibc_p_t == 1 )  THEN
238             !$acc kernels present( tric )
239             DO  j = nys_z, nyn_z
240                DO  i = nxl_z, nxr_z
241                   tric(i,j,nz-1) = tric(i,j,nz-1) + ddzuw(nz-1,2)
242                ENDDO
243             ENDDO
244             !$acc end kernels
245          ENDIF
246
247    END SUBROUTINE maketri
248
249
250!------------------------------------------------------------------------------!
251! Description:
252! ------------
253!> Substitution (Forward and Backward) (Thomas algorithm)
254!------------------------------------------------------------------------------!
255    SUBROUTINE tridia_substi( ar )
256
257
258          USE arrays_3d,                                                       & 
259              ONLY:  tri
260
261          USE control_parameters,                                              &
262              ONLY:  ibc_p_b, ibc_p_t
263
264          USE kinds
265
266          IMPLICIT NONE
267
268          INTEGER(iwp) ::  i !<
269          INTEGER(iwp) ::  j !<
270          INTEGER(iwp) ::  k !<
271
272          REAL(wp)     ::  ar(nxl_z:nxr_z,nys_z:nyn_z,1:nz) !<
273
274          REAL(wp), DIMENSION(nxl_z:nxr_z,nys_z:nyn_z,0:nz-1)   ::  ar1 !<
275          !$acc declare create( ar1 )
276
277!
278!--       Forward substitution
279          DO  k = 0, nz - 1
280             !$acc kernels present( ar, tri )
281             DO  j = nys_z, nyn_z
282                DO  i = nxl_z, nxr_z
283
284                   IF ( k == 0 )  THEN
285                      ar1(i,j,k) = ar(i,j,k+1)
286                   ELSE
287                      ar1(i,j,k) = ar(i,j,k+1) - tri(i,j,k,2) * ar1(i,j,k-1)
288                   ENDIF
289
290                ENDDO
291             ENDDO
292             !$acc end kernels
293          ENDDO
294
295!
296!--       Backward substitution
297!--       Note, the 1.0E-20 in the denominator is due to avoid divisions
298!--       by zero appearing if the pressure bc is set to neumann at the top of
299!--       the model domain.
300          DO  k = nz-1, 0, -1
301             !$acc kernels present( ar, tri )
302             DO  j = nys_z, nyn_z
303                DO  i = nxl_z, nxr_z
304
305                   IF ( k == nz-1 )  THEN
306                      ar(i,j,k+1) = ar1(i,j,k) / ( tri(i,j,k,1) + 1.0E-20_wp )
307                   ELSE
308                      ar(i,j,k+1) = ( ar1(i,j,k) - ddzuw(k,2) * ar(i,j,k+2) ) &
309                              / tri(i,j,k,1)
310                   ENDIF
311                ENDDO
312             ENDDO
313             !$acc end kernels
314          ENDDO
315
316!
317!--       Indices i=0, j=0 correspond to horizontally averaged pressure.
318!--       The respective values of ar should be zero at all k-levels if
319!--       acceleration of horizontally averaged vertical velocity is zero.
320          IF ( ibc_p_b == 1  .AND.  ibc_p_t == 1 )  THEN
321             IF ( nys_z == 0  .AND.  nxl_z == 0 )  THEN
322                !$acc kernels loop present( ar )
323                DO  k = 1, nz
324                   ar(nxl_z,nys_z,k) = 0.0_wp
325                ENDDO
326                !$acc end kernels loop
327             ENDIF
328          ENDIF
329
330    END SUBROUTINE tridia_substi
331
332
333!------------------------------------------------------------------------------!
334! Description:
335! ------------
336!> Substitution (Forward and Backward) (Thomas algorithm)
337!------------------------------------------------------------------------------!
338    SUBROUTINE tridia_substi_overlap( ar, jj )
339
340
341          USE arrays_3d,                                                       &
342              ONLY:  tri
343
344          USE control_parameters,                                              &
345              ONLY:  ibc_p_b, ibc_p_t
346
347          USE kinds
348
349          IMPLICIT NONE
350
351          INTEGER(iwp) ::  i  !<
352          INTEGER(iwp) ::  j  !<
353          INTEGER(iwp) ::  jj !<
354          INTEGER(iwp) ::  k  !<
355
356          REAL(wp)     ::  ar(nxl_z:nxr_z,nys_z:nyn_z,1:nz) !<
357
358          REAL(wp), DIMENSION(nxl_z:nxr_z,nys_z:nyn_z,0:nz-1) ::  ar1 !<
359          !$acc declare create( ar1 )
360
361!
362!--       Forward substitution
363          DO  k = 0, nz - 1
364             !$acc kernels present( ar, tri )
365             !$acc loop
366             DO  j = nys_z, nyn_z
367                DO  i = nxl_z, nxr_z
368
369                   IF ( k == 0 )  THEN
370                      ar1(i,j,k) = ar(i,j,k+1)
371                   ELSE
372                      ar1(i,j,k) = ar(i,j,k+1) - tri(i,jj,k,2) * ar1(i,j,k-1)
373                   ENDIF
374
375                ENDDO
376             ENDDO
377             !$acc end kernels
378          ENDDO
379
380!
381!--       Backward substitution
382!--       Note, the 1.0E-20 in the denominator is due to avoid divisions
383!--       by zero appearing if the pressure bc is set to neumann at the top of
384!--       the model domain.
385          DO  k = nz-1, 0, -1
386             !$acc kernels present( ar, tri )
387             !$acc loop
388             DO  j = nys_z, nyn_z
389                DO  i = nxl_z, nxr_z
390
391                   IF ( k == nz-1 )  THEN
392                      ar(i,j,k+1) = ar1(i,j,k) / ( tri(i,jj,k,1) + 1.0E-20_wp )
393                   ELSE
394                      ar(i,j,k+1) = ( ar1(i,j,k) - ddzuw(k,2) * ar(i,j,k+2) ) &
395                              / tri(i,jj,k,1)
396                   ENDIF
397                ENDDO
398             ENDDO
399             !$acc end kernels
400          ENDDO
401
402!
403!--       Indices i=0, j=0 correspond to horizontally averaged pressure.
404!--       The respective values of ar should be zero at all k-levels if
405!--       acceleration of horizontally averaged vertical velocity is zero.
406          IF ( ibc_p_b == 1  .AND.  ibc_p_t == 1 )  THEN
407             IF ( nys_z == 0  .AND.  nxl_z == 0 )  THEN
408                !$acc kernels loop present( ar )
409                DO  k = 1, nz
410                   ar(nxl_z,nys_z,k) = 0.0_wp
411                ENDDO
412             ENDIF
413          ENDIF
414
415    END SUBROUTINE tridia_substi_overlap
416
417
418!------------------------------------------------------------------------------!
419! Description:
420! ------------
421!> Splitting of the tridiagonal matrix (Thomas algorithm)
422!------------------------------------------------------------------------------!
423    SUBROUTINE split
424
425
426          USE arrays_3d,                                                       & 
427              ONLY:  tri, tric
428
429          USE kinds
430
431          IMPLICIT NONE
432
433          INTEGER(iwp) ::  i !<
434          INTEGER(iwp) ::  j !<
435          INTEGER(iwp) ::  k !<
436!
437!--       Splitting
438          !$acc kernels present( tri, tric )
439          !$acc loop
440          DO  j = nys_z, nyn_z
441             !$acc loop vector( 32 )
442             DO  i = nxl_z, nxr_z
443                tri(i,j,0,1) = tric(i,j,0)
444             ENDDO
445          ENDDO
446          !$acc end kernels
447
448          DO  k = 1, nz-1
449             !$acc kernels present( tri, tric )
450             !$acc loop
451             DO  j = nys_z, nyn_z
452                !$acc loop vector( 32 )
453                DO  i = nxl_z, nxr_z
454                   tri(i,j,k,2) = ddzuw(k,1) / tri(i,j,k-1,1)
455                   tri(i,j,k,1) = tric(i,j,k) - ddzuw(k-1,2) * tri(i,j,k,2)
456                ENDDO
457             ENDDO
458             !$acc end kernels
459          ENDDO
460
461    END SUBROUTINE split
462
463
464!------------------------------------------------------------------------------!
465! Description:
466! ------------
467!> Solves the linear system of equations for a 1d-decomposition along x (see
468!> tridia)
469!>
470!> @attention when using the intel compilers older than 12.0, array tri must
471!>            be passed as an argument to the contained subroutines. Otherwise
472!>            addres faults will occur. This feature can be activated with
473!>            cpp-switch __intel11
474!>            On NEC, tri should not be passed (except for routine substi_1dd)
475!>            because this causes very bad performance.
476!------------------------------------------------------------------------------!
477 
478    SUBROUTINE tridia_1dd( ddx2, ddy2, nx, ny, j, ar, tri_for_1d )
479
480
481       USE arrays_3d,                                                          &
482           ONLY:  ddzu_pres, ddzw
483
484       USE control_parameters,                                                 &
485           ONLY:  ibc_p_b, ibc_p_t
486
487       USE kinds
488
489       IMPLICIT NONE
490
491       INTEGER(iwp) ::  i                  !<
492       INTEGER(iwp) ::  j                  !<
493       INTEGER(iwp) ::  k                  !<
494       INTEGER(iwp) ::  nnyh               !<
495       INTEGER(iwp) ::  nx                 !<
496       INTEGER(iwp) ::  ny                 !<
497       INTEGER(iwp) ::  omp_get_thread_num !<
498       INTEGER(iwp) ::  tn                 !<
499
500       REAL(wp)     ::  ddx2 !<
501       REAL(wp)     ::  ddy2 !<
502
503       REAL(wp), DIMENSION(0:nx,1:nz)     ::  ar         !<
504       REAL(wp), DIMENSION(5,0:nx,0:nz-1) ::  tri_for_1d !<
505
506
507       nnyh = ( ny + 1 ) / 2
508
509!
510!--    Define constant elements of the tridiagonal matrix.
511!--    The compiler on SX6 does loop exchange. If 0:nx is a high power of 2,
512!--    the exchanged loops create bank conflicts. The following directive
513!--    prohibits loop exchange and the loops perform much better.
514!CDIR NOLOOPCHG
515       DO  k = 0, nz-1
516          DO  i = 0,nx
517             tri_for_1d(2,i,k) = ddzu_pres(k+1) * ddzw(k+1)
518             tri_for_1d(3,i,k) = ddzu_pres(k+2) * ddzw(k+1)
519          ENDDO
520       ENDDO
521
522       IF ( j <= nnyh )  THEN
523          CALL maketri_1dd( j )
524       ELSE
525          CALL maketri_1dd( ny+1-j )
526       ENDIF
527
528       CALL split_1dd
529       CALL substi_1dd( ar, tri_for_1d )
530
531    CONTAINS
532
533
534!------------------------------------------------------------------------------!
535! Description:
536! ------------
537!> computes the i- and j-dependent component of the matrix
538!------------------------------------------------------------------------------!
539       SUBROUTINE maketri_1dd( j )
540
541          USE constants,                                                       &
542              ONLY:  pi
543
544          USE kinds
545
546          IMPLICIT NONE
547
548          INTEGER(iwp) ::  i    !<
549          INTEGER(iwp) ::  j    !<
550          INTEGER(iwp) ::  k    !<
551          INTEGER(iwp) ::  nnxh !<
552
553          REAL(wp)     ::  a !<
554          REAL(wp)     ::  c !<
555
556          REAL(wp), DIMENSION(0:nx) ::  l !<
557
558
559          nnxh = ( nx + 1 ) / 2
560!
561!--       Provide the tridiagonal matrix for solution of the Poisson equation in
562!--       Fourier space. The coefficients are computed following the method of
563!--       Schmidt et al. (DFVLR-Mitteilung 84-15), which departs from Stephan
564!--       Siano's original version by discretizing the Poisson equation,
565!--       before it is Fourier-transformed
566          DO  i = 0, nx
567             IF ( i >= 0 .AND. i <= nnxh ) THEN
568                l(i) = 2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * i ) / &
569                                   REAL( nx+1, KIND=wp ) ) ) * ddx2 + &
570                       2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * j ) / &
571                                   REAL( ny+1, KIND=wp ) ) ) * ddy2
572             ELSE
573                l(i) = 2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * ( nx+1-i ) ) / &
574                                   REAL( nx+1, KIND=wp ) ) ) * ddx2 + &
575                       2.0_wp * ( 1.0_wp - COS( ( 2.0_wp * pi * j ) / &
576                                   REAL( ny+1, KIND=wp ) ) ) * ddy2
577             ENDIF
578          ENDDO
579
580          DO  k = 0, nz-1
581             DO  i = 0, nx
582                a = -1.0_wp * ddzu_pres(k+2) * ddzw(k+1)
583                c = -1.0_wp * ddzu_pres(k+1) * ddzw(k+1)
584                tri_for_1d(1,i,k) = a + c - l(i)
585             ENDDO
586          ENDDO
587          IF ( ibc_p_b == 1 )  THEN
588             DO  i = 0, nx
589                tri_for_1d(1,i,0) = tri_for_1d(1,i,0) + tri_for_1d(2,i,0)
590             ENDDO
591          ENDIF
592          IF ( ibc_p_t == 1 )  THEN
593             DO  i = 0, nx
594                tri_for_1d(1,i,nz-1) = tri_for_1d(1,i,nz-1) + tri_for_1d(3,i,nz-1)
595             ENDDO
596          ENDIF
597
598       END SUBROUTINE maketri_1dd
599
600
601!------------------------------------------------------------------------------!
602! Description:
603! ------------
604!> Splitting of the tridiagonal matrix (Thomas algorithm)
605!------------------------------------------------------------------------------!
606       SUBROUTINE split_1dd
607
608          IMPLICIT NONE
609
610          INTEGER(iwp) ::  i !<
611          INTEGER(iwp) ::  k !<
612
613
614!
615!--       Splitting
616          DO  i = 0, nx
617             tri_for_1d(4,i,0) = tri_for_1d(1,i,0)
618          ENDDO
619          DO  k = 1, nz-1
620             DO  i = 0, nx
621                tri_for_1d(5,i,k) = tri_for_1d(2,i,k) / tri_for_1d(4,i,k-1)
622                tri_for_1d(4,i,k) = tri_for_1d(1,i,k) - tri_for_1d(3,i,k-1) * tri_for_1d(5,i,k)
623             ENDDO
624          ENDDO
625
626       END SUBROUTINE split_1dd
627
628
629!------------------------------------------------------------------------------!
630! Description:
631! ------------
632!> Substitution (Forward and Backward) (Thomas algorithm)
633!------------------------------------------------------------------------------!
634       SUBROUTINE substi_1dd( ar, tri_for_1d )
635
636
637          IMPLICIT NONE
638
639          INTEGER(iwp) ::  i !<
640          INTEGER(iwp) ::  k !<
641
642          REAL(wp), DIMENSION(0:nx,nz)       ::  ar         !<
643          REAL(wp), DIMENSION(0:nx,0:nz-1)   ::  ar1        !<
644          REAL(wp), DIMENSION(5,0:nx,0:nz-1) ::  tri_for_1d !<
645
646!
647!--       Forward substitution
648          DO  i = 0, nx
649             ar1(i,0) = ar(i,1)
650          ENDDO
651          DO  k = 1, nz-1
652             DO  i = 0, nx
653                ar1(i,k) = ar(i,k+1) - tri_for_1d(5,i,k) * ar1(i,k-1)
654             ENDDO
655          ENDDO
656
657!
658!--       Backward substitution
659!--       Note, the add of 1.0E-20 in the denominator is due to avoid divisions
660!--       by zero appearing if the pressure bc is set to neumann at the top of
661!--       the model domain.
662          DO  i = 0, nx
663             ar(i,nz) = ar1(i,nz-1) / ( tri_for_1d(4,i,nz-1) + 1.0E-20_wp )
664          ENDDO
665          DO  k = nz-2, 0, -1
666             DO  i = 0, nx
667                ar(i,k+1) = ( ar1(i,k) - tri_for_1d(3,i,k) * ar(i,k+2) ) &
668                            / tri_for_1d(4,i,k)
669             ENDDO
670          ENDDO
671
672!
673!--       Indices i=0, j=0 correspond to horizontally averaged pressure.
674!--       The respective values of ar should be zero at all k-levels if
675!--       acceleration of horizontally averaged vertical velocity is zero.
676          IF ( ibc_p_b == 1  .AND.  ibc_p_t == 1 )  THEN
677             IF ( j == 0 )  THEN
678                DO  k = 1, nz
679                   ar(0,k) = 0.0_wp
680                ENDDO
681             ENDIF
682          ENDIF
683
684       END SUBROUTINE substi_1dd
685
686    END SUBROUTINE tridia_1dd
687
688
689 END MODULE tridia_solver
Note: See TracBrowser for help on using the repository browser.