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