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