Actual source code: subspace.c

slepc-3.15.0 2021-03-31
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-2021, 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:    SLEPc eigensolver: "subspace"

 13:    Method: Subspace Iteration

 15:    Algorithm:

 17:        Subspace iteration with Rayleigh-Ritz projection and locking,
 18:        based on the SRRIT implementation.

 20:    References:

 22:        [1] "Subspace Iteration in SLEPc", SLEPc Technical Report STR-3,
 23:            available at https://slepc.upv.es.
 24: */

 26: #include <slepc/private/epsimpl.h>

 28: PetscErrorCode EPSSetUp_Subspace(EPS eps)
 29: {

 33:   EPSCheckDefinite(eps);
 34:   EPSSetDimensions_Default(eps,eps->nev,&eps->ncv,&eps->mpd);
 35:   if (eps->max_it==PETSC_DEFAULT) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
 36:   if (!eps->which) { EPSSetWhichEigenpairs_Default(eps); }
 37:   if (eps->which!=EPS_LARGEST_MAGNITUDE && eps->which!=EPS_TARGET_MAGNITUDE) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only largest magnitude or target magnitude eigenvalues");
 38:   EPSCheckUnsupported(eps,EPS_FEATURE_ARBITRARY | EPS_FEATURE_EXTRACTION | EPS_FEATURE_TWOSIDED);
 39:   if (eps->converged != EPSConvergedRelative) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver only supports relative convergence test");

 41:   EPSAllocateSolution(eps,0);
 42:   EPS_SetInnerProduct(eps);
 43:   if (eps->ishermitian) {
 44:     DSSetType(eps->ds,DSHEP);
 45:   } else {
 46:     DSSetType(eps->ds,DSNHEP);
 47:   }
 48:   DSAllocate(eps->ds,eps->ncv);
 49:   return(0);
 50: }

 52: /*
 53:    EPSSubspaceFindGroup - Find a group of nearly equimodular eigenvalues, provided
 54:    in arrays wr and wi, according to the tolerance grptol. Also the 2-norms
 55:    of the residuals must be passed in (rsd). Arrays are processed from index
 56:    l to index m only. The output information is:

 58:    ngrp - number of entries of the group
 59:    ctr  - (w(l)+w(l+ngrp-1))/2
 60:    ae   - average of wr(l),...,wr(l+ngrp-1)
 61:    arsd - average of rsd(l),...,rsd(l+ngrp-1)
 62: */
 63: static PetscErrorCode EPSSubspaceFindGroup(PetscInt l,PetscInt m,PetscScalar *wr,PetscScalar *wi,PetscReal *rsd,PetscReal grptol,PetscInt *ngrp,PetscReal *ctr,PetscReal *ae,PetscReal *arsd)
 64: {
 65:   PetscInt  i;
 66:   PetscReal rmod,rmod1;

 69:   *ngrp = 0;
 70:   *ctr = 0;
 71:   rmod = SlepcAbsEigenvalue(wr[l],wi[l]);

 73:   for (i=l;i<m;) {
 74:     rmod1 = SlepcAbsEigenvalue(wr[i],wi[i]);
 75:     if (PetscAbsReal(rmod-rmod1) > grptol*(rmod+rmod1)) break;
 76:     *ctr = (rmod+rmod1)/2.0;
 77:     if (wi[i] != 0.0) {
 78:       (*ngrp)+=2;
 79:       i+=2;
 80:     } else {
 81:       (*ngrp)++;
 82:       i++;
 83:     }
 84:   }

 86:   *ae = 0;
 87:   *arsd = 0;
 88:   if (*ngrp) {
 89:     for (i=l;i<l+*ngrp;i++) {
 90:       (*ae) += PetscRealPart(wr[i]);
 91:       (*arsd) += rsd[i]*rsd[i];
 92:     }
 93:     *ae = *ae / *ngrp;
 94:     *arsd = PetscSqrtScalar(*arsd / *ngrp);
 95:   }
 96:   return(0);
 97: }

 99: /*
100:    EPSSubspaceResidualNorms - Computes the column norms of residual vectors
101:    OP*V(1:n,l:m) - V*T(1:m,l:m), where, on entry, OP*V has been computed and
102:    stored in R. On exit, rsd(l) to rsd(m) contain the computed norms.
103: */
104: static PetscErrorCode EPSSubspaceResidualNorms(BV R,BV V,Mat T,PetscInt l,PetscInt m,PetscScalar *eigi,PetscReal *rsd)
105: {
107:   PetscInt       i;

110:   BVMult(R,-1.0,1.0,V,T);
111:   for (i=l;i<m;i++) { BVNormColumnBegin(R,i,NORM_2,rsd+i); }
112:   for (i=l;i<m;i++) { BVNormColumnEnd(R,i,NORM_2,rsd+i); }
113: #if !defined(PETSC_USE_COMPLEX)
114:   for (i=l;i<m-1;i++) {
115:     if (eigi[i]!=0.0) {
116:       rsd[i]   = SlepcAbs(rsd[i],rsd[i+1]);
117:       rsd[i+1] = rsd[i];
118:       i++;
119:     }
120:   }
121: #endif
122:   return(0);
123: }

125: PetscErrorCode EPSSolve_Subspace(EPS eps)
126: {
128:   Mat            H,Q,S,T,B;
129:   BV             AV,R;
130:   PetscBool      indef;
131:   PetscInt       i,k,ld,ngrp,nogrp,*itrsd,*itrsdold;
132:   PetscInt       nxtsrr,idsrr,idort,nxtort,nv,ncv = eps->ncv,its;
133:   PetscReal      arsd,oarsd,ctr,octr,ae,oae,*rsd,tcond=1.0;
134:   /* Parameters */
135:   PetscInt       init = 5;        /* Number of initial iterations */
136:   PetscReal      stpfac = 1.5;    /* Max num of iter before next SRR step */
137:   PetscReal      alpha = 1.0;     /* Used to predict convergence of next residual */
138:   PetscReal      beta = 1.1;      /* Used to predict convergence of next residual */
139:   PetscReal      grptol = SLEPC_DEFAULT_TOL;   /* Tolerance for EPSSubspaceFindGroup */
140:   PetscReal      cnvtol = 1e-6;   /* Convergence criterion for cnv */
141:   PetscInt       orttol = 2;      /* Number of decimal digits whose loss
142:                                      can be tolerated in orthogonalization */

145:   its = 0;
146:   PetscMalloc3(ncv,&rsd,ncv,&itrsd,ncv,&itrsdold);
147:   DSGetLeadingDimension(eps->ds,&ld);
148:   BVDuplicate(eps->V,&AV);
149:   BVDuplicate(eps->V,&R);
150:   STGetOperator(eps->st,&S);

152:   for (i=0;i<ncv;i++) {
153:     rsd[i] = 0.0;
154:     itrsd[i] = -1;
155:   }

157:   /* Complete the initial basis with random vectors and orthonormalize them */
158:   for (k=eps->nini;k<ncv;k++) {
159:     BVSetRandomColumn(eps->V,k);
160:     BVOrthonormalizeColumn(eps->V,k,PETSC_TRUE,NULL,NULL);
161:   }

163:   while (eps->reason == EPS_CONVERGED_ITERATING) {
164:     eps->its++;
165:     nv = PetscMin(eps->nconv+eps->mpd,ncv);
166:     DSSetDimensions(eps->ds,nv,0,eps->nconv,0);

168:     /* Find group in previously computed eigenvalues */
169:     EPSSubspaceFindGroup(eps->nconv,nv,eps->eigr,eps->eigi,rsd,grptol,&nogrp,&octr,&oae,&oarsd);

171:     /* AV(:,idx) = OP * V(:,idx) */
172:     BVSetActiveColumns(eps->V,eps->nconv,nv);
173:     BVSetActiveColumns(AV,eps->nconv,nv);
174:     BVMatMult(eps->V,S,AV);

176:     /* T(:,idx) = V' * AV(:,idx) */
177:     BVSetActiveColumns(eps->V,0,nv);
178:     DSGetMat(eps->ds,DS_MAT_A,&H);
179:     BVDot(AV,eps->V,H);
180:     DSRestoreMat(eps->ds,DS_MAT_A,&H);
181:     DSSetState(eps->ds,DS_STATE_RAW);

183:     /* Solve projected problem */
184:     DSSolve(eps->ds,eps->eigr,eps->eigi);
185:     DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL);
186:     DSSynchronize(eps->ds,eps->eigr,eps->eigi);

188:     /* Update vectors V(:,idx) = V * U(:,idx) */
189:     DSGetMat(eps->ds,DS_MAT_Q,&Q);
190:     BVSetActiveColumns(AV,0,nv);
191:     BVSetActiveColumns(R,0,nv);
192:     BVMultInPlace(eps->V,Q,eps->nconv,nv);
193:     BVMultInPlace(AV,Q,eps->nconv,nv);
194:     BVCopy(AV,R);
195:     MatDestroy(&Q);

197:     /* Convergence check */
198:     DSGetMat(eps->ds,DS_MAT_A,&T);
199:     EPSSubspaceResidualNorms(R,eps->V,T,eps->nconv,nv,eps->eigi,rsd);
200:     DSRestoreMat(eps->ds,DS_MAT_A,&T);

202:     for (i=eps->nconv;i<nv;i++) {
203:       itrsdold[i] = itrsd[i];
204:       itrsd[i] = its;
205:       eps->errest[i] = rsd[i];
206:     }

208:     for (;;) {
209:       /* Find group in currently computed eigenvalues */
210:       EPSSubspaceFindGroup(eps->nconv,nv,eps->eigr,eps->eigi,eps->errest,grptol,&ngrp,&ctr,&ae,&arsd);
211:       if (ngrp!=nogrp) break;
212:       if (ngrp==0) break;
213:       if (PetscAbsReal(ae-oae)>ctr*cnvtol*(itrsd[eps->nconv]-itrsdold[eps->nconv])) break;
214:       if (arsd>ctr*eps->tol) break;
215:       eps->nconv = eps->nconv + ngrp;
216:       if (eps->nconv>=nv) break;
217:     }

219:     EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,nv);
220:     (*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx);
221:     if (eps->reason != EPS_CONVERGED_ITERATING) break;

223:     /* Compute nxtsrr (iteration of next projection step) */
224:     nxtsrr = PetscMin(eps->max_it,PetscMax((PetscInt)PetscFloorReal(stpfac*its),init));

226:     if (ngrp!=nogrp || ngrp==0 || arsd>=oarsd) {
227:       idsrr = nxtsrr - its;
228:     } else {
229:       idsrr = (PetscInt)PetscFloorReal(alpha+beta*(itrsdold[eps->nconv]-itrsd[eps->nconv])*PetscLogReal(arsd/eps->tol)/PetscLogReal(arsd/oarsd));
230:       idsrr = PetscMax(1,idsrr);
231:     }
232:     nxtsrr = PetscMin(nxtsrr,its+idsrr);

234:     /* Compute nxtort (iteration of next orthogonalization step) */
235:     DSCond(eps->ds,&tcond);
236:     idort = PetscMax(1,(PetscInt)PetscFloorReal(orttol/PetscMax(1,PetscLog10Real(tcond))));
237:     nxtort = PetscMin(its+idort,nxtsrr);

239:     /* V(:,idx) = AV(:,idx) */
240:     BVSetActiveColumns(eps->V,eps->nconv,nv);
241:     BVSetActiveColumns(AV,eps->nconv,nv);
242:     BVCopy(AV,eps->V);
243:     its++;

245:     /* Orthogonalization loop */
246:     do {
247:       BVGetMatrix(eps->V,&B,&indef);
248:       BVSetMatrix(eps->V,NULL,PETSC_FALSE);
249:       while (its<nxtort) {
250:         /* A(:,idx) = OP*V(:,idx) with normalization */
251:         BVMatMult(eps->V,S,AV);
252:         BVCopy(AV,eps->V);
253:         BVNormalize(eps->V,NULL);
254:         its++;
255:       }
256:       BVSetMatrix(eps->V,B,indef);
257:       /* Orthonormalize vectors */
258:       BVOrthogonalize(eps->V,NULL);
259:       nxtort = PetscMin(its+idort,nxtsrr);
260:     } while (its<nxtsrr);
261:   }

263:   PetscFree3(rsd,itrsd,itrsdold);
264:   BVDestroy(&AV);
265:   BVDestroy(&R);
266:   STRestoreOperator(eps->st,&S);
267:   DSTruncate(eps->ds,eps->nconv,PETSC_TRUE);
268:   return(0);
269: }

271: SLEPC_EXTERN PetscErrorCode EPSCreate_Subspace(EPS eps)
272: {
274:   eps->useds = PETSC_TRUE;
275:   eps->categ = EPS_CATEGORY_OTHER;

277:   eps->ops->solve          = EPSSolve_Subspace;
278:   eps->ops->setup          = EPSSetUp_Subspace;
279:   eps->ops->setupsort      = EPSSetUpSort_Default;
280:   eps->ops->backtransform  = EPSBackTransform_Default;
281:   eps->ops->computevectors = EPSComputeVectors_Schur;
282:   return(0);
283: }