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,1338 @@
1
+ !
2
+ ! file sepx4.f90
3
+ !
4
+ ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5
+ ! * *
6
+ ! * copyright(c) 2005 by UCAR *
7
+ ! * *
8
+ ! * University Corporation for Atmospheric Research *
9
+ ! * *
10
+ ! * all rights reserved *
11
+ ! * *
12
+ ! * Fishpack *
13
+ ! * *
14
+ ! * A Package of Fortran *
15
+ ! * *
16
+ ! * Subroutines and Example Programs *
17
+ ! * *
18
+ ! * for Modeling Geophysical Processes *
19
+ ! * *
20
+ ! * by *
21
+ ! * *
22
+ ! * John Adams, Paul Swarztrauber and Roland Sweet *
23
+ ! * *
24
+ ! * of *
25
+ ! * *
26
+ ! * the National Center for Atmospheric Research *
27
+ ! * *
28
+ ! * Boulder, Colorado (80307) U.S.A. *
29
+ ! * *
30
+ ! * which is sponsored by *
31
+ ! * *
32
+ ! * the National Science Foundation *
33
+ ! * *
34
+ ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
35
+ !
36
+ ! SUBROUTINE sepx4(iorder, a, b, m, mbdcnd, bda, alpha, bdb, beta, c, d, n,
37
+ ! + nbdcnd, bdc, bdd, cofx, grhs, usol, idmn, pertrb,
38
+ ! + ierror)
39
+ !
40
+ !
41
+ !
42
+ ! DIMENSION OF bda(n+1), bdb(n+1), bdc(m+1), bdd(m+1),
43
+ ! ARGUMENTS usol(idmn, n+1), grhs(idmn, n+1),
44
+ !
45
+ !
46
+ ! LATEST REVISION May 2016
47
+ !
48
+ ! PURPOSE sepx4 solves for either the second-order
49
+ ! finite difference approximation or a
50
+ ! fourth-order approximation to a separable
51
+ ! elliptic equation
52
+ !
53
+ ! af(x)*uxx+bf(x)*ux+cf(x)*u+uyy = g(x, y)
54
+ !
55
+ ! on a rectangle(x greater than or equal to
56
+ ! a and less than or equal to b, y greater than
57
+ ! or equal to c and less than or equal to d).
58
+ ! any combination of periodic or mixed boundary
59
+ ! conditions is allowed. if boundary
60
+ ! conditions in the x direction are periodic
61
+ ! (see mbdcnd=0 below) then the coefficients
62
+ ! must satisfy
63
+ !
64
+ ! af(x)=c1, bf(x)=0, cf(x)=c2 for all x.
65
+ !
66
+ ! here c1, c2 are constants, c1>0.
67
+ !
68
+ ! the possible boundary conditions are:
69
+ ! in the x-direction:
70
+ ! (0) periodic, u(x+b-a, y)=u(x, y) for
71
+ ! all y, x
72
+ ! (1) u(a, y), u(b, y) are specified for all y
73
+ ! (2) u(a, y), du(b, y)/dx+beta*u(b, y) are
74
+ ! specified for all y
75
+ ! (3) du(a, y)/dx+alpha*u(a, y), du(b, y)/dx+
76
+ ! beta*u(b, y) are specified for all y
77
+ ! (4) du(a, y)/dx+alpha*u(a, y), u(b, y) are
78
+ ! specified for all y
79
+ !
80
+ ! in the y-direction:
81
+ ! (0) periodic, u(x, y+d-c)=u(x, y) for all x, y
82
+ ! (1) u(x, c), u(x, d) are specified for all x
83
+ ! (2) u(x, c), du(x, d)/dy are specified for
84
+ ! all x
85
+ ! (3) du(x, c)/dy, du(x, d)/dy are specified for
86
+ ! all x
87
+ ! (4) du(x, c)/dy, u(x, d) are specified for
88
+ ! all x
89
+ !
90
+ ! USAGE call sepx4(iorder, a, b, m, mbdcnd, bda, alpha, bdb,
91
+ ! beta, c, d, n, nbdcnd, bdc, bdd, cofx,
92
+ ! grhs, usol, idmn, w, pertrb, ierror)
93
+ !
94
+ ! ARGUMENTS
95
+ ! ON INPUT iorder
96
+ ! = 2 if a second-order approximation is
97
+ ! sought
98
+ ! = 4 if a fourth-order approximation is
99
+ ! sought
100
+ !
101
+ ! *** CAUTION *** grhs should be reset if sepx4 was first called
102
+ ! with iorder=2 and will be called again with
103
+ ! iorder=4. values in grhs are destroyed by the
104
+ ! iorder=2 call.
105
+ !
106
+ !
107
+ ! a, b
108
+ ! the range of the x-independent variable,
109
+ ! i.e., x is greater than or equal to a
110
+ ! and less than or equal to b. a must be
111
+ ! less than b.
112
+ !
113
+ ! m
114
+ ! the number of panels into which the
115
+ ! interval(a, b) is subdivided. hence,
116
+ ! there will be m+1 grid points in the x-
117
+ ! direction given by xi=a+(i-1)*dlx
118
+ ! for i=1, 2, ..., m+1 where dlx=(b-a)/m is
119
+ ! the panel width. m must be less than
120
+ ! idmn and greater than 5.
121
+ !
122
+ ! mbdcnd
123
+ ! indicates the type of boundary condition
124
+ ! at x=a and x=b
125
+ ! = 0 if the solution is periodic in x, i.e.,
126
+ ! u(x+b-a, y)=u(x, y) for all y, x
127
+ ! = 1 if the solution is specified at x=a
128
+ ! and x=b, i.e., u(a, y) and u(b, y) are
129
+ ! specified for all y
130
+ ! = 2 if the solution is specified at x=a
131
+ ! and the boundary condition is mixed at
132
+ ! x=b, i.e., u(a, y) and
133
+ ! du(b, y)/dx+beta*u(b, y) are specified
134
+ ! for all y
135
+ ! = 3 if the boundary conditions at x=a and
136
+ ! x=b are mixed, i.e.,
137
+ ! du(a, y)/dx+alpha*u(a, y) and
138
+ ! du(b, y)/dx+beta*u(b, y) are specified
139
+ ! for all y
140
+ ! = 4 if the boundary condition at x=a is
141
+ ! mixed and the solution is specified
142
+ ! at x=b, i.e., du(a, y)/dx+alpha*u(a, y)
143
+ ! and u(b, y) are specified for all y
144
+ !
145
+ ! bda
146
+ ! a one-dimensional array of length n+1 that
147
+ ! specifies the values of
148
+ ! du(a, y)/dx+ alpha*u(a, y) at x=a, when
149
+ ! mbdcnd=3 or 4.
150
+ ! bda(j) = du(a, yj)/dx+alpha*u(a, yj),
151
+ ! j=1, 2, ..., n+1
152
+ ! when mbdcnd has any other value, bda is
153
+ ! a dummy parameter.
154
+ !
155
+ ! alpha
156
+ ! the scalar multiplying the solution in case
157
+ ! of a mixed boundary condition at x=a
158
+ ! (see argument bda). if mbdcnd is not equal
159
+ ! to either 3 or 4, then alpha is a dummy
160
+ ! parameter.
161
+ !
162
+ ! bdb
163
+ ! a one-dimensional array of length n+1 that
164
+ ! specifies the values of
165
+ ! du(b, y)/dx+ beta*u(b, y) at x=b.
166
+ ! when mbdcnd=2 or 3
167
+ ! bdb(j) = du(b, yj)/dx+beta*u(b, yj),
168
+ ! j=1, 2, ..., n+1
169
+ ! when mbdcnd has any other value, bdb is
170
+ ! a dummy parameter.
171
+ !
172
+ ! beta
173
+ ! the scalar multiplying the solution in
174
+ ! case of a mixed boundary condition at x=b
175
+ ! (see argument bdb). if mbdcnd is not equal
176
+ ! to 2 or 3, then beta is a dummy parameter.
177
+ !
178
+ ! c, d
179
+ ! the range of the y-independent variable,
180
+ ! i.e., y is greater than or equal to c and
181
+ ! less than or equal to d. c must be less
182
+ ! than d.
183
+ !
184
+ ! n
185
+ ! the number of panels into which the
186
+ ! interval(c, d) is subdivided. hence,
187
+ ! there will be n+1 grid points in the y-
188
+ ! direction given by yj=c+(j-1)*dly for
189
+ ! j=1, 2, ..., n+1 where dly=(d-c)/n is the
190
+ ! panel width. in addition, n must be
191
+ ! greater than 4.
192
+ !
193
+ ! nbdcnd
194
+ ! indicates the types of boundary conditions
195
+ ! at y=c and y=d
196
+ ! = 0 if the solution is periodic in y,
197
+ ! i.e., u(x, y+d-c)=u(x, y) for all x, y
198
+ ! = 1 if the solution is specified at y=c
199
+ ! and y = d, i.e., u(x, c) and u(x, d)
200
+ ! are specified for all x
201
+ ! = 2 if the solution is specified at y=c
202
+ ! and the boundary condition is mixed
203
+ ! at y=d, i.e., du(x, c)/dy and u(x, d)
204
+ ! are specified for all x
205
+ ! = 3 if the boundary conditions are mixed
206
+ ! at y=cand y=d i.e.,
207
+ ! du(x, d)/dy and du(x, d)/dy are
208
+ ! specified for all x
209
+ ! = 4 if the boundary condition is mixed
210
+ ! at y=c and the solution is specified
211
+ ! at y=d, i.e. du(x, c)/dy+gama*u(x, c)
212
+ ! and u(x, d) are specified for all x
213
+ !
214
+ ! bdc
215
+ ! a one-dimensional array of length m+1 that
216
+ ! specifies the value du(x, c)/dy at y=c.
217
+ !
218
+ ! when nbdcnd=3 or 4
219
+ ! bdc(i) = du(xi, c)/dy i=1, 2, ..., m+1.
220
+ !
221
+ ! when nbdcnd has any other value, bdc is
222
+ ! a dummy parameter.
223
+ !
224
+ ! bdd
225
+ ! a one-dimensional array of length m+1 that
226
+ ! specified the value of du(x, d)/dy at y=d.
227
+ !
228
+ ! when nbdcnd=2 or 3
229
+ ! bdd(i)=du(xi, d)/dy i=1, 2, ..., m+1.
230
+ !
231
+ ! when nbdcnd has any other value, bdd is
232
+ ! a dummy parameter.
233
+ !
234
+ ! cofx
235
+ ! a user-supplied subprogram with parameters
236
+ ! x, afun, bfun, cfun which returns the
237
+ ! values of the x-dependent coefficients
238
+ ! af(x), bf(x), cf(x) in the elliptic
239
+ ! equation at x. if boundary conditions in
240
+ ! the x direction are periodic then the
241
+ ! coefficients must satisfy af(x)=c1, bf(x)=0,
242
+ ! cf(x)=c2 for all x. here c1>0
243
+ ! and c2 are constants.
244
+ !
245
+ ! note that cofx must be declared external
246
+ ! in the calling routine.
247
+ !
248
+ ! grhs
249
+ ! a two-dimensional array that specifies the
250
+ ! values of the right-hand side of the
251
+ ! elliptic equation, i.e., grhs(i, j)=g(xi, yi),
252
+ ! for i=2, ..., m, j=2, ..., n. at the
253
+ ! boundaries, grhs is defined by
254
+ !
255
+ ! mbdcnd grhs(1, j) grhs(m+1, j)
256
+ ! ------ --------- -----------
257
+ ! 0 g(a, yj) g(b, yj)
258
+ ! 1 * *
259
+ ! 2 * g(b, yj) j=1, 2, ..., n+1
260
+ ! 3 g(a, yj) g(b, yj)
261
+ ! 4 g(a, yj) *
262
+ !
263
+ ! nbdcnd grhs(i, 1) grhs(i, n+1)
264
+ ! ------ --------- -----------
265
+ ! 0 g(xi, c) g(xi, d)
266
+ ! 1 * *
267
+ ! 2 * g(xi, d) i=1, 2, ..., m+1
268
+ ! 3 g(xi, c) g(xi, d)
269
+ ! 4 g(xi, c) *
270
+ !
271
+ ! where * means these quantites are not used.
272
+ ! grhs should be dimensioned idmn by at least
273
+ ! n+1 in the calling routine.
274
+ !
275
+ ! *** CAUTION grhs should be reset if sepx4 was first called
276
+ ! with iorder=2 and will be called again with
277
+ ! iorder=4. values in grhs are destroyed by the
278
+ ! iorder=2 call.
279
+ !
280
+ ! usol
281
+ ! a two-dimensional array that specifies the
282
+ ! values of the solution along the boundaries.
283
+ ! at the boundaries, usol is defined by
284
+ !
285
+ ! mbdcnd usol(1, j) usol(m+1, j)
286
+ ! ------ --------- -----------
287
+ ! 0 * *
288
+ ! 1 u(a, yj) u(b, yj)
289
+ ! 2 u(a, yj) * j=1, 2, ..., n+1
290
+ ! 3 * *
291
+ ! 4 * u(b, yj)
292
+ !
293
+ ! nbdcnd usol(i, 1) usol(i, n+1)
294
+ ! ------ --------- -----------
295
+ ! 0 * *
296
+ ! 1 u(xi, c) u(xi, d)
297
+ ! 2 u(xi, c) * i=1, 2, ..., m+1
298
+ ! 3 * *
299
+ ! 4 * u(xi, d)
300
+ !
301
+ ! where * means the quantites are not used
302
+ ! in the solution.
303
+ !
304
+ ! if iorder=2, the user may equivalence grhs
305
+ ! and usol to save space. note that in this
306
+ ! case the tables specifying the boundaries
307
+ ! of the grhs and usol arrays determine the
308
+ ! boundaries uniquely except at the corners.
309
+ ! if the tables call for both g(x, y) and
310
+ ! u(x, y) at a corner then the solution must
311
+ ! be chosen.
312
+ ! for example, if mbdcnd=2 and nbdcnd=4,
313
+ ! then u(a, c), u(a, d), u(b, d) must be chosen
314
+ ! at the corners in addition to g(b, c).
315
+ !
316
+ ! if iorder=4, then the two arrays, usol and
317
+ ! grhs, must be distinct.
318
+ !
319
+ ! usol should be dimensioned idmn by at least
320
+ ! n+1 in the calling routine.
321
+ !
322
+ ! idmn
323
+ ! the row(or first) dimension of the arrays
324
+ ! grhs and usol as it appears in the program
325
+ ! calling sepeli. this parameter is used
326
+ ! to specify the variable dimension of grhs
327
+ ! and usol. idmn must be at least 7 and
328
+ ! greater than or equal to m+1.
329
+ !
330
+ !
331
+ ! ON OUTPUT usol
332
+ ! contains the approximate solution to the
333
+ ! elliptic equation. usol(i, j) is the
334
+ ! approximation to u(xi, yj) for i=1, 2..., m+1
335
+ ! and j=1, 2, ..., n+1. the approximation has
336
+ ! error o(dlx**2+dly**2) if called with
337
+ ! iorder=2 and o(dlx**4+dly**4) if called
338
+ ! with iorder=4.
339
+ !
340
+ ! pertrb
341
+ ! if a combination of periodic or derivative
342
+ ! boundary conditions(i.e., alpha=beta=0 if
343
+ ! mbdcnd=3) is specified and if cf(x)=0 for
344
+ ! all x then a solution to the discretized
345
+ ! matrix equation may not exist
346
+ ! (reflecting the non-uniqueness of solutions
347
+ ! to the pde).
348
+ ! pertrb is a constant calculated and
349
+ ! subtracted from the right hand side of the
350
+ ! matrix equation insuring the existence of a
351
+ ! solution. sepx4 computes this solution
352
+ ! which is a weighted minimal least squares
353
+ ! solution to the original problem. if
354
+ ! singularity is not detected pertrb=ZERO is
355
+ ! returned by sepx4.
356
+ !
357
+ ! ierror
358
+ ! an error flag that indicates invalid input
359
+ ! parameters or failure to find a solution
360
+ !
361
+ ! = 0 no error
362
+ ! = 1 if a greater than b or c greater
363
+ ! than d
364
+ ! = 2 if mbdcnd less than 0 or mbdcnd
365
+ ! greater than 4
366
+ ! = 3 if nbdcnd less than 0 or nbdcnd
367
+ ! greater than 4
368
+ ! = 4 if attempt to find a solution fails.
369
+ ! (the linear system generated is not
370
+ ! diagonally dominant.)
371
+ ! = 5 if idmn is too small(see discussion
372
+ ! of idmn)
373
+ ! = 6 if m is too small or too large
374
+ ! (see discussion of m)
375
+ ! = 7 if n is too small(see discussion of n)
376
+ ! = 8 if iorder is not 2 or 4
377
+ ! = 9 if intl is not 0 or 1
378
+ ! = 10 if afun is less than or equal to zero
379
+ ! for some interior mesh point xi some
380
+ ! interior mesh point(xi, yj)
381
+ ! = 12 if mbdcnd=0 and af(x)=cf(x)=constant
382
+ ! or bf(x)=0 for all x is not true.
383
+ ! = 20 if the dynamic allocation of real and
384
+ ! complex workspace required for solution
385
+ ! fails(for example if n, m are too large
386
+ ! for your computer)
387
+ !
388
+ ! SPECIAL CONDITIONS None
389
+ !
390
+ ! I/O None
391
+ !
392
+ ! REQUIRED FILES type_FishpackWorkspace.f90, genbun.f90, type_CyclicReductionUtility.f9090, type_SepAux.f90
393
+ !
394
+ !
395
+ ! PRECISION 64-bit double precision
396
+ !
397
+ !
398
+ ! STANDARD Fortran 2008
399
+ !
400
+ ! HISTORY sepx4 was developed at NCAR by John C.
401
+ ! Adams of the scientific computing division
402
+ ! in October 1978. The basis of this code is
403
+ ! NCAR routine sepeli. Both packages were
404
+ ! released on NCAR's public libraries in
405
+ ! January 1980. sepx4 was modified in June 2004
406
+ ! incorporating Fortran 90 dynamical storage
407
+ ! allocation for workspace requirements
408
+ !
409
+ !
410
+ ! ALGORITHM sepx4 automatically discretizes the separable
411
+ ! elliptic equation which is then solved by a
412
+ ! generalized cyclic reduction algorithm in the
413
+ ! subroutine pois. The fourth order solution
414
+ ! is obtained using the technique of defferred
415
+ ! corrections referenced below.
416
+ !
417
+ ! TIMING When possible, sepx4 should be used instead
418
+ ! of package sepeli. The increase in speed
419
+ ! is at least a factor of three.
420
+ !
421
+ ! REFERENCES Keller, H.B., Numerical methods for two-point
422
+ ! boundary-value problems, BLAISDEL (1968),
423
+ ! Waltham, Mass.
424
+ !
425
+ ! Swarztrauber, P., and R. Sweet (1975):
426
+ ! Efficient FORTRAN subprograms for the
427
+ ! solution of elliptic partial differential
428
+ ! equations. NCAR Technical note
429
+ ! NCAR-TN/IA-109, pp. 135-137.
430
+ !
431
+ module module_sepx4
432
+
433
+ use fishpack_precision, only: &
434
+ wp, & ! Working precision
435
+ ip ! Integer precision
436
+
437
+ use type_FishpackWorkspace, only: &
438
+ FishpackWorkspace
439
+
440
+ use centered_real_linear_systems_solver, only: &
441
+ genbun
442
+
443
+ use type_SepAux, only: &
444
+ SepAux, &
445
+ get_coefficients
446
+
447
+ ! Explicit typing only!
448
+ implicit none
449
+
450
+ ! Everything is private unless stated otherwise
451
+ private
452
+ public :: sepx4
453
+
454
+ type, private, extends(SepAux) :: Sepx4Aux
455
+ !---------------------------------------------------------------
456
+ ! Type components
457
+ !---------------------------------------------------------------
458
+ type(FishpackWorkspace), public :: workspace
459
+ !---------------------------------------------------------------
460
+ contains
461
+ !---------------------------------------------------------------
462
+ ! Type-bound procedures
463
+ !---------------------------------------------------------------
464
+ procedure, public :: initialize_workspace
465
+ procedure, public :: s4elip
466
+ procedure, private :: is_PDE_singular
467
+ procedure, private :: defer
468
+ !---------------------------------------------------------------
469
+ end type Sepx4Aux
470
+
471
+ !---------------------------------------------------------------
472
+ ! Parameters confined to the module
473
+ !---------------------------------------------------------------
474
+ real(wp), parameter :: ZERO = 0.0_wp
475
+ real(wp), parameter :: HALF = 0.5_wp
476
+ real(wp), parameter :: ONE = 1.0_wp
477
+ real(wp), parameter :: TWO = 2.0_wp
478
+ integer(ip), parameter :: IIWK = 12 !! Size of workspace indices
479
+ !---------------------------------------------------------------
480
+
481
+ contains
482
+
483
+ subroutine sepx4(iorder, a, b, m, mbdcnd, bda, alpha, bdb, beta, c, &
484
+ d, n, nbdcnd, bdc, bdd, cofx, grhs, usol, idmn, pertrb, &
485
+ ierror)
486
+ !--------------------------------------------------------------
487
+ ! Dummy arguments
488
+ !--------------------------------------------------------------
489
+ integer(ip), intent(in) :: iorder
490
+ integer(ip), intent(in) :: m
491
+ integer(ip), intent(in) :: mbdcnd
492
+ integer(ip), intent(in) :: n
493
+ integer(ip), intent(in) :: nbdcnd
494
+ integer(ip), intent(in) :: idmn
495
+ integer(ip), intent(out) :: ierror
496
+ real(wp), intent(in) :: a
497
+ real(wp), intent(in) :: b
498
+ real(wp), intent(in) :: alpha
499
+ real(wp), intent(in) :: beta
500
+ real(wp), intent(in) :: c
501
+ real(wp), intent(in) :: d
502
+ real(wp), intent(out) :: pertrb
503
+ real(wp), intent(in) :: bda(:)
504
+ real(wp), intent(in) :: bdb(:)
505
+ real(wp), intent(in) :: bdc(:)
506
+ real(wp), intent(in) :: bdd(:)
507
+ real(wp), intent(inout) :: grhs(:,:)
508
+ real(wp), intent(out) :: usol(:,:)
509
+ procedure(get_coefficients) :: cofx
510
+ !--------------------------------------------------------------
511
+ ! Local variables
512
+ !--------------------------------------------------------------
513
+ type(Sepx4Aux) :: aux
514
+ !--------------------------------------------------------------
515
+
516
+ ! Check input parameters
517
+ call check_input_parameters(iorder, a, b, m, mbdcnd, c, d, n, nbdcnd, cofx, idmn, ierror)
518
+
519
+ if (ierror /= 0) return
520
+
521
+ ! Initialize workspace arrays and indices
522
+ call aux%initialize_workspace(n, m, nbdcnd)
523
+
524
+ ! Solve system
525
+ associate( &
526
+ i => aux%workspace%workspace_indices, &
527
+ rew => aux%workspace%real_workspace &
528
+ )
529
+ associate( &
530
+ an => rew(i(1):), &
531
+ bn => rew(i(2):), &
532
+ cn => rew(i(3):), &
533
+ dn => rew(i(4):), &
534
+ un => rew(i(5):), &
535
+ zn => rew(i(6):), &
536
+ am => rew(i(7):i(7)), &
537
+ bm => rew(i(8):i(8)), &
538
+ cm => rew(i(9):i(9)), &
539
+ dm => rew(i(10):), &
540
+ um => rew(i(11):), &
541
+ zm => rew(i(12):) &
542
+ )
543
+ call aux%s4elip(iorder, a, b, m, mbdcnd, bda, alpha, bdb, beta, &
544
+ c, d, n, nbdcnd, bdc, bdd, cofx, an, bn, cn, dn, un, zn, am, bm, &
545
+ cm, dm, um, zm, grhs, usol, idmn, pertrb, ierror)
546
+ end associate
547
+ end associate
548
+
549
+ !
550
+ ! Release memory
551
+ !
552
+ call aux%workspace%destroy()
553
+
554
+ end subroutine sepx4
555
+
556
+ subroutine initialize_workspace(self, n, m, nbdcnd)
557
+ !--------------------------------------------------------------
558
+ ! Dummy arguments
559
+ !--------------------------------------------------------------
560
+ class(Sepx4Aux), intent(inout) :: self
561
+ integer(ip), intent(in) :: n, m, nbdcnd
562
+ !--------------------------------------------------------------
563
+ ! Local variables
564
+ !--------------------------------------------------------------
565
+ integer(ip) :: l, k, length, irwk, icwk
566
+ !--------------------------------------------------------------
567
+
568
+ associate( w => self%workspace )
569
+ ! Compute minimum workspace and check workspace length input
570
+ select case (nbdcnd)
571
+ case (0)
572
+ l = n
573
+ k = m + 1
574
+ case default
575
+ l = n + 1
576
+ k = m + 1
577
+ end select
578
+
579
+ ! Compute required real and complex workspace sizes
580
+ call compute_workspace_dimensions(n, l, k, length, irwk, icwk)
581
+
582
+ ! Allocate memory for workspace arrays
583
+ call w%create(irwk, icwk, IIWK)
584
+
585
+ ! Set workspace indices
586
+ w%workspace_indices = get_workspace_indices(length, l, k)
587
+ end associate
588
+
589
+ end subroutine initialize_workspace
590
+
591
+ pure subroutine compute_workspace_dimensions(n, l, k, length, irwk, icwk)
592
+ !--------------------------------------------------------------
593
+ ! Dummy arguments
594
+ !--------------------------------------------------------------
595
+ integer(ip), intent(in) :: n
596
+ integer(ip), intent(in) :: l
597
+ integer(ip), intent(in) :: k
598
+ integer(ip), intent(out) :: length
599
+ integer(ip), intent(out) :: irwk
600
+ integer(ip), intent(out) :: icwk
601
+ !--------------------------------------------------------------
602
+ integer(ip) :: log2n
603
+ !--------------------------------------------------------------
604
+
605
+ log2n = int(log(real(n + 1, kind=wp))/log(TWO) + HALF, kind=ip)
606
+ length = 4*(n + 1) +(10 + log2n) * k
607
+
608
+ ! set real and complex workspace sizes
609
+ irwk = length + 6 * (k + l) + 1
610
+ icwk = 0
611
+
612
+ end subroutine compute_workspace_dimensions
613
+
614
+ pure function get_workspace_indices(length, l, k) result (return_value)
615
+ !--------------------------------------------------------------
616
+ ! Dummy arguments
617
+ !--------------------------------------------------------------
618
+ integer(ip), intent(in) :: length
619
+ integer(ip), intent(in) :: l
620
+ integer(ip), intent(in) :: k
621
+ integer(ip) :: return_value(IIWK)
622
+ !--------------------------------------------------------------
623
+ integer(ip) :: j !! Counter
624
+ !--------------------------------------------------------------
625
+
626
+ associate( i => return_value)
627
+ i(1) = length + 1
628
+
629
+ do j = 1, 6
630
+ i(j+1) = i(j) + l
631
+ end do
632
+
633
+ do j = 7, 11
634
+ i(j+1) = i(j) + k
635
+ end do
636
+ end associate
637
+
638
+ end function get_workspace_indices
639
+
640
+ subroutine s4elip(self, iorder, a, b, m, mbdcnd, bda, alpha, bdb, beta, &
641
+ c, d, n, nbdcnd, bdc, bdd, cofx, an, bn, cn, dn, un, zn, am, bm, &
642
+ cm, dm, um, zm, grhs, usol, idmn, pertrb, ierror)
643
+ !
644
+ ! Purpose:
645
+ !
646
+ ! s4elip sets up vectors and arrays for input to blktri
647
+ ! and computes a second order solution in usol. a return jump to
648
+ ! sepeli occurrs if iorder=2. if iorder=4 a fourth order
649
+ ! solution is generated in usol.
650
+ !
651
+ !--------------------------------------------------------------
652
+ ! Dummy arguments
653
+ !--------------------------------------------------------------
654
+ class(Sepx4Aux), intent(inout) :: self
655
+ integer(ip), intent(in) :: iorder
656
+ integer(ip), intent(in) :: m
657
+ integer(ip), intent(in) :: mbdcnd
658
+ integer(ip), intent(in) :: n
659
+ integer(ip), intent(in) :: nbdcnd
660
+ integer(ip), intent(in) :: idmn
661
+ integer(ip), intent(inout) :: ierror
662
+ real(wp), intent(in) :: a
663
+ real(wp), intent(in) :: b
664
+ real(wp), intent(in) :: alpha
665
+ real(wp), intent(in) :: beta
666
+ real(wp), intent(in) :: c
667
+ real(wp), intent(in) :: d
668
+ real(wp), intent(out) :: pertrb
669
+ real(wp), intent(in) :: bda(:)
670
+ real(wp), intent(in) :: bdb(:)
671
+ real(wp), intent(in) :: bdc(:)
672
+ real(wp), intent(in) :: bdd(:)
673
+ real(wp), intent(inout) :: an(:)
674
+ real(wp), intent(inout) :: bn(:)
675
+ real(wp), intent(inout) :: cn(:)
676
+ real(wp), intent(inout) :: dn(:)
677
+ real(wp), intent(inout) :: un(:)
678
+ real(wp), intent(inout) :: zn(:)
679
+ real(wp), intent(inout) :: am(:)
680
+ real(wp), intent(inout) :: bm(:)
681
+ real(wp), intent(inout) :: cm(:)
682
+ real(wp), intent(inout) :: dm(:)
683
+ real(wp), intent(inout) :: um(:)
684
+ real(wp), intent(inout) :: zm(:)
685
+ real(wp), intent(inout) :: grhs(:,:)
686
+ real(wp), intent(inout) :: usol(:,:)
687
+ procedure(get_coefficients) :: cofx
688
+ !--------------------------------------------------------------
689
+ ! Local variables
690
+ !--------------------------------------------------------------
691
+ integer(ip) :: i, i1, mp, np, local_error_flag
692
+ real(wp) :: xi, ai, bi, ci, axi, bxi, cxi
693
+ real(wp) :: dyj, eyj, fyj, ax1, cxm
694
+ real(wp) :: dy1, fyn, gama, xnu, prtrb
695
+ logical :: singular
696
+ !-----------------------------------------------
697
+
698
+ ! Associate various quantities
699
+ associate( &
700
+ kswx => self%kswx, &
701
+ kswy => self%kswy, &
702
+ k => self%k, &
703
+ l=>self%l, &
704
+ mit=>self%mit, &
705
+ nit=> self%nit, &
706
+ is=> self%is, &
707
+ ms=> self%ms, &
708
+ js=> self%js, &
709
+ ns=> self%ns, &
710
+ ait => self%ait, &
711
+ bit => self%bit, &
712
+ cit => self%cit, &
713
+ dit => self%dit, &
714
+ dlx => self%dlx, &
715
+ dly => self%dly, &
716
+ tdlx3 => self%tdlx3, &
717
+ tdly3 => self%tdly3, &
718
+ dlx4 => self%dlx4, &
719
+ dly4 => self%dly4 &
720
+ )
721
+
722
+ ! set parameters internally
723
+ !
724
+ kswx = mbdcnd + 1
725
+ kswy = nbdcnd + 1
726
+ k = m + 1
727
+ l = n + 1
728
+ ait = a
729
+ bit = b
730
+ cit = c
731
+ dit = d
732
+ dly =(dit - cit)/n
733
+ !
734
+ ! set right hand side values from grhs in usol on the interior
735
+ ! and non-specified boundaries.
736
+ !
737
+ usol(2:m, 2:n) = (dly**2) * grhs(2:m, 2:n)
738
+
739
+ if (kswx /= 2 .and. kswx /= 3) then
740
+ usol(1, 2:n) = (dly**2) * grhs(1, 2:n)
741
+ end if
742
+
743
+ if (kswx /= 2 .and. kswx /= 5) then
744
+ usol(k, 2:n) = (dly**2) * grhs(k, 2:n)
745
+ end if
746
+
747
+ if (kswy /= 2 .and. kswy /= 3) then
748
+ usol(2:m, 1) = (dly**2) * grhs(2:m, 1)
749
+ end if
750
+
751
+ if (kswy /= 2 .and. kswy /= 5) then
752
+ usol(2:m, l) = (dly**2) * grhs(2:m, l)
753
+ end if
754
+
755
+ if (kswx /= 2 .and. kswx /= 3 .and. kswy /= 2 .and. kswy /= 3) then
756
+ usol(1, 1) = (dly**2) * grhs(1, 1)
757
+ end if
758
+
759
+ if (kswx /= 2 .and. kswx /= 5 .and. kswy /= 2 .and. kswy /= 3) then
760
+ usol(k, 1) = (dly**2) * grhs(k, 1)
761
+ end if
762
+
763
+ if (kswx /= 2 .and. kswx /= 3 .and. kswy /= 2 .and. kswy /= 5) then
764
+ usol(1, l) = (dly**2) * grhs(1, l)
765
+ end if
766
+
767
+ if (kswx /= 2 .and. kswx /= 5 .and. kswy /= 2 .and. kswy /= 5) then
768
+ usol(k, l) = (dly**2) * grhs(k, l)
769
+ end if
770
+
771
+ i1 = 1
772
+ !
773
+ ! set switches for periodic or non-periodic boundaries
774
+ !
775
+ if (kswx == 1) then
776
+ mp = 0
777
+ else
778
+ mp = 1
779
+ end if
780
+
781
+ np = nbdcnd
782
+ !
783
+ ! set dlx, dly and size of block tri-diagonal system generated
784
+ ! in nint, mint
785
+ !
786
+ dlx =(bit - ait)/m
787
+ mit = k - 1
788
+
789
+ if (kswx == 2) then
790
+ mit = k - 2
791
+ end if
792
+
793
+ if (kswx == 4) then
794
+ mit = k
795
+ end if
796
+
797
+ dly =(dit - cit)/n
798
+ nit = l - 1
799
+
800
+ if (kswy == 2) then
801
+ nit = l - 2
802
+ end if
803
+
804
+ if (kswy == 4) then
805
+ nit = l
806
+ end if
807
+
808
+ tdlx3 = TWO * (dlx**3)
809
+ dlx4 = dlx**4
810
+ tdly3 = TWO * (dly**3)
811
+ dly4 = dly**4
812
+ !
813
+ ! set subscript limits for portion of array to input to blktri
814
+ !
815
+ if (kswx==2 .or. kswx==3) then
816
+ is = 2
817
+ else
818
+ is = 1
819
+ end if
820
+
821
+ if (kswy==2 .or. kswy==3) then
822
+ js = 2
823
+ else
824
+ js = 1
825
+ end if
826
+
827
+ ns = nit + js - 1
828
+ ms = mit + is - 1
829
+ !
830
+ ! set x - direction
831
+ !
832
+ do i = 1, mit
833
+ xi = ait + real(is + i - 2, kind=wp)*dlx
834
+ call cofx(xi, ai, bi, ci)
835
+ axi =(ai/dlx - HALF*bi)/dlx
836
+ bxi =(-TWO * ai/dlx**2) + ci
837
+ cxi =(ai/dlx + HALF*bi)/dlx
838
+ am(i) = (dly**2) * axi
839
+ bm(i) = (dly**2)*bxi
840
+ cm(i) = (dly**2)*cxi
841
+ end do
842
+ !
843
+ ! set y direction
844
+ !
845
+ dyj = ONE
846
+ eyj = -TWO
847
+ fyj = ONE
848
+ an(:nit) = dyj
849
+ bn(:nit) = eyj
850
+ cn(:nit) = fyj
851
+ !
852
+ ! adjust edges in x direction unless periodic
853
+ !
854
+ ax1 = am(1)
855
+ cxm = cm(mit)
856
+ select case(kswx)
857
+ case(2)
858
+ !
859
+ ! dirichlet-dirichlet in x direction
860
+ !
861
+ am(1) = ZERO
862
+ cm(mit) = ZERO
863
+ case(3)
864
+ !
865
+ ! dirichlet-mixed in x direction
866
+ !
867
+ am(1) = ZERO
868
+ am(mit) = am(mit) + cxm
869
+ bm(mit) = bm(mit) - TWO * beta*dlx*cxm
870
+ cm(mit) = ZERO
871
+ case(4)
872
+ !
873
+ ! mixed - mixed in x direction
874
+ !
875
+ am(1) = ZERO
876
+ bm(1) = bm(1) + TWO * dlx * alpha * ax1
877
+ cm(1) = cm(1) + ax1
878
+ am(mit) = am(mit) + cxm
879
+ bm(mit) = bm(mit) - TWO * dlx * beta * cxm
880
+ cm(mit) = ZERO
881
+ case(5)
882
+ !
883
+ ! mixed-dirichlet in x direction
884
+ !
885
+ am(1) = ZERO
886
+ bm(1) = bm(1) + TWO * alpha * dlx * ax1
887
+ cm(1) = cm(1) + ax1
888
+ cm(mit) = ZERO
889
+ end select
890
+ !
891
+ ! adjust in y direction unless periodic
892
+ !
893
+ dy1 = an(1)
894
+ fyn = cn(nit)
895
+ gama = ZERO
896
+ xnu = ZERO
897
+ select case(kswy)
898
+ case(2)
899
+ !
900
+ ! dirichlet-dirichlet in y direction
901
+ !
902
+ an(1) = ZERO
903
+ cn(nit) = ZERO
904
+ case(3)
905
+ !
906
+ ! dirichlet-mixed in y direction
907
+ !
908
+ an(1) = ZERO
909
+ an(nit) = an(nit) + fyn
910
+ bn(nit) = bn(nit) - TWO * dly * xnu * fyn
911
+ cn(nit) = ZERO
912
+ case(4)
913
+ !
914
+ ! mixed - mixed direction in y direction
915
+ !
916
+ an(1) = ZERO
917
+ bn(1) = bn(1) + TWO * dly * gama * dy1
918
+ cn(1) = cn(1) + dy1
919
+ an(nit) = an(nit) + fyn
920
+ bn(nit) = bn(nit) - TWO * dly * xnu * fyn
921
+ cn(nit) = ZERO
922
+ case(5)
923
+ !
924
+ ! mixed-dirichlet in y direction
925
+ !
926
+ an(1) = ZERO
927
+ bn(1) = bn(1) + TWO * dly * gama * dy1
928
+ cn(1) = cn(1) + dy1
929
+ cn(nit) = ZERO
930
+ end select
931
+
932
+ if (kswx /= 1) then
933
+ !
934
+ ! adjust usol along x edge
935
+ !
936
+ if (kswx==2 .or. kswx==3) then
937
+ if (kswx==2 .or. kswx==5) then
938
+ usol(is,js:ns) = usol(is,js:ns) - ax1*usol(1,js:ns)
939
+ usol(ms,js:ns) = usol(ms,js:ns) - cxm*usol(k,js:ns)
940
+ else
941
+ usol(is,js:ns) = usol(is,js:ns) - ax1*usol(1,js:ns)
942
+ usol(ms,js:ns) = usol(ms,js:ns) - TWO * dlx*cxm*bdb(js:ns)
943
+ end if
944
+ else
945
+ if (kswx==2 .or. kswx==5) then
946
+ usol(is,js:ns) = usol(is,js:ns) + TWO * dlx*ax1*bda(js:ns)
947
+ usol(ms,js:ns) = usol(ms,js:ns) - cxm*usol(k,js:ns)
948
+ else
949
+ usol(is,js:ns) = usol(is,js:ns) + TWO * dlx*ax1*bda(js:ns)
950
+ usol(ms,js:ns) = usol(ms,js:ns) - TWO * dlx*cxm*bdb(js:ns)
951
+ end if
952
+ end if
953
+ end if
954
+ if (kswy /= 1) then
955
+ !
956
+ ! adjust usol along y edge
957
+ !
958
+ if (kswy==2 .or. kswy==3) then
959
+ if (kswy==2 .or. kswy==5) then
960
+ usol(is:ms,js) = usol(is:ms,js) - dy1*usol(is:ms, 1)
961
+ usol(is:ms, ns) = usol(is:ms, ns) - fyn*usol(is:ms, l)
962
+ else
963
+ usol(is:ms,js) = usol(is:ms,js) - dy1*usol(is:ms, 1)
964
+ usol(is:ms, ns) = usol(is:ms, ns) - TWO * dly*fyn*bdd(is:ms)
965
+ end if
966
+ else
967
+ if (kswy==2 .or. kswy==5) then
968
+ usol(is:ms,js) = usol(is:ms,js) + TWO * dly*dy1*bdc(is:ms)
969
+ usol(is:ms, ns) = usol(is:ms, ns) - fyn*usol(is:ms, l)
970
+ else
971
+ usol(is:ms,js) = usol(is:ms,js) + TWO * dly*dy1*bdc(is:ms)
972
+ usol(is:ms, ns) = usol(is:ms, ns) - TWO * dly*fyn*bdd(is:ms)
973
+ end if
974
+ end if
975
+ end if
976
+ !
977
+ ! save adjusted edges in grhs if iorder=4
978
+ !
979
+ if (iorder == 4) then
980
+ grhs(is,js:ns) = usol(is,js:ns)
981
+ grhs(ms,js:ns) = usol(ms,js:ns)
982
+ grhs(is:ms,js) = usol(is:ms,js)
983
+ grhs(is:ms, ns) = usol(is:ms, ns)
984
+ end if
985
+
986
+ pertrb = ZERO
987
+ !
988
+ ! check if operator is singular
989
+ !
990
+ call self%is_PDE_singular(mbdcnd, nbdcnd, alpha, beta, cofx, singular)
991
+ !
992
+ ! compute non-zero eigenvector in null space of transpose
993
+ ! if singular
994
+ !
995
+ if (singular) then
996
+ call self%septri(mit, am, bm, cm, dm, um, zm)
997
+ end if
998
+
999
+ if (singular) then
1000
+ call self%septri(nit, an, bn, cn, dn, un, zn)
1001
+ end if
1002
+ !
1003
+ ! adjust right hand side if necessary
1004
+ !
1005
+ if (singular) then
1006
+ call self%seport(usol, zn, zm, pertrb)
1007
+ end if
1008
+
1009
+ !
1010
+ ! compute solution
1011
+ !
1012
+ ! save adjusted right hand side in grhs
1013
+ grhs(is:ms,js:ns) = usol(is:ms,js:ns)
1014
+
1015
+ call genbun(np, nit, mp, mit, am, bm, cm, idmn, usol(is:,js:), local_error_flag)
1016
+ !
1017
+ ! Check if error detected in pois
1018
+ ! this can only correspond to ierror=12
1019
+ if (local_error_flag /= 0) then
1020
+ ! set error flag if improper coefficients input to pois
1021
+ ierror = 12
1022
+ return
1023
+ end if
1024
+
1025
+ if (ierror /= 0) return
1026
+ !
1027
+ ! set periodic boundaries if necessary
1028
+ !
1029
+ if (kswx == 1) usol(k, :l) = usol(1, :l)
1030
+
1031
+ if (kswy == 1) usol(:k, l) = usol(:k, 1)
1032
+ !
1033
+ ! minimize solution with respect to weighted least squares
1034
+ ! norm if operator is singular
1035
+ !
1036
+ if (singular) call self%sepmin(usol, zn, zm, prtrb)
1037
+ !
1038
+ ! return if deferred corrections and a fourth order solution are
1039
+ ! not flagged
1040
+ !
1041
+ if (iorder == 2) return
1042
+ !
1043
+ ! compute new right hand side for fourth order solution
1044
+ !
1045
+ call self%defer(cofx, idmn, usol, grhs)
1046
+
1047
+ if (singular) call self%seport(usol, zn, zm, pertrb)
1048
+ !
1049
+ ! compute solution
1050
+ !
1051
+ ! save adjusted right hand side in grhs
1052
+ grhs(is:ms,js:ns) = usol(is:ms,js:ns)
1053
+
1054
+ call genbun(np, nit, mp, mit, am, bm, cm, idmn, usol(is:,js:), local_error_flag)
1055
+
1056
+ !
1057
+ ! check if error detected in pois
1058
+ ! this can only correspond to ierror=12
1059
+ !
1060
+ if (local_error_flag /= 0) then
1061
+ ! set error flag if improper coefficients input to pois
1062
+ ierror = 12
1063
+ return
1064
+ end if
1065
+
1066
+ if (ierror /= 0) return
1067
+ !
1068
+ ! set periodic boundaries if necessary
1069
+ !
1070
+ if (kswx == 1) usol(k, :l) = usol(1, :l)
1071
+ if (kswy == 1) usol(:k, l) = usol(:k, 1)
1072
+
1073
+ !
1074
+ ! minimize solution with respect to weighted least squares
1075
+ ! norm if operator is singular
1076
+ !
1077
+ if (singular) call self%sepmin(usol, zn, zm, prtrb)
1078
+ end associate
1079
+
1080
+ end subroutine s4elip
1081
+
1082
+ subroutine check_input_parameters(iorder, a, b, m, mbdcnd, c, d, n, nbdcnd, cofx, &
1083
+ idmn, ierror)
1084
+ !
1085
+ ! Purpose:
1086
+ !
1087
+ ! This program checks the input parameters for errors
1088
+ !
1089
+ !--------------------------------------------------------------
1090
+ ! Dummy arguments
1091
+ !--------------------------------------------------------------
1092
+ integer(ip), intent(in) :: iorder
1093
+ integer(ip), intent(in) :: m
1094
+ integer(ip), intent(in) :: mbdcnd
1095
+ integer(ip), intent(in) :: n
1096
+ integer(ip), intent(in) :: nbdcnd
1097
+ integer(ip), intent(in) :: idmn
1098
+ integer(ip), intent(out) :: ierror
1099
+ real(wp), intent(in) :: a
1100
+ real(wp), intent(in) :: b
1101
+ real(wp), intent(in) :: c
1102
+ real(wp), intent(in) :: d
1103
+ procedure(get_coefficients) :: cofx
1104
+ !--------------------------------------------------------------
1105
+ ! Local variables
1106
+ !--------------------------------------------------------------
1107
+ integer(ip) :: i
1108
+ real(wp) :: xi, ai, bi, ci
1109
+ real(wp) :: dlx
1110
+ !--------------------------------------------------------------
1111
+
1112
+ if (a >= b .or. c >= d) then ! check definition of solution region
1113
+ ierror = 1
1114
+ return
1115
+ else if (mbdcnd < 0 .or. mbdcnd > 4) then ! check boundary switches
1116
+ ierror = 2
1117
+ return
1118
+ else if (nbdcnd < 0 .or. nbdcnd > 4) then
1119
+ ierror = 3
1120
+ return
1121
+ else if (idmn < 7) then ! check first dimension in calling routine
1122
+ ierror = 5
1123
+ return
1124
+ else if (m > idmn - 1 .or. m < 6) then ! check m
1125
+ ierror = 6
1126
+ return
1127
+ else if (n < 5) then ! check n
1128
+ ierror = 7
1129
+ return
1130
+ else if (iorder /= 2 .and. iorder /= 4) then ! Check iorder
1131
+ ierror = 8
1132
+ return
1133
+ end if
1134
+ !
1135
+ ! Check that equation is elliptic
1136
+ !
1137
+ dlx =(b - a)/m
1138
+ do i = 2, m
1139
+ xi = a + real(i - 1, kind=wp) * dlx
1140
+ call cofx(xi, ai, bi, ci)
1141
+
1142
+ if (ai > ZERO) cycle
1143
+
1144
+ ierror = 10
1145
+ return
1146
+ end do
1147
+ !
1148
+ ! no error found
1149
+ !
1150
+ ierror = 0
1151
+
1152
+
1153
+ end subroutine check_input_parameters
1154
+
1155
+ subroutine is_PDE_singular(self, mbdcnd, nbdcnd, alpha, beta, cofx, singlr)
1156
+ !
1157
+ ! Purpose:
1158
+ !
1159
+ ! this subroutine checks if the pde sepeli
1160
+ ! must solve is a singular operator
1161
+ !
1162
+ !--------------------------------------------------------------
1163
+ ! Dummy arguments
1164
+ !--------------------------------------------------------------
1165
+ class(Sepx4Aux), intent(inout) :: self
1166
+ integer(ip), intent(in) :: mbdcnd
1167
+ integer(ip), intent(in) :: nbdcnd
1168
+ real(wp), intent(in) :: alpha
1169
+ real(wp), intent(in) :: beta
1170
+ logical , intent(out) :: singlr
1171
+ procedure(get_coefficients) :: cofx
1172
+ !--------------------------------------------------------------
1173
+ ! Local variables
1174
+ !--------------------------------------------------------------
1175
+ integer(ip) :: i
1176
+ real(wp) :: xi, ai, bi, ci
1177
+ !--------------------------------------------------------------
1178
+
1179
+ ! Associate various quantities
1180
+ associate( &
1181
+ kswx => self%kswx, &
1182
+ kswy => self%kswy, &
1183
+ k => self%k, &
1184
+ l=>self%l, &
1185
+ mit=>self%mit, &
1186
+ nit=> self%nit, &
1187
+ is=> self%is, &
1188
+ ms=> self%ms, &
1189
+ js=> self%js, &
1190
+ ns=> self%ns, &
1191
+ ait => self%ait, &
1192
+ bit => self%bit, &
1193
+ cit => self%cit, &
1194
+ dit => self%dit, &
1195
+ dlx => self%dlx, &
1196
+ dly => self%dly, &
1197
+ tdlx3 => self%tdlx3, &
1198
+ tdly3 => self%tdly3, &
1199
+ dlx4 => self%dlx4, &
1200
+ dly4 => self%dly4 &
1201
+ )
1202
+
1203
+ singlr = .false.
1204
+ !
1205
+ ! check if the boundary conditions are
1206
+ ! entirely periodic and/or mixed
1207
+ !
1208
+ if (mbdcnd /=0 .and. mbdcnd /=3 .or. nbdcnd /=0 .and. nbdcnd /= 3) return
1209
+ !
1210
+ ! check that mixed conditions are pure neuman
1211
+ !
1212
+ if (mbdcnd == 3 .and. (alpha /= ZERO .or. beta /= ZERO)) return
1213
+ !
1214
+ ! check that non-derivative coefficient functions
1215
+ ! are zero
1216
+ !
1217
+ do i = is, ms
1218
+ xi = ait + real(i - 1, kind=wp)*dlx
1219
+ call cofx(xi, ai, bi, ci)
1220
+ if (ci == ZERO) cycle
1221
+ return
1222
+ end do
1223
+ !
1224
+ ! the operator must be singular if this point is reached
1225
+ !
1226
+ singlr = .true.
1227
+
1228
+ end associate
1229
+
1230
+ end subroutine is_PDE_singular
1231
+
1232
+ subroutine defer(self, cofx, idmn, usol, grhs)
1233
+ !
1234
+ ! Purpose:
1235
+ !
1236
+ ! this subroutine first approximates the truncation error given by
1237
+ ! trun1(x, y)=dlx**2*tx+dly**2*ty where
1238
+ ! tx=afun(x)*uxxxx/12 + bfun(x)*uxxx/6 on the interior and
1239
+ ! at the boundaries if periodic(here uxxx, uxxxx are the third
1240
+ ! and fourth partial derivatives of u with respect to x).
1241
+ ! tx is of the form afun(x)/3 * (uxxxx/4+uxxx/dlx)
1242
+ ! at x=a or x=b if the boundary condition there is mixed.
1243
+ ! tx=ZERO along specified boundaries. ty has symmetric form
1244
+ ! in y with x, afun(x), bfun(x) replaced by y, dfun(y), efun(y).
1245
+ ! the second order solution in usol is used to approximate
1246
+ ! (via second order finite differencing) the truncation error
1247
+ ! and the result is added to the right hand side in grhs
1248
+ ! and then transferred to usol to be used as a new right
1249
+ ! hand side when calling blktri for a fourth order solution.
1250
+ !
1251
+ !--------------------------------------------------------------
1252
+ ! Dummy arguments
1253
+ !--------------------------------------------------------------
1254
+ class(Sepx4Aux), intent(inout) :: self
1255
+ integer(ip), intent(in) :: idmn
1256
+ real(wp), intent(inout) :: usol(:,:)
1257
+ real(wp), intent(inout) :: grhs(:,:)
1258
+ procedure(get_coefficients) :: cofx
1259
+ !--------------------------------------------------------------
1260
+ ! Local variables
1261
+ !--------------------------------------------------------------
1262
+ integer(ip) :: i, j
1263
+ real(wp) :: xi, ai, bi, ci
1264
+ real(wp) :: uxxx, uxxxx, uyyy, uyyyy, tx, ty
1265
+ !--------------------------------------------------------------
1266
+
1267
+ ! Associate various quantities
1268
+ associate( &
1269
+ kswx => self%kswx, &
1270
+ kswy => self%kswy, &
1271
+ k => self%k, &
1272
+ l=>self%l, &
1273
+ mit=>self%mit, &
1274
+ nit=> self%nit, &
1275
+ is=> self%is, &
1276
+ ms=> self%ms, &
1277
+ js=> self%js, &
1278
+ ns=> self%ns, &
1279
+ ait => self%ait, &
1280
+ bit => self%bit, &
1281
+ cit => self%cit, &
1282
+ dit => self%dit, &
1283
+ dlx => self%dlx, &
1284
+ dly => self%dly, &
1285
+ tdlx3 => self%tdlx3, &
1286
+ tdly3 => self%tdly3, &
1287
+ dlx4 => self%dlx4, &
1288
+ dly4 => self%dly4 &
1289
+ )
1290
+
1291
+ ! compute truncation error approximation over the entire mesh
1292
+ !
1293
+ do i = is, ms
1294
+ xi = ait + real(i - 1, kind=wp)*dlx
1295
+ call cofx(xi, ai, bi, ci)
1296
+ do j = js, ns
1297
+ !
1298
+ ! compute partial derivative approximations at(xi, yj)
1299
+ !
1300
+ call self%sepdx(usol, i, j, uxxx, uxxxx)
1301
+ call self%sepdy(usol, idmn, i, j, uyyy, uyyyy)
1302
+ tx = ai*(uxxxx/12) + bi*(uxxx/6)
1303
+ ty = uyyyy/12
1304
+ !
1305
+ ! reset form of truncation if at boundary which is non-periodic
1306
+ !
1307
+ if (kswx /= 1 .and. (i==1 .or. i==k)) then
1308
+ tx = (ai/3) * ((uxxxx/4) + uxxx/dlx)
1309
+ end if
1310
+
1311
+ if (kswy /= 1 .and. (j==1 .or. j==l)) then
1312
+ ty = ((uyyyy/4)+uyyy/dly)/3
1313
+ end if
1314
+
1315
+ grhs(i, j) = grhs(i, j) + (dly**2)*((dlx**2)*tx + (dly**2)*ty)
1316
+ end do
1317
+ end do
1318
+ !
1319
+ ! reset the right hand side in usol
1320
+ !
1321
+ usol(is:ms,js:ns) = grhs(is:ms,js:ns)
1322
+
1323
+ end associate
1324
+
1325
+ end subroutine defer
1326
+
1327
+ end module module_sepx4
1328
+ !
1329
+ ! REVISION HISTORY
1330
+ !
1331
+ ! September 1973 Version 1
1332
+ ! April 1976 Version 2
1333
+ ! January 1978 Version 3
1334
+ ! December 1979 Version 3.1
1335
+ ! February 1985 Documentation upgrade
1336
+ ! November 1988 Version 3.2, FORTRAN 77 changes
1337
+ ! June 2004 Version 5.0, Fortran 90 changes
1338
+ ! May 2016 Fortran 2008 changes