PyFishPack 0.1.0__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. PyFishPack/__init__.py +86 -0
  2. PyFishPack/__pycache__/__init__.cpython-313.pyc +0 -0
  3. PyFishPack/__pycache__/apps.cpython-313.pyc +0 -0
  4. PyFishPack/_dummy.c +23 -0
  5. PyFishPack/_dummy.cp313-win_amd64.pyd +0 -0
  6. PyFishPack/apps.py +3640 -0
  7. PyFishPack/fishpack.cp313-win_amd64.dll.a +0 -0
  8. PyFishPack/fishpack.cp313-win_amd64.pyd +0 -0
  9. PyFishPack/meson.build +213 -0
  10. PyFishPack/src/archive/f77/Makefile +19 -0
  11. PyFishPack/src/archive/f77/blktri.f +1404 -0
  12. PyFishPack/src/archive/f77/cblktri.f +1414 -0
  13. PyFishPack/src/archive/f77/cmgnbn.f +1592 -0
  14. PyFishPack/src/archive/f77/comf.f +186 -0
  15. PyFishPack/src/archive/f77/fftpack.f +2968 -0
  16. PyFishPack/src/archive/f77/genbun.f +1335 -0
  17. PyFishPack/src/archive/f77/gnbnaux.f +314 -0
  18. PyFishPack/src/archive/f77/hstcrt.f +443 -0
  19. PyFishPack/src/archive/f77/hstcsp.f +683 -0
  20. PyFishPack/src/archive/f77/hstcyl.f +485 -0
  21. PyFishPack/src/archive/f77/hstplr.f +538 -0
  22. PyFishPack/src/archive/f77/hstssp.f +634 -0
  23. PyFishPack/src/archive/f77/hw3crt.f +687 -0
  24. PyFishPack/src/archive/f77/hwscrt.f +512 -0
  25. PyFishPack/src/archive/f77/hwscsp.f +728 -0
  26. PyFishPack/src/archive/f77/hwscyl.f +538 -0
  27. PyFishPack/src/archive/f77/hwsplr.f +602 -0
  28. PyFishPack/src/archive/f77/hwsssp.f +780 -0
  29. PyFishPack/src/archive/f77/pois3d.f +550 -0
  30. PyFishPack/src/archive/f77/poistg.f +875 -0
  31. PyFishPack/src/archive/f77/sepaux.f +361 -0
  32. PyFishPack/src/archive/f77/sepeli.f +1029 -0
  33. PyFishPack/src/archive/f77/sepx4.f +958 -0
  34. PyFishPack/src/centered_axisymmetric_spherical_solver.f90 +1002 -0
  35. PyFishPack/src/centered_cartesian_helmholtz_solver_3d.f90 +819 -0
  36. PyFishPack/src/centered_cartesian_solver.f90 +583 -0
  37. PyFishPack/src/centered_cylindrical_solver.f90 +634 -0
  38. PyFishPack/src/centered_helmholtz_solvers.f90 +156 -0
  39. PyFishPack/src/centered_polar_solver.f90 +746 -0
  40. PyFishPack/src/centered_real_linear_systems_solver.f90 +280 -0
  41. PyFishPack/src/centered_spherical_solver.f90 +928 -0
  42. PyFishPack/src/complex_block_tridiagonal_linear_systems_solver.f90 +1947 -0
  43. PyFishPack/src/complex_linear_systems_solver.f90 +1787 -0
  44. PyFishPack/src/fftpack_c_api.f90 +86 -0
  45. PyFishPack/src/fishpack.f90 +191 -0
  46. PyFishPack/src/fishpack.pyf +504 -0
  47. PyFishPack/src/fishpack_c_api.f90 +365 -0
  48. PyFishPack/src/fishpack_original.pyf +2119 -0
  49. PyFishPack/src/fishpack_precision.f90 +53 -0
  50. PyFishPack/src/general_linear_systems_solver_3d.f90 +296 -0
  51. PyFishPack/src/iterative_solvers.f90 +969 -0
  52. PyFishPack/src/main.f90 +10 -0
  53. PyFishPack/src/pyfishpack_module.c +1302 -0
  54. PyFishPack/src/real_block_tridiagonal_linear_systems_solver.f90 +319 -0
  55. PyFishPack/src/sepeli.f90 +1454 -0
  56. PyFishPack/src/sepx4.f90 +1338 -0
  57. PyFishPack/src/staggered_axisymmetric_spherical_solver.f90 +908 -0
  58. PyFishPack/src/staggered_cartesian_solver.f90 +553 -0
  59. PyFishPack/src/staggered_cylindrical_solver.f90 +630 -0
  60. PyFishPack/src/staggered_helmholtz_solvers.f90 +172 -0
  61. PyFishPack/src/staggered_polar_solver.f90 +651 -0
  62. PyFishPack/src/staggered_real_linear_systems_solver.f90 +258 -0
  63. PyFishPack/src/staggered_spherical_solver.f90 +758 -0
  64. PyFishPack/src/three_dimensional_solvers.f90 +602 -0
  65. PyFishPack/src/type_CenteredCyclicReductionUtility.f90 +1714 -0
  66. PyFishPack/src/type_CyclicReductionUtility.f90 +472 -0
  67. PyFishPack/src/type_FishpackWorkspace.f90 +290 -0
  68. PyFishPack/src/type_GeneralizedCyclicReductionUtility.f90 +1980 -0
  69. PyFishPack/src/type_PeriodicFastFourierTransform.f90 +3789 -0
  70. PyFishPack/src/type_SepAux.f90 +586 -0
  71. PyFishPack/src/type_StaggeredCyclicReductionUtility.f90 +893 -0
  72. pyfishpack-0.1.0.dist-info/DELVEWHEEL +2 -0
  73. pyfishpack-0.1.0.dist-info/METADATA +81 -0
  74. pyfishpack-0.1.0.dist-info/RECORD +81 -0
  75. pyfishpack-0.1.0.dist-info/WHEEL +5 -0
  76. pyfishpack-0.1.0.dist-info/licenses/LICENSE +21 -0
  77. pyfishpack-0.1.0.dist-info/top_level.txt +1 -0
  78. pyfishpack.libs/libgcc_s_seh-1-25d59ccffa1a9009644065b069829e07.dll +0 -0
  79. pyfishpack.libs/libgfortran-5-08f2195cfa0d823e13371c5c3186a82a.dll +0 -0
  80. pyfishpack.libs/libquadmath-0-c5abb9113f1ee64b87a889958e4b7418.dll +0 -0
  81. pyfishpack.libs/libwinpthread-1-83908d14abfafb8b3bfa38cf51ecee56.dll +0 -0
@@ -0,0 +1,1714 @@
1
+ !
2
+ ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3
+ ! * *
4
+ ! * copyright (c) 2005 by UCAR *
5
+ ! * *
6
+ ! * University Corporation for Atmospheric Research *
7
+ ! * *
8
+ ! * all rights reserved *
9
+ ! * *
10
+ ! * Fishpack *
11
+ ! * *
12
+ ! * A Package of Fortran *
13
+ ! * *
14
+ ! * Subroutines and Example Programs *
15
+ ! * *
16
+ ! * for Modeling Geophysical Processes *
17
+ ! * *
18
+ ! * by *
19
+ ! * *
20
+ ! * John Adams, Paul Swarztrauber and Roland Sweet *
21
+ ! * *
22
+ ! * of *
23
+ ! * *
24
+ ! * the National Center for Atmospheric Research *
25
+ ! * *
26
+ ! * Boulder, Colorado (80307) U.S.A. *
27
+ ! * *
28
+ ! * which is sponsored by *
29
+ ! * *
30
+ ! * the National Science Foundation *
31
+ ! * *
32
+ ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33
+ !
34
+ ! SUBROUTINE genbun(nperod, n, mperod, m, a, b, c, idimy, y, ierror)
35
+ !
36
+ !
37
+ ! DIMENSION OF a(m), b(m), c(m), y(idimy, n)
38
+ ! ARGUMENTS
39
+ !
40
+ ! LATEST REVISION April 2016
41
+ !
42
+ ! PURPOSE The name of this package is a mnemonic for the
43
+ ! generalized buneman algorithm.
44
+ !
45
+ ! It solves the real linear system of equations
46
+ !
47
+ ! a(i)*x(i-1, j) + b(i)*x(i, j) + c(i)*x(i+1, j)
48
+ ! + x(i, j-1) - 2.0*x(i, j) + x(i, j+1) = y(i, j)
49
+ !
50
+ ! for i = 1, 2, ..., m and j = 1, 2, ..., n.
51
+ !
52
+ ! indices i+1 and i-1 are evaluated modulo m,
53
+ ! i.e., x(0, j) = x(m, j) and x(m+1, j) = x(1, j),
54
+ ! and x(i, 0) may equal 0, x(i, 2), or x(i, n),
55
+ ! and x(i, n+1) may equal 0, x(i, n-1), or x(i, 1)
56
+ ! depending on an input parameter.
57
+ !
58
+ ! USAGE call genbun(nperod, n, mperod, m, a, b, c, idimy, y, ierror)
59
+ !
60
+ ! ARGUMENTS
61
+ !
62
+ ! ON INPUT nperod
63
+ !
64
+ ! Indicates the values that x(i, 0) and
65
+ ! x(i, n+1) are assumed to have.
66
+ !
67
+ ! = 0 if x(i, 0) = x(i, n) and x(i, n+1) =
68
+ ! x(i, 1).
69
+ ! = 1 if x(i, 0) = x(i, n+1) = 0 .
70
+ ! = 2 if x(i, 0) = 0 and x(i, n+1) = x(i, n-1).
71
+ ! = 3 if x(i, 0) = x(i, 2) and x(i, n+1) =
72
+ ! x(i, n-1).
73
+ ! = 4 if x(i, 0) = x(i, 2) and x(i, n+1) = 0.
74
+ !
75
+ ! n
76
+ ! The number of unknowns in the j-direction.
77
+ ! n must be greater than 2.
78
+ !
79
+ ! mperod
80
+ ! = 0 if a(1) and c(m) are not zero
81
+ ! = 1 if a(1) = c(m) = 0
82
+ !
83
+ ! m
84
+ ! The number of unknowns in the i-direction.
85
+ ! n must be greater than 2.
86
+ !
87
+ ! a, b, c
88
+ ! One-dimensional arrays of length m that
89
+ ! specify the coefficients in the linear
90
+ ! equations given above. if mperod = 0
91
+ ! the array elements must not depend upon
92
+ ! the index i, but must be constant.
93
+ ! specifically, the subroutine checks the
94
+ ! following condition .
95
+ !
96
+ ! a(i) = c(1)
97
+ ! c(i) = c(1)
98
+ ! b(i) = b(1)
99
+ !
100
+ ! for i=1, 2, ..., m.
101
+ !
102
+ ! idimy
103
+ ! The row (or first) dimension of the
104
+ ! two-dimensional array y as it appears
105
+ ! in the program calling genbun.
106
+ ! this parameter is used to specify the
107
+ ! variable dimension of y.
108
+ ! idimy must be at least m.
109
+ !
110
+ ! y
111
+ ! A two-dimensional complex array that
112
+ ! specifies the values of the right side
113
+ ! of the linear system of equations given
114
+ ! above.
115
+ ! y must be dimensioned at least m*n.
116
+ !
117
+ !
118
+ ! ON OUTPUT y
119
+ !
120
+ ! Contains the solution x.
121
+ !
122
+ ! ierror
123
+ ! An error flag which indicates invalid
124
+ ! input parameters except for number
125
+ ! zero, a solution is not attempted.
126
+ !
127
+ ! = 0 no error
128
+ ! = 1 m <= 2
129
+ ! = 2 n <= 2
130
+ ! = 3 idimy <= m
131
+ ! = 4 nperod <= 0 or nperod > 4
132
+ ! = 5 mperod < 0 or mperod > 1
133
+ ! = 6 a(i) /= c(1) or c(i) /= c(1) or
134
+ ! b(i) /= b(1) for
135
+ ! some i=1, 2, ..., m.
136
+ ! = 7 a(1) /= 0 or c(m) /= 0 and
137
+ ! mperod = 1
138
+ ! = 20 If the dynamic allocation of real and
139
+ ! complex workspace required for solution
140
+ ! fails (for example if n, m are too large
141
+ ! for your computer)
142
+ !
143
+ !
144
+ ! HISTORY Written in 1979 by Roland Sweet of NCAR'S
145
+ ! scientific computing division. made available
146
+ ! on NCAR'S public libraries in January, 1980.
147
+ !
148
+ ! Revised in June 2004 by John Adams using
149
+ ! Fortran 90 dynamically allocated workspace.
150
+ !
151
+ ! ALGORITHM The linear system is solved by a cyclic
152
+ ! reduction algorithm described in the
153
+ ! reference.
154
+ !
155
+ ! PORTABILITY Fortran 2008 --
156
+ ! the machine dependent constant pi is
157
+ ! defined as acos(-ONE) where wp = REAL64
158
+ ! from the intrinsic module ISO_Fortran_env.
159
+ !
160
+ ! REFERENCES Sweet, R., "A cyclic reduction algorithm for
161
+ ! solving block tridiagonal systems of arbitrary
162
+ ! dimensions, " SIAM J. On Numer. Anal., 14 (1977)
163
+ ! PP. 706-720.
164
+ !
165
+ ! ACCURACY This test was performed on a platform with
166
+ ! 64 bit floating point arithmetic.
167
+ ! a uniform random number generator was used
168
+ ! to create a solution array x for the system
169
+ ! given in the 'purpose' description above
170
+ ! with
171
+ ! a(i) = c(i) = -HALF *b(i) = 1, i=1, 2, ..., m
172
+ !
173
+ ! and, when mperod = 1
174
+ !
175
+ ! a(1) = c(m) = 0
176
+ ! a(m) = c(1) = 2.
177
+ !
178
+ ! The solution x was substituted into the
179
+ ! given system and, using double precision
180
+ ! a right side y was computed.
181
+ ! using this array y, subroutine genbun
182
+ ! was called to produce approximate
183
+ ! solution z. then relative error
184
+ ! e = max(abs(z(i, j)-x(i, j)))/
185
+ ! max(abs(x(i, j)))
186
+ ! was computed, where the two maxima are taken
187
+ ! over i=1, 2, ..., m and j=1, ..., n.
188
+ !
189
+ ! The value of e is given in the table
190
+ ! below for some typical values of m and n.
191
+ !
192
+ ! m (=n) mperod nperod e
193
+ ! ------ ------ ------ ------
194
+ !
195
+ ! 31 0 0 6.e-14
196
+ ! 31 1 1 4.e-13
197
+ ! 31 1 3 3.e-13
198
+ ! 32 0 0 9.e-14
199
+ ! 32 1 1 3.e-13
200
+ ! 32 1 3 1.e-13
201
+ ! 33 0 0 9.e-14
202
+ ! 33 1 1 4.e-13
203
+ ! 33 1 3 1.e-13
204
+ ! 63 0 0 1.e-13
205
+ ! 63 1 1 1.e-12
206
+ ! 63 1 3 2.e-13
207
+ ! 64 0 0 1.e-13
208
+ ! 64 1 1 1.e-12
209
+ ! 64 1 3 6.e-13
210
+ ! 65 0 0 2.e-13
211
+ ! 65 1 1 1.e-12
212
+ ! 65 1 3 4.e-13
213
+ !
214
+ module type_CenteredCyclicReductionUtility
215
+
216
+ use fishpack_precision, only: &
217
+ wp, & ! Working precision
218
+ ip ! Integer precision
219
+
220
+ use type_FishpackWorkspace, only: &
221
+ FishpackWorkspace
222
+
223
+ use type_CyclicReductionUtility, only: &
224
+ CyclicReductionUtility
225
+
226
+ ! Explicit typing only
227
+ implicit none
228
+
229
+ ! Everything is private unless stated otherwise
230
+ private
231
+ public :: CenteredCyclicReductionUtility
232
+
233
+ ! Parameters confined to the module
234
+ real(wp), parameter :: ZERO = 0.0_wp
235
+ real(wp), parameter :: HALF = 0.5_wp
236
+ real(wp), parameter :: ONE = 1.0_wp
237
+ real(wp), parameter :: TWO = 2.0_wp
238
+
239
+ type, public, extends(CyclicReductionUtility) :: CenteredCyclicReductionUtility
240
+ contains
241
+ ! Public type-bound procedures
242
+ procedure, public :: genbun_lower_routine
243
+ ! Private type-bound procedures
244
+ procedure, private :: genbun_solve_poisson_periodic
245
+ procedure, private :: genbun_solve_poisson_dirichlet
246
+ procedure, private :: genbun_solve_poisson_neumann
247
+ end type
248
+
249
+ contains
250
+
251
+ subroutine genbun_lower_routine(self, &
252
+ nperod, n, mperod, m, a, b, c, idimy, y, ierror, w)
253
+
254
+ ! Dummy arguments
255
+ class(CenteredCyclicReductionUtility), intent(inout) :: self
256
+ integer(ip), intent(in) :: nperod
257
+ integer(ip), intent(in) :: n
258
+ integer(ip), intent(in) :: mperod
259
+ integer(ip), intent(in) :: m
260
+ integer(ip), intent(in) :: idimy
261
+ integer(ip), intent(out) :: ierror
262
+ real(wp), intent(in) :: a(m)
263
+ real(wp), intent(in) :: b(m)
264
+ real(wp), intent(in) :: c(m)
265
+ real(wp), intent(inout) :: y(idimy,n)
266
+ real(wp), intent(inout) :: w(:)
267
+
268
+ ! Local variables
269
+ integer(ip) :: workspace_indices(12)
270
+ integer(ip) :: i, k, j, mp, np, irev, mh, mhm1, modd
271
+ integer(ip) :: nby2, mskip
272
+ real(wp) :: ipstor
273
+
274
+ ! Check input arguments
275
+ call genbun_check_input_arguments(nperod, n, mperod, m, idimy, ierror, a, b, c)
276
+
277
+ ! Check error flag
278
+ if (ierror /= 0) return
279
+
280
+ !
281
+ ! Set up workspace for lower routine poisson solvers
282
+ !
283
+ workspace_indices = genbun_get_workspace_indices(n, m)
284
+
285
+ associate( &
286
+ mp1 => workspace_indices(1), &
287
+ iwba => workspace_indices(2), &
288
+ iwbb => workspace_indices(3), &
289
+ iwbc => workspace_indices(4), &
290
+ iwb2 => workspace_indices(5), &
291
+ iwb3 => workspace_indices(6), &
292
+ iww1 => workspace_indices(7), &
293
+ iww2 => workspace_indices(8), &
294
+ iww3 => workspace_indices(9), &
295
+ iwd => workspace_indices(10), &
296
+ iwtcos => workspace_indices(11), &
297
+ iwp => workspace_indices(12) &
298
+ )
299
+
300
+ w(iwba:m-1+iwba) = -a(:m)
301
+ w(iwbc:m-1+iwbc) = -c(:m)
302
+ w(iwbb:m-1+iwbb) = TWO - b(:m)
303
+ y(:m, :n) = -y(:m, :n)
304
+
305
+ mp = mperod + 1
306
+ np = nperod + 1
307
+
308
+ select case (mp)
309
+ case (1)
310
+ mh = (m + 1)/2
311
+ mhm1 = mh - 1
312
+
313
+ if (mh*2 == m) then
314
+ modd = 2
315
+ else
316
+ modd = 1
317
+ end if
318
+
319
+ do j = 1, n
320
+ w(:mhm1) = y(mh-1:mh-mhm1:(-1), j) - y(mh+1:mhm1+mh, j)
321
+ w(mh+1:mhm1+mh) = y(mh-1:mh-mhm1:(-1), j) + y(mh+1:mhm1+mh, j)
322
+ w(mh) = TWO*y(mh, j)
323
+ select case (modd)
324
+ case (1)
325
+ y(:m, j) = w(:m)
326
+ case (2)
327
+ w(m) = TWO * y(m, j)
328
+ y(:m, j) = w(:m)
329
+ end select
330
+ end do
331
+
332
+ k = iwbc + mhm1 - 1
333
+ i = iwba + mhm1
334
+ w(k) = ZERO
335
+ w(i) = ZERO
336
+ w(k+1) = TWO * w(k+1)
337
+
338
+ select case (modd)
339
+ case default
340
+ k = iwbb + mhm1 - 1
341
+ w(k) = w(k) - w(i-1)
342
+ w(iwbc-1) = w(iwbc-1) + w(iwbb-1)
343
+ case (2)
344
+ w(iwbb-1) = w(k+1)
345
+ end select
346
+ end select
347
+
348
+ main_loop: do
349
+
350
+ associate( &
351
+ ba => w(iwba:), &
352
+ bb => w(iwbb:), &
353
+ bc => w(iwbc:), &
354
+ b2 => w(iwb2:), &
355
+ b3 => w(iwb3:), &
356
+ w1 => w(iww1:), &
357
+ w2 => w(iww2:), &
358
+ w3 => w(iww3:), &
359
+ d => w(iwd:), &
360
+ tcos => w(iwtcos:), &
361
+ p => w(iwp:) &
362
+ )
363
+ !
364
+ ! Invoke lower routines
365
+ !
366
+ select case (np)
367
+ case (1)
368
+ call self%genbun_solve_poisson_periodic(m, n, ba, bb, bc, &
369
+ y, idimy, w, b2, b3, w1, w2, w3, d, tcos, p)
370
+ case (2)
371
+ call self%genbun_solve_poisson_dirichlet(m, n, 1, ba, bb, bc, &
372
+ y, idimy, w, w1, d, tcos, p)
373
+ case (3)
374
+ call self%genbun_solve_poisson_neumann(m, n, 1, 2, ba, bb, bc, &
375
+ y, idimy, w, b2, b3, w1, w2, w3, d, tcos, p)
376
+ case (4)
377
+ call self%genbun_solve_poisson_neumann(m, n, 1, 1, ba, bb, bc, &
378
+ y, idimy, w, b2, b3, w1, w2, w3, d, tcos, p)
379
+ end select
380
+ end associate
381
+
382
+ loop_113: do
383
+
384
+ select case (np)
385
+ case (1:4)
386
+ select case (mp)
387
+ case (1)
388
+ do j = 1, n
389
+ w(mh-1:mh-mhm1:(-1)) = HALF*(y(mh+1:mhm1+mh, j)+y(:mhm1, j))
390
+ w(mh+1:mhm1+mh) = HALF*(y(mh+1:mhm1+mh, j)-y(:mhm1, j))
391
+ w(mh) = HALF*y(mh, j)
392
+ select case (modd)
393
+ case (1)
394
+ y(:m, j) = w(:m)
395
+ case (2)
396
+ w(m) = HALF*y(m, j)
397
+ y(:m, j) = w(:m)
398
+ end select
399
+ end do
400
+ w(1) = ipstor + real(iwp - 1, kind=wp)
401
+ return
402
+ case (2)
403
+ w(1) = ipstor + real(iwp - 1, kind=wp)
404
+ return
405
+ end select
406
+
407
+ mh = (m + 1)/2
408
+ mhm1 = mh - 1
409
+
410
+ if (mh*2 == m) then
411
+ modd = 2
412
+ else
413
+ modd = 1
414
+ end if
415
+
416
+ do j = 1, n
417
+ w(:mhm1) = y(mh-1:mh-mhm1:(-1), j) - y(mh+1:mhm1+mh, j)
418
+ w(mh+1:mhm1+mh) = y(mh-1:mh-mhm1:(-1), j) + y(mh+1:mhm1+mh, j)
419
+ w(mh) = TWO*y(mh, j)
420
+ select case (modd)
421
+ case (1)
422
+ y(:m, j) = w(:m)
423
+ case (2)
424
+ w(m) = TWO*y(m, j)
425
+ y(:m, j) = w(:m)
426
+ end select
427
+ end do
428
+
429
+ k = iwbc + mhm1 - 1
430
+ i = iwba + mhm1
431
+ w(k) = ZERO
432
+ w(i) = ZERO
433
+ w(k+1) = TWO*w(k+1)
434
+
435
+ select case (modd)
436
+ case (2)
437
+ w(iwbb-1) = w(k+1)
438
+ case default
439
+ k = iwbb + mhm1 - 1
440
+ w(k) = w(k) - w(i-1)
441
+ w(iwbc-1) = w(iwbc-1) + w(iwbb-1)
442
+ end select
443
+
444
+ cycle main_loop
445
+ !
446
+ ! reverse columns when nperod = 4.
447
+ !
448
+ end select
449
+
450
+ irev = 1
451
+ nby2 = n/2
452
+
453
+ loop_124: do
454
+
455
+ do j = 1, nby2
456
+ mskip = n + 1 - j
457
+ do i = 1, m
458
+ call self%swap(y(i, j), y(i, mskip))
459
+ end do
460
+ end do
461
+
462
+ select case (irev)
463
+ case (1)
464
+ associate( &
465
+ ba => w(iwba:), &
466
+ bb => w(iwbb:), &
467
+ bc => w(iwbc:), &
468
+ b2 => w(iwb2:), &
469
+ b3 => w(iwb3:), &
470
+ w1 => w(iww1:), &
471
+ w2 => w(iww2:), &
472
+ w3 => w(iww3:), &
473
+ d => w(iwd:), &
474
+ tcos => w(iwtcos:), &
475
+ p => w(iwp:) &
476
+ )
477
+ call self%genbun_solve_poisson_neumann(m, n, 1, 2, ba, bb, bc, &
478
+ y, idimy, w, b2, b3, w1, w2, w3, d, tcos, p)
479
+ end associate
480
+
481
+ ipstor = w(iww1)
482
+ irev = 2
483
+
484
+ if (nperod == 4) cycle loop_124
485
+ cycle loop_113
486
+
487
+ case (2)
488
+ cycle loop_113
489
+ end select
490
+ exit loop_124
491
+ end do loop_124
492
+ exit loop_113
493
+ end do loop_113
494
+ end do main_loop
495
+
496
+ do j = 1, n
497
+ w(mh-1:mh-mhm1:(-1)) = HALF*(y(mh+1:mhm1+mh, j)+y(:mhm1, j))
498
+ w(mh+1:mhm1+mh) = HALF*(y(mh+1:mhm1+mh, j)-y(:mhm1, j))
499
+ w(mh) = HALF*y(mh, j)
500
+ select case (modd)
501
+ case (1)
502
+ y(:m, j) = w(:m)
503
+ case (2)
504
+ w(m) = HALF*y(m, j)
505
+ y(:m, j) = w(:m)
506
+ end select
507
+ end do
508
+
509
+ w(1) = ipstor + real(iwp - 1, kind=wp)
510
+
511
+ end associate
512
+
513
+ end subroutine genbun_lower_routine
514
+
515
+ pure subroutine genbun_check_input_arguments(nperod, n, mperod, m, idimy, ierror, a, b, c)
516
+
517
+ ! Dummy arguments
518
+ integer(ip), intent(in) :: nperod
519
+ integer(ip), intent(in) :: n
520
+ integer(ip), intent(in) :: mperod
521
+ integer(ip), intent(in) :: m
522
+ integer(ip), intent(in) :: idimy
523
+ integer(ip), intent(out) :: ierror
524
+ real(wp), intent(in) :: a(m)
525
+ real(wp), intent(in) :: b(m)
526
+ real(wp), intent(in) :: c(m)
527
+
528
+ if (3 > m) then
529
+ ierror = 1
530
+ return
531
+ else if (3 > n) then
532
+ ierror = 2
533
+ return
534
+ else if (idimy < m) then
535
+ ierror = 3
536
+ return
537
+ else if (nperod < 0 .or. nperod > 4) then
538
+ ierror = 4
539
+ return
540
+ else if (mperod < 0 .or. mperod > 1) then
541
+ ierror = 5
542
+ return
543
+ else if (mperod /= 1) then
544
+ if (any(a /= c(1)) .or. any(c /= c(1)) .or. any(b /= b(1))) then
545
+ ierror = 6
546
+ return
547
+ end if
548
+ else if (a(1) /= ZERO .or. c(m) /= ZERO) then
549
+ ierror = 7
550
+ return
551
+ else
552
+ ierror = 0
553
+ end if
554
+
555
+ end subroutine genbun_check_input_arguments
556
+
557
+ function genbun_get_workspace_indices(n, m) &
558
+ result (return_value)
559
+
560
+ ! Dummy arguments
561
+ integer(ip), intent(in) :: n
562
+ integer(ip), intent(in) :: m
563
+ integer(ip) :: return_value(12)
564
+
565
+ integer(ip) :: j !! Counter
566
+
567
+ associate( i => return_value)
568
+ i(1:2) = m + 1
569
+ do j = 3, 11
570
+ i(j) = i(j-1) + m
571
+ end do
572
+ i(12) = i(11) + 4 * n
573
+ end associate
574
+
575
+ end function genbun_get_workspace_indices
576
+
577
+ !
578
+ ! Purpose:
579
+ !
580
+ ! Solve poisson equation with periodic
581
+ ! boundary conditions.
582
+ !
583
+ subroutine genbun_solve_poisson_periodic(self, &
584
+ m, n, a, bb, c, q, idimq, b, b2, b3, w, w2, w3, d, tcos, p)
585
+
586
+ ! Dummy arguments
587
+ class(CenteredCyclicReductionUtility), intent(inout) :: self
588
+ integer(ip), intent(in) :: m
589
+ integer(ip), intent(in) :: n
590
+ integer(ip), intent(in) :: idimq
591
+ real(wp), intent(in) :: a(m)
592
+ real(wp), intent(in) :: bb(m)
593
+ real(wp), intent(in) :: c(m)
594
+ real(wp), intent(inout) :: q(idimq,n)
595
+ real(wp), intent(inout) :: b(m)
596
+ real(wp), intent(inout) :: b2(m)
597
+ real(wp), intent(inout) :: b3(m)
598
+ real(wp), intent(inout) :: w(m)
599
+ real(wp), intent(inout) :: w2(m)
600
+ real(wp), intent(inout) :: w3(m)
601
+ real(wp), intent(inout) :: d(m)
602
+ real(wp), intent(inout) :: tcos(4*n)
603
+ real(wp), intent(inout) :: p(4*n)
604
+
605
+ ! Local variables
606
+ integer(ip) :: mr, nr, nrm1, j, nrmj, nrpj, i, lh
607
+ real(wp) :: ipstor
608
+ real(wp) :: s, t
609
+
610
+ mr = m
611
+ nr = (n + 1)/2
612
+ nrm1 = nr - 1
613
+
614
+ if (2*nr == n) then
615
+
616
+ ! even number of unknowns
617
+ do j = 1, nrm1
618
+ nrmj = nr - j
619
+ nrpj = nr + j
620
+ do i = 1, mr
621
+ s = q(i, nrmj) - q(i, nrpj)
622
+ t = q(i, nrmj) + q(i, nrpj)
623
+ q(i, nrmj) = s
624
+ q(i, nrpj) = t
625
+ end do
626
+ end do
627
+
628
+ q(:mr, nr) = TWO * q(:mr, nr)
629
+ q(:mr, n) = TWO * q(:mr, n)
630
+
631
+ call self%genbun_solve_poisson_dirichlet(mr, nrm1, 1, a, bb, c, q, idimq, b, w, d, tcos, p)
632
+
633
+ ipstor = w(1)
634
+
635
+ call self%genbun_solve_poisson_neumann(mr, (nr + 1), 1, 1, a, bb, c, q(1, nr), idimq, b, b2, &
636
+ b3, w, w2, w3, d, tcos, p)
637
+
638
+ ipstor = max(ipstor, w(1))
639
+
640
+ do j = 1, nrm1
641
+ nrmj = nr - j
642
+ nrpj = nr + j
643
+ do i = 1, mr
644
+ s = HALF*(q(i, nrpj)+q(i, nrmj))
645
+ t = HALF*(q(i, nrpj)-q(i, nrmj))
646
+ q(i, nrmj) = s
647
+ q(i, nrpj) = t
648
+ end do
649
+ end do
650
+ q(:mr, nr) = HALF*q(:mr, nr)
651
+ q(:mr, n) = HALF*q(:mr, n)
652
+ else
653
+ do j = 1, nrm1
654
+ nrpj = n + 1 - j
655
+ do i = 1, mr
656
+ s = q(i, j) - q(i, nrpj)
657
+ t = q(i, j) + q(i, nrpj)
658
+ q(i, j) = s
659
+ q(i, nrpj) = t
660
+ end do
661
+ end do
662
+
663
+ q(:mr, nr) = TWO*q(:mr, nr)
664
+ lh = nrm1/2
665
+
666
+ do j = 1, lh
667
+ nrmj = nr - j
668
+ do i = 1, mr
669
+ s = q(i, j)
670
+ q(i, j) = q(i, nrmj)
671
+ q(i, nrmj) = s
672
+ end do
673
+ end do
674
+
675
+ call self%genbun_solve_poisson_dirichlet(mr, nrm1, 2, a, bb, c, q, &
676
+ idimq, b, w, d, tcos, p)
677
+
678
+ ipstor = w(1)
679
+
680
+ call self%genbun_solve_poisson_neumann(mr, nr, 2, 1, a, bb, c, q(1, nr), &
681
+ idimq, b, b2, b3, w, w2, w3, d, tcos, p)
682
+
683
+ ipstor = max(ipstor, w(1))
684
+
685
+ do j = 1, nrm1
686
+ nrpj = nr + j
687
+ do i = 1, mr
688
+ s = HALF*(q(i, nrpj)+q(i, j))
689
+ t = HALF*(q(i, nrpj)-q(i, j))
690
+ q(i, nrpj) = t
691
+ q(i, j) = s
692
+ end do
693
+ end do
694
+
695
+ q(:mr, nr) = HALF*q(:mr, nr)
696
+
697
+ do j = 1, lh
698
+ nrmj = nr - j
699
+ do i = 1, mr
700
+ s = q(i, j)
701
+ q(i, j) = q(i, nrmj)
702
+ q(i, nrmj) = s
703
+ end do
704
+ end do
705
+ end if
706
+
707
+ w(1) = ipstor
708
+
709
+ end subroutine genbun_solve_poisson_periodic
710
+
711
+ !
712
+ ! Purpose:
713
+ !
714
+ ! subroutine to solve poisson's equation for dirichlet boundary
715
+ ! conditions.
716
+ !
717
+ ! istag = 1 if the last diagonal block is the matrix a.
718
+ ! istag = 2 if the last diagonal block is the matrix a+i.
719
+ !
720
+ subroutine genbun_solve_poisson_dirichlet(self, &
721
+ mr, nr, istag, ba, bb, bc, q, idimq, b, w, d, tcos, p)
722
+
723
+ ! Dummy arguments
724
+ class(CenteredCyclicReductionUtility), intent(inout) :: self
725
+ integer(ip), intent(in) :: mr
726
+ integer(ip), intent(in) :: nr
727
+ integer(ip), intent(in) :: istag
728
+ integer(ip), intent(in) :: idimq
729
+ real(wp), intent(in) :: ba(:)
730
+ real(wp), intent(in) :: bb(:)
731
+ real(wp), intent(in) :: bc(:)
732
+ real(wp), intent(inout) :: q(:,:)
733
+ real(wp), intent(inout) :: b(:)
734
+ real(wp), intent(inout) :: w(:)
735
+ real(wp), intent(inout) :: d(:)
736
+ real(wp), intent(inout) :: tcos(:)
737
+ real(wp), intent(inout) :: p(:)
738
+
739
+ ! Local variables
740
+ integer(ip) :: m, n, jsh, ipp, ipstor, kr
741
+ integer(ip) :: irreg, jstsav, i, lr, nun, nodd, noddpr
742
+ integer(ip) :: jst, jsp, l, j, jm1, jp1, jm2, jp2, jm3, jp3
743
+ integer(ip) :: krpi, ideg, jdeg
744
+ real(wp) :: fi, t
745
+
746
+ m = mr
747
+ n = nr
748
+ jsh = 0
749
+ fi = ONE/istag
750
+ ipp = -m
751
+ ipstor = 0
752
+
753
+ select case (istag)
754
+ case (2)
755
+ kr = 1
756
+ jstsav = 1
757
+ irreg = 2
758
+ if (n <= 1) then
759
+ tcos(1) = -ONE
760
+ b(:m) = q(:m, 1)
761
+ call self%solve_tridiag(1, 0, m, ba, bb, bc, b, tcos, d, w)
762
+ q(:m, 1) = b(:m)
763
+ w(1) = ipstor
764
+ return
765
+ end if
766
+ case default
767
+ kr = 0
768
+ irreg = 1
769
+ if (n <= 1) then
770
+ tcos(1) = ZERO
771
+ b(:m) = q(:m, 1)
772
+ call self%solve_tridiag(1, 0, m, ba, bb, bc, b, tcos, d, w)
773
+ q(:m, 1) = b(:m)
774
+ w(1) = ipstor
775
+ return
776
+ end if
777
+ end select
778
+
779
+ lr = 0
780
+ p(:m) = ZERO
781
+ nun = n
782
+ jst = 1
783
+ jsp = n
784
+ !
785
+ ! irreg = 1 when no irregularities have occurred, otherwise it is 2.
786
+ !
787
+ loop_108: do
788
+
789
+ l = 2*jst
790
+ nodd = 2 - 2*((nun + 1)/2) + nun
791
+ !
792
+ ! nodd = 1 when nun is odd, otherwise it is 2.
793
+ !
794
+ select case (nodd)
795
+ case (1)
796
+ jsp = jsp - jst
797
+ if (irreg /= 1) then
798
+ jsp = jsp - l
799
+ end if
800
+ case default
801
+ jsp = jsp - l
802
+ end select
803
+
804
+ call self%generate_cosines(jst, 1, HALF, ZERO, tcos)
805
+
806
+ if (l <= jsp) then
807
+ do j = l, jsp, l
808
+ jm1 = j - jsh
809
+ jp1 = j + jsh
810
+ jm2 = j - jst
811
+ jp2 = j + jst
812
+ jm3 = jm2 - jsh
813
+ jp3 = jp2 + jsh
814
+
815
+ if (jst == 1) then
816
+ b(:m) = TWO*q(:m, j)
817
+ q(:m, j) = q(:m, jm2) + q(:m, jp2)
818
+ else
819
+ do i = 1, m
820
+ t = q(i, j) - q(i, jm1) - q(i, jp1) + q(i, jm2) + q(i, jp2)
821
+ b(i) = t + q(i, j) - q(i, jm3) - q(i, jp3)
822
+ q(i, j) = t
823
+ end do
824
+ end if
825
+
826
+ call self%solve_tridiag(jst, 0, m, ba, bb, bc, b, tcos, d, w)
827
+ q(:m, j) = q(:m, j) + b(:m)
828
+
829
+ end do
830
+ end if
831
+ !
832
+ ! reduction for last unknown
833
+ !
834
+ case_block: block
835
+ select case (nodd)
836
+ !
837
+ ! even number of unknowns
838
+ !
839
+ case (2)
840
+ jsp = jsp + l
841
+ j = jsp
842
+ jm1 = j - jsh
843
+ jp1 = j + jsh
844
+ jm2 = j - jst
845
+ jp2 = j + jst
846
+ jm3 = jm2 - jsh
847
+
848
+ select case (irreg)
849
+ case (2)
850
+ call self%generate_cosines(kr, jstsav, ZERO, fi, tcos)
851
+ call self%generate_cosines(lr, jstsav, ZERO, fi, tcos(kr+1:))
852
+ ideg = kr
853
+ kr = kr + jst
854
+ case default
855
+ jstsav = jst
856
+ ideg = jst
857
+ kr = l
858
+ end select
859
+
860
+ if (jst == 1) then
861
+ irreg = 2
862
+ b(:m) = q(:m, j)
863
+ q(:m, j) = q(:m, jm2)
864
+ else
865
+ b(:m) = q(:m, j) + HALF*(q(:m, jm2)-q(:m, jm1)-q(:m, jm3))
866
+ select case (irreg)
867
+ case (2)
868
+ select case (noddpr)
869
+ case (2)
870
+ q(:m, j) = q(:m, jm2) + q(:m, j) - q(:m, jm1)
871
+ case default
872
+ q(:m, j) = q(:m, jm2) + p(ipp+1:m+ipp)
873
+ ipp = ipp - m
874
+ end select
875
+ case default
876
+ q(:m, j) = q(:m, jm2) + HALF *(q(:m, j)-q(:m, jm1)-q(:m, jp1))
877
+ irreg = 2
878
+ end select
879
+ end if
880
+
881
+ call self%solve_tridiag(ideg, lr, m, ba, bb, bc, b, tcos, d, w)
882
+ q(:m, j) = q(:m, j) + b(:m)
883
+
884
+ case default
885
+ !
886
+ ! odd number of unknowns
887
+ !
888
+ if (irreg == 1) exit case_block
889
+
890
+ jsp = jsp + l
891
+ j = jsp
892
+ jm1 = j - jsh
893
+ jp1 = j + jsh
894
+ jm2 = j - jst
895
+ jp2 = j + jst
896
+ jm3 = jm2 - jsh
897
+
898
+ select case (istag)
899
+ case (1)
900
+ select case (noddpr)
901
+ case (2)
902
+ b(:m) = HALF*(q(:m, jm2)-q(:m, jm1)-q(:m, jm3)) &
903
+ + q(:m, jp2) - q(:m, jp1) + q(:m, j)
904
+ case default
905
+ b(:m) = HALF*(q(:m, jm2)-q(:m, jm1)&
906
+ -q(:m, jm3)) + p(ipp+1:m+ipp) + q(:m, j)
907
+ end select
908
+
909
+ q(:m, j) = HALF *(q(:m, j)-q(:m, jm1)-q(:m, jp1))
910
+ case (2)
911
+ if (jst /= 1) then
912
+ select case (noddpr)
913
+ case (2)
914
+ b(:m) = HALF*(q(:m, jm2)-q(:m, jm1)-q(:m, jm3)) &
915
+ + q(:m, jp2) - q(:m, jp1) + q(:m, j)
916
+ case default
917
+ b(:m) = HALF*(q(:m, jm2)-q(:m, jm1)&
918
+ -q(:m, jm3)) + p(ipp+1:m+ipp) + q(:m, j)
919
+ end select
920
+ q(:m, j) = HALF *(q(:m, j)-q(:m, jm1)-q(:m, jp1))
921
+ else
922
+
923
+ b(:m) = q(:m, j)
924
+ q(:m, j) = ZERO
925
+ end if
926
+ end select
927
+
928
+ call self%solve_tridiag(jst, 0, m, ba, bb, bc, b, tcos, d, w)
929
+
930
+ ipp = ipp + m
931
+ ipstor = max(ipstor, ipp + m)
932
+ p(ipp+1:m+ipp) = q(:m, j) + b(:m)
933
+ b(:m) = q(:m, jp2) + p(ipp+1:m+ipp)
934
+
935
+ if (lr == 0) then
936
+ do i = 1, jst
937
+ krpi = kr + i
938
+ tcos(krpi) = tcos(i)
939
+ end do
940
+ else
941
+ call self%generate_cosines(lr, jstsav, ZERO, fi, tcos(jst+1:))
942
+ call self%merge_cosines(tcos, 0, jst, jst, lr, kr)
943
+ end if
944
+
945
+ call self%generate_cosines(kr, jstsav, ZERO, fi, tcos)
946
+ call self%solve_tridiag(kr, kr, m, ba, bb, bc, b, tcos, d, w)
947
+
948
+ q(:m, j) = q(:m, jm2) + b(:m) + p(ipp+1:m+ipp)
949
+ lr = kr
950
+ kr = kr + l
951
+
952
+ end select
953
+ end block case_block
954
+
955
+ nun = nun/2
956
+ noddpr = nodd
957
+ jsh = jst
958
+ jst = 2*jst
959
+
960
+ if (nun < 2) exit loop_108
961
+ end do loop_108
962
+ !
963
+ ! start solution.
964
+ !
965
+ j = jsp
966
+ b(:m) = q(:m, j)
967
+
968
+ select case (irreg)
969
+ case (2)
970
+ kr = lr + jst
971
+ call self%generate_cosines(kr, jstsav, ZERO, fi, tcos)
972
+ call self%generate_cosines(lr, jstsav, ZERO, fi, tcos(kr+1:))
973
+ ideg = kr
974
+ case default
975
+ call self%generate_cosines(jst, 1, HALF, ZERO, tcos)
976
+ ideg = jst
977
+ end select
978
+
979
+ call self%solve_tridiag(ideg, lr, m, ba, bb, bc, b, tcos, d, w)
980
+ jm1 = j - jsh
981
+ jp1 = j + jsh
982
+
983
+ select case (irreg)
984
+ case (2)
985
+ select case (noddpr)
986
+ case (2)
987
+ q(:m, j) = q(:m, j) - q(:m, jm1) + b(:m)
988
+ case default
989
+ q(:m, j) = p(ipp+1:m+ipp) + b(:m)
990
+ ipp = ipp - m
991
+ end select
992
+ case default
993
+ q(:m, j) = HALF *(q(:m, j)-q(:m, jm1)-q(:m, jp1)) + b(:m)
994
+ end select
995
+
996
+ loop_164: do
997
+
998
+ jst = jst/2
999
+ jsh = jst/2
1000
+ nun = 2*nun
1001
+
1002
+ if (nun > n) then
1003
+ w(1) = ipstor
1004
+ return
1005
+ end if
1006
+
1007
+ inner_loop: do j = jst, n, l
1008
+ jm1 = j - jsh
1009
+ jp1 = j + jsh
1010
+ jm2 = j - jst
1011
+ jp2 = j + jst
1012
+
1013
+ block_construct: block
1014
+ if (j <= jst) then
1015
+ b(:m) = q(:m, j) + q(:m, jp2)
1016
+ else
1017
+ if (jp2 > n) then
1018
+ b(:m) = q(:m, j) + q(:m, jm2)
1019
+ if (jst < jstsav) irreg = 1
1020
+ select case (irreg)
1021
+ case (2)
1022
+ if (j + l > n) lr = lr - jst
1023
+ kr = jst + lr
1024
+ call self%generate_cosines(kr, jstsav, ZERO, fi, tcos)
1025
+ call self%generate_cosines(lr, jstsav, ZERO, fi, tcos(kr+1:))
1026
+ ideg = kr
1027
+ jdeg = lr
1028
+ exit block_construct
1029
+ end select
1030
+ else
1031
+ b(:m) = q(:m, j) + q(:m, jm2) + q(:m, jp2)
1032
+ end if
1033
+ end if
1034
+
1035
+ call self%generate_cosines(jst, 1, HALF, ZERO, tcos)
1036
+ ideg = jst
1037
+ jdeg = 0
1038
+
1039
+ end block block_construct
1040
+
1041
+ call self%solve_tridiag(ideg, jdeg, m, ba, bb, bc, b, tcos, d, w)
1042
+
1043
+ if_construct: if (jst <= 1) then
1044
+ q(:m, j) = b(:m)
1045
+ else
1046
+ if (jp2 > n) then
1047
+ select case (irreg)
1048
+ case (2)
1049
+ if (j + jsh <= n) then
1050
+ q(:m, j) = b(:m) + p(ipp+1:m+ipp)
1051
+ ipp = ipp - m
1052
+ else
1053
+ q(:m, j) = b(:m) + q(:m, j) - q(:m, jm1)
1054
+ end if
1055
+ exit if_construct
1056
+ end select
1057
+ end if
1058
+
1059
+ loop_175: do
1060
+ q(:m, j) = HALF *(q(:m, j)-q(:m, jm1)-q(:m, jp1)) + b(:m)
1061
+ cycle inner_loop
1062
+ select case (irreg)
1063
+ case (1)
1064
+ cycle loop_175
1065
+ case (2)
1066
+ if (j + jsh <= n) then
1067
+ q(:m, j) = b(:m) + p(ipp+1:m+ipp)
1068
+ ipp = ipp - m
1069
+ else
1070
+ q(:m, j) = b(:m) + q(:m, j) - q(:m, jm1)
1071
+ end if
1072
+ exit loop_175
1073
+ end select
1074
+ end do loop_175
1075
+ end if if_construct
1076
+ end do inner_loop
1077
+
1078
+ l = l/2
1079
+
1080
+ end do loop_164
1081
+
1082
+ w(1) = ipstor
1083
+
1084
+ end subroutine genbun_solve_poisson_dirichlet
1085
+
1086
+ !
1087
+ ! Purpose
1088
+ !
1089
+ ! To solve poisson's equation with neumann boundary
1090
+ ! conditions.
1091
+ !
1092
+ ! istag = 1 if the last diagonal block is a.
1093
+ ! istag = 2 if the last diagonal block is a-i.
1094
+ ! mixbnd = 1 if have neumann boundary conditions at both boundaries.
1095
+ ! mixbnd = 2 if have neumann boundary conditions at bottom and
1096
+ ! dirichlet condition at top. (for this case, must have istag = 1.)
1097
+ !
1098
+ subroutine genbun_solve_poisson_neumann(self, &
1099
+ m, n, istag, mixbnd, a, bb, c, q, idimq, b, b2, &
1100
+ b3, w, w2, w3, d, tcos, p)
1101
+
1102
+ ! Dummy arguments
1103
+ class(CenteredCyclicReductionUtility), intent(inout) :: self
1104
+ integer(ip), intent(in) :: m
1105
+ integer(ip), intent(in) :: n
1106
+ integer(ip), intent(in) :: istag
1107
+ integer(ip), intent(in) :: mixbnd
1108
+ integer(ip), intent(in) :: idimq
1109
+ real(wp), intent(in) :: a(m)
1110
+ real(wp), intent(in) :: bb(m)
1111
+ real(wp), intent(in) :: c(m)
1112
+ real(wp), intent(inout) :: q(idimq,n)
1113
+ real(wp), intent(inout) :: b(m)
1114
+ real(wp), intent(inout) :: b2(m)
1115
+ real(wp), intent(inout) :: b3(m)
1116
+ real(wp), intent(inout) :: w(m)
1117
+ real(wp), intent(inout) :: w2(m)
1118
+ real(wp), intent(inout) :: w3(m)
1119
+ real(wp), intent(inout) :: d(m)
1120
+ real(wp), intent(inout) :: tcos(4*n)
1121
+ real(wp), intent(inout) :: p(4*n)
1122
+
1123
+ ! Local variables
1124
+ integer(ip) :: k(4)
1125
+ integer(ip) :: mr, ipp, ipstor, i2r, jr, nr, nlast, kr
1126
+ integer(ip) :: lr, i, nrod, jstart, jstop, i2rby2, j, jp1, jp2, jp3, jm1
1127
+ integer(ip) :: jm2, jm3, nrodpr, ii, i1, i2, jr2, nlastp, jstep
1128
+ real(wp) :: fistag, fnum, fden, fi, t
1129
+
1130
+ associate( &
1131
+ k1 => k(1), &
1132
+ k2 => k(2), &
1133
+ k3 => k(3), &
1134
+ k4 => k(4) &
1135
+ )
1136
+
1137
+ fistag = 3 - istag
1138
+ fnum = ONE/istag
1139
+ fden = HALF * real(istag - 1, kind=wp)
1140
+ mr = m
1141
+ ipp = -mr
1142
+ ipstor = 0
1143
+ i2r = 1
1144
+ jr = 2
1145
+ nr = n
1146
+ nlast = n
1147
+ kr = 1
1148
+ lr = 0
1149
+
1150
+ select case (istag)
1151
+ case (1)
1152
+ goto 101
1153
+ case (2)
1154
+ goto 103
1155
+ end select
1156
+
1157
+ 101 continue
1158
+
1159
+ q(:mr, n) = HALF * q(:mr, n)
1160
+
1161
+ select case (mixbnd)
1162
+ case (1)
1163
+ goto 103
1164
+ case (2)
1165
+ goto 104
1166
+ end select
1167
+
1168
+ 103 continue
1169
+
1170
+ if (n <= 3) then
1171
+ goto 155
1172
+ end if
1173
+
1174
+ 104 continue
1175
+
1176
+ jr = 2*i2r
1177
+
1178
+ if ((nr/2)*2 == nr) then
1179
+ nrod = 0
1180
+ else
1181
+ nrod = 1
1182
+ end if
1183
+
1184
+ select case (mixbnd)
1185
+ case default
1186
+ jstart = 1
1187
+ case (2)
1188
+ jstart = jr
1189
+ nrod = 1 - nrod
1190
+ end select
1191
+
1192
+ jstop = nlast - jr
1193
+
1194
+ if (nrod == 0) then
1195
+ jstop = jstop - i2r
1196
+ end if
1197
+
1198
+ call self%generate_cosines(i2r, 1, HALF, ZERO, tcos)
1199
+
1200
+ i2rby2 = i2r/2
1201
+
1202
+ if (jstop < jstart) then
1203
+ j = jr
1204
+ else
1205
+ do j = jstart, jstop, jr
1206
+ jp1 = j + i2rby2
1207
+ jp2 = j + i2r
1208
+ jp3 = jp2 + i2rby2
1209
+ jm1 = j - i2rby2
1210
+ jm2 = j - i2r
1211
+ jm3 = jm2 - i2rby2
1212
+
1213
+ if (j == 1) then
1214
+ jm1 = jp1
1215
+ jm2 = jp2
1216
+ jm3 = jp3
1217
+ end if
1218
+
1219
+ if (i2r == 1) then
1220
+ if (j == 1) jm2 = jp2
1221
+ b(:mr) = TWO*q(:mr, j)
1222
+ q(:mr, j) = q(:mr, jm2) + q(:mr, jp2)
1223
+ else
1224
+ do i = 1, mr
1225
+ fi = q(i, j)
1226
+ q(i, j)=q(i, j)-q(i, jm1)-q(i, jp1)+q(i, jm2)+q(i, jp2)
1227
+ b(i) = fi + q(i, j) - q(i, jm3) - q(i, jp3)
1228
+ end do
1229
+ end if
1230
+
1231
+ call self%solve_tridiag(i2r, 0, mr, a, bb, c, b, tcos, d, w)
1232
+
1233
+ q(:mr, j) = q(:mr, j) + b(:mr)
1234
+ !
1235
+ ! end of reduction for regular unknowns.
1236
+ !
1237
+ end do
1238
+ !
1239
+ ! begin special reduction for last unknown.
1240
+ !
1241
+ j = jstop + jr
1242
+ end if
1243
+
1244
+ nlast = j
1245
+ jm1 = j - i2rby2
1246
+ jm2 = j - i2r
1247
+ jm3 = jm2 - i2rby2
1248
+
1249
+ if (nrod /= 0) then
1250
+ !
1251
+ ! odd number of unknowns
1252
+ !
1253
+ if (i2r == 1) then
1254
+ b(:mr) = fistag*q(:mr, j)
1255
+ q(:mr, j) = q(:mr, jm2)
1256
+ else
1257
+ b(:mr) = q(:mr, j) + HALF*(q(:mr, jm2)-q(:mr, jm1)-q(:mr, jm3))
1258
+ if (nrodpr == 0) then
1259
+ q(:mr, j) = q(:mr, jm2) + p(ipp+1:mr+ipp)
1260
+ ipp = ipp - mr
1261
+ else
1262
+ q(:mr, j) = q(:mr, j) - q(:mr, jm1) + q(:mr, jm2)
1263
+ end if
1264
+ if (lr /= 0) then
1265
+ call self%generate_cosines(lr, 1, HALF, fden, tcos(kr+1:))
1266
+ else
1267
+ b(:mr) = fistag*b(:mr)
1268
+ end if
1269
+ end if
1270
+ call self%generate_cosines(kr, 1, HALF, fden, tcos)
1271
+ call self%solve_tridiag(kr, lr, mr, a, bb, c, b, tcos, d, w)
1272
+ q(:mr, j) = q(:mr, j) + b(:mr)
1273
+ kr = kr + i2r
1274
+ else
1275
+ jp1 = j + i2rby2
1276
+ jp2 = j + i2r
1277
+ if (i2r == 1) then
1278
+ b(:mr) = q(:mr, j)
1279
+ call self%solve_tridiag(1, 0, mr, a, bb, c, b, tcos, d, w)
1280
+ ipp = 0
1281
+ ipstor = mr
1282
+ select case (istag)
1283
+ case default
1284
+ p(:mr) = b(:mr)
1285
+ b(:mr) = b(:mr) + q(:mr, n)
1286
+ tcos(1) = ONE
1287
+ tcos(2) = ZERO
1288
+ call self%solve_tridiag(1, 1, mr, a, bb, c, b, tcos, d, w)
1289
+ q(:mr, j) = q(:mr, jm2) + p(:mr) + b(:mr)
1290
+ goto 150
1291
+ case (1)
1292
+ p(:mr) = b(:mr)
1293
+ q(:mr, j) = q(:mr, jm2) + TWO*q(:mr, jp2) + 3.0_wp*b(:mr)
1294
+ goto 150
1295
+ end select
1296
+ end if
1297
+
1298
+ b(:mr) = q(:mr, j) + HALF *(q(:mr, jm2)-q(:mr, jm1)-q(:mr, jm3))
1299
+
1300
+ if (nrodpr == 0) then
1301
+ b(:mr) = b(:mr) + p(ipp+1:mr+ipp)
1302
+ else
1303
+ b(:mr) = b(:mr) + q(:mr, jp2) - q(:mr, jp1)
1304
+ end if
1305
+
1306
+ call self%solve_tridiag(i2r, 0, mr, a, bb, c, b, tcos, d, w)
1307
+ ipp = ipp + mr
1308
+ ipstor = max(ipstor, ipp + mr)
1309
+ p(ipp+1:mr+ipp) = b(:mr) + HALF*(q(:mr, j)-q(:mr, jm1)-q(:mr, jp1))
1310
+ b(:mr) = p(ipp+1:mr+ipp) + q(:mr, jp2)
1311
+
1312
+ if (lr /= 0) then
1313
+ call self%generate_cosines(lr, 1, HALF, fden, tcos(i2r+1:))
1314
+ call self%merge_cosines(tcos, 0, i2r, i2r, lr, kr)
1315
+ else
1316
+ do i = 1, i2r
1317
+ ii = kr + i
1318
+ tcos(ii) = tcos(i)
1319
+ end do
1320
+ end if
1321
+
1322
+ call self%generate_cosines(kr, 1, HALF, fden, tcos)
1323
+
1324
+ if (lr == 0) then
1325
+ select case (istag)
1326
+ case (1)
1327
+ goto 146
1328
+ case (2)
1329
+ goto 145
1330
+ end select
1331
+ end if
1332
+
1333
+ 145 continue
1334
+
1335
+ call self%solve_tridiag(kr, kr, mr, a, bb, c, b, tcos, d, w)
1336
+ goto 148
1337
+
1338
+ 146 continue
1339
+
1340
+ b(:mr) = fistag*b(:mr)
1341
+
1342
+ 148 continue
1343
+
1344
+ q(:mr, j) = q(:mr, jm2) + p(ipp+1:mr+ipp) + b(:mr)
1345
+
1346
+ 150 continue
1347
+ lr = kr
1348
+ kr = kr + jr
1349
+ end if
1350
+
1351
+ select case (mixbnd)
1352
+ case default
1353
+
1354
+ nr = (nlast - 1)/jr + 1
1355
+
1356
+ if (nr <= 3) then
1357
+ goto 155
1358
+ end if
1359
+ case (2)
1360
+
1361
+ nr = nlast/jr
1362
+
1363
+ if (nr <= 1) then
1364
+ goto 192
1365
+ end if
1366
+ end select
1367
+
1368
+ i2r = jr
1369
+ nrodpr = nrod
1370
+
1371
+ goto 104
1372
+
1373
+ 155 continue
1374
+
1375
+ j = 1 + jr
1376
+ jm1 = j - i2r
1377
+ jp1 = j + i2r
1378
+ jm2 = nlast - i2r
1379
+
1380
+ if (nr /= 2) then
1381
+ if (lr /= 0) then
1382
+ goto 170
1383
+ end if
1384
+
1385
+ if (n == 3) then
1386
+ !
1387
+ ! case n = 3.
1388
+ !
1389
+ select case (istag)
1390
+ case (1)
1391
+ goto 156
1392
+ case (2)
1393
+ goto 168
1394
+ end select
1395
+
1396
+ 156 continue
1397
+
1398
+ b(:mr) = q(:mr, 2)
1399
+ tcos(1) = ZERO
1400
+
1401
+ call self%solve_tridiag(1, 0, mr, a, bb, c, b, tcos, d, w)
1402
+
1403
+ q(:mr, 2) = b(:mr)
1404
+ b(:mr) = 4.0_wp*b(:mr) + q(:mr, 1) + TWO*q(:mr, 3)
1405
+ tcos(1) = -TWO
1406
+ tcos(2) = TWO
1407
+ i1 = 2
1408
+ i2 = 0
1409
+
1410
+ call self%solve_tridiag(i1, i2, mr, a, bb, c, b, tcos, d, w)
1411
+
1412
+ q(:mr, 2) = q(:mr, 2) + b(:mr)
1413
+ b(:mr) = q(:mr, 1) + TWO*q(:mr, 2)
1414
+ tcos(1) = ZERO
1415
+
1416
+ call self%solve_tridiag(1, 0, mr, a, bb, c, b, tcos, d, w)
1417
+
1418
+ q(:mr, 1) = b(:mr)
1419
+ jr = 1
1420
+ i2r = 0
1421
+ goto 194
1422
+ end if
1423
+ !
1424
+ ! case n = 2**p+1
1425
+ !
1426
+ select case (istag)
1427
+ case (1)
1428
+ goto 162
1429
+ case (2)
1430
+ goto 170
1431
+ end select
1432
+
1433
+ 162 continue
1434
+
1435
+ b(:mr) = &
1436
+ q(:mr, j) + HALF*q(:mr, 1) &
1437
+ - q(:mr, jm1) + q(:mr, nlast) - &
1438
+ q(:mr, jm2)
1439
+
1440
+ call self%generate_cosines(jr, 1, HALF, ZERO, tcos)
1441
+
1442
+ call self%solve_tridiag(jr, 0, mr, a, bb, c, b, tcos, d, w)
1443
+
1444
+ q(:mr, j) = HALF*(q(:mr, j)-q(:mr, jm1)-q(:mr, jp1)) + b(:mr)
1445
+
1446
+ b(:mr) = q(:mr, 1) + TWO*q(:mr, nlast) + 4.0_wp*q(:mr, j)
1447
+
1448
+ jr2 = 2*jr
1449
+
1450
+ call self%generate_cosines(jr, 1, ZERO, ZERO, tcos)
1451
+
1452
+ tcos(jr+1:jr*2) = -tcos(jr:1:(-1))
1453
+
1454
+ call self%solve_tridiag(jr2, 0, mr, a, bb, c, b, tcos, d, w)
1455
+
1456
+ q(:mr, j) = q(:mr, j) + b(:mr)
1457
+ b(:mr) = q(:mr, 1) + TWO*q(:mr, j)
1458
+
1459
+ call self%generate_cosines(jr, 1, HALF, ZERO, tcos)
1460
+
1461
+ call self%solve_tridiag(jr, 0, mr, a, bb, c, b, tcos, d, w)
1462
+
1463
+ q(:mr, 1) = HALF*q(:mr, 1) - q(:mr, jm1) + b(:mr)
1464
+
1465
+ goto 194
1466
+ !
1467
+ ! case of general n with nr = 3 .
1468
+ !
1469
+ 168 continue
1470
+
1471
+ b(:mr) = q(:mr, 2)
1472
+ q(:mr, 2) = ZERO
1473
+ b2(:mr) = q(:mr, 3)
1474
+ b3(:mr) = q(:mr, 1)
1475
+ jr = 1
1476
+ i2r = 0
1477
+ j = 2
1478
+
1479
+ goto 177
1480
+
1481
+ 170 continue
1482
+
1483
+ b(:mr) = HALF*q(:mr, 1) - q(:mr, jm1) + q(:mr, j)
1484
+
1485
+ if (nrod == 0) then
1486
+ b(:mr) = b(:mr) + p(ipp+1:mr+ipp)
1487
+ else
1488
+ b(:mr) = b(:mr) + q(:mr, nlast) - q(:mr, jm2)
1489
+ end if
1490
+
1491
+ do i = 1, mr
1492
+ t = HALF*(q(i, j)-q(i, jm1)-q(i, jp1))
1493
+ q(i, j) = t
1494
+ b2(i) = q(i, nlast) + t
1495
+ b3(i) = q(i, 1) + TWO*t
1496
+ end do
1497
+
1498
+ 177 continue
1499
+
1500
+ k1 = kr + 2*jr - 1
1501
+ k2 = kr + jr
1502
+ tcos(k1+1) = -2.
1503
+ k4 = k1 + 3 - istag
1504
+
1505
+ call self%generate_cosines(k2 + istag - 2, 1, ZERO, fnum, tcos(k4:))
1506
+
1507
+ k4 = k1 + k2 + 1
1508
+
1509
+ call self%generate_cosines(jr - 1, 1, ZERO, ONE, tcos(k4:))
1510
+ call self%merge_cosines(tcos, k1, k2, k1 + k2, jr - 1, 0)
1511
+
1512
+ k3 = k1 + k2 + lr
1513
+
1514
+ call self%generate_cosines(jr, 1, HALF, ZERO, tcos(k3+1:))
1515
+
1516
+ k4 = k3 + jr + 1
1517
+
1518
+ call self%generate_cosines(kr, 1, HALF, fden, tcos(k4:))
1519
+ call self%merge_cosines(tcos, k3, jr, k3 + jr, kr, k1)
1520
+
1521
+ if (lr /= 0) then
1522
+ call self%generate_cosines(lr, 1, HALF, fden, tcos(k4:))
1523
+ call self%merge_cosines(tcos, k3, jr, k3 + jr, lr, k3 - lr)
1524
+ call self%generate_cosines(kr, 1, HALF, fden, tcos(k4:))
1525
+ end if
1526
+
1527
+ k3 = kr
1528
+ k4 = kr
1529
+
1530
+ call self%solve_tridiag3(mr, a, bb, c, k, b, b2, b3, tcos, d, w, w2, w3)
1531
+
1532
+ b(:mr) = b(:mr) + b2(:mr) + b3(:mr)
1533
+ tcos(1) = TWO
1534
+
1535
+ call self%solve_tridiag(1, 0, mr, a, bb, c, b, tcos, d, w)
1536
+
1537
+ q(:mr, j) = q(:mr, j) + b(:mr)
1538
+ b(:mr) = q(:mr, 1) + TWO*q(:mr, j)
1539
+
1540
+ call self%generate_cosines(jr, 1, HALF, ZERO, tcos)
1541
+ call self%solve_tridiag(jr, 0, mr, a, bb, c, b, tcos, d, w)
1542
+
1543
+ if (jr == 1) then
1544
+ q(:mr, 1) = b(:mr)
1545
+ goto 194
1546
+ end if
1547
+
1548
+ q(:mr, 1) = HALF*q(:mr, 1) - q(:mr, jm1) + b(:mr)
1549
+ goto 194
1550
+ end if
1551
+
1552
+ if (n == 2) then
1553
+ !
1554
+ ! case n = 2
1555
+ !
1556
+ b(:mr) = q(:mr, 1)
1557
+ tcos(1) = ZERO
1558
+
1559
+ call self%solve_tridiag(1, 0, mr, a, bb, c, b, tcos, d, w)
1560
+
1561
+ q(:mr, 1) = b(:mr)
1562
+ b(:mr) = TWO *(q(:mr, 2)+b(:mr))*fistag
1563
+ tcos(1) = -fistag
1564
+ tcos(2) = TWO
1565
+
1566
+ call self%solve_tridiag(2, 0, mr, a, bb, c, b, tcos, d, w)
1567
+
1568
+ q(:mr, 1) = q(:mr, 1) + b(:mr)
1569
+ jr = 1
1570
+ i2r = 0
1571
+ goto 194
1572
+ end if
1573
+
1574
+ b3(:mr) = ZERO
1575
+ b(:mr) = q(:mr, 1) + TWO *p(ipp+1:mr+ipp)
1576
+ q(:mr, 1) = HALF *q(:mr, 1) - q(:mr, jm1)
1577
+ b2(:mr) = TWO *(q(:mr, 1)+q(:mr, nlast))
1578
+ k1 = kr + jr - 1
1579
+ tcos(k1+1) = -2.
1580
+ k4 = k1 + 3 - istag
1581
+
1582
+ call self%generate_cosines(kr + istag - 2, 1, ZERO, fnum, tcos(k4:))
1583
+
1584
+ k4 = k1 + kr + 1
1585
+
1586
+ call self%generate_cosines(jr - 1, 1, ZERO, ONE, tcos(k4:))
1587
+ call self%merge_cosines(tcos, k1, kr, k1 + kr, jr - 1, 0)
1588
+ call self%generate_cosines(kr, 1, HALF, fden, tcos(k1+1:))
1589
+
1590
+ k2 = kr
1591
+ k4 = k1 + k2 + 1
1592
+
1593
+ call self%generate_cosines(lr, 1, HALF, fden, tcos(k4:))
1594
+
1595
+ k3 = lr
1596
+ k4 = 0
1597
+
1598
+ call self%solve_tridiag3(mr, a, bb, c, k, b, b2, b3, tcos, d, w, w2, w3)
1599
+
1600
+ b(:mr) = b(:mr) + b2(:mr)
1601
+ tcos(1) = TWO
1602
+
1603
+ call self%solve_tridiag(1, 0, mr, a, bb, c, b, tcos, d, w)
1604
+
1605
+ q(:mr, 1) = q(:mr, 1) + b(:mr)
1606
+ goto 194
1607
+
1608
+ 192 continue
1609
+
1610
+ b(:mr) = q(:mr, nlast)
1611
+ goto 196
1612
+
1613
+ 194 continue
1614
+
1615
+ j = nlast - jr
1616
+ b(:mr) = q(:mr, nlast) + q(:mr, j)
1617
+
1618
+ 196 continue
1619
+
1620
+ jm2 = nlast - i2r
1621
+
1622
+ if (jr == 1) then
1623
+ q(:mr, nlast) = ZERO
1624
+ else
1625
+ if (nrod == 0) then
1626
+ q(:mr, nlast) = p(ipp+1:mr+ipp)
1627
+ ipp = ipp - mr
1628
+ else
1629
+ q(:mr, nlast) = q(:mr, nlast) - q(:mr, jm2)
1630
+ end if
1631
+ end if
1632
+ call self%generate_cosines(kr, 1, HALF, fden, tcos)
1633
+ call self%generate_cosines(lr, 1, HALF, fden, tcos(kr+1:))
1634
+
1635
+ if (lr == 0) then
1636
+ b(:mr) = fistag*b(:mr)
1637
+ end if
1638
+
1639
+ call self%solve_tridiag(kr, lr, mr, a, bb, c, b, tcos, d, w)
1640
+
1641
+ q(:mr, nlast) = q(:mr, nlast) + b(:mr)
1642
+ nlastp = nlast
1643
+
1644
+ 206 continue
1645
+
1646
+ jstep = jr
1647
+ jr = i2r
1648
+ i2r = i2r/2
1649
+
1650
+ if (jr == 0) then
1651
+ w(1) = ipstor
1652
+ return
1653
+ end if
1654
+
1655
+ select case (mixbnd)
1656
+ case (2)
1657
+ jstart = jr
1658
+ case default
1659
+ jstart = 1 + jr
1660
+ end select
1661
+
1662
+ kr = kr - jr
1663
+
1664
+ if (nlast + jr <= n) then
1665
+ kr = kr - jr
1666
+ nlast = nlast + jr
1667
+ jstop = nlast - jstep
1668
+ else
1669
+ jstop = nlast - jr
1670
+ end if
1671
+
1672
+ lr = kr - jr
1673
+ call self%generate_cosines(jr, 1, HALF, ZERO, tcos)
1674
+
1675
+ do j = jstart, jstop, jstep
1676
+ jm2 = j - jr
1677
+ jp2 = j + jr
1678
+
1679
+ if (j == jr) then
1680
+ b(:mr) = q(:mr, j) + q(:mr, jp2)
1681
+ else
1682
+ b(:mr) = q(:mr, j) + q(:mr, jm2) + q(:mr, jp2)
1683
+ end if
1684
+
1685
+ if (jr == 1) then
1686
+ q(:mr, j) = ZERO
1687
+ else
1688
+ jm1 = j - i2r
1689
+ jp1 = j + i2r
1690
+ q(:mr, j) = HALF*(q(:mr, j)-q(:mr, jm1)-q(:mr, jp1))
1691
+ end if
1692
+
1693
+ call self%solve_tridiag(jr, 0, mr, a, bb, c, b, tcos, d, w)
1694
+ q(:mr, j) = q(:mr, j) + b(:mr)
1695
+ end do
1696
+
1697
+ nrod = 1
1698
+ if (nlast + i2r <= n) then
1699
+ nrod = 0
1700
+ end if
1701
+
1702
+ if (nlastp /= nlast) then
1703
+ goto 194
1704
+ end if
1705
+
1706
+ goto 206
1707
+
1708
+ w(1) = ipstor
1709
+
1710
+ end associate
1711
+
1712
+ end subroutine genbun_solve_poisson_neumann
1713
+
1714
+ end module type_CenteredCyclicReductionUtility