Actual source code: epsdefault.c

slepc-3.17.2 2022-08-09
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

  6:    This file is part of SLEPc.
  7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
  8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  9: */
 10: /*
 11:    This file contains some simple default routines for common operations
 12: */

 14: #include <slepc/private/epsimpl.h>
 15: #include <slepcvec.h>

 17: PetscErrorCode EPSBackTransform_Default(EPS eps)
 18: {
 19:   STBackTransform(eps->st,eps->nconv,eps->eigr,eps->eigi);
 20:   PetscFunctionReturn(0);
 21: }

 23: /*
 24:   EPSComputeVectors_Hermitian - Copies the Lanczos vectors as eigenvectors
 25:   using purification for generalized eigenproblems.
 26:  */
 27: PetscErrorCode EPSComputeVectors_Hermitian(EPS eps)
 28: {
 29:   PetscBool      iscayley,indef;
 30:   Mat            B,C;

 32:   if (eps->purify) {
 33:     EPS_Purify(eps,eps->nconv);
 34:     BVNormalize(eps->V,NULL);
 35:   } else {
 36:     /* In the case of Cayley transform, eigenvectors need to be B-normalized */
 37:     PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley);
 38:     if (iscayley && eps->isgeneralized) {
 39:       STGetMatrix(eps->st,1,&B);
 40:       BVGetMatrix(eps->V,&C,&indef);
 42:       BVSetMatrix(eps->V,B,PETSC_FALSE);
 43:       BVNormalize(eps->V,NULL);
 44:       BVSetMatrix(eps->V,C,PETSC_FALSE);  /* restore original matrix */
 45:     }
 46:   }
 47:   PetscFunctionReturn(0);
 48: }

 50: /*
 51:   EPSComputeVectors_Indefinite - similar to the Schur version but
 52:   for indefinite problems
 53:  */
 54: PetscErrorCode EPSComputeVectors_Indefinite(EPS eps)
 55: {
 56:   PetscInt       n;
 57:   Mat            X;

 59:   DSGetDimensions(eps->ds,&n,NULL,NULL,NULL);
 60:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);
 61:   DSGetMat(eps->ds,DS_MAT_X,&X);
 62:   BVMultInPlace(eps->V,X,0,n);
 63:   MatDestroy(&X);

 65:   /* purification */
 66:   if (eps->purify) EPS_Purify(eps,eps->nconv);

 68:   /* normalization */
 69:   BVNormalize(eps->V,eps->eigi);
 70:   PetscFunctionReturn(0);
 71: }

 73: /*
 74:   EPSComputeVectors_Twosided - Adjust left eigenvectors in generalized problems: y = B^-* y.
 75:  */
 76: PetscErrorCode EPSComputeVectors_Twosided(EPS eps)
 77: {
 78:   PetscInt       i;
 79:   Vec            w,y;

 81:   if (!eps->twosided || !eps->isgeneralized) PetscFunctionReturn(0);
 82:   EPSSetWorkVecs(eps,1);
 83:   w = eps->work[0];
 84:   for (i=0;i<eps->nconv;i++) {
 85:     BVCopyVec(eps->W,i,w);
 86:     VecConjugate(w);
 87:     BVGetColumn(eps->W,i,&y);
 88:     STMatSolveTranspose(eps->st,w,y);
 89:     VecConjugate(y);
 90:     BVRestoreColumn(eps->W,i,&y);
 91:   }
 92:   PetscFunctionReturn(0);
 93: }

 95: /*
 96:   EPSComputeVectors_Schur - Compute eigenvectors from the vectors
 97:   provided by the eigensolver. This version is intended for solvers
 98:   that provide Schur vectors. Given the partial Schur decomposition
 99:   OP*V=V*T, the following steps are performed:
100:       1) compute eigenvectors of T: T*Z=Z*D
101:       2) compute eigenvectors of OP: X=V*Z
102:  */
103: PetscErrorCode EPSComputeVectors_Schur(EPS eps)
104: {
105:   PetscInt       i;
106:   Mat            Z;
107:   Vec            z;

109:   if (eps->ishermitian) {
110:     if (eps->isgeneralized && !eps->ispositive) EPSComputeVectors_Indefinite(eps);
111:     else EPSComputeVectors_Hermitian(eps);
112:     PetscFunctionReturn(0);
113:   }

115:   /* right eigenvectors */
116:   DSVectors(eps->ds,DS_MAT_X,NULL,NULL);

118:   /* V = V * Z */
119:   DSGetMat(eps->ds,DS_MAT_X,&Z);
120:   BVMultInPlace(eps->V,Z,0,eps->nconv);
121:   MatDestroy(&Z);

123:   /* Purify eigenvectors */
124:   if (eps->purify) EPS_Purify(eps,eps->nconv);

126:   /* Fix eigenvectors if balancing was used */
127:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
128:     for (i=0;i<eps->nconv;i++) {
129:       BVGetColumn(eps->V,i,&z);
130:       VecPointwiseDivide(z,z,eps->D);
131:       BVRestoreColumn(eps->V,i,&z);
132:     }
133:   }

135:   /* normalize eigenvectors (when using purification or balancing) */
136:   if (eps->purify || (eps->balance!=EPS_BALANCE_NONE && eps->D)) BVNormalize(eps->V,eps->eigi);

138:   /* left eigenvectors */
139:   if (eps->twosided) {
140:     DSVectors(eps->ds,DS_MAT_Y,NULL,NULL);
141:     /* W = W * Z */
142:     DSGetMat(eps->ds,DS_MAT_Y,&Z);
143:     BVMultInPlace(eps->W,Z,0,eps->nconv);
144:     MatDestroy(&Z);
145:     /* Fix left eigenvectors if balancing was used */
146:     if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
147:       for (i=0;i<eps->nconv;i++) {
148:         BVGetColumn(eps->W,i,&z);
149:         VecPointwiseMult(z,z,eps->D);
150:         BVRestoreColumn(eps->W,i,&z);
151:       }
152:     }
153:     EPSComputeVectors_Twosided(eps);
154:     /* normalize */
155:     BVNormalize(eps->W,eps->eigi);
156: #if !defined(PETSC_USE_COMPLEX)
157:     for (i=0;i<eps->nconv-1;i++) {
158:       if (eps->eigi[i] != 0.0) {
159:         if (eps->eigi[i] > 0.0) BVScaleColumn(eps->W,i+1,-1.0);
160:         i++;
161:       }
162:     }
163: #endif
164:   }
165:   PetscFunctionReturn(0);
166: }

168: /*@
169:    EPSSetWorkVecs - Sets a number of work vectors into an EPS object.

171:    Collective on eps

173:    Input Parameters:
174: +  eps - eigensolver context
175: -  nw  - number of work vectors to allocate

177:    Developer Notes:
178:    This is SLEPC_EXTERN because it may be required by user plugin EPS
179:    implementations.

181:    Level: developer

183: .seealso: EPSSetUp()
184: @*/
185: PetscErrorCode EPSSetWorkVecs(EPS eps,PetscInt nw)
186: {
187:   Vec            t;

192:   if (eps->nwork < nw) {
193:     VecDestroyVecs(eps->nwork,&eps->work);
194:     eps->nwork = nw;
195:     BVGetColumn(eps->V,0,&t);
196:     VecDuplicateVecs(t,nw,&eps->work);
197:     BVRestoreColumn(eps->V,0,&t);
198:     PetscLogObjectParents(eps,nw,eps->work);
199:   }
200:   PetscFunctionReturn(0);
201: }

203: /*
204:   EPSSetWhichEigenpairs_Default - Sets the default value for which,
205:   depending on the ST.
206:  */
207: PetscErrorCode EPSSetWhichEigenpairs_Default(EPS eps)
208: {
209:   PetscBool      target;

211:   PetscObjectTypeCompareAny((PetscObject)eps->st,&target,STSINVERT,STCAYLEY,"");
212:   if (target) eps->which = EPS_TARGET_MAGNITUDE;
213:   else eps->which = EPS_LARGEST_MAGNITUDE;
214:   PetscFunctionReturn(0);
215: }

217: /*
218:   EPSConvergedRelative - Checks convergence relative to the eigenvalue.
219: */
220: PetscErrorCode EPSConvergedRelative(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
221: {
222:   PetscReal w;

224:   w = SlepcAbsEigenvalue(eigr,eigi);
225:   *errest = res/w;
226:   PetscFunctionReturn(0);
227: }

229: /*
230:   EPSConvergedAbsolute - Checks convergence absolutely.
231: */
232: PetscErrorCode EPSConvergedAbsolute(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
233: {
234:   *errest = res;
235:   PetscFunctionReturn(0);
236: }

238: /*
239:   EPSConvergedNorm - Checks convergence relative to the eigenvalue and
240:   the matrix norms.
241: */
242: PetscErrorCode EPSConvergedNorm(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
243: {
244:   PetscReal w;

246:   w = SlepcAbsEigenvalue(eigr,eigi);
247:   *errest = res / (eps->nrma + w*eps->nrmb);
248:   PetscFunctionReturn(0);
249: }

251: /*@C
252:    EPSStoppingBasic - Default routine to determine whether the outer eigensolver
253:    iteration must be stopped.

255:    Collective on eps

257:    Input Parameters:
258: +  eps    - eigensolver context obtained from EPSCreate()
259: .  its    - current number of iterations
260: .  max_it - maximum number of iterations
261: .  nconv  - number of currently converged eigenpairs
262: .  nev    - number of requested eigenpairs
263: -  ctx    - context (not used here)

265:    Output Parameter:
266: .  reason - result of the stopping test

268:    Notes:
269:    A positive value of reason indicates that the iteration has finished successfully
270:    (converged), and a negative value indicates an error condition (diverged). If
271:    the iteration needs to be continued, reason must be set to EPS_CONVERGED_ITERATING
272:    (zero).

274:    EPSStoppingBasic() will stop if all requested eigenvalues are converged, or if
275:    the maximum number of iterations has been reached.

277:    Use EPSSetStoppingTest() to provide your own test instead of using this one.

279:    Level: advanced

281: .seealso: EPSSetStoppingTest(), EPSConvergedReason, EPSGetConvergedReason()
282: @*/
283: PetscErrorCode EPSStoppingBasic(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
284: {
285:   *reason = EPS_CONVERGED_ITERATING;
286:   if (nconv >= nev) {
287:     PetscInfo(eps,"Linear eigensolver finished successfully: %" PetscInt_FMT " eigenpairs converged at iteration %" PetscInt_FMT "\n",nconv,its);
288:     *reason = EPS_CONVERGED_TOL;
289:   } else if (its >= max_it) {
290:     *reason = EPS_DIVERGED_ITS;
291:     PetscInfo(eps,"Linear eigensolver iteration reached maximum number of iterations (%" PetscInt_FMT ")\n",its);
292:   }
293:   PetscFunctionReturn(0);
294: }

296: /*
297:   EPSComputeRitzVector - Computes the current Ritz vector.

299:   Simple case (complex scalars or real scalars with Zi=NULL):
300:     x = V*Zr  (V is a basis of nv vectors, Zr has length nv)

302:   Split case:
303:     x = V*Zr  y = V*Zi  (Zr and Zi have length nv)
304: */
305: PetscErrorCode EPSComputeRitzVector(EPS eps,PetscScalar *Zr,PetscScalar *Zi,BV V,Vec x,Vec y)
306: {
307:   PetscInt       l,k;
308:   PetscReal      norm;
309: #if !defined(PETSC_USE_COMPLEX)
310:   Vec            z;
311: #endif

313:   /* compute eigenvector */
314:   BVGetActiveColumns(V,&l,&k);
315:   BVSetActiveColumns(V,0,k);
316:   BVMultVec(V,1.0,0.0,x,Zr);

318:   /* purify eigenvector if necessary */
319:   if (eps->purify) {
320:     STApply(eps->st,x,y);
321:     if (eps->ishermitian) BVNormVec(eps->V,y,NORM_2,&norm);
322:     else VecNorm(y,NORM_2,&norm);
323:     VecScale(y,1.0/norm);
324:     VecCopy(y,x);
325:   }
326:   /* fix eigenvector if balancing is used */
327:   if (!eps->ishermitian && eps->balance!=EPS_BALANCE_NONE && eps->D) VecPointwiseDivide(x,x,eps->D);
328: #if !defined(PETSC_USE_COMPLEX)
329:   /* compute imaginary part of eigenvector */
330:   if (Zi) {
331:     BVMultVec(V,1.0,0.0,y,Zi);
332:     if (eps->ispositive) {
333:       BVCreateVec(V,&z);
334:       STApply(eps->st,y,z);
335:       VecNorm(z,NORM_2,&norm);
336:       VecScale(z,1.0/norm);
337:       VecCopy(z,y);
338:       VecDestroy(&z);
339:     }
340:     if (eps->balance!=EPS_BALANCE_NONE && eps->D) VecPointwiseDivide(y,y,eps->D);
341:   } else
342: #endif
343:     VecSet(y,0.0);

345:   /* normalize eigenvectors (when using balancing) */
346:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
347: #if !defined(PETSC_USE_COMPLEX)
348:     if (Zi) VecNormalizeComplex(x,y,PETSC_TRUE,NULL);
349:     else
350: #endif
351:     VecNormalize(x,NULL);
352:   }
353:   BVSetActiveColumns(V,l,k);
354:   PetscFunctionReturn(0);
355: }

357: /*
358:   EPSBuildBalance_Krylov - uses a Krylov subspace method to compute the
359:   diagonal matrix to be applied for balancing in non-Hermitian problems.
360: */
361: PetscErrorCode EPSBuildBalance_Krylov(EPS eps)
362: {
363:   Vec               z,p,r;
364:   PetscInt          i,j;
365:   PetscReal         norma;
366:   PetscScalar       *pz,*pD;
367:   const PetscScalar *pr,*pp;
368:   PetscRandom       rand;

370:   EPSSetWorkVecs(eps,3);
371:   BVGetRandomContext(eps->V,&rand);
372:   r = eps->work[0];
373:   p = eps->work[1];
374:   z = eps->work[2];
375:   VecSet(eps->D,1.0);

377:   for (j=0;j<eps->balance_its;j++) {

379:     /* Build a random vector of +-1's */
380:     VecSetRandom(z,rand);
381:     VecGetArray(z,&pz);
382:     for (i=0;i<eps->nloc;i++) {
383:       if (PetscRealPart(pz[i])<0.5) pz[i]=-1.0;
384:       else pz[i]=1.0;
385:     }
386:     VecRestoreArray(z,&pz);

388:     /* Compute p=DA(D\z) */
389:     VecPointwiseDivide(r,z,eps->D);
390:     STApply(eps->st,r,p);
391:     VecPointwiseMult(p,p,eps->D);
392:     if (eps->balance == EPS_BALANCE_TWOSIDE) {
393:       if (j==0) {
394:         /* Estimate the matrix inf-norm */
395:         VecAbs(p);
396:         VecMax(p,NULL,&norma);
397:       }
398:       /* Compute r=D\(A'Dz) */
399:       VecPointwiseMult(z,z,eps->D);
400:       STApplyHermitianTranspose(eps->st,z,r);
401:       VecPointwiseDivide(r,r,eps->D);
402:     }

404:     /* Adjust values of D */
405:     VecGetArrayRead(r,&pr);
406:     VecGetArrayRead(p,&pp);
407:     VecGetArray(eps->D,&pD);
408:     for (i=0;i<eps->nloc;i++) {
409:       if (eps->balance == EPS_BALANCE_TWOSIDE) {
410:         if (PetscAbsScalar(pp[i])>eps->balance_cutoff*norma && pr[i]!=0.0)
411:           pD[i] *= PetscSqrtReal(PetscAbsScalar(pr[i]/pp[i]));
412:       } else {
413:         if (pp[i]!=0.0) pD[i] /= PetscAbsScalar(pp[i]);
414:       }
415:     }
416:     VecRestoreArrayRead(r,&pr);
417:     VecRestoreArrayRead(p,&pp);
418:     VecRestoreArray(eps->D,&pD);
419:   }
420:   PetscFunctionReturn(0);
421: }