Actual source code: arnoldi.c
slepc-3.13.1 2020-04-12
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 eigensolver: "arnoldi"
13: Method: Explicitly Restarted Arnoldi
15: Algorithm:
17: Arnoldi method with explicit restart and deflation.
19: References:
21: [1] "Arnoldi Methods in SLEPc", SLEPc Technical Report STR-4,
22: available at https://slepc.upv.es.
23: */
25: #include <slepc/private/epsimpl.h> /*I "slepceps.h" I*/
27: typedef struct {
28: PetscBool delayed;
29: } EPS_ARNOLDI;
31: PetscErrorCode EPSSetUp_Arnoldi(EPS eps)
32: {
36: EPSSetDimensions_Default(eps,eps->nev,&eps->ncv,&eps->mpd);
37: if (eps->ncv>eps->nev+eps->mpd) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must not be larger than nev+mpd");
38: if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
39: if (!eps->which) { EPSSetWhichEigenpairs_Default(eps); }
40: if (eps->which==EPS_ALL || (eps->ishermitian && eps->ispositive && (eps->which==EPS_LARGEST_IMAGINARY || eps->which==EPS_SMALLEST_IMAGINARY))) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");
42: if (!eps->extraction) {
43: EPSSetExtraction(eps,EPS_RITZ);
44: }
45: if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not supported in this solver");
47: EPSAllocateSolution(eps,1);
48: EPS_SetInnerProduct(eps);
49: DSSetType(eps->ds,DSNHEP);
50: if (eps->extraction==EPS_REFINED || eps->extraction==EPS_REFINED_HARMONIC) {
51: DSSetRefined(eps->ds,PETSC_TRUE);
52: }
53: DSSetExtraRow(eps->ds,PETSC_TRUE);
54: DSAllocate(eps->ds,eps->ncv+1);
56: if (eps->isgeneralized && eps->ishermitian && !eps->ispositive) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Requested method does not work for indefinite problems");
57: return(0);
58: }
60: PetscErrorCode EPSSolve_Arnoldi(EPS eps)
61: {
62: PetscErrorCode ierr;
63: PetscInt k,nv,ld;
64: Mat U,Op;
65: PetscScalar *H;
66: PetscReal beta,gamma=1.0;
67: PetscBool breakdown,harmonic,refined;
68: BVOrthogRefineType orthog_ref;
69: EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;
72: DSGetLeadingDimension(eps->ds,&ld);
73: DSGetRefined(eps->ds,&refined);
74: harmonic = (eps->extraction==EPS_HARMONIC || eps->extraction==EPS_REFINED_HARMONIC)?PETSC_TRUE:PETSC_FALSE;
75: BVGetOrthogonalization(eps->V,NULL,&orthog_ref,NULL,NULL);
77: /* Get the starting Arnoldi vector */
78: EPSGetStartVector(eps,0,NULL);
80: /* Restart loop */
81: while (eps->reason == EPS_CONVERGED_ITERATING) {
82: eps->its++;
84: /* Compute an nv-step Arnoldi factorization */
85: nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
86: DSSetDimensions(eps->ds,nv,0,eps->nconv,0);
87: DSGetArray(eps->ds,DS_MAT_A,&H);
88: if (!arnoldi->delayed) {
89: STGetOperator(eps->st,&Op);
90: BVMatArnoldi(eps->V,Op,H,ld,eps->nconv,&nv,&beta,&breakdown);
91: STRestoreOperator(eps->st,&Op);
92: } else if (orthog_ref == BV_ORTHOG_REFINE_NEVER) {
93: EPSDelayedArnoldi1(eps,H,ld,eps->nconv,&nv,&beta,&breakdown);
94: } else {
95: EPSDelayedArnoldi(eps,H,ld,eps->nconv,&nv,&beta,&breakdown);
96: }
97: DSRestoreArray(eps->ds,DS_MAT_A,&H);
98: DSSetState(eps->ds,DS_STATE_INTERMEDIATE);
99: BVSetActiveColumns(eps->V,eps->nconv,nv);
101: /* Compute translation of Krylov decomposition if harmonic extraction used */
102: if (harmonic) {
103: DSTranslateHarmonic(eps->ds,eps->target,beta,PETSC_FALSE,NULL,&gamma);
104: }
106: /* Solve projected problem */
107: DSSolve(eps->ds,eps->eigr,eps->eigi);
108: DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL);
109: DSUpdateExtraRow(eps->ds);
110: DSSynchronize(eps->ds,eps->eigr,eps->eigi);
112: /* Check convergence */
113: EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,0.0,gamma,&k);
114: if (refined) {
115: DSGetMat(eps->ds,DS_MAT_X,&U);
116: BVMultInPlace(eps->V,U,eps->nconv,k+1);
117: MatDestroy(&U);
118: BVOrthonormalizeColumn(eps->V,k,PETSC_FALSE,NULL,NULL);
119: } else {
120: DSGetMat(eps->ds,DS_MAT_Q,&U);
121: BVMultInPlace(eps->V,U,eps->nconv,PetscMin(k+1,nv));
122: MatDestroy(&U);
123: }
124: (*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx);
125: if (eps->reason == EPS_CONVERGED_ITERATING && breakdown) {
126: PetscInfo2(eps,"Breakdown in Arnoldi method (it=%D norm=%g)\n",eps->its,(double)beta);
127: EPSGetStartVector(eps,k,&breakdown);
128: if (breakdown) {
129: eps->reason = EPS_DIVERGED_BREAKDOWN;
130: PetscInfo(eps,"Unable to generate more start vectors\n");
131: }
132: }
133: eps->nconv = k;
134: EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,nv);
135: }
137: /* truncate Schur decomposition and change the state to raw so that
138: DSVectors() computes eigenvectors from scratch */
139: DSSetDimensions(eps->ds,eps->nconv,0,0,0);
140: DSSetState(eps->ds,DS_STATE_RAW);
141: return(0);
142: }
144: PetscErrorCode EPSSetFromOptions_Arnoldi(PetscOptionItems *PetscOptionsObject,EPS eps)
145: {
147: PetscBool set,val;
148: EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;
151: PetscOptionsHead(PetscOptionsObject,"EPS Arnoldi Options");
153: PetscOptionsBool("-eps_arnoldi_delayed","Use delayed reorthogonalization","EPSArnoldiSetDelayed",arnoldi->delayed,&val,&set);
154: if (set) { EPSArnoldiSetDelayed(eps,val); }
156: PetscOptionsTail();
157: return(0);
158: }
160: static PetscErrorCode EPSArnoldiSetDelayed_Arnoldi(EPS eps,PetscBool delayed)
161: {
162: EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;
165: arnoldi->delayed = delayed;
166: return(0);
167: }
169: /*@
170: EPSArnoldiSetDelayed - Activates or deactivates delayed reorthogonalization
171: in the Arnoldi iteration.
173: Logically Collective on eps
175: Input Parameters:
176: + eps - the eigenproblem solver context
177: - delayed - boolean flag
179: Options Database Key:
180: . -eps_arnoldi_delayed - Activates delayed reorthogonalization in Arnoldi
182: Note:
183: Delayed reorthogonalization is an aggressive optimization for the Arnoldi
184: eigensolver than may provide better scalability, but sometimes makes the
185: solver converge less than the default algorithm.
187: Level: advanced
189: .seealso: EPSArnoldiGetDelayed()
190: @*/
191: PetscErrorCode EPSArnoldiSetDelayed(EPS eps,PetscBool delayed)
192: {
198: PetscTryMethod(eps,"EPSArnoldiSetDelayed_C",(EPS,PetscBool),(eps,delayed));
199: return(0);
200: }
202: static PetscErrorCode EPSArnoldiGetDelayed_Arnoldi(EPS eps,PetscBool *delayed)
203: {
204: EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;
207: *delayed = arnoldi->delayed;
208: return(0);
209: }
211: /*@
212: EPSArnoldiGetDelayed - Gets the type of reorthogonalization used during the Arnoldi
213: iteration.
215: Not Collective
217: Input Parameter:
218: . eps - the eigenproblem solver context
220: Input Parameter:
221: . delayed - boolean flag indicating if delayed reorthogonalization has been enabled
223: Level: advanced
225: .seealso: EPSArnoldiSetDelayed()
226: @*/
227: PetscErrorCode EPSArnoldiGetDelayed(EPS eps,PetscBool *delayed)
228: {
234: PetscUseMethod(eps,"EPSArnoldiGetDelayed_C",(EPS,PetscBool*),(eps,delayed));
235: return(0);
236: }
238: PetscErrorCode EPSDestroy_Arnoldi(EPS eps)
239: {
243: PetscFree(eps->data);
244: PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiSetDelayed_C",NULL);
245: PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiGetDelayed_C",NULL);
246: return(0);
247: }
249: PetscErrorCode EPSView_Arnoldi(EPS eps,PetscViewer viewer)
250: {
252: PetscBool isascii;
253: EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;
256: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
257: if (isascii && arnoldi->delayed) {
258: PetscViewerASCIIPrintf(viewer," using delayed reorthogonalization\n");
259: }
260: return(0);
261: }
263: SLEPC_EXTERN PetscErrorCode EPSCreate_Arnoldi(EPS eps)
264: {
265: EPS_ARNOLDI *ctx;
269: PetscNewLog(eps,&ctx);
270: eps->data = (void*)ctx;
272: eps->useds = PETSC_TRUE;
274: eps->ops->solve = EPSSolve_Arnoldi;
275: eps->ops->setup = EPSSetUp_Arnoldi;
276: eps->ops->setfromoptions = EPSSetFromOptions_Arnoldi;
277: eps->ops->destroy = EPSDestroy_Arnoldi;
278: eps->ops->view = EPSView_Arnoldi;
279: eps->ops->backtransform = EPSBackTransform_Default;
280: eps->ops->computevectors = EPSComputeVectors_Schur;
282: PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiSetDelayed_C",EPSArnoldiSetDelayed_Arnoldi);
283: PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiGetDelayed_C",EPSArnoldiGetDelayed_Arnoldi);
284: return(0);
285: }