source: palm/trunk/SOURCE/tridia_solver_mod.f90 @ 4851

Last change on this file since 4851 was 4828, checked in by Giersch, 4 years ago

Copyright updated to year 2021, interface pmc_sort removed to accelarate the nesting code

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