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,1947 @@
1
+ !
2
+ ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3
+ ! * *
4
+ ! * copyright (c) 2005 by UCAR *
5
+ ! * *
6
+ ! * University Corporation for Atmospheric Research *
7
+ ! * *
8
+ ! * all rights reserved *
9
+ ! * *
10
+ ! * Fishpack *
11
+ ! * *
12
+ ! * A Package of Fortran *
13
+ ! * *
14
+ ! * Subroutines and Example Programs *
15
+ ! * *
16
+ ! * for Modeling Geophysical Processes *
17
+ ! * *
18
+ ! * by *
19
+ ! * *
20
+ ! * John Adams, Paul Swarztrauber and Roland Sweet *
21
+ ! * *
22
+ ! * of *
23
+ ! * *
24
+ ! * the National Center for Atmospheric Research *
25
+ ! * *
26
+ ! * Boulder, Colorado (80307) U.S.A. *
27
+ ! * *
28
+ ! * which is sponsored by *
29
+ ! * *
30
+ ! * the National Science Foundation *
31
+ ! * *
32
+ ! * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33
+ !
34
+ module complex_block_tridiagonal_linear_systems_solver
35
+
36
+ use fishpack_precision, only: &
37
+ wp, & ! Working precision
38
+ ip, & ! Integer precision
39
+ MACHINE_EPSILON
40
+
41
+ use type_GeneralizedCyclicReductionUtility, only: &
42
+ psgf, &
43
+ ppspf, &
44
+ ppsgf, &
45
+ comf_interface, &
46
+ GeneralizedCyclicReductionUtility
47
+
48
+ use type_FishpackWorkspace, only: &
49
+ FishpackWorkspace
50
+
51
+ ! Explicit typing only
52
+ implicit none
53
+
54
+ ! Everything is private unless stated otherwise
55
+ private
56
+ public :: cblktri
57
+
58
+ ! Parameters confined to the module
59
+ real(wp), parameter :: ZERO = 0.0_wp
60
+ real(wp), parameter :: HALF = 0.5_wp
61
+ real(wp), parameter :: ONE = 1.0_wp
62
+ real(wp), parameter :: TWO = 2.0_wp
63
+
64
+ type, private, extends(GeneralizedCyclicReductionUtility) :: ComplexGeneralizedCyclicReductionUtility
65
+ contains
66
+ ! Public type-bound procedures
67
+ procedure, public :: cblktri_lower_routine
68
+ ! Private type-bound procedures
69
+ procedure, private :: cblktri_bsrh
70
+ procedure, private :: cblktri_compute_roots_of_b_polynomials
71
+ procedure, private :: cblktri_compute_eigenvalues
72
+ procedure, private :: cblktri_tevls
73
+ procedure, private :: cblktri_compute_index_a_coeff
74
+ procedure, private :: cblktri_compute_index_b_coeff
75
+ procedure, private :: cblktri_compute_index_c_coeff
76
+ end type ComplexGeneralizedCyclicReductionUtility
77
+
78
+ contains
79
+
80
+ ! PURPOSE cblktri solves a system of linear equations
81
+ ! of the form
82
+ !
83
+ ! an(j)*x(i, j-1) + am(i)*x(i-1, j) +
84
+ ! (bn(j)+bm(i))*x(i, j) + cn(j)*x(i, j+1) +
85
+ ! cm(i)*x(i+1, j) = y(i, j)
86
+ !
87
+ ! for i = 1, 2, ..., m and j = 1, 2, ..., n.
88
+ !
89
+ ! i+1 and i-1 are evaluated modulo m and
90
+ ! j+1 and j-1 modulo n, i.e.,
91
+ !
92
+ ! x(i, 0) = x(i, n), x(i, n+1) = x(i, 1),
93
+ ! x(0, j) = x(m, j), x(m+1, j) = x(1, j).
94
+ !
95
+ ! these equations usually result from the
96
+ ! discretization of separable elliptic
97
+ ! equations. boundary conditions may be
98
+ ! dirichlet, neumann, or periodic.
99
+ !
100
+ ! cblktri is a complex version of package
101
+ ! blktri on ulib.
102
+ !
103
+ ! USAGE call cblktri(iflg, np, n, an, bn, cn, mp, m, am, bm,
104
+ ! cm, idimy, y, ierror, w)
105
+ !
106
+ !
107
+ ! DIMENSION OF an(n), bn(n), cn(n), am(m), bm(m), cm(m), y(idimy, n)
108
+ ! ARGUMENTS
109
+ !
110
+ ! ARGUMENTS
111
+ !
112
+ ! ON INPUT iflg
113
+ !
114
+ ! = 0 initialization only.
115
+ ! certain quantities that depend on np,
116
+ ! n, an, bn, and cn are computed and
117
+ ! stored in the derived data type w
118
+ !
119
+ ! = 1 the quantities that were computed
120
+ ! in the initialization are used
121
+ ! to obtain the solution x(i, j).
122
+ !
123
+ ! note:
124
+ ! a call with iflg=0 takes
125
+ ! approximately one half the time
126
+ ! as a call with iflg = 1.
127
+ ! however, the initialization does
128
+ ! not have to be repeated unless np,
129
+ ! n, an, bn, or cn change.
130
+ !
131
+ ! np
132
+ ! = 0 if an(1) and cn(n) are not zero,
133
+ ! which corresponds to periodic
134
+ ! bounary conditions.
135
+ !
136
+ ! = 1 if an(1) and cn(n) are zero.
137
+ !
138
+ ! n
139
+ ! the number of unknowns in the j-direction.
140
+ ! n must be greater than 4.
141
+ ! the operation count is proportional to
142
+ ! mnlog2(n), hence n should be selected
143
+ ! less than or equal to m.
144
+ !
145
+ ! an, bn, cn
146
+ ! one-dimensional arrays of length n
147
+ ! that specify the coefficients in the
148
+ ! linear equations given above.
149
+ !
150
+ ! mp
151
+ ! = 0 if am(1) and cm(m) are not zero,
152
+ ! which corresponds to periodic
153
+ ! boundary conditions.
154
+ !
155
+ ! = 1 if am(1) = cm(m) = 0 .
156
+ !
157
+ ! m
158
+ ! the number of unknowns in the i-direction.
159
+ ! m must be greater than 4.
160
+ !
161
+ ! am, bm, cm
162
+ ! complex one-dimensional arrays of length m
163
+ ! that specify the coefficients in the linear
164
+ ! equations given above.
165
+ !
166
+ ! idimy
167
+ ! the row (or first) dimension of the
168
+ ! two-dimensional array y as it appears
169
+ ! in the program calling cblktri.
170
+ ! this parameter is used to specify the
171
+ ! variable dimension of y.
172
+ ! idimy must be at least m.
173
+ !
174
+ ! y
175
+ ! a complex two-dimensional array that
176
+ ! specifies the values of the right side of
177
+ ! the linear system of equations given above.
178
+ ! y must be dimensioned y(idimy, n) with
179
+ ! idimy >= m.
180
+ !
181
+ ! w
182
+ ! A FishpackWorkspace derived data type variable
183
+ ! which is used internally in cblktri to
184
+ ! dynamically allocate real and complex workspace
185
+ ! arrays used in solution. An error flag
186
+ ! (ierror = 20) is set if the required workspace
187
+ ! allocation fails (for example if n, m are too large)
188
+ ! real and complex values are set in the components
189
+ ! of w on a initial (iflg=0) call to cblktri. These
190
+ ! must be preserved on non-initial calls (iflg=1)
191
+ ! to cblktri. This eliminates redundant calculations
192
+ ! and saves compute time.
193
+ ! **** IMPORTANT! the user program calling cblktri should
194
+ ! include the statement:
195
+ !
196
+ ! call w%destroy()
197
+ !
198
+ ! after the final approximation is generated by
199
+ ! cblktri. The will deallocate the real and complex
200
+ ! workspace arrays of w. Tailure to include this statement
201
+ ! could result in serious memory leakage.
202
+ !
203
+ !
204
+ ! ARGUMENTS
205
+ !
206
+ ! ON OUTPUT y
207
+ ! contains the solution x.
208
+ !
209
+ ! ierror
210
+ ! an error flag that indicates invalid
211
+ ! input parameters. except for number zer0,
212
+ ! a solution is not attempted.
213
+ !
214
+ ! = 0 no error.
215
+ ! = 1 m < 5
216
+ ! = 2 n < 5
217
+ ! = 3 idimy < m.
218
+ ! = 4 cblktri failed while computing results
219
+ ! that depend on the coefficient arrays
220
+ ! an, bn, cn. check these arrays.
221
+ ! = 5 an(j)*cn(j-1) is less than 0 for some j.
222
+ !
223
+ ! possible reasons for this condition are
224
+ ! 1. the arrays an and cn are not correct
225
+ ! 2. too large a grid spacing was used
226
+ ! in the discretization of the elliptic
227
+ ! equation.
228
+ ! 3. the linear equations resulted from a
229
+ ! partial differential equation which
230
+ ! was not elliptic.
231
+ !
232
+ ! = 20 if the dynamic allocation of real and
233
+ ! complex workspace in the derived type
234
+ ! (FishpackWorkspace) variable w fails (e.g.,
235
+ ! if n, m are too large for the platform used)
236
+ !
237
+ !
238
+ !
239
+ ! SPECIAL CONDITIONS The algorithm may fail if
240
+ !
241
+ ! abs(bm(i)+bn(j)) < abs(am(i))+abs(an(j)) +
242
+ ! abs(cm(i))+abs(cn(j))
243
+ !
244
+ ! for some i and j. the algorithm will also
245
+ ! fail if an(j)*cn(j-1) < 0 zero for some j.
246
+ ! see the description of the output parameter
247
+ ! ierror.
248
+ !
249
+ !
250
+ ! HISTORY * Written by Paul Swarztrauber at NCAR in
251
+ ! the early 1970's. Rewritten an released
252
+ ! on NCAR's public software libraries in
253
+ ! January, 1980.
254
+ ! * Revised in June 2004 by John Adams using
255
+ ! Fortran 90 dynamically allocated workspace
256
+ ! and derived data types to eliminate mixed
257
+ ! mode conflicts in the earlier versions.
258
+ !
259
+ ! ALGORITHM Generalized cyclic reduction
260
+ ! (see reference below)
261
+ !
262
+ ! PORTABILITY The approximate machine accuracy is computed
263
+ ! by calling the intrinsic function epsilon
264
+ !
265
+ ! REFERENCES Swarztrauber, P. and R. Sweet, 'Efficient
266
+ ! FORTRAN subprograms for the solution of
267
+ ! elliptic equations'
268
+ ! NCAR TN/IA-109, July, 1975, 138 pp.
269
+ !
270
+ ! Swarztrauber P. N., A direct method for
271
+ ! the discrete solution of separable
272
+ ! elliptic equations, S.I.A.M.
273
+ ! J. Numer. Anal., 11(1974) pp. 1136-1150.
274
+ !
275
+ subroutine cblktri(iflg, np, n, an, bn, cn, mp, m, am, bm, cm, &
276
+ idimy, y, ierror, w)
277
+
278
+ ! Dummy arguments
279
+ integer(ip), intent(in) :: iflg
280
+ integer(ip), intent(in) :: np
281
+ integer(ip), intent(in) :: n
282
+ integer(ip), intent(in) :: mp
283
+ integer(ip), intent(in) :: m
284
+ integer(ip), intent(in) :: idimy
285
+ integer(ip), intent(out) :: ierror
286
+ real(wp), intent(in) :: an(:)
287
+ real(wp), intent(in) :: bn(:)
288
+ real(wp), intent(in) :: cn(:)
289
+ complex(wp), intent(in) :: am(:)
290
+ complex(wp), intent(in) :: bm(:)
291
+ complex(wp), intent(in) :: cm(:)
292
+ complex(wp), intent(inout) :: y(:,:)
293
+ class(FishpackWorkspace), intent(inout) :: w
294
+
295
+ ! Local variables
296
+ type(ComplexGeneralizedCyclicReductionUtility) :: util
297
+ integer(ip) :: m2, nh, nl, iwah, iw1, iwbh
298
+ integer(ip) :: iw2, iw3, iwd, iww, iwu
299
+ integer(ip) :: irwk, icwk
300
+
301
+ common_variables: associate( &
302
+ npp => util%npp, &
303
+ k => util%k, &
304
+ nm => util%nm, &
305
+ ncmplx=> util%ncmplx, &
306
+ ik => util%ik, &
307
+ cnv => util%cnv &
308
+ )
309
+
310
+ ! Test m and n for the proper form
311
+ nm = n
312
+ m2 = 2*m
313
+
314
+ ! Check input arguments
315
+ if (m < 5) then
316
+ ierror = 1
317
+ return
318
+ else if (nm < 3) then
319
+ ierror = 2
320
+ return
321
+ else if (idimy < m) then
322
+ ierror = 3
323
+ return
324
+ else
325
+ ierror = 0
326
+ end if
327
+
328
+ ! Compute workspace indices
329
+ nh = n
330
+ npp = np
331
+
332
+ if (npp /= 0) nh = nh + 1
333
+
334
+ ik = 4
335
+ k = 3
336
+
337
+ do
338
+ if (nh <= ik) exit
339
+ ik = 2*ik
340
+ k = k + 1
341
+ end do
342
+
343
+ nl = ik
344
+ ik = 2*ik
345
+ nl = nl - 1
346
+ iwah = (k - 2)*ik + k + 6
347
+
348
+ select case (npp)
349
+ case(0)
350
+ iwbh = iwah + 2*nm
351
+ iw1 = iwbh
352
+ nm = nm - 1
353
+ case default
354
+ iw1 = iwah
355
+ iwbh = iw1 + nm
356
+ end select
357
+
358
+ iw2 = iw1 + m
359
+ iw3 = iw2 + m
360
+ iwd = iw3 + m
361
+ iww = iwd + m
362
+ iwu = iww + m
363
+
364
+ select case (iflg)
365
+ case (0)
366
+ ! Initialize solver
367
+
368
+ ! Set required workspace sizes
369
+ irwk = iw1 + 2*n
370
+ icwk = iw1 + 6*m
371
+
372
+ ! Allocate memory
373
+ call w%create(irwk, icwk)
374
+
375
+ ! Check if allocation was successful
376
+ if (ierror == 20) return
377
+
378
+ associate( &
379
+ rew => w%real_workspace, &
380
+ cxw => w%complex_workspace &
381
+ )
382
+ ! Compute roots of b polynomials
383
+ call util%cblktri_compute_roots_of_b_polynomials(ierror, an, bn, cn, rew, cxw, rew(iwah:), rew(iwbh:))
384
+ end associate
385
+ case default
386
+ ! Solve system
387
+ associate( &
388
+ rew => w%real_workspace, &
389
+ cxw => w%complex_workspace &
390
+ )
391
+ select case (mp)
392
+ case (0)
393
+ call util%cblktri_lower_routine(nl, an, cn, m, am, bm, cm, &
394
+ idimy, y, rew, cxw, &
395
+ cxw(iw1), cxw(iw2), cxw(iw3), cxw(iwd), cxw(iww), &
396
+ cxw(iwu), procp, cprocp)
397
+ case default
398
+ call util%cblktri_lower_routine(nl, an, cn, m, am, bm, cm, &
399
+ idimy, y, rew, cxw, &
400
+ cxw(iw1), cxw(iw2), cxw(iw3), cxw(iwd), cxw(iww), &
401
+ cxw(iwu), proc, cproc)
402
+ end select
403
+ end associate
404
+ end select
405
+ end associate common_variables
406
+
407
+ end subroutine cblktri
408
+
409
+ ! Purpose:
410
+ !
411
+ ! Solves the linear system
412
+ !
413
+ ! Remarks:
414
+ !
415
+ ! b contains the roots of all the b polynomials
416
+ ! w1, w2, w3, wd, ww, wu are all working arrays
417
+ ! prdct is either procp or proc depending on whether the boundary
418
+ ! conditions in the m direction are periodic or not
419
+ ! cprdct is either cprocp or cproc which are called if some of the zeros
420
+ ! of the b polynomials are complex.
421
+ !
422
+ subroutine cblktri_lower_routine(self, n, an, cn, m, am, bm, cm, idimy, y, b, bc, &
423
+ w1, w2, w3, wd, ww, wu, prdct, cprdct)
424
+
425
+ ! Dummy arguments
426
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
427
+ integer(ip), intent(in) :: n
428
+ integer(ip), intent(in) :: m
429
+ integer(ip), intent(in) :: idimy
430
+ real(wp), intent(in) :: an(:)
431
+ real(wp), intent(in) :: cn(:)
432
+ complex(wp), intent(in) :: am(:)
433
+ complex(wp), intent(in) :: bm(:)
434
+ complex(wp), intent(in) :: cm(:)
435
+ real(wp), intent(out) :: b(*)
436
+ complex(wp), intent(inout) :: y(idimy,n)
437
+ complex(wp), intent(out) :: bc(*)
438
+ complex(wp), intent(out) :: w1(*)
439
+ complex(wp), intent(out) :: w2(*)
440
+ complex(wp), intent(out) :: w3(*)
441
+ complex(wp), intent(out) :: wd(*)
442
+ complex(wp), intent(out) :: ww(*)
443
+ complex(wp), intent(out) :: wu(*)
444
+ external :: prdct, cprdct
445
+
446
+ ! Local variables
447
+ integer(ip) :: kdo, l, ir, i2, i1, i3, i4, irm1, im2, nm2, im3, nm3
448
+ integer(ip) :: im1, nm1, iif, i, ipi1, ipi2, ipi3, idxc, nc, idxa, na, ip2, np2
449
+ integer(ip) :: ip1, np1, ip3, np3, iz, nz, izr, ll, ifd
450
+ integer(ip) :: iip, np, imi1, imi2
451
+ real(wp) :: dummy_variable(1)
452
+
453
+ common_variables: associate( &
454
+ npp => self%npp, &
455
+ k => self%k, &
456
+ nm => self%nm, &
457
+ ncmplx=> self%ncmplx, &
458
+ ik => self%ik, &
459
+ cnv => self%cnv &
460
+ )
461
+
462
+ ! begin reduction phase
463
+ kdo = k - 1
464
+ do l = 1, kdo
465
+ ir = l - 1
466
+ i2 = 2**ir
467
+ i1 = i2/2
468
+ i3 = i2 + i1
469
+ i4 = i2 + i2
470
+ irm1 = ir - 1
471
+ call self%cblktri_compute_index_b_coeff(i2, ir, im2, nm2)
472
+ call self%cblktri_compute_index_b_coeff(i1, irm1, im3, nm3)
473
+ call self%cblktri_compute_index_b_coeff(i3, irm1, im1, nm1)
474
+ call prdct(nm2, b(im2), nm3, b(im3), nm1, b(im1), 0, dummy_variable, &
475
+ y(1,i2), w3, m, am, bm, cm, wd, ww, wu)
476
+ iif = 2**k
477
+ do i = i4, iif, i4
478
+ if (i > nm) cycle
479
+ ipi1 = i + i1
480
+ ipi2 = i + i2
481
+ ipi3 = i + i3
482
+ call self%cblktri_compute_index_c_coeff(i, ir, idxc, nc)
483
+ if (iif <= i) cycle
484
+ call self%cblktri_compute_index_a_coeff(i, ir, idxa, na)
485
+ call self%cblktri_compute_index_b_coeff(i - i1, irm1, im1, nm1)
486
+ call self%cblktri_compute_index_b_coeff(ipi2, ir, ip2, np2)
487
+ call self%cblktri_compute_index_b_coeff(ipi1, irm1, ip1, np1)
488
+ call self%cblktri_compute_index_b_coeff(ipi3, irm1, ip3, np3)
489
+ call prdct(nm1, b(im1), 0, dummy_variable, 0, dummy_variable, na, an(idxa), w3, &
490
+ w1, m, am, bm, cm, wd, ww, wu)
491
+ if (ipi2 > nm) then
492
+ w3(:m) = ZERO
493
+ w2(:m) = ZERO
494
+ else
495
+ call prdct(np2, b(ip2), np1, b(ip1), np3, b(ip3), 0, dummy_variable, &
496
+ y(1, ipi2), w3, m, am, bm, cm, wd, ww, wu)
497
+ call prdct(np1, b(ip1), 0, dummy_variable, 0, dummy_variable, nc, cn(idxc), w3, &
498
+ w2, m, am, bm, cm, wd, ww, wu)
499
+ end if
500
+ y(:m, i) = w1(:m) + w2(:m) + y(:m, i)
501
+ end do
502
+ end do
503
+
504
+ if (npp == 0) then
505
+ iif = 2**k
506
+ i = iif/2
507
+ i1 = i/2
508
+ call self%cblktri_compute_index_b_coeff(i - i1, k - 2, im1, nm1)
509
+ call self%cblktri_compute_index_b_coeff(i + i1, k - 2, ip1, np1)
510
+ call self%cblktri_compute_index_b_coeff(i, k - 1, iz, nz)
511
+ call prdct(nz, b(iz), nm1, b(im1), np1, b(ip1), 0, dummy_variable, &
512
+ y(1, i), w1, m, am, bm, cm, wd, ww, wu)
513
+
514
+ izr = i
515
+ w2(:m) = w1(:m)
516
+
517
+ do ll = 2, k
518
+ l = k - ll + 1
519
+ ir = l - 1
520
+ i2 = 2**ir
521
+ i1 = i2/2
522
+ i = i2
523
+ call self%cblktri_compute_index_c_coeff(i, ir, idxc, nc)
524
+ call self%cblktri_compute_index_b_coeff(i, ir, iz, nz)
525
+ call self%cblktri_compute_index_b_coeff(i - i1, ir - 1, im1, nm1)
526
+ call self%cblktri_compute_index_b_coeff(i + i1, ir - 1, ip1, np1)
527
+ call prdct(np1, b(ip1), 0, dummy_variable, 0, dummy_variable, nc, cn(idxc), w1, &
528
+ w1, m, am, bm, cm, wd, ww, wu)
529
+ w1(:m) = y(:m, i) + w1(:m)
530
+ call prdct(nz, b(iz), nm1, b(im1), np1, b(ip1), 0, dummy_variable, w1 &
531
+ , w1, m, am, bm, cm, wd, ww, wu)
532
+ end do
533
+
534
+ loop_118: do ll = 2, k
535
+ l = k - ll + 1
536
+ ir = l - 1
537
+ i2 = 2**ir
538
+ i1 = i2/2
539
+ i4 = i2 + i2
540
+ ifd = iif - i2
541
+ do i = i2, ifd, i4
542
+
543
+ if (i - i2 /= izr) cycle
544
+
545
+ if (i > nm) cycle loop_118
546
+
547
+ call self%cblktri_compute_index_a_coeff(i, ir, idxa, na)
548
+ call self%cblktri_compute_index_b_coeff(i, ir, iz, nz)
549
+ call self%cblktri_compute_index_b_coeff(i - i1, ir - 1, im1, nm1)
550
+ call self%cblktri_compute_index_b_coeff(i + i1, ir - 1, ip1, np1)
551
+ call prdct(nm1, b(im1), 0, dummy_variable, 0, dummy_variable, na, an(idxa), w2 &
552
+ , w2, m, am, bm, cm, wd, ww, wu)
553
+ w2(:m) = y(:m, i) + w2(:m)
554
+ call prdct(nz, b(iz), nm1, b(im1), np1, b(ip1), 0, dummy_variable, &
555
+ w2, w2, m, am, bm, cm, wd, ww, wu)
556
+ izr = i
557
+ if (i == nm) exit loop_118
558
+ end do
559
+ end do loop_118
560
+
561
+ y(:m, nm+1) = y(:m, nm+1) - cn(nm+1)*w1(:m) - an(nm+1)*w2(:m)
562
+
563
+ call self%cblktri_compute_index_b_coeff(iif/2, k - 1, im1, nm1)
564
+ call self%cblktri_compute_index_b_coeff(iif, k - 1, iip, np)
565
+
566
+ select case (ncmplx)
567
+ case (0)
568
+ call prdct(nm + 1, b(iip), nm1, b(im1), 0, dummy_variable, 0, dummy_variable, &
569
+ y(1,nm+1), y(1, nm+1), m, am, bm, cm, wd, ww, wu)
570
+ case default
571
+ call cprdct(nm + 1, bc(iip), nm1, b(im1), 0, dummy_variable, 0, dummy_variable, &
572
+ y(1,nm+1), y(1, nm+1), m, am, bm, cm, w1, w3, ww)
573
+ end select
574
+
575
+ w1(:m) = an(1)*y(:m, nm+1)
576
+ w2(:m) = cn(nm)*y(:m, nm+1)
577
+ y(:m, 1) = y(:m, 1) - w1(:m)
578
+ y(:m, nm) = y(:m, nm) - w2(:m)
579
+
580
+ do l = 1, kdo
581
+ ir = l - 1
582
+ i2 = 2**ir
583
+ i4 = i2 + i2
584
+ i1 = i2/2
585
+ i = i4
586
+ call self%cblktri_compute_index_a_coeff(i, ir, idxa, na)
587
+ call self%cblktri_compute_index_b_coeff(i - i2, ir, im2, nm2)
588
+ call self%cblktri_compute_index_b_coeff(i - i2 - i1, ir - 1, im3, nm3)
589
+ call self%cblktri_compute_index_b_coeff(i - i1, ir - 1, im1, nm1)
590
+ call prdct(nm2, b(im2), nm3, b(im3), nm1, b(im1), 0, dummy_variable, &
591
+ w1, w1, m, am, bm, cm, wd, ww, wu)
592
+ call prdct(nm1, b(im1), 0, dummy_variable, 0, dummy_variable, na, an(idxa), w1, &
593
+ w1, m, am, bm, cm, wd, ww, wu)
594
+ y(:m, i) = y(:m, i) - w1(:m)
595
+ end do
596
+
597
+ izr = nm
598
+ loop_131: do l = 1, kdo
599
+ ir = l - 1
600
+ i2 = 2**ir
601
+ i1 = i2/2
602
+ i3 = i2 + i1
603
+ i4 = i2 + i2
604
+ irm1 = ir - 1
605
+ do i = i4, iif, i4
606
+ ipi1 = i + i1
607
+ ipi2 = i + i2
608
+ ipi3 = i + i3
609
+
610
+ if (ipi2 /= izr) then
611
+ if (i /= izr) cycle
612
+ cycle loop_131
613
+ end if
614
+
615
+ call self%cblktri_compute_index_c_coeff(i, ir, idxc, nc)
616
+ call self%cblktri_compute_index_b_coeff(ipi2, ir, ip2, np2)
617
+ call self%cblktri_compute_index_b_coeff(ipi1, irm1, ip1, np1)
618
+ call self%cblktri_compute_index_b_coeff(ipi3, irm1, ip3, np3)
619
+ call prdct(np2, b(ip2), np1, b(ip1), np3, b(ip3), 0, dummy_variable, &
620
+ w2, w2, m, am, bm, cm, wd, ww, wu)
621
+ call prdct(np1, b(ip1), 0, dummy_variable, 0, dummy_variable, nc, cn(idxc), w2, &
622
+ w2, m, am, bm, cm, wd, ww, wu)
623
+ y(:m, i) = y(:m, i) - w2(:m)
624
+ izr = i
625
+ cycle loop_131
626
+ end do
627
+ end do loop_131
628
+ end if
629
+
630
+ ! begin back substitution phase
631
+ do ll = 1, k
632
+ l = k - ll + 1
633
+ ir = l - 1
634
+ irm1 = ir - 1
635
+ i2 = 2**ir
636
+ i1 = i2/2
637
+ i4 = i2 + i2
638
+ ifd = iif - i2
639
+ do i = i2, ifd, i4
640
+ if (i > nm) cycle
641
+ imi1 = i - i1
642
+ imi2 = i - i2
643
+ ipi1 = i + i1
644
+ ipi2 = i + i2
645
+ call self%cblktri_compute_index_a_coeff(i, ir, idxa, na)
646
+ call self%cblktri_compute_index_c_coeff(i, ir, idxc, nc)
647
+ call self%cblktri_compute_index_b_coeff(i, ir, iz, nz)
648
+ call self%cblktri_compute_index_b_coeff(imi1, irm1, im1, nm1)
649
+ call self%cblktri_compute_index_b_coeff(ipi1, irm1, ip1, np1)
650
+
651
+ if (i <= i2) then
652
+ w1(:m) = ZERO
653
+ else
654
+ call prdct(nm1, b(im1), 0, dummy_variable, 0, dummy_variable, na, an(idxa), &
655
+ y(1,imi2), w1, m, am, bm, cm, wd, ww, wu)
656
+ end if
657
+
658
+ if (ipi2 > nm) then
659
+ w2(:m) = ZERO
660
+ else
661
+ call prdct(np1, b(ip1), 0, dummy_variable, 0, dummy_variable, nc, cn(idxc), y( &
662
+ 1, ipi2), w2, m, am, bm, cm, wd, ww, wu)
663
+ end if
664
+ w1(:m) = y(:m, i) + w1(:m) + w2(:m)
665
+ call prdct(nz, b(iz), nm1, b(im1), np1, b(ip1), 0, dummy_variable, w1, &
666
+ y(1, i), m, am, bm, cm, wd, ww, wu)
667
+ end do
668
+ end do
669
+
670
+ end associate common_variables
671
+
672
+ end subroutine cblktri_lower_routine
673
+
674
+ function cblktri_bsrh(self, xll, xrr, iz, c, a, bh, f, sgn) &
675
+ result(return_value)
676
+
677
+ ! Dummy arguments
678
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
679
+ integer(ip) :: iz
680
+ real(wp), intent(in) :: xll
681
+ real(wp), intent(in) :: xrr
682
+ real(wp) :: c(*)
683
+ real(wp) :: a(*)
684
+ real(wp) :: bh(*)
685
+ procedure(comf_interface) :: f
686
+ real(wp), intent(in) :: sgn
687
+ real(wp) :: return_value
688
+
689
+ ! Local variables
690
+ real(wp) :: r1, xl, xr, dx, x
691
+
692
+ common_variables: associate( &
693
+ npp => self%npp, &
694
+ k => self%k, &
695
+ nm => self%nm, &
696
+ ncmplx=> self%ncmplx, &
697
+ ik => self%ik, &
698
+ cnv => self%cnv &
699
+ )
700
+
701
+ xl = xll
702
+ xr = xrr
703
+ dx = HALF*abs(xr - xl)
704
+ x = HALF*(xl + xr)
705
+ r1 = sgn*f(x, iz, c, a, bh)
706
+
707
+ if (r1 >= ZERO) then
708
+ if (r1 == ZERO) then
709
+ return_value = HALF*(xl + xr)
710
+ return
711
+ end if
712
+ xr = x
713
+ else
714
+ xl = x
715
+ end if
716
+
717
+ dx = HALF * dx
718
+
719
+ do
720
+ if (dx <= cnv) exit
721
+ x = HALF*(xl + xr)
722
+ r1 = sgn*f(x, iz, c, a, bh)
723
+ if (r1 >= ZERO) then
724
+ if (r1 == ZERO) then
725
+ return_value = HALF*(xl + xr)
726
+ return
727
+ end if
728
+ xr = x
729
+ else
730
+ xl = x
731
+ end if
732
+ dx = HALF*dx
733
+ end do
734
+
735
+ return_value = HALF*(xl + xr)
736
+
737
+ end associate common_variables
738
+
739
+ end function cblktri_bsrh
740
+
741
+ ! Purpose:
742
+ !
743
+ ! Computes the roots of the b polynomials using subroutine
744
+ ! cblktri_tevls which is a modification the eispack program tqlrat.
745
+ ! ierror is set to 4 if either cblktri_tevls fails or if a(j+1)*c(j) is
746
+ ! less than zero for some j. ah, bh are temporary work arrays.
747
+ !
748
+ subroutine cblktri_compute_roots_of_b_polynomials(self, ierror, an, bn, cn, b, bc, ah, bh)
749
+
750
+ ! Dummy arguments
751
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
752
+ integer(ip), intent(out) :: ierror
753
+ real(wp), intent(in) :: an(:)
754
+ real(wp), intent(in) :: bn(:)
755
+ real(wp), intent(in) :: cn(:)
756
+ real(wp), target, contiguous, intent(inout) :: b(:)
757
+ real(wp), intent(inout) :: ah(:)
758
+ real(wp), intent(inout) :: bh(:)
759
+ complex(wp), intent(inout) :: bc(:)
760
+
761
+ ! Local variables
762
+ integer(ip) :: j, iif, kdo, l, ir, i2, i4
763
+ integer(ip) :: ipl, ifd, i, ib, nb, js, jf
764
+ integer(ip) :: ls, lh, nmp, l1, l2, j2, j1, n2m2
765
+ real(wp) :: bnorm, arg, d1, d2, d3
766
+
767
+ common_variables: associate( &
768
+ npp => self%npp, &
769
+ k => self%k, &
770
+ nm => self%nm, &
771
+ ncmplx=> self%ncmplx, &
772
+ ik => self%ik, &
773
+ cnv => self%cnv &
774
+ )
775
+
776
+ bnorm = abs(bn(1))
777
+
778
+ do j = 2, nm
779
+ bnorm = max(bnorm, abs(bn(j)))
780
+ arg = an(j)*cn(j-1)
781
+ if (arg < ZERO) then
782
+ ierror = 5
783
+ return
784
+ end if
785
+ b(j) = sign(sqrt(arg), an(j))
786
+ end do
787
+
788
+ cnv = MACHINE_EPSILON*bnorm
789
+ iif = 2**k
790
+ kdo = k - 1
791
+
792
+ outer_loop: do l = 1, kdo
793
+
794
+ ir = l - 1
795
+ i2 = 2**ir
796
+ i4 = i2 + i2
797
+ ipl = i4 - 1
798
+ ifd = iif - i4
799
+
800
+ do i = i4, ifd, i4
801
+
802
+ call self%cblktri_compute_index_b_coeff(i, l, ib, nb)
803
+
804
+ if (nb <= 0) cycle outer_loop
805
+
806
+ js = i - ipl
807
+ jf = js + nb - 1
808
+ ls = 0
809
+ bh(:jf-js+1) = bn(js:jf)
810
+ ah(:jf-js+1) = b(js:jf)
811
+
812
+ call self%cblktri_tevls(bh(1:nb), ah(1:nb), ierror)
813
+
814
+ if (ierror /= 0) then
815
+ ierror = 4
816
+ return
817
+ end if
818
+
819
+ lh = ib - 1
820
+
821
+ if (nb > 0) then
822
+ b(lh+1:nb+lh) = -bh(:nb)
823
+ lh = nb + lh
824
+ end if
825
+
826
+ end do
827
+ end do outer_loop
828
+
829
+ b(:nm) = -bn(:nm)
830
+
831
+ if (npp == 0) then
832
+ nmp = nm + 1
833
+ nb = nm + nmp
834
+ do j = 1, nb
835
+ l1 = mod(j - 1, nmp) + 1
836
+ l2 = mod(j + nm - 1, nmp) + 1
837
+ arg = an(l1)*cn(l2)
838
+
839
+ if (arg < ZERO) then
840
+ ierror = 5
841
+ return
842
+ end if
843
+
844
+ bh(j) = sign(sqrt(arg), (-an(l1)))
845
+ ah(j) = -bn(l1)
846
+ end do
847
+
848
+ call self%cblktri_tevls(ah(1:nb), bh(1:nb), ierror)
849
+
850
+ if (ierror /= 0) then
851
+ ierror = 4
852
+ return
853
+ end if
854
+
855
+ call self%cblktri_compute_index_b_coeff(iif, k - 1, j2, lh)
856
+ call self%cblktri_compute_index_b_coeff(iif/2, k - 1, j1, lh)
857
+
858
+ j2 = j2 + 1
859
+ lh = j2
860
+ n2m2 = j2 + 2*nm - 2
861
+
862
+ iteration: do
863
+
864
+ d1 = abs(b(j1)-b(j2-1))
865
+ d2 = abs(b(j1)-b(j2))
866
+ d3 = abs(b(j1)-b(j2+1))
867
+
868
+ if (d1 <= d2 .or. d3 <= d2) then
869
+ b(lh) = b(j2)
870
+ j2 = j2 + 1
871
+ lh = lh + 1
872
+ if (j2 <= n2m2) cycle iteration
873
+ else
874
+ j2 = j2 + 1
875
+ j1 = j1 + 1
876
+ if (j2 <= n2m2) cycle iteration
877
+ end if
878
+ exit iteration
879
+ end do iteration
880
+
881
+ b(lh) = b(n2m2+1)
882
+
883
+ call self%cblktri_compute_index_b_coeff(iif, k - 1, j1, j2)
884
+
885
+ j2 = j1 + nmp + nmp
886
+
887
+ ! Compute eigenvalues of the periodic tridiagonal
888
+ block
889
+ complex(wp) :: cbp_arg(1)
890
+ real(wp) :: bp_arg(1)
891
+ real(wp), contiguous, pointer :: bh_arg(:) => null()
892
+
893
+ ! Associate arguments
894
+ cbp_arg = cmplx(b(j1), kind=wp)
895
+ bp_arg = real(bc(j1), kind=wp)
896
+ bh_arg(1:) => b(j2:)
897
+
898
+ ! Call solver
899
+ call self%cblktri_compute_eigenvalues(nm + 1, ierror, an, cn, cbp_arg, bp_arg, bh_arg)
900
+
901
+ ! Terminate association
902
+ nullify(bh_arg)
903
+ end block
904
+ end if
905
+
906
+ end associate common_variables
907
+
908
+ end subroutine cblktri_compute_roots_of_b_polynomials
909
+
910
+ ! Purpose:
911
+ !
912
+ ! Applies a sequence of matrix operations to the vector x and
913
+ ! stores the result in y
914
+ ! aa array containing scalar multipliers of the vector x
915
+ ! nd, nm1, nm2 are the lengths of the arrays bd, bm1, bm2 respectively
916
+ ! bd, bm1, bm2 are arrays containing roots of certian b polynomials
917
+ ! na is the length of the array aa
918
+ ! x, y the matrix operations are applied to x and the result is y
919
+ ! a, b, c are arrays which contain the tridiagonal matrix
920
+ ! m is the order of the matrix
921
+ ! d, w are work arrays
922
+ ! isgn determines whether or not a change in sign is made
923
+ !
924
+ pure subroutine cproc(nd, bd, nm1, bm1, nm2, bm2, na, aa, x, y, m, a, b, c, d, w, yy)
925
+
926
+ ! Dummy arguments
927
+ integer(ip), intent(in) :: nd
928
+ integer(ip), intent(in) :: nm1
929
+ integer(ip), intent(in) :: nm2
930
+ integer(ip), intent(in) :: na
931
+ integer(ip), intent(in) :: m
932
+ real(wp), intent(in) :: bm1(nm1)
933
+ real(wp), intent(in) :: bm2(nm2)
934
+ real(wp), intent(in) :: aa(na)
935
+ real(wp), intent(in) :: x(m)
936
+ real(wp), intent(out) :: yy(m)
937
+ real(wp), intent(in) :: a(m)
938
+ real(wp), intent(in) :: b(m)
939
+ real(wp), intent(in) :: c(m)
940
+ complex(wp), intent(in) :: bd(nd)
941
+ complex(wp), intent(out) :: d(m)
942
+ complex(wp), intent(out) :: w(m)
943
+ complex(wp), intent(out) :: y(m)
944
+
945
+ ! Local variables
946
+ integer(ip) :: j, mm, id, m1, m2, ia, iflg, k
947
+ real(wp) :: rt
948
+ complex(wp) :: crt, den, y1, y2
949
+
950
+ y(:m) = x(:m)
951
+ mm = m - 1
952
+ id = nd
953
+ m1 = nm1
954
+ m2 = nm2
955
+ ia = na
956
+
957
+ main_loop: do
958
+
959
+ iflg = 0
960
+ if (id > 0) then
961
+ crt = bd(id)
962
+ id = id - 1
963
+
964
+ ! begin solution to system
965
+ d(m) = a(m)/(b(m)-crt)
966
+ w(m) = y(m)/(b(m)-crt)
967
+
968
+ do j = 2, mm
969
+ k = m - j
970
+ den = b(k+1) - crt - c(k+1)*d(k+2)
971
+ d(k+1) = a(k+1)/den
972
+ w(k+1) = (y(k+1)-c(k+1)*w(k+2))/den
973
+ end do
974
+
975
+ den = b(1) - crt - c(1)*d(2)
976
+
977
+ if (abs(den) /= ZERO) then
978
+ y(1) = (y(1)-c(1)*w(2))/den
979
+ else
980
+ y(1) = cmplx(ONE, ZERO, kind=wp)
981
+ end if
982
+
983
+ do j = 2, m
984
+ y(j) = w(j) - d(j)*y(j-1)
985
+ end do
986
+
987
+ end if
988
+
989
+ if (.not.(m1 <= 0 .and. m2 <= 0)) then
990
+ if (m1 <= 0) then
991
+ rt = bm2(m2)
992
+ m2 = m2 - 1
993
+ else
994
+ if (m2 <= 0) then
995
+ rt = bm1(m1)
996
+ m1 = m1 - 1
997
+ else
998
+ if (abs(bm1(m1)) - abs(bm2(m2)) > ZERO) then
999
+ rt = bm1(m1)
1000
+ m1 = m1 - 1
1001
+ else
1002
+ rt = bm2(m2)
1003
+ m2 = m2 - 1
1004
+ end if
1005
+ end if
1006
+ end if
1007
+
1008
+ y1 = (b(1)-rt)*y(1) + c(1)*y(2)
1009
+
1010
+ if (mm >= 2) then
1011
+ do j = 2, mm
1012
+ y2 = a(j)*y(j-1) + (b(j)-rt)*y(j) + c(j)*y(j+1)
1013
+ y(j-1) = y1
1014
+ y1 = y2
1015
+ end do
1016
+ end if
1017
+
1018
+ y(m) = a(m)*y(m-1) + (b(m)-rt)*y(m)
1019
+ y(m-1) = y1
1020
+ iflg = 1
1021
+
1022
+ cycle main_loop
1023
+
1024
+ end if
1025
+
1026
+ if (ia > 0) then
1027
+ rt = aa(ia)
1028
+ ia = ia - 1
1029
+ iflg = 1
1030
+
1031
+ ! scalar multiplication
1032
+ y(:m) = rt*y(:m)
1033
+ end if
1034
+
1035
+ if (iflg <= 0) exit main_loop
1036
+
1037
+ end do main_loop
1038
+
1039
+ end subroutine cproc
1040
+
1041
+ ! Purpose:
1042
+ !
1043
+ ! cprocp applies a sequence of matrix operations to the vector x and
1044
+ ! stores the result in y
1045
+ !
1046
+ ! bd, bm1, bm2 are arrays containing roots of certian b polynomials
1047
+ ! nd, nm1, nm2 are the lengths of the arrays bd, bm1, bm2 respectively
1048
+ ! aa array containing scalar multipliers of the vector x
1049
+ ! na is the length of the array aa
1050
+ ! x, y the matrix operations are applied to x and the result is y
1051
+ ! a, b, c are arrays which contain the tridiagonal matrix
1052
+ ! m is the order of the matrix
1053
+ ! d, u are work arrays
1054
+ ! isgn determines whether or not a change in sign is made
1055
+ !
1056
+ pure subroutine cprocp(nd, bd, nm1, bm1, nm2, bm2, na, aa, x, y, m, a, b, c, d, u, yy)
1057
+
1058
+ ! Dummy arguments
1059
+ integer(ip), intent(in) :: nd
1060
+ integer(ip), intent(in) :: nm1
1061
+ integer(ip), intent(in) :: nm2
1062
+ integer(ip), intent(in) :: na
1063
+ integer(ip), intent(in) :: m
1064
+ real(wp), intent(in) :: bm1(nm1)
1065
+ real(wp), intent(in) :: bm2(nm2)
1066
+ real(wp), intent(in) :: aa(na)
1067
+ real(wp), intent(in) :: x(m)
1068
+ real(wp), intent(out) :: yy(m)
1069
+ real(wp), intent(in) :: a(m)
1070
+ real(wp), intent(in) :: b(m)
1071
+ real(wp), intent(in) :: c(m)
1072
+ complex(wp), intent(in) :: bd(nd)
1073
+ complex(wp), intent(out) :: d(m)
1074
+ complex(wp), intent(out) :: u(m)
1075
+ complex(wp), intent(out) :: y(m)
1076
+
1077
+ ! Local variables
1078
+ integer(ip) :: j, mm, mm2, id, m1, m2, ia, iflg, k
1079
+ real(wp) :: rt
1080
+ complex(wp) :: v, den, bh, ym, am, y1, y2, yh, crt
1081
+
1082
+ y(:m) = x(:m)
1083
+ mm = m - 1
1084
+ mm2 = m - 2
1085
+ id = nd
1086
+ m1 = nm1
1087
+ m2 = nm2
1088
+ ia = na
1089
+
1090
+ main_loop: do
1091
+
1092
+ iflg = 0
1093
+ if (id > 0) then
1094
+ crt = bd(id)
1095
+ id = id - 1
1096
+ iflg = 1
1097
+
1098
+ ! begin solution to system
1099
+ bh = b(m) - crt
1100
+ ym = y(m)
1101
+ den = b(1) - crt
1102
+ d(1) = c(1)/den
1103
+ u(1) = a(1)/den
1104
+ y(1) = y(1)/den
1105
+ v = c(m)
1106
+ if (mm2 >= 2) then
1107
+ do j = 2, mm2
1108
+ den = b(j) - crt - a(j)*d(j-1)
1109
+ d(j) = c(j)/den
1110
+ u(j) = -a(j)*u(j-1)/den
1111
+ y(j) = (y(j)-a(j)*y(j-1))/den
1112
+ bh = bh - v*u(j-1)
1113
+ ym = ym - v*y(j-1)
1114
+ v = -v*d(j-1)
1115
+ end do
1116
+ end if
1117
+ den = b(m-1) - crt - a(m-1)*d(m-2)
1118
+ d(m-1) = (c(m-1)-a(m-1)*u(m-2))/den
1119
+ y(m-1) = (y(m-1)-a(m-1)*y(m-2))/den
1120
+ am = a(m) - v*d(m-2)
1121
+ bh = bh - v*u(m-2)
1122
+ ym = ym - v*y(m-2)
1123
+ den = bh - am*d(m-1)
1124
+ if (abs(den) /= ZERO) then
1125
+ y(m) = (ym - am*y(m-1))/den
1126
+ else
1127
+ y(m) = cmplx(ONE, ZERO, kind=wp)
1128
+ end if
1129
+ y(m-1) = y(m-1) - d(m-1)*y(m)
1130
+ do j = 2, mm
1131
+ k = m - j
1132
+ y(k) = y(k) - d(k)*y(k+1) - u(k)*y(m)
1133
+ end do
1134
+ end if
1135
+
1136
+ if (.not.(m1 <= 0 .and. m2 <= 0)) then
1137
+ if (m1 <= 0) then
1138
+ rt = bm2(m2)
1139
+ m2 = m2 - 1
1140
+ else
1141
+ if (m2 <= 0) then
1142
+ rt = bm1(m1)
1143
+ m1 = m1 - 1
1144
+ else
1145
+ if (abs(bm1(m1)) > abs(bm2(m2))) then
1146
+ rt = bm1(m1)
1147
+ m1 = m1 - 1
1148
+ else
1149
+ rt = bm2(m2)
1150
+ m2 = m2 - 1
1151
+
1152
+ ! matrix multiplication
1153
+ end if
1154
+ end if
1155
+ end if
1156
+
1157
+ yh = y(1)
1158
+ y1 = (b(1)-rt)*y(1) + c(1)*y(2) + a(1)*y(m)
1159
+
1160
+ if (mm >= 2) then
1161
+ do j = 2, mm
1162
+ y2 = a(j)*y(j-1) + (b(j)-rt)*y(j) + c(j)*y(j+1)
1163
+ y(j-1) = y1
1164
+ y1 = y2
1165
+ end do
1166
+ end if
1167
+
1168
+ y(m) = a(m)*y(m-1) + (b(m)-rt)*y(m) + c(m)*yh
1169
+ y(m-1) = y1
1170
+ iflg = 1
1171
+
1172
+ cycle main_loop
1173
+ end if
1174
+
1175
+ if (ia > 0) then
1176
+ rt = aa(ia)
1177
+ ia = ia - 1
1178
+ iflg = 1
1179
+
1180
+ ! scalar multiplication
1181
+ y(:m) = rt*y(:m)
1182
+ end if
1183
+
1184
+ if (iflg <= 0) exit main_loop
1185
+
1186
+ end do main_loop
1187
+
1188
+ end subroutine cprocp
1189
+
1190
+ subroutine cblktri_compute_index_a_coeff(self, i, ir, idxa, na)
1191
+
1192
+ ! Dummy arguments
1193
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
1194
+ integer(ip), intent(in) :: i
1195
+ integer(ip), intent(in) :: ir
1196
+ integer(ip), intent(out) :: idxa
1197
+ integer(ip), intent(out) :: na
1198
+
1199
+ associate( nm => self%nm )
1200
+ na = 2**ir
1201
+ idxa = i - na + 1
1202
+ if (i > nm) na = 0
1203
+ end associate
1204
+
1205
+ end subroutine cblktri_compute_index_a_coeff
1206
+
1207
+ subroutine cblktri_compute_index_b_coeff(self, i, ir, idx, idp)
1208
+
1209
+ ! Dummy arguments
1210
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
1211
+ integer(ip), intent(in) :: i
1212
+ integer(ip), intent(in) :: ir
1213
+ integer(ip), intent(out) :: idx
1214
+ integer(ip), intent(out) :: idp
1215
+
1216
+ ! Local variables
1217
+ integer(ip) :: izh, id, ipl
1218
+
1219
+ common_variables: associate( &
1220
+ npp => self%npp, &
1221
+ k => self%k, &
1222
+ nm => self%nm, &
1223
+ ncmplx=> self%ncmplx, &
1224
+ ik => self%ik, &
1225
+ cnv => self%cnv &
1226
+ )
1227
+
1228
+ ! b(idx) is the location of the first root of the b(i, ir) polynomial
1229
+ idp = 0
1230
+ if (ir >= 0) then
1231
+ if (ir <= 0) then
1232
+
1233
+ if (i > nm) return
1234
+
1235
+ idx = i
1236
+ idp = 1
1237
+ return
1238
+ end if
1239
+ izh = 2**ir
1240
+ id = i - 2*izh
1241
+ idx = 2*id + (ir - 1)*ik + ir + (ik - i)/izh + 4
1242
+ ipl = izh - 1
1243
+ idp = 2*izh - 1
1244
+
1245
+ if (i - ipl > nm) then
1246
+ idp = 0
1247
+ return
1248
+ end if
1249
+
1250
+ if (i + ipl > nm) idp = nm + ipl - i + 1
1251
+
1252
+ end if
1253
+
1254
+ end associate common_variables
1255
+
1256
+ end subroutine cblktri_compute_index_b_coeff
1257
+
1258
+ subroutine cblktri_compute_index_c_coeff(self, i, ir, idxc, nc)
1259
+
1260
+ ! Dummy arguments
1261
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
1262
+ integer(ip), intent(in) :: i
1263
+ integer(ip), intent(in) :: ir
1264
+ integer(ip), intent(out) :: idxc
1265
+ integer(ip), intent(out) :: nc
1266
+
1267
+ associate( nm => self%nm )
1268
+ nc = 2**ir
1269
+ idxc = i
1270
+ if (idxc + nc - 1 > nm) nc = 0
1271
+ end associate
1272
+
1273
+ end subroutine cblktri_compute_index_c_coeff
1274
+
1275
+ ! Purpose:
1276
+ !
1277
+ ! Computes the eigenvalues of the periodic tridiagonal
1278
+ ! matrix with coefficients an, bn, cn
1279
+ !
1280
+ ! n is the order of the bh and bp polynomials
1281
+ ! on output bp contains the eigenvalues
1282
+ ! cbp is the same as bp except type complex
1283
+ ! bh is used to temporarily store the roots of the b hat polynomial
1284
+ ! which enters through bp
1285
+ subroutine cblktri_compute_eigenvalues(self, n, ierror, a, c, cbp, bp, bh)
1286
+
1287
+ ! Dummy arguments
1288
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
1289
+ integer(ip), intent(in) :: n
1290
+ integer(ip), intent(out) :: ierror
1291
+ real(wp), intent(in) :: a(:)
1292
+ real(wp), intent(in) :: c(:)
1293
+ complex(wp) :: cbp(:)
1294
+ real(wp) :: bp(:)
1295
+ real(wp) :: bh(:)
1296
+
1297
+ ! Local variables
1298
+ integer(ip) :: iz, izm, izm2, j, nt, modiz
1299
+ integer(ip) :: iis, iif, ig, it, icv, i3, i2, nhalf
1300
+ real(wp) :: r4, r5, r6, scnv, xl, db, sgn, xr, xm, psg
1301
+ real(wp) :: temp
1302
+ complex(wp) :: cx, fsg, hsg, dd, f, fp, fpp, cdis, r1, r2, r3
1303
+
1304
+ common_variables: associate( &
1305
+ npp => self%npp, &
1306
+ k => self%k, &
1307
+ nm => self%nm, &
1308
+ ncmplx=> self%ncmplx, &
1309
+ ik => self%ik, &
1310
+ cnv => self%cnv &
1311
+ )
1312
+
1313
+ scnv = sqrt(cnv)
1314
+ iz = n
1315
+ izm = iz - 1
1316
+ izm2 = iz - 2
1317
+
1318
+ main_block: block
1319
+
1320
+ if (bp(n) <= bp(1)) then
1321
+ if (bp(n) == bp(1)) exit main_block
1322
+ bh(:n) = bp(n:1:(-1))
1323
+ else
1324
+ bh(:n) = bp(:n)
1325
+ end if
1326
+
1327
+ ncmplx = 0
1328
+ modiz = mod(iz, 2)
1329
+ iis = 1
1330
+
1331
+ block_110: block
1332
+ if (modiz /= 0) then
1333
+ if (a(1) < ZERO) exit block_110
1334
+ if (a(1) == ZERO) exit main_block
1335
+ end if
1336
+ xl = bh(1)
1337
+ db = bh(3) - bh(1)
1338
+ xl = xl - db
1339
+ r4 = psgf(xl, iz, c, a, bh)
1340
+ do while (r4 <= ZERO)
1341
+ xl = xl - db
1342
+ r4 = psgf(xl, iz, c, a, bh)
1343
+ end do
1344
+ sgn = -ONE
1345
+ temp = self%cblktri_bsrh(xl, bh(1), iz, c, a, bh, psgf, sgn)
1346
+ cbp(1) = cmplx(temp, ZERO, kind=wp)
1347
+ iis = 2
1348
+ end block block_110
1349
+
1350
+ iif = iz - 1
1351
+
1352
+ block_115: block
1353
+ if (modiz /= 0) then
1354
+ if (a(1) > ZERO) exit block_115
1355
+ if (a(1) == ZERO) exit main_block
1356
+ end if
1357
+ xr = bh(iz)
1358
+ db = bh(iz) - bh(iz-2)
1359
+ xr = xr + db
1360
+ r5 = psgf(xr, iz, c, a, bh)
1361
+ do while (r5 < ZERO)
1362
+ xr = xr + db
1363
+ r5 = psgf(xr, iz, c, a, bh)
1364
+ end do
1365
+ sgn = ONE
1366
+ temp = self%cblktri_bsrh(bh(iz), xr, iz, c, a, bh, psgf, sgn)
1367
+ cbp(iz) = cmplx(temp, ZERO, kind=wp)
1368
+ iif = iz - 2
1369
+ end block block_115
1370
+
1371
+ main_loop: do ig = iis, iif, 2
1372
+ xl = bh(ig)
1373
+ xr = bh(ig+1)
1374
+ sgn = -1.
1375
+ xm = self%cblktri_bsrh(xl, xr, iz, c, a, bh, ppspf, sgn)
1376
+ psg = psgf(xm, iz, c, a, bh)
1377
+
1378
+ if_block: block
1379
+ if (abs(psg) > MACHINE_EPSILON) then
1380
+ r6 = psg*ppsgf(xm, iz, c, a, bh)
1381
+ if (r6 > ZERO) exit if_block
1382
+ if (r6 /= ZERO) then
1383
+ sgn = ONE
1384
+ cbp(ig) = cmplx(self%cblktri_bsrh(bh(ig), xm, iz, c, a, bh, psgf, sgn), ZERO, kind=wp)
1385
+ sgn = -ONE
1386
+ cbp(ig+1) = cmplx(self%cblktri_bsrh(xm, bh(ig+1), iz, c, a, bh, psgf, sgn), ZERO, kind=wp)
1387
+ cycle main_loop
1388
+
1389
+ ! case of a multiple zero
1390
+ end if
1391
+ end if
1392
+ cbp(ig) = cmplx(xm, ZERO, kind=wp)
1393
+ cbp(ig+1) = cmplx(xm, ZERO, kind=wp)
1394
+ cycle main_loop
1395
+
1396
+ ! case of a complex zero
1397
+ end block if_block
1398
+
1399
+ it = 0
1400
+ icv = 0
1401
+ cx = cmplx(xm, ZERO, kind=wp)
1402
+
1403
+ loop_120: do
1404
+ fsg = cmplx(ONE, ZERO, kind=wp)
1405
+ hsg = cmplx(ONE, ZERO, kind=wp)
1406
+ fp = ZERO
1407
+ fpp = ZERO
1408
+
1409
+ do j = 1, iz
1410
+ dd = ONE /(cx - bh(j))
1411
+ fsg = fsg*a(j)*dd
1412
+ hsg = hsg*c(j)*dd
1413
+ fp = fp + dd
1414
+ fpp = fpp - dd*dd
1415
+ end do
1416
+
1417
+ if (modiz == 0) then
1418
+ f = cmplx(ONE, ZERO, kind=wp) - fsg - hsg
1419
+ else
1420
+ f = cmplx(ONE, ZERO, kind=wp) + fsg + hsg
1421
+ end if
1422
+
1423
+ i3 = 0
1424
+
1425
+ if (abs(fp) > ZERO) then
1426
+ i3 = 1
1427
+ r3 = -f/fp
1428
+ end if
1429
+
1430
+ i2 = 0
1431
+
1432
+ if (abs(fpp) > ZERO) then
1433
+ i2 = 1
1434
+ cdis = sqrt(fp**2 - TWO*f*fpp)
1435
+ r1 = cdis - fp
1436
+ r2 = (-fp) - cdis
1437
+ if (abs(r1) - abs(r2) > ZERO) then
1438
+ r1 = r1/fpp
1439
+ else
1440
+ r1 = r2/fpp
1441
+ end if
1442
+ r2 = TWO*f/fpp/r1
1443
+ if (abs(r2) < abs(r1)) r1 = r2
1444
+ if (i3 > 0) then
1445
+ if (abs(r3) < abs(r1)) r1 = r3
1446
+ end if
1447
+ else
1448
+ r1 = r3
1449
+ end if
1450
+
1451
+ cx = cx + r1
1452
+ it = it + 1
1453
+ if (it > 50) exit main_block
1454
+ if (abs(r1) > scnv) cycle loop_120
1455
+ if (icv > 0) exit loop_120
1456
+ icv = 1
1457
+ end do loop_120
1458
+
1459
+ cbp(ig) = cx
1460
+ cbp(ig+1) = conjg(cx)
1461
+ end do main_loop
1462
+
1463
+ if (abs(cbp(n)) - abs(cbp(1)) <= ZERO) then
1464
+ if (abs(cbp(n)) - abs(cbp(1)) == ZERO) exit main_block
1465
+ nhalf = n/2
1466
+ do j = 1, nhalf
1467
+ nt = n - j
1468
+ cx = cbp(j)
1469
+ cbp(j) = cbp(nt+1)
1470
+ cbp(nt+1) = cx
1471
+ end do
1472
+ end if
1473
+
1474
+ ncmplx = 1
1475
+
1476
+ do j = 2, iz
1477
+ if (aimag(cbp(j)) /= ZERO) return
1478
+ end do
1479
+
1480
+ ncmplx = 0
1481
+
1482
+ do j = 2, iz
1483
+ bp(j) = real(cbp(j), kind=wp)
1484
+ end do
1485
+
1486
+ return
1487
+ end block main_block
1488
+ !
1489
+ ! Procedure failed
1490
+ !
1491
+ ierror = 4
1492
+
1493
+ end associate common_variables
1494
+
1495
+ end subroutine cblktri_compute_eigenvalues
1496
+
1497
+ ! Purpose:
1498
+ !
1499
+ ! proc applies a sequence of matrix operations to the vector x and
1500
+ ! stores the result in y
1501
+ ! bd, bm1, bm2 are arrays containing roots of certian b polynomials
1502
+ ! nd, nm1, nm2 are the lengths of the arrays bd, bm1, bm2 respectively
1503
+ ! aa array containing scalar multipliers of the vector x
1504
+ ! na is the length of the array aa
1505
+ ! x, y the matrix operations are applied to x and the result is y
1506
+ ! a, b, c are arrays which contain the tridiagonal matrix
1507
+ ! m is the order of the matrix
1508
+ ! d, w, u are working arrays
1509
+ ! is determines whether or not a change in sign is made
1510
+ !
1511
+ pure subroutine proc(nd, bd, nm1, bm1, nm2, bm2, na, aa, x, y, m, a, b, c, d, w, u)
1512
+
1513
+ ! Dummy arguments
1514
+ integer(ip), intent(in) :: nd
1515
+ integer(ip), intent(in) :: nm1
1516
+ integer(ip), intent(in) :: nm2
1517
+ integer(ip), intent(in) :: na
1518
+ integer(ip), intent(in) :: m
1519
+ real(wp), intent(in) :: bd(nd)
1520
+ real(wp), intent(in) :: bm1(nm1)
1521
+ real(wp), intent(in) :: bm2(nm2)
1522
+ real(wp), intent(in) :: aa(na)
1523
+ complex(wp), intent(in) :: x(m)
1524
+ complex(wp), intent(out) :: y(m)
1525
+ complex(wp), intent(in) :: a(m)
1526
+ complex(wp), intent(in) :: b(m)
1527
+ complex(wp), intent(in) :: c(m)
1528
+ complex(wp), intent(out) :: d(m)
1529
+ complex(wp), intent(out) :: w(m)
1530
+ complex(wp), intent(out) :: u(m)
1531
+
1532
+ ! Local variables
1533
+ integer(ip) :: j, mm, id, ibr, m1, m2, ia, k
1534
+ real(wp) :: rt
1535
+ complex(wp) :: den
1536
+
1537
+ w = x
1538
+ y = w
1539
+ mm = m - 1
1540
+ id = nd
1541
+ ibr = 0
1542
+ m1 = nm1
1543
+ m2 = nm2
1544
+ ia = na
1545
+
1546
+ main_loop: do
1547
+ if (ia > 0) then
1548
+ if (nd == 0) then
1549
+ rt = -aa(ia)
1550
+ else
1551
+ rt = aa(ia)
1552
+ end if
1553
+ ia = ia - 1
1554
+
1555
+ ! scalar multiplication
1556
+ y = rt*w
1557
+ end if
1558
+
1559
+ if (id <= 0) return
1560
+
1561
+ rt = bd(id)
1562
+ id = id - 1
1563
+
1564
+ if (id == 0) ibr = 1
1565
+
1566
+ ! begin solution to system
1567
+ d(m) = a(m)/(b(m)-rt)
1568
+ w(m) = y(m)/(b(m)-rt)
1569
+
1570
+ do j = 2, mm
1571
+ k = m - j
1572
+ den = b(k+1) - rt - c(k+1)*d(k+2)
1573
+ d(k+1) = a(k+1)/den
1574
+ w(k+1) = (y(k+1)-c(k+1)*w(k+2))/den
1575
+ end do
1576
+
1577
+ den = b(1) - rt - c(1)*d(2)
1578
+ w(1) = cmplx(ONE, ZERO, kind=wp)
1579
+
1580
+ if (abs(den) /= ZERO) then
1581
+ w(1) = (y(1)-c(1)*w(2))/den
1582
+ end if
1583
+
1584
+ do j = 2, m
1585
+ w(j) = w(j) - d(j)*w(j-1)
1586
+ end do
1587
+
1588
+ if (na > 0) cycle main_loop
1589
+
1590
+ if (m1 <= 0) then
1591
+ if (m2 <= 0) then
1592
+ y = w
1593
+ ibr = 1
1594
+ cycle main_loop
1595
+ end if
1596
+ else
1597
+ if (.not.(m2 > 0 .and. abs(bm1(m1)) <= abs(bm2(m2)))) then
1598
+ if (ibr <= 0 .and. abs(bm1(m1)-bd(id)) < abs(bm1(m1)-rt)) then
1599
+ y = w
1600
+ ibr = 1
1601
+ cycle main_loop
1602
+ end if
1603
+ end if
1604
+ rt = rt - bm1(m1)
1605
+ m1 = m1 - 1
1606
+ y = y + rt*w
1607
+ cycle main_loop
1608
+ end if
1609
+
1610
+ if (ibr <= 0 .and. abs(bm2(m2)-bd(id)) < abs(bm2(m2)-rt)) then
1611
+ y = w
1612
+ ibr = 1
1613
+ cycle main_loop
1614
+ end if
1615
+
1616
+ rt = rt - bm2(m2)
1617
+ m2 = m2 - 1
1618
+ y = y + rt*w
1619
+
1620
+ end do main_loop
1621
+
1622
+ end subroutine proc
1623
+
1624
+ ! Purpose:
1625
+ !
1626
+ ! procp applies a sequence of matrix operations to the vector x and
1627
+ ! stores the result in y periodic boundary conditions
1628
+ !
1629
+ ! bd, bm1, bm2 are arrays containing roots of certian b polynomials
1630
+ ! nd, nm1, nm2 are the lengths of the arrays bd, bm1, bm2 respectively
1631
+ ! aa array containing scalar multipliers of the vector x
1632
+ ! na is the length of the array aa
1633
+ ! x, y the matrix operations are applied to x and the result is y
1634
+ ! a, b, c are arrays which contain the tridiagonal matrix
1635
+ ! m is the order of the matrix
1636
+ ! d, u, w are working arrays
1637
+ ! is determines whether or not a change in sign is made
1638
+ !
1639
+ pure subroutine procp(nd, bd, nm1, bm1, nm2, bm2, na, aa, x, y, m, a, b, c, d, u, w)
1640
+
1641
+ ! Dummy arguments
1642
+ integer(ip), intent(in) :: nd
1643
+ integer(ip), intent(in) :: nm1
1644
+ integer(ip), intent(in) :: nm2
1645
+ integer(ip), intent(in) :: na
1646
+ integer(ip), intent(in) :: m
1647
+ real(wp), intent(in) :: bd(nd)
1648
+ real(wp), intent(in) :: bm1(nm1)
1649
+ real(wp), intent(in) :: bm2(nm2)
1650
+ real(wp), intent(in) :: aa(na)
1651
+ complex(wp), intent(in) :: x(m)
1652
+ complex(wp), intent(out) :: y(m)
1653
+ complex(wp), intent(in) :: a(m)
1654
+ complex(wp), intent(in) :: b(m)
1655
+ complex(wp), intent(in) :: c(m)
1656
+ complex(wp), intent(out) :: d(m)
1657
+ complex(wp), intent(out) :: u(m)
1658
+ complex(wp), intent(out) :: w(m)
1659
+
1660
+ ! Local variables
1661
+ integer(ip) :: j, mm, mm2, id, ibr, m1, m2, ia, k
1662
+ real(wp) :: rt
1663
+ complex(wp) :: den, ym, v, bh, am
1664
+
1665
+ y = x
1666
+ w = y
1667
+ mm = m - 1
1668
+ mm2 = m - 2
1669
+ id = nd
1670
+ ibr = 0
1671
+ m1 = nm1
1672
+ m2 = nm2
1673
+ ia = na
1674
+
1675
+ main_loop: do
1676
+
1677
+ if (ia > 0) then
1678
+ if (nd == 0) then
1679
+ rt = -aa(ia)
1680
+ else
1681
+ rt = aa(ia)
1682
+ end if
1683
+ ia = ia - 1
1684
+ y = rt*w
1685
+ end if
1686
+
1687
+ if (id <= 0) return
1688
+
1689
+ rt = bd(id)
1690
+ id = id - 1
1691
+
1692
+ if (id == 0) ibr = 1
1693
+
1694
+ ! begin solution to system
1695
+ bh = b(m) - rt
1696
+ ym = y(m)
1697
+ den = b(1) - rt
1698
+ d(1) = c(1)/den
1699
+ u(1) = a(1)/den
1700
+ w(1) = y(1)/den
1701
+ v = c(m)
1702
+
1703
+ if (mm2 >= 2) then
1704
+ do j = 2, mm2
1705
+ den = b(j) - rt - a(j)*d(j-1)
1706
+ d(j) = c(j)/den
1707
+ u(j) = -a(j)*u(j-1)/den
1708
+ w(j) = (y(j)-a(j)*w(j-1))/den
1709
+ bh = bh - v*u(j-1)
1710
+ ym = ym - v*w(j-1)
1711
+ v = -v*d(j-1)
1712
+ end do
1713
+ end if
1714
+
1715
+ den = b(m-1) - rt - a(m-1)*d(m-2)
1716
+ d(m-1) = (c(m-1)-a(m-1)*u(m-2))/den
1717
+ w(m-1) = (y(m-1)-a(m-1)*w(m-2))/den
1718
+ am = a(m) - v*d(m-2)
1719
+ bh = bh - v*u(m-2)
1720
+ ym = ym - v*w(m-2)
1721
+ den = bh - am*d(m-1)
1722
+
1723
+ if (abs(den) /= ZERO) then
1724
+ w(m) = (ym - am*w(m-1))/den
1725
+ else
1726
+ w(m) = cmplx(ONE, ZERO, kind=wp)
1727
+ end if
1728
+
1729
+ w(m-1) = w(m-1) - d(m-1)*w(m)
1730
+
1731
+ do j = 2, mm
1732
+ k = m - j
1733
+ w(k) = w(k) - d(k)*w(k+1) - u(k)*w(m)
1734
+ end do
1735
+
1736
+ if (na > 0) cycle main_loop
1737
+
1738
+ if (m1 <= 0) then
1739
+ if (m2 <= 0) then
1740
+ y = w
1741
+ ibr = 1
1742
+ cycle main_loop
1743
+ end if
1744
+ else
1745
+ if (.not.(m2 > 0 .and. abs(bm1(m1)) <= abs(bm2(m2)))) then
1746
+ if (ibr <= 0 .and. abs(bm1(m1)-bd(id)) < abs(bm1(m1)-rt)) then
1747
+ y = w
1748
+ ibr = 1
1749
+ cycle main_loop
1750
+ end if
1751
+ rt = rt - bm1(m1)
1752
+ m1 = m1 - 1
1753
+ y = y + rt*w
1754
+ cycle main_loop
1755
+ end if
1756
+ end if
1757
+
1758
+ if (ibr <= 0 .and. abs(bm2(m2)-bd(id)) < abs(bm2(m2)-rt)) then
1759
+ y = w
1760
+ ibr = 1
1761
+ cycle main_loop
1762
+ end if
1763
+
1764
+ rt = rt - bm2(m2)
1765
+ m2 = m2 - 1
1766
+ y = y + rt*w
1767
+
1768
+ end do main_loop
1769
+
1770
+ end subroutine procp
1771
+
1772
+ ! Purpose:
1773
+ !
1774
+ ! Finds the eigenvalues of a symmetric
1775
+ ! tridiagonal matrix by the rational ql method.
1776
+ ! This subroutine is a modification of the eispack subroutine tqlrat
1777
+ ! algorithm 464, comm. acm 16, 689(1973) by reinsch.
1778
+ !
1779
+ ! on input-
1780
+ !
1781
+ ! n is the order of the matrix,
1782
+ !
1783
+ ! d contains the diagonal elements of the input matrix,
1784
+ !
1785
+ ! e2 contains the subdiagonal elements of the
1786
+ ! input matrix in its last n-1 positions. e2(1) is arbitrary.
1787
+ !
1788
+ ! on output-
1789
+ !
1790
+ ! d contains the eigenvalues in ascending order. if an
1791
+ ! error exit is made, the eigenvalues are correct and
1792
+ ! ordered for indices 1, 2, ...ierr-1, but may not be
1793
+ ! the smallest eigenvalues,
1794
+ !
1795
+ ! e2 has been destroyed,
1796
+ !
1797
+ ! ierr is set to
1798
+ ! zero for normal return,
1799
+ ! j if the j-th eigenvalue has not been
1800
+ ! determined after 30 iterations.
1801
+ !
1802
+ ! questions and comments should be directed to b. s. garbow,
1803
+ ! applied mathematics division, argonne national laboratory
1804
+ !
1805
+ !
1806
+ ! eps is a machine dependent parameter specifying
1807
+ ! the relative precision of floating point arithmetic.
1808
+ !
1809
+ !
1810
+ subroutine cblktri_tevls(self, diagonal, subdiagonal, error_flag)
1811
+
1812
+ ! Dummy arguments
1813
+ class(ComplexGeneralizedCyclicReductionUtility), intent(inout) :: self
1814
+ real(wp), intent(inout) :: diagonal(:)
1815
+ real(wp), intent(inout) :: subdiagonal(:)
1816
+ integer(ip), intent(out) :: error_flag
1817
+
1818
+ ! Local variables
1819
+ integer(ip) :: i, j, l, m, ii, l1, mml, nhalf, ntop
1820
+ real(wp) :: b, c, f, g, h, p, r, s, dhold
1821
+
1822
+ associate( &
1823
+ n => size(diagonal), &
1824
+ d => diagonal, &
1825
+ e2 => subdiagonal &
1826
+ )
1827
+
1828
+ error_flag = 0
1829
+ if (n /= 1) then
1830
+
1831
+ e2(:n-1) = e2(2:n)*e2(2:n)
1832
+ f = ZERO
1833
+ b = ZERO
1834
+ e2(n) = ZERO
1835
+
1836
+ main_loop: do l = 1, n
1837
+ j = 0
1838
+ h = MACHINE_EPSILON*(abs(d(l))+sqrt(e2(l)))
1839
+
1840
+ if (b <= h) then
1841
+ b = h
1842
+ c = b*b
1843
+ end if
1844
+
1845
+ ! look for small squared sub-diagonal element
1846
+ do m = l, n
1847
+ if (e2(m) > c) cycle
1848
+ exit
1849
+
1850
+ ! 2(n) is always zero, so there is no exit
1851
+ ! through the bottom of the loop
1852
+ end do
1853
+
1854
+ if_block: block
1855
+ if (m /= l) then
1856
+ loop_105: do
1857
+ if (j == 30) then
1858
+
1859
+ ! set error no convergence to an
1860
+ ! eigenvalue after 30 iterations
1861
+ error_flag = l
1862
+ return
1863
+ end if
1864
+
1865
+ j = j + 1
1866
+
1867
+ ! form shift
1868
+ l1 = l + 1
1869
+ s = sqrt(e2(l))
1870
+ g = d(l)
1871
+ p = (d(l1)-g)/(TWO*s)
1872
+ r = sqrt(p**2 + ONE)
1873
+ d(l) = s/(p + sign(r, p))
1874
+ h = g - d(l)
1875
+ d(l1:n) = d(l1:n) - h
1876
+ f = f + h
1877
+
1878
+ ! rational ql transformation
1879
+ g = d(m)
1880
+
1881
+ if (g == ZERO) g = b
1882
+
1883
+ h = g
1884
+ s = ZERO
1885
+ mml = m - l
1886
+
1887
+ ! for i=m-1 step -1 until l do
1888
+ do ii = 1, mml
1889
+ i = m - ii
1890
+ p = g*h
1891
+ r = p + e2(i)
1892
+ e2(i+1) = s*r
1893
+ s = e2(i)/r
1894
+ d(i+1) = h + s*(h + d(i))
1895
+ g = d(i) - e2(i)/g
1896
+ if (g == ZERO) g = b
1897
+ h = g*p/r
1898
+ end do
1899
+
1900
+ e2(l) = s*g
1901
+ d(l) = h
1902
+
1903
+ ! guard against underflowed h
1904
+ if (h == ZERO .or. abs(e2(l)) <= abs(c/h)) exit if_block
1905
+
1906
+ e2(l) = h*e2(l)
1907
+
1908
+ if (e2(l) == ZERO) exit loop_105
1909
+ end do loop_105
1910
+ end if
1911
+ end block if_block
1912
+
1913
+ p = d(l) + f
1914
+
1915
+ ! order eigenvalues
1916
+ if (l /= 1) then
1917
+
1918
+ ! for i=l step -1 until 2 do
1919
+ do ii = 2, l
1920
+ i = l + 2 - ii
1921
+ if (p >= d(i-1)) then
1922
+ d(i) = p
1923
+ cycle main_loop
1924
+ end if
1925
+ d(i) = d(i-1)
1926
+ end do
1927
+ end if
1928
+ i = 1
1929
+ d(i) = p
1930
+ end do main_loop
1931
+
1932
+ if (abs(d(n)) >= abs(d(1))) return
1933
+
1934
+ nhalf = n/2
1935
+
1936
+ do i = 1, nhalf
1937
+ ntop = n - i
1938
+ dhold = d(i)
1939
+ d(i) = d(ntop+1)
1940
+ d(ntop+1) = dhold
1941
+ end do
1942
+ end if
1943
+ end associate
1944
+
1945
+ end subroutine cblktri_tevls
1946
+
1947
+ end module complex_block_tridiagonal_linear_systems_solver