Actual source code: narnoldi.c
slepc-3.14.1 2020-12-08
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-2020, 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 nonlinear eigensolver: "narnoldi"
13: Method: Nonlinear Arnoldi
15: Algorithm:
17: Arnoldi for nonlinear eigenproblems.
19: References:
21: [1] H. Voss, "An Arnoldi method for nonlinear eigenvalue problems",
22: BIT 44:387-401, 2004.
23: */
25: #include <slepc/private/nepimpl.h>
26: #include <../src/nep/impls/nepdefl.h>
28: typedef struct {
29: PetscInt lag; /* interval to rebuild preconditioner */
30: KSP ksp; /* linear solver object */
31: } NEP_NARNOLDI;
33: PetscErrorCode NEPSetUp_NArnoldi(NEP nep)
34: {
38: NEPSetDimensions_Default(nep,nep->nev,&nep->ncv,&nep->mpd);
39: if (nep->ncv>nep->nev+nep->mpd) SETERRQ(PetscObjectComm((PetscObject)nep),1,"The value of ncv must not be larger than nev+mpd");
40: if (nep->max_it==PETSC_DEFAULT) nep->max_it = nep->nev*nep->ncv;
41: if (!nep->which) nep->which = NEP_TARGET_MAGNITUDE;
42: if (nep->which!=NEP_TARGET_MAGNITUDE) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver supports only target magnitude eigenvalues");
43: NEPCheckUnsupported(nep,NEP_FEATURE_CALLBACK | NEP_FEATURE_REGION | NEP_FEATURE_TWOSIDED);
44: NEPAllocateSolution(nep,0);
45: NEPSetWorkVecs(nep,3);
46: return(0);
47: }
49: PetscErrorCode NEPSolve_NArnoldi(NEP nep)
50: {
51: PetscErrorCode ierr;
52: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
53: Mat T,H;
54: Vec f,r,u,uu;
55: PetscScalar *X,lambda=0.0,lambda2=0.0,*eigr,*Hp,*Ap,sigma;
56: PetscReal beta,resnorm=0.0,nrm,perr=0.0;
57: PetscInt n,i,j,ldds,ldh;
58: PetscBool breakdown,skip=PETSC_FALSE;
59: BV Vext;
60: DS ds;
61: NEP_EXT_OP extop=NULL;
62: SlepcSC sc;
63: KSPConvergedReason kspreason;
66: /* get initial space and shift */
67: NEPGetDefaultShift(nep,&sigma);
68: if (!nep->nini) {
69: BVSetRandomColumn(nep->V,0);
70: BVNormColumn(nep->V,0,NORM_2,&nrm);
71: BVScaleColumn(nep->V,0,1.0/nrm);
72: n = 1;
73: } else n = nep->nini;
75: if (!ctx->ksp) { NEPNArnoldiGetKSP(nep,&ctx->ksp); }
76: NEPDeflationInitialize(nep,nep->V,ctx->ksp,PETSC_FALSE,nep->nev,&extop);
77: NEPDeflationCreateBV(extop,nep->ncv,&Vext);
79: /* prepare linear solver */
80: NEPDeflationSolveSetUp(extop,sigma);
82: BVGetColumn(Vext,0,&f);
83: VecDuplicate(f,&r);
84: VecDuplicate(f,&u);
85: BVGetColumn(nep->V,0,&uu);
86: NEPDeflationCopyToExtendedVec(extop,uu,NULL,f,PETSC_FALSE);
87: BVRestoreColumn(nep->V,0,&uu);
88: VecCopy(f,r);
89: NEPDeflationFunctionSolve(extop,r,f);
90: VecNorm(f,NORM_2,&nrm);
91: VecScale(f,1.0/nrm);
92: BVRestoreColumn(Vext,0,&f);
94: DSCreate(PetscObjectComm((PetscObject)nep),&ds);
95: PetscLogObjectParent((PetscObject)nep,(PetscObject)ds);
96: DSSetType(ds,DSNEP);
97: DSNEPSetFN(ds,nep->nt,nep->f);
98: DSAllocate(ds,nep->ncv);
99: DSGetSlepcSC(ds,&sc);
100: sc->comparison = nep->sc->comparison;
101: sc->comparisonctx = nep->sc->comparisonctx;
102: DSSetFromOptions(ds);
104: /* build projected matrices for initial space */
105: DSSetDimensions(ds,n,0,0,0);
106: NEPDeflationProjectOperator(extop,Vext,ds,0,n);
108: PetscMalloc1(nep->ncv,&eigr);
110: /* Restart loop */
111: while (nep->reason == NEP_CONVERGED_ITERATING) {
112: nep->its++;
114: /* solve projected problem */
115: DSSetDimensions(ds,n,0,0,0);
116: DSSetState(ds,DS_STATE_RAW);
117: DSSolve(ds,eigr,NULL);
118: DSSynchronize(ds,eigr,NULL);
119: if (nep->its>1) lambda2 = lambda;
120: lambda = eigr[0];
121: nep->eigr[nep->nconv] = lambda;
123: /* compute Ritz vector, x = V*s */
124: DSGetArray(ds,DS_MAT_X,&X);
125: BVSetActiveColumns(Vext,0,n);
126: BVMultVec(Vext,1.0,0.0,u,X);
127: DSRestoreArray(ds,DS_MAT_X,&X);
129: /* compute the residual, r = T(lambda)*x */
130: NEPDeflationComputeFunction(extop,lambda,&T);
131: MatMult(T,u,r);
133: /* convergence test */
134: VecNorm(r,NORM_2,&resnorm);
135: if (nep->its>1) perr=nep->errest[nep->nconv];
136: (*nep->converged)(nep,lambda,0,resnorm,&nep->errest[nep->nconv],nep->convergedctx);
137: if (nep->errest[nep->nconv]<=nep->tol) {
138: nep->nconv = nep->nconv + 1;
139: NEPDeflationLocking(extop,u,lambda);
140: skip = PETSC_TRUE;
141: }
142: (*nep->stopping)(nep,nep->its,nep->max_it,nep->nconv,nep->nev,&nep->reason,nep->stoppingctx);
143: if (!skip || nep->reason>0) {
144: NEPMonitor(nep,nep->its,nep->nconv,nep->eigr,nep->eigi,nep->errest,(nep->reason>0)?nep->nconv:nep->nconv+1);
145: }
147: if (nep->reason == NEP_CONVERGED_ITERATING) {
148: if (!skip) {
149: if (n>=nep->ncv) {
150: nep->reason = NEP_DIVERGED_SUBSPACE_EXHAUSTED;
151: break;
152: }
153: if (ctx->lag && !(nep->its%ctx->lag) && nep->its>=2*ctx->lag && perr && nep->errest[nep->nconv]>.5*perr) {
154: NEPDeflationSolveSetUp(extop,lambda2);
155: }
157: /* continuation vector: f = T(sigma)\r */
158: BVGetColumn(Vext,n,&f);
159: NEPDeflationFunctionSolve(extop,r,f);
160: BVRestoreColumn(Vext,n,&f);
161: KSPGetConvergedReason(ctx->ksp,&kspreason);
162: if (kspreason<0) {
163: PetscInfo1(nep,"iter=%D, linear solve failed, stopping solve\n",nep->its);
164: nep->reason = NEP_DIVERGED_LINEAR_SOLVE;
165: break;
166: }
168: /* orthonormalize */
169: BVOrthonormalizeColumn(Vext,n,PETSC_FALSE,&beta,&breakdown);
170: if (breakdown || beta==0.0) {
171: PetscInfo1(nep,"iter=%D, orthogonalization failed, stopping solve\n",nep->its);
172: nep->reason = NEP_DIVERGED_BREAKDOWN;
173: break;
174: }
176: /* update projected matrices */
177: DSSetDimensions(ds,n+1,0,0,0);
178: NEPDeflationProjectOperator(extop,Vext,ds,n,n+1);
179: n++;
180: } else {
181: nep->its--; /* do not count this as a full iteration */
182: BVGetColumn(Vext,0,&f);
183: NEPDeflationSetRandomVec(extop,f);
184: NEPDeflationSolveSetUp(extop,sigma);
185: VecCopy(f,r);
186: NEPDeflationFunctionSolve(extop,r,f);
187: VecNorm(f,NORM_2,&nrm);
188: VecScale(f,1.0/nrm);
189: BVRestoreColumn(Vext,0,&f);
190: n = 1;
191: DSSetDimensions(ds,n,0,0,0);
192: NEPDeflationProjectOperator(extop,Vext,ds,n-1,n);
193: skip = PETSC_FALSE;
194: }
195: }
196: }
198: NEPDeflationGetInvariantPair(extop,NULL,&H);
199: MatGetSize(H,NULL,&ldh);
200: DSSetType(nep->ds,DSNHEP);
201: DSAllocate(nep->ds,PetscMax(nep->nconv,1));
202: DSGetLeadingDimension(nep->ds,&ldds);
203: MatDenseGetArray(H,&Hp);
204: DSGetArray(nep->ds,DS_MAT_A,&Ap);
205: for (j=0;j<nep->nconv;j++)
206: for (i=0;i<nep->nconv;i++) Ap[j*ldds+i] = Hp[j*ldh+i];
207: DSRestoreArray(nep->ds,DS_MAT_A,&Ap);
208: MatDenseRestoreArray(H,&Hp);
209: MatDestroy(&H);
210: DSSetDimensions(nep->ds,nep->nconv,0,0,nep->nconv);
211: DSSolve(nep->ds,nep->eigr,nep->eigi);
212: NEPDeflationReset(extop);
213: VecDestroy(&u);
214: VecDestroy(&r);
215: BVDestroy(&Vext);
216: DSDestroy(&ds);
217: PetscFree(eigr);
218: return(0);
219: }
221: static PetscErrorCode NEPNArnoldiSetLagPreconditioner_NArnoldi(NEP nep,PetscInt lag)
222: {
223: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
226: if (lag<0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Lag must be non-negative");
227: ctx->lag = lag;
228: return(0);
229: }
231: /*@
232: NEPNArnoldiSetLagPreconditioner - Determines when the preconditioner is rebuilt in the
233: nonlinear solve.
235: Logically Collective on nep
237: Input Parameters:
238: + nep - nonlinear eigenvalue solver
239: - lag - 0 indicates NEVER rebuild, 1 means rebuild every time the Jacobian is
240: computed within the nonlinear iteration, 2 means every second time
241: the Jacobian is built, etc.
243: Options Database Keys:
244: . -nep_narnoldi_lag_preconditioner <lag>
246: Notes:
247: The default is 1.
248: The preconditioner is ALWAYS built in the first iteration of a nonlinear solve.
250: Level: intermediate
252: .seealso: NEPNArnoldiGetLagPreconditioner()
253: @*/
254: PetscErrorCode NEPNArnoldiSetLagPreconditioner(NEP nep,PetscInt lag)
255: {
261: PetscTryMethod(nep,"NEPNArnoldiSetLagPreconditioner_C",(NEP,PetscInt),(nep,lag));
262: return(0);
263: }
265: static PetscErrorCode NEPNArnoldiGetLagPreconditioner_NArnoldi(NEP nep,PetscInt *lag)
266: {
267: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
270: *lag = ctx->lag;
271: return(0);
272: }
274: /*@
275: NEPNArnoldiGetLagPreconditioner - Indicates how often the preconditioner is rebuilt.
277: Not Collective
279: Input Parameter:
280: . nep - nonlinear eigenvalue solver
282: Output Parameter:
283: . lag - the lag parameter
285: Level: intermediate
287: .seealso: NEPNArnoldiSetLagPreconditioner()
288: @*/
289: PetscErrorCode NEPNArnoldiGetLagPreconditioner(NEP nep,PetscInt *lag)
290: {
296: PetscUseMethod(nep,"NEPNArnoldiGetLagPreconditioner_C",(NEP,PetscInt*),(nep,lag));
297: return(0);
298: }
300: PetscErrorCode NEPSetFromOptions_NArnoldi(PetscOptionItems *PetscOptionsObject,NEP nep)
301: {
303: PetscInt i;
304: PetscBool flg;
305: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
308: PetscOptionsHead(PetscOptionsObject,"NEP N-Arnoldi Options");
309: i = 0;
310: PetscOptionsInt("-nep_narnoldi_lag_preconditioner","Interval to rebuild preconditioner","NEPNArnoldiSetLagPreconditioner",ctx->lag,&i,&flg);
311: if (flg) { NEPNArnoldiSetLagPreconditioner(nep,i); }
313: PetscOptionsTail();
315: if (!ctx->ksp) { NEPNArnoldiGetKSP(nep,&ctx->ksp); }
316: KSPSetFromOptions(ctx->ksp);
317: return(0);
318: }
320: static PetscErrorCode NEPNArnoldiSetKSP_NArnoldi(NEP nep,KSP ksp)
321: {
323: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
326: PetscObjectReference((PetscObject)ksp);
327: KSPDestroy(&ctx->ksp);
328: ctx->ksp = ksp;
329: PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->ksp);
330: nep->state = NEP_STATE_INITIAL;
331: return(0);
332: }
334: /*@
335: NEPNArnoldiSetKSP - Associate a linear solver object (KSP) to the nonlinear
336: eigenvalue solver.
338: Collective on nep
340: Input Parameters:
341: + nep - eigenvalue solver
342: - ksp - the linear solver object
344: Level: advanced
346: .seealso: NEPNArnoldiGetKSP()
347: @*/
348: PetscErrorCode NEPNArnoldiSetKSP(NEP nep,KSP ksp)
349: {
356: PetscTryMethod(nep,"NEPNArnoldiSetKSP_C",(NEP,KSP),(nep,ksp));
357: return(0);
358: }
360: static PetscErrorCode NEPNArnoldiGetKSP_NArnoldi(NEP nep,KSP *ksp)
361: {
363: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
366: if (!ctx->ksp) {
367: KSPCreate(PetscObjectComm((PetscObject)nep),&ctx->ksp);
368: PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)nep,1);
369: KSPSetOptionsPrefix(ctx->ksp,((PetscObject)nep)->prefix);
370: KSPAppendOptionsPrefix(ctx->ksp,"nep_narnoldi_");
371: PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->ksp);
372: PetscObjectSetOptions((PetscObject)ctx->ksp,((PetscObject)nep)->options);
373: KSPSetErrorIfNotConverged(ctx->ksp,PETSC_TRUE);
374: KSPSetTolerances(ctx->ksp,SLEPC_DEFAULT_TOL,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
375: }
376: *ksp = ctx->ksp;
377: return(0);
378: }
380: /*@
381: NEPNArnoldiGetKSP - Retrieve the linear solver object (KSP) associated with
382: the nonlinear eigenvalue solver.
384: Not Collective
386: Input Parameter:
387: . nep - nonlinear eigenvalue solver
389: Output Parameter:
390: . ksp - the linear solver object
392: Level: advanced
394: .seealso: NEPNArnoldiSetKSP()
395: @*/
396: PetscErrorCode NEPNArnoldiGetKSP(NEP nep,KSP *ksp)
397: {
403: PetscUseMethod(nep,"NEPNArnoldiGetKSP_C",(NEP,KSP*),(nep,ksp));
404: return(0);
405: }
407: PetscErrorCode NEPView_NArnoldi(NEP nep,PetscViewer viewer)
408: {
410: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
411: PetscBool isascii;
414: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
415: if (isascii) {
416: if (ctx->lag) {
417: PetscViewerASCIIPrintf(viewer," updating the preconditioner every %D iterations\n",ctx->lag);
418: }
419: if (!ctx->ksp) { NEPNArnoldiGetKSP(nep,&ctx->ksp); }
420: PetscViewerASCIIPushTab(viewer);
421: KSPView(ctx->ksp,viewer);
422: PetscViewerASCIIPopTab(viewer);
423: }
424: return(0);
425: }
427: PetscErrorCode NEPReset_NArnoldi(NEP nep)
428: {
430: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
433: KSPReset(ctx->ksp);
434: return(0);
435: }
437: PetscErrorCode NEPDestroy_NArnoldi(NEP nep)
438: {
440: NEP_NARNOLDI *ctx = (NEP_NARNOLDI*)nep->data;
443: KSPDestroy(&ctx->ksp);
444: PetscFree(nep->data);
445: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiSetLagPreconditioner_C",NULL);
446: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiGetLagPreconditioner_C",NULL);
447: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiSetKSP_C",NULL);
448: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiGetKSP_C",NULL);
449: return(0);
450: }
452: SLEPC_EXTERN PetscErrorCode NEPCreate_NArnoldi(NEP nep)
453: {
455: NEP_NARNOLDI *ctx;
458: PetscNewLog(nep,&ctx);
459: nep->data = (void*)ctx;
460: ctx->lag = 1;
462: nep->useds = PETSC_TRUE;
464: nep->ops->solve = NEPSolve_NArnoldi;
465: nep->ops->setup = NEPSetUp_NArnoldi;
466: nep->ops->setfromoptions = NEPSetFromOptions_NArnoldi;
467: nep->ops->reset = NEPReset_NArnoldi;
468: nep->ops->destroy = NEPDestroy_NArnoldi;
469: nep->ops->view = NEPView_NArnoldi;
470: nep->ops->computevectors = NEPComputeVectors_Schur;
472: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiSetLagPreconditioner_C",NEPNArnoldiSetLagPreconditioner_NArnoldi);
473: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiGetLagPreconditioner_C",NEPNArnoldiGetLagPreconditioner_NArnoldi);
474: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiSetKSP_C",NEPNArnoldiSetKSP_NArnoldi);
475: PetscObjectComposeFunction((PetscObject)nep,"NEPNArnoldiGetKSP_C",NEPNArnoldiGetKSP_NArnoldi);
476: return(0);
477: }