Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
mydsaup2.f
1 c @HEADER
2 c *****************************************************************************
3 c Anasazi: Block Eigensolvers Package
4 c
5 c Copyright 2004 NTESS and the Anasazi contributors.
6 c SPDX-License-Identifier: BSD-3-Clause
7 c *****************************************************************************
8 c @HEADER
9 
10 c This software is a result of the research described in the report
11 c
12 c "A comparison of algorithms for modal analysis in the absence
13 c of a sparse direct method", P. Arbenz, R. Lehoucq, and U. Hetmaniuk,
14 c Sandia National Laboratories, Technical report SAND2003-1028J.
15 c
16 c It is based on the Epetra, AztecOO, and ML packages defined in the Trilinos
17 c framework ( http://trilinos.org/ ).
18 c-----------------------------------------------------------------------
19 c\BeginDoc
20 c
21 c\Name: mydsaup2
22 c
23 c\Description:
24 c Intermediate level interface called by dsaupd.
25 c
26 c\Usage:
27 c call mydsaup2
28 c ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD,
29 c ISHIFT, MXITER, V, LDV, H, LDH, RITZ, BOUNDS, Q, LDQ, WORKL,
30 c IPNTR, WORKD, INFO, VERBOSE, USRCHK, UNCONV )
31 c
32 c\Arguments
33 c
34 c IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dsaupd.
35 c MODE, ISHIFT, MXITER: see the definition of IPARAM in dsaupd.
36 c
37 c NP Integer. (INPUT/OUTPUT)
38 c Contains the number of implicit shifts to apply during
39 c each Arnoldi/Lanczos iteration.
40 c If ISHIFT=1, NP is adjusted dynamically at each iteration
41 c to accelerate convergence and prevent stagnation.
42 c This is also roughly equal to the number of matrix-vector
43 c products (involving the operator OP) per Arnoldi iteration.
44 c The logic for adjusting is contained within the current
45 c subroutine.
46 c If ISHIFT=0, NP is the number of shifts the user needs
47 c to provide via reverse comunication. 0 < NP < NCV-NEV.
48 c NP may be less than NCV-NEV since a leading block of the current
49 c upper Tridiagonal matrix has split off and contains "unwanted"
50 c Ritz values.
51 c Upon termination of the IRA iteration, NP contains the number
52 c of "converged" wanted Ritz values.
53 c
54 c IUPD Integer. (INPUT)
55 c IUPD .EQ. 0: use explicit restart instead implicit update.
56 c IUPD .NE. 0: use implicit update.
57 c
58 c V Double precision N by (NEV+NP) array. (INPUT/OUTPUT)
59 c The Lanczos basis vectors.
60 c
61 c LDV Integer. (INPUT)
62 c Leading dimension of V exactly as declared in the calling
63 c program.
64 c
65 c H Double precision (NEV+NP) by 2 array. (OUTPUT)
66 c H is used to store the generated symmetric tridiagonal matrix
67 c The subdiagonal is stored in the first column of H starting
68 c at H(2,1). The main diagonal is stored in the second column
69 c of H starting at H(1,2). If dsaup2 converges store the
70 c B-norm of the final residual vector in H(1,1).
71 c
72 c LDH Integer. (INPUT)
73 c Leading dimension of H exactly as declared in the calling
74 c program.
75 c
76 c RITZ Double precision array of length NEV+NP. (OUTPUT)
77 c RITZ(1:NEV) contains the computed Ritz values of OP.
78 c
79 c BOUNDS Double precision array of length NEV+NP. (OUTPUT)
80 c BOUNDS(1:NEV) contain the error bounds corresponding to RITZ.
81 c
82 c Q Double precision (NEV+NP) by (NEV+NP) array. (WORKSPACE)
83 c Private (replicated) work array used to accumulate the
84 c rotation in the shift application step.
85 c
86 c LDQ Integer. (INPUT)
87 c Leading dimension of Q exactly as declared in the calling
88 c program.
89 c
90 c WORKL Double precision array of length at least 3*(NEV+NP). (INPUT/WORKSPACE)
91 c Private (replicated) array on each PE or array allocated on
92 c the front end. It is used in the computation of the
93 c tridiagonal eigenvalue problem, the calculation and
94 c application of the shifts and convergence checking.
95 c If ISHIFT .EQ. O and IDO .EQ. 3, the first NP locations
96 c of WORKL are used in reverse communication to hold the user
97 c supplied shifts.
98 c
99 c IPNTR Integer array of length 3. (OUTPUT)
100 c Pointer to mark the starting locations in the WORKD for
101 c vectors used by the Lanczos iteration.
102 c -------------------------------------------------------------
103 c IPNTR(1): pointer to the current operand vector X.
104 c IPNTR(2): pointer to the current result vector Y.
105 c IPNTR(3): pointer to the vector B * X when used in one of
106 c the spectral transformation modes. X is the current
107 c operand.
108 c -------------------------------------------------------------
109 c
110 c WORKD Double precision work array of length 3*N. (REVERSE COMMUNICATION)
111 c Distributed array to be used in the basic Lanczos iteration
112 c for reverse communication. The user should not use WORKD
113 c as temporary workspace during the iteration !!!!!!!!!!
114 c See Data Distribution Note in dsaupd.
115 c
116 c INFO Integer. (INPUT/OUTPUT)
117 c If INFO .EQ. 0, a randomly initial residual vector is used.
118 c If INFO .NE. 0, RESID contains the initial residual vector,
119 c possibly from a previous run.
120 c Error flag on output.
121 c = 0: Normal return.
122 c = 1: All possible eigenvalues of OP has been found.
123 c NP returns the size of the invariant subspace
124 c spanning the operator OP.
125 c = 2: No shifts could be applied.
126 c = -8: Error return from trid. eigenvalue calculation;
127 c This should never happen.
128 c = -9: Starting vector is zero.
129 c = -9999: Could not build an Lanczos factorization.
130 c Size that was built in returned in NP.
131 c
132 c VERBOSE : Flag to print out the status of the computation per iteration
133 c
134 c USRCHK Integer. (INPUT) A nonzero value implies that reverse
135 c communication is done so that the user can check convergence.
136 c
137 c UNCONV Integer. (INPUT) Only used if USRCHK is not equal to zero.
138 c
139 c\EndDoc
140 c
141 c-----------------------------------------------------------------------
142 c
143 c\BeginLib
144 c
145 c\References:
146 c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in
147 c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),
148 c pp 357-385.
149 c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly
150 c Restarted Arnoldi Iteration", Rice University Technical Report
151 c TR95-13, Department of Computational and Applied Mathematics.
152 c 3. B.N. Parlett, "The Symmetric Eigenvalue Problem". Prentice-Hall,
153 c 1980.
154 c 4. B.N. Parlett, B. Nour-Omid, "Towards a Black Box Lanczos Program",
155 c Computer Physics Communications, 53 (1989), pp 169-179.
156 c 5. B. Nour-Omid, B.N. Parlett, T. Ericson, P.S. Jensen, "How to
157 c Implement the Spectral Transformation", Math. Comp., 48 (1987),
158 c pp 663-673.
159 c 6. R.G. Grimes, J.G. Lewis and H.D. Simon, "A Shifted Block Lanczos
160 c Algorithm for Solving Sparse Symmetric Generalized Eigenproblems",
161 c SIAM J. Matr. Anal. Apps., January (1993).
162 c 7. L. Reichel, W.B. Gragg, "Algorithm 686: FORTRAN Subroutines
163 c for Updating the QR decomposition", ACM TOMS, December 1990,
164 c Volume 16 Number 4, pp 369-377.
165 c
166 c\Routines called:
167 c dgetv0 ARPACK initial vector generation routine.
168 c dsaitr ARPACK Lanczos factorization routine.
169 c dsapps ARPACK application of implicit shifts routine.
170 c dsconv ARPACK convergence of Ritz values routine.
171 c dseigt ARPACK compute Ritz values and error bounds routine.
172 c dsgets ARPACK reorder Ritz values and error bounds routine.
173 c dsortr ARPACK sorting routine.
174 c ivout ARPACK utility routine that prints integers.
175 c second ARPACK utility routine for timing.
176 c dvout ARPACK utility routine that prints vectors.
177 c dlamch LAPACK routine that determines machine constants.
178 c dcopy Level 1 BLAS that copies one vector to another.
179 c ddot Level 1 BLAS that computes the scalar product of two vectors.
180 c dnrm2 Level 1 BLAS that computes the norm of a vector.
181 c dscal Level 1 BLAS that scales a vector.
182 c dswap Level 1 BLAS that swaps two vectors.
183 c
184 c\Author
185 c Danny Sorensen Phuong Vu
186 c Richard Lehoucq CRPC / Rice University
187 c Dept. of Computational & Houston, Texas
188 c Applied Mathematics
189 c Rice University
190 c Houston, Texas
191 c
192 c\Revision history:
193 c 12/15/93: Version ' 2.4'
194 c xx/xx/95: Version ' 2.4'. (R.B. Lehoucq)
195 c
196 c\SCCS Information: @(#)
197 c FILE: saup2.F SID: 2.7 DATE OF SID: 5/19/98 RELEASE: 2
198 c
199 c\EndLib
200 c
201 c-----------------------------------------------------------------------
202 c
203  subroutine mydsaup2
204  & ( ido, bmat, n, which, nev, np, tol, resid, mode, iupd,
205  & ishift, mxiter, v, ldv, h, ldh, ritz, bounds,
206  & q, ldq, workl, ipntr, workd, info, verbose, usrchk, unconv )
207 c
208 c %----------------------------------------------------%
209 c | Include files for debugging and timing information |
210 c %----------------------------------------------------%
211 c
212  include 'debug.h'
213  include 'stat.h'
214 c
215 c %------------------%
216 c | Scalar Arguments |
217 c %------------------%
218 c
219  character bmat*1, which*2
220  integer ido, info, ishift, iupd, ldh, ldq, ldv, mxiter,
221  & n, mode, nev, np
222  integer verbose, urschk, unconv
223  double precision
224  & tol
225 c
226 c %-----------------%
227 c | Array Arguments |
228 c %-----------------%
229 c
230  integer ipntr(3)
231  double precision
232  & bounds(nev+np), h(ldh,2), q(ldq,nev+np), resid(n),
233  & ritz(nev+np), v(ldv,nev+np), workd(3*n),
234  & workl(3*(nev+np))
235 c
236 c %------------%
237 c | Parameters |
238 c %------------%
239 c
240  double precision
241  & one, zero
242  parameter(one = 1.0d+0, zero = 0.0d+0)
243 c
244 c %---------------%
245 c | Local Scalars |
246 c %---------------%
247 c
248  character wprime*2
249  logical cnorm, getv0, initv, update, ushift
250  logical cnvchk
251  integer ierr, iter, j, kplusp, msglvl, nconv, nevbef, nev0,
252  & np0, nptemp, nevd2, nevm2, kp(3)
253  double precision
254  & rnorm, temp, eps23
255  save cnorm, getv0, initv, update, ushift,
256  & iter, kplusp, msglvl, nconv, nev0, np0,
257  & rnorm, eps23, cnvchk
258 c
259 c %----------------------%
260 c | External Subroutines |
261 c %----------------------%
262 c
263  external dcopy, dgetv0, dsaitr, dscal, dsconv, dseigt, dsgets,
264  & dsapps, dsortr, dvout, ivout, second, dswap
265 c
266 c %--------------------%
267 c | External Functions |
268 c %--------------------%
269 c
270  double precision
271  & ddot, dnrm2, dlamch
272  external ddot, dnrm2, dlamch
273 c
274 c %---------------------%
275 c | Intrinsic Functions |
276 c %---------------------%
277 c
278  intrinsic min
279 c
280 c %-----------------------%
281 c | Executable Statements |
282 c %-----------------------%
283 c
284  if (ido .eq. 0) then
285 c
286 c %-------------------------------%
287 c | Initialize timing statistics |
288 c | & message level for debugging |
289 c %-------------------------------%
290 c
291  call second(t0)
292  msglvl = msaup2
293 c
294 c %---------------------------------%
295 c | Set machine dependent constant. |
296 c %---------------------------------%
297 c
298  eps23 = dlamch('Epsilon-Machine')
299  eps23 = eps23**(2.0d+0/3.0d+0)
300 c
301 c %-------------------------------------%
302 c | nev0 and np0 are integer variables |
303 c | hold the initial values of NEV & NP |
304 c %-------------------------------------%
305 c
306  nev0 = nev
307  np0 = np
308 c
309 c %-------------------------------------%
310 c | kplusp is the bound on the largest |
311 c | Lanczos factorization built. |
312 c | nconv is the current number of |
313 c | "converged" eigenvlues. |
314 c | iter is the counter on the current |
315 c | iteration step. |
316 c %-------------------------------------%
317 c
318  kplusp = nev0 + np0
319  nconv = 0
320  iter = 0
321 c
322 c %--------------------------------------------%
323 c | Set flags for computing the first NEV steps |
324 c | of the Lanczos factorization. |
325 c %--------------------------------------------%
326 c
327  getv0 = .true.
328  update = .false.
329  ushift = .false.
330  cnorm = .false.
331  cnvchk = .false.
332 c
333  if (info .ne. 0) then
334 c
335 c %--------------------------------------------%
336 c | User provides the initial residual vector. |
337 c %--------------------------------------------%
338 c
339  initv = .true.
340  info = 0
341  else
342  initv = .false.
343  end if
344  end if
345 c
346 c %---------------------------------------------%
347 c | Get a possibly random starting vector and |
348 c | force it into the range of the operator OP. |
349 c %---------------------------------------------%
350 c
351  10 continue
352 c
353  if (getv0) then
354  call dgetv0(ido, bmat, 1, initv, n, 1, v, ldv, resid, rnorm,
355  & ipntr, workd, info)
356 c
357  if (ido .ne. 99) go to 9000
358 c
359  if (rnorm .eq. zero) then
360 c
361 c %-----------------------------------------%
362 c | The initial vector is zero. Error exit. |
363 c %-----------------------------------------%
364 c
365  info = -9
366  go to 1200
367  end if
368  getv0 = .false.
369  ido = 0
370  end if
371 c
372 c %------------------------------------------------------------%
373 c | Back from reverse communication: continue with update step |
374 c %------------------------------------------------------------%
375 c
376  if (update) go to 20
377 c
378 c %-------------------------------------------%
379 c | Back from computing user specified shifts |
380 c %-------------------------------------------%
381 c
382  if (ushift) go to 50
383 c
384 c %-------------------------------------%
385 c | Back from computing residual norm |
386 c | at the end of the current iteration |
387 c %-------------------------------------%
388 c
389  if (cnorm) go to 100
390 c
391 c %---------------------------------%
392 c | Back from checking convergence. |
393 c %---------------------------------%
394 c
395  if (cnvchk) go to 110
396 c
397 c %----------------------------------------------------------%
398 c | Compute the first NEV steps of the Lanczos factorization |
399 c %----------------------------------------------------------%
400 c
401  call dsaitr(ido, bmat, n, 0, nev0, mode, resid, rnorm, v, ldv,
402  & h, ldh, ipntr, workd, info)
403 c
404 c %---------------------------------------------------%
405 c | ido .ne. 99 implies use of reverse communication |
406 c | to compute operations involving OP and possibly B |
407 c %---------------------------------------------------%
408 c
409  if (ido .ne. 99) go to 9000
410 c
411  if (info .gt. 0) then
412 c
413 c %-----------------------------------------------------%
414 c | dsaitr was unable to build an Lanczos factorization |
415 c | of length NEV0. INFO is returned with the size of |
416 c | the factorization built. Exit main loop. |
417 c %-----------------------------------------------------%
418 c
419  np = info
420  mxiter = iter
421  info = -9999
422  go to 1200
423  end if
424 c
425 c %--------------------------------------------------------------%
426 c | |
427 c | M A I N LANCZOS I T E R A T I O N L O O P |
428 c | Each iteration implicitly restarts the Lanczos |
429 c | factorization in place. |
430 c | |
431 c %--------------------------------------------------------------%
432 c
433  1000 continue
434 c
435  iter = iter + 1
436 c
437  if (verbose .gt. 0) then
438  write(*,*)' Iteration ',iter,
439  & ' - Number of converged eigenvalues ',nconv
440  end if
441 c
442  if (msglvl .gt. 0) then
443  call ivout(logfil, 1, iter, ndigit,
444  & '_saup2: **** Start of major iteration number ****')
445  end if
446  if (msglvl .gt. 1) then
447  call ivout(logfil, 1, nev, ndigit,
448  & '_saup2: The length of the current Lanczos factorization')
449  call ivout(logfil, 1, np, ndigit,
450  & '_saup2: Extend the Lanczos factorization by')
451  end if
452 c
453 c %------------------------------------------------------------%
454 c | Compute NP additional steps of the Lanczos factorization. |
455 c %------------------------------------------------------------%
456 c
457  ido = 0
458  20 continue
459  update = .true.
460 c
461  call dsaitr(ido, bmat, n, nev, np, mode, resid, rnorm, v,
462  & ldv, h, ldh, ipntr, workd, info)
463 c
464 c %---------------------------------------------------%
465 c | ido .ne. 99 implies use of reverse communication |
466 c | to compute operations involving OP and possibly B |
467 c %---------------------------------------------------%
468 c
469  if (ido .ne. 99) go to 9000
470 c
471  if (info .gt. 0) then
472 c
473 c %-----------------------------------------------------%
474 c | dsaitr was unable to build an Lanczos factorization |
475 c | of length NEV0+NP0. INFO is returned with the size |
476 c | of the factorization built. Exit main loop. |
477 c %-----------------------------------------------------%
478 c
479  np = info
480  mxiter = iter
481  info = -9999
482  go to 1200
483  end if
484  update = .false.
485 c
486  if (msglvl .gt. 1) then
487  call dvout(logfil, 1, rnorm, ndigit,
488  & '_saup2: Current B-norm of residual for factorization')
489  end if
490 c
491 c %--------------------------------------------------------%
492 c | Compute the eigenvalues and corresponding error bounds |
493 c | of the current symmetric tridiagonal matrix. |
494 c %--------------------------------------------------------%
495 c
496  call dseigt(rnorm, kplusp, h, ldh, ritz, bounds, workl, ierr)
497 c
498  if (ierr .ne. 0) then
499  info = -8
500  go to 1200
501  end if
502 c
503 c %----------------------------------------------------%
504 c | Make a copy of eigenvalues and corresponding error |
505 c | bounds obtained from _seigt. |
506 c %----------------------------------------------------%
507 c
508  call dcopy(kplusp, ritz, 1, workl(kplusp+1), 1)
509  call dcopy(kplusp, bounds, 1, workl(2*kplusp+1), 1)
510 c
511 c %---------------------------------------------------%
512 c | Select the wanted Ritz values and their bounds |
513 c | to be used in the convergence test. |
514 c | The selection is based on the requested number of |
515 c | eigenvalues instead of the current NEV and NP to |
516 c | prevent possible misconvergence. |
517 c | * Wanted Ritz values := RITZ(NP+1:NEV+NP) |
518 c | * Shifts := RITZ(1:NP) := WORKL(1:NP) |
519 c %---------------------------------------------------%
520 c
521  nev = nev0
522  np = np0
523  call dsgets(ishift, which, nev, np, ritz, bounds, workl)
524 c
525 c %-------------------%
526 c | Convergence test. |
527 c %-------------------%
528 c
529  call dcopy(nev, bounds(np+1), 1, workl(np+1), 1)
530  if (usrchk .eq. zero) then
531  call dsconv(nev, ritz(np+1), workl(np+1), tol, nconv)
532  else
533 c
534 c %--------------------------------------------------%
535 c | reverse communication so that the user can check |
536 c | convergence. |
537 c %--------------------------------------------------%
538 c
539  cnvchk = .true.
540  ido = 4
541  go to 9000
542  end if
543 c
544  110 continue
545 c
546 c %------------------------------------%
547 c | Back from reverse communication; |
548 c %------------------------------------%
549 c
550  if (usrchk .ne. zero) then
551  nconv = unconv
552  cnvchk = .false.
553  end if
554 c
555  if (msglvl .gt. 2) then
556  kp(1) = nev
557  kp(2) = np
558  kp(3) = nconv
559  call ivout(logfil, 3, kp, ndigit,
560  & '_saup2: NEV, NP, NCONV are')
561  call dvout(logfil, kplusp, ritz, ndigit,
562  & '_saup2: The eigenvalues of H')
563  call dvout(logfil, kplusp, bounds, ndigit,
564  & '_saup2: Ritz estimates of the current NCV Ritz values')
565  end if
566 c
567 c %---------------------------------------------------------%
568 c | Count the number of unwanted Ritz values that have zero |
569 c | Ritz estimates. If any Ritz estimates are equal to zero |
570 c | then a leading block of H of order equal to at least |
571 c | the number of Ritz values with zero Ritz estimates has |
572 c | split off. None of these Ritz values may be removed by |
573 c | shifting. Decrease NP the number of shifts to apply. If |
574 c | no shifts may be applied, then prepare to exit |
575 c %---------------------------------------------------------%
576 c
577  nptemp = np
578  do 30 j=1, nptemp
579  if (bounds(j) .eq. zero) then
580  np = np - 1
581  nev = nev + 1
582  end if
583  30 continue
584 c
585  if ( (nconv .ge. nev0) .or.
586  & (iter .gt. mxiter) .or.
587  & (np .eq. 0) ) then
588 c
589 c %------------------------------------------------%
590 c | Prepare to exit. Put the converged Ritz values |
591 c | and corresponding bounds in RITZ(1:NCONV) and |
592 c | BOUNDS(1:NCONV) respectively. Then sort. Be |
593 c | careful when NCONV > NP since we don't want to |
594 c | swap overlapping locations. |
595 c %------------------------------------------------%
596 c
597  if (which .eq. 'BE') then
598 c
599 c %-----------------------------------------------------%
600 c | Both ends of the spectrum are requested. |
601 c | Sort the eigenvalues into algebraically decreasing |
602 c | order first then swap low end of the spectrum next |
603 c | to high end in appropriate locations. |
604 c | NOTE: when np < floor(nev/2) be careful not to swap |
605 c | overlapping locations. |
606 c %-----------------------------------------------------%
607 c
608  wprime = 'SA'
609  call dsortr(wprime, .true., kplusp, ritz, bounds)
610  nevd2 = nev0 / 2
611  nevm2 = nev0 - nevd2
612  if ( nev .gt. 1 ) then
613  call dswap( min(nevd2,np), ritz(nevm2+1), 1,
614  & ritz( max(kplusp-nevd2+1,kplusp-np+1) ), 1)
615  call dswap( min(nevd2,np), bounds(nevm2+1), 1,
616  & bounds( max(kplusp-nevd2+1,kplusp-np+1)), 1)
617  end if
618 c
619  else
620 c
621 c %--------------------------------------------------%
622 c | LM, SM, LA, SA case. |
623 c | Sort the eigenvalues of H into the an order that |
624 c | is opposite to WHICH, and apply the resulting |
625 c | order to BOUNDS. The eigenvalues are sorted so |
626 c | that the wanted part are always within the first |
627 c | NEV locations. |
628 c %--------------------------------------------------%
629 c
630  if (which .eq. 'LM') wprime = 'SM'
631  if (which .eq. 'SM') wprime = 'LM'
632  if (which .eq. 'LA') wprime = 'SA'
633  if (which .eq. 'SA') wprime = 'LA'
634 c
635  call dsortr(wprime, .true., kplusp, ritz, bounds)
636 c
637  end if
638 c
639 c %--------------------------------------------------%
640 c | Scale the Ritz estimate of each Ritz value |
641 c | by 1 / max(eps23,magnitude of the Ritz value). |
642 c %--------------------------------------------------%
643 c
644  do 35 j = 1, nev0
645  temp = max( eps23, abs(ritz(j)) )
646  bounds(j) = bounds(j)/temp
647  35 continue
648 c
649 c %----------------------------------------------------%
650 c | Sort the Ritz values according to the scaled Ritz |
651 c | esitmates. This will push all the converged ones |
652 c | towards the front of ritzr, ritzi, bounds |
653 c | (in the case when NCONV < NEV.) |
654 c %----------------------------------------------------%
655 c
656  wprime = 'LA'
657  call dsortr(wprime, .true., nev0, bounds, ritz)
658 c
659 c %----------------------------------------------%
660 c | Scale the Ritz estimate back to its original |
661 c | value. |
662 c %----------------------------------------------%
663 c
664  do 40 j = 1, nev0
665  temp = max( eps23, abs(ritz(j)) )
666  bounds(j) = bounds(j)*temp
667  40 continue
668 c
669 c %--------------------------------------------------%
670 c | Sort the "converged" Ritz values again so that |
671 c | the "threshold" values and their associated Ritz |
672 c | estimates appear at the appropriate position in |
673 c | ritz and bound. |
674 c %--------------------------------------------------%
675 c
676  if (which .eq. 'BE') then
677 c
678 c %------------------------------------------------%
679 c | Sort the "converged" Ritz values in increasing |
680 c | order. The "threshold" values are in the |
681 c | middle. |
682 c %------------------------------------------------%
683 c
684  wprime = 'LA'
685  call dsortr(wprime, .true., nconv, ritz, bounds)
686 c
687  else
688 c
689 c %----------------------------------------------%
690 c | In LM, SM, LA, SA case, sort the "converged" |
691 c | Ritz values according to WHICH so that the |
692 c | "threshold" value appears at the front of |
693 c | ritz. |
694 c %----------------------------------------------%
695 
696  call dsortr(which, .true., nconv, ritz, bounds)
697 c
698  end if
699 c
700 c %------------------------------------------%
701 c | Use h( 1,1 ) as storage to communicate |
702 c | rnorm to _seupd if needed |
703 c %------------------------------------------%
704 c
705  h(1,1) = rnorm
706 c
707  if (msglvl .gt. 1) then
708  call dvout(logfil, kplusp, ritz, ndigit,
709  & '_saup2: Sorted Ritz values.')
710  call dvout(logfil, kplusp, bounds, ndigit,
711  & '_saup2: Sorted ritz estimates.')
712  end if
713 c
714 c %------------------------------------%
715 c | Max iterations have been exceeded. |
716 c %------------------------------------%
717 c
718  if (iter .gt. mxiter .and. nconv .lt. nev) info = 1
719 c
720 c %---------------------%
721 c | No shifts to apply. |
722 c %---------------------%
723 c
724  if (np .eq. 0 .and. nconv .lt. nev0) info = 2
725 c
726  np = nconv
727  go to 1100
728 c
729  else if (nconv .lt. nev .and. ishift .eq. 1) then
730 c
731 c %---------------------------------------------------%
732 c | Do not have all the requested eigenvalues yet. |
733 c | To prevent possible stagnation, adjust the number |
734 c | of Ritz values and the shifts. |
735 c %---------------------------------------------------%
736 c
737  nevbef = nev
738  nev = nev + min(nconv, np/2)
739  if (nev .eq. 1 .and. kplusp .ge. 6) then
740  nev = kplusp / 2
741  else if (nev .eq. 1 .and. kplusp .gt. 2) then
742  nev = 2
743  end if
744  np = kplusp - nev
745 c
746 c %---------------------------------------%
747 c | If the size of NEV was just increased |
748 c | resort the eigenvalues. |
749 c %---------------------------------------%
750 c
751  if (nevbef .lt. nev)
752  & call dsgets(ishift, which, nev, np, ritz, bounds,
753  & workl)
754 c
755  end if
756 c
757  if (msglvl .gt. 0) then
758  call ivout(logfil, 1, nconv, ndigit,
759  & '_saup2: no. of "converged" Ritz values at this iter.')
760  if (msglvl .gt. 1) then
761  kp(1) = nev
762  kp(2) = np
763  call ivout(logfil, 2, kp, ndigit,
764  & '_saup2: NEV and NP are')
765  call dvout(logfil, nev, ritz(np+1), ndigit,
766  & '_saup2: "wanted" Ritz values.')
767  call dvout(logfil, nev, bounds(np+1), ndigit,
768  & '_saup2: Ritz estimates of the "wanted" values ')
769  end if
770  end if
771 
772 c
773  if (ishift .eq. 0) then
774 c
775 c %-----------------------------------------------------%
776 c | User specified shifts: reverse communication to |
777 c | compute the shifts. They are returned in the first |
778 c | NP locations of WORKL. |
779 c %-----------------------------------------------------%
780 c
781  ushift = .true.
782  ido = 3
783  go to 9000
784  end if
785 c
786  50 continue
787 c
788 c %------------------------------------%
789 c | Back from reverse communication; |
790 c | User specified shifts are returned |
791 c | in WORKL(1:*NP) |
792 c %------------------------------------%
793 c
794  ushift = .false.
795 c
796 c
797 c %---------------------------------------------------------%
798 c | Move the NP shifts to the first NP locations of RITZ to |
799 c | free up WORKL. This is for the non-exact shift case; |
800 c | in the exact shift case, dsgets already handles this. |
801 c %---------------------------------------------------------%
802 c
803  if (ishift .eq. 0) call dcopy(np, workl, 1, ritz, 1)
804 c
805  if (msglvl .gt. 2) then
806  call ivout(logfil, 1, np, ndigit,
807  & '_saup2: The number of shifts to apply ')
808  call dvout(logfil, np, workl, ndigit,
809  & '_saup2: shifts selected')
810  if (ishift .eq. 1) then
811  call dvout(logfil, np, bounds, ndigit,
812  & '_saup2: corresponding Ritz estimates')
813  end if
814  end if
815 c
816 c %---------------------------------------------------------%
817 c | Apply the NP0 implicit shifts by QR bulge chasing. |
818 c | Each shift is applied to the entire tridiagonal matrix. |
819 c | The first 2*N locations of WORKD are used as workspace. |
820 c | After dsapps is done, we have a Lanczos |
821 c | factorization of length NEV. |
822 c %---------------------------------------------------------%
823 c
824  call dsapps(n, nev, np, ritz, v, ldv, h, ldh, resid, q, ldq,
825  & workd)
826 c
827 c %---------------------------------------------%
828 c | Compute the B-norm of the updated residual. |
829 c | Keep B*RESID in WORKD(1:N) to be used in |
830 c | the first step of the next call to dsaitr. |
831 c %---------------------------------------------%
832 c
833  cnorm = .true.
834  call second(t2)
835  if (bmat .eq. 'G') then
836  nbx = nbx + 1
837  call dcopy(n, resid, 1, workd(n+1), 1)
838  ipntr(1) = n + 1
839  ipntr(2) = 1
840  ido = 2
841 c
842 c %----------------------------------%
843 c | Exit in order to compute B*RESID |
844 c %----------------------------------%
845 c
846  go to 9000
847  else if (bmat .eq. 'I') then
848  call dcopy(n, resid, 1, workd, 1)
849  end if
850 c
851  100 continue
852 c
853 c %----------------------------------%
854 c | Back from reverse communication; |
855 c | WORKD(1:N) := B*RESID |
856 c %----------------------------------%
857 c
858  if (bmat .eq. 'G') then
859  call second(t3)
860  tmvbx = tmvbx + (t3 - t2)
861  end if
862 c
863  if (bmat .eq. 'G') then
864  rnorm = ddot(n, resid, 1, workd, 1)
865  rnorm = sqrt(abs(rnorm))
866  else if (bmat .eq. 'I') then
867  rnorm = dnrm2(n, resid, 1)
868  end if
869  cnorm = .false.
870  130 continue
871 c
872  if (msglvl .gt. 2) then
873  call dvout(logfil, 1, rnorm, ndigit,
874  & '_saup2: B-norm of residual for NEV factorization')
875  call dvout(logfil, nev, h(1,2), ndigit,
876  & '_saup2: main diagonal of compressed H matrix')
877  call dvout(logfil, nev-1, h(2,1), ndigit,
878  & '_saup2: subdiagonal of compressed H matrix')
879  end if
880 c
881  go to 1000
882 c
883 c %---------------------------------------------------------------%
884 c | |
885 c | E N D O F M A I N I T E R A T I O N L O O P |
886 c | |
887 c %---------------------------------------------------------------%
888 c
889  1100 continue
890 c
891  mxiter = iter
892  nev = nconv
893 c
894  1200 continue
895  ido = 99
896 c
897 c %------------%
898 c | Error exit |
899 c %------------%
900 c
901  call second(t1)
902  tsaup2 = t1 - t0
903 c
904  9000 continue
905  return
906 c
907 c %---------------%
908 c | End of dsaup2 |
909 c %---------------%
910 c
911  end