Actual source code: arnoldi.c

slepc-3.7.0 2016-05-16
Report Typos and Errors
  1: /*

  3:    SLEPc eigensolver: "arnoldi"

  5:    Method: Explicitly Restarted Arnoldi

  7:    Algorithm:

  9:        Arnoldi method with explicit restart and deflation.

 11:    References:

 13:        [1] "Arnoldi Methods in SLEPc", SLEPc Technical Report STR-4,
 14:            available at http://slepc.upv.es.

 16:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 17:    SLEPc - Scalable Library for Eigenvalue Problem Computations
 18:    Copyright (c) 2002-2016, Universitat Politecnica de Valencia, Spain

 20:    This file is part of SLEPc.

 22:    SLEPc is free software: you can redistribute it and/or modify it under  the
 23:    terms of version 3 of the GNU Lesser General Public License as published by
 24:    the Free Software Foundation.

 26:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
 27:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
 28:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
 29:    more details.

 31:    You  should have received a copy of the GNU Lesser General  Public  License
 32:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
 33:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 34: */

 36: #include <slepc/private/epsimpl.h>                /*I "slepceps.h" I*/

 38: PetscErrorCode EPSSolve_Arnoldi(EPS);

 40: typedef struct {
 41:   PetscBool delayed;
 42: } EPS_ARNOLDI;

 46: PetscErrorCode EPSSetUp_Arnoldi(EPS eps)
 47: {

 51:   EPSSetDimensions_Default(eps,eps->nev,&eps->ncv,&eps->mpd);
 52:   if (eps->ncv>eps->nev+eps->mpd) SETERRQ(PetscObjectComm((PetscObject)eps),1,"The value of ncv must not be larger than nev+mpd");
 53:   if (!eps->max_it) eps->max_it = PetscMax(100,2*eps->n/eps->ncv);
 54:   if (!eps->which) { EPSSetWhichEigenpairs_Default(eps); }
 55:   if (eps->ishermitian && eps->ispositive && (eps->which==EPS_LARGEST_IMAGINARY || eps->which==EPS_SMALLEST_IMAGINARY)) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Wrong value of eps->which");

 57:   if (!eps->extraction) {
 58:     EPSSetExtraction(eps,EPS_RITZ);
 59:   }
 60:   if (eps->arbitrary) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Arbitrary selection of eigenpairs not supported in this solver");

 62:   EPSAllocateSolution(eps,1);
 63:   EPS_SetInnerProduct(eps);
 64:   DSSetType(eps->ds,DSNHEP);
 65:   if (eps->extraction==EPS_REFINED || eps->extraction==EPS_REFINED_HARMONIC) {
 66:     DSSetRefined(eps->ds,PETSC_TRUE);
 67:   }
 68:   DSSetExtraRow(eps->ds,PETSC_TRUE);
 69:   DSAllocate(eps->ds,eps->ncv+1);

 71:   /* dispatch solve method */
 72:   if (eps->isgeneralized && eps->ishermitian && !eps->ispositive) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Requested method does not work for indefinite problems");
 73:   eps->ops->solve = EPSSolve_Arnoldi;
 74:   return(0);
 75: }

 79: PetscErrorCode EPSSolve_Arnoldi(EPS eps)
 80: {
 81:   PetscErrorCode     ierr;
 82:   PetscInt           k,nv,ld;
 83:   Mat                U;
 84:   PetscScalar        *H,*X;
 85:   PetscReal          beta,gamma=1.0;
 86:   PetscBool          breakdown,harmonic,refined;
 87:   BVOrthogRefineType orthog_ref;
 88:   EPS_ARNOLDI        *arnoldi = (EPS_ARNOLDI*)eps->data;

 91:   DSGetLeadingDimension(eps->ds,&ld);
 92:   DSGetRefined(eps->ds,&refined);
 93:   harmonic = (eps->extraction==EPS_HARMONIC || eps->extraction==EPS_REFINED_HARMONIC)?PETSC_TRUE:PETSC_FALSE;
 94:   BVGetOrthogonalization(eps->V,NULL,&orthog_ref,NULL,NULL);

 96:   /* Get the starting Arnoldi vector */
 97:   EPSGetStartVector(eps,0,NULL);

 99:   /* Restart loop */
100:   while (eps->reason == EPS_CONVERGED_ITERATING) {
101:     eps->its++;

103:     /* Compute an nv-step Arnoldi factorization */
104:     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
105:     DSSetDimensions(eps->ds,nv,0,eps->nconv,0);
106:     DSGetArray(eps->ds,DS_MAT_A,&H);
107:     if (!arnoldi->delayed) {
108:       EPSBasicArnoldi(eps,PETSC_FALSE,H,ld,eps->nconv,&nv,&beta,&breakdown);
109:     } else if (orthog_ref == BV_ORTHOG_REFINE_NEVER) {
110:       EPSDelayedArnoldi1(eps,H,ld,eps->nconv,&nv,&beta,&breakdown);
111:     } else {
112:       EPSDelayedArnoldi(eps,H,ld,eps->nconv,&nv,&beta,&breakdown);
113:     }
114:     DSRestoreArray(eps->ds,DS_MAT_A,&H);
115:     DSSetState(eps->ds,DS_STATE_INTERMEDIATE);
116:     BVSetActiveColumns(eps->V,eps->nconv,nv);

118:     /* Compute translation of Krylov decomposition if harmonic extraction used */
119:     if (harmonic) {
120:       DSTranslateHarmonic(eps->ds,eps->target,beta,PETSC_FALSE,NULL,&gamma);
121:     }

123:     /* Solve projected problem */
124:     DSSolve(eps->ds,eps->eigr,eps->eigi);
125:     DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL);
126:     DSUpdateExtraRow(eps->ds);

128:     /* Check convergence */
129:     EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta,gamma,&k);
130:     if (refined) {
131:       DSGetArray(eps->ds,DS_MAT_X,&X);
132:       BVMultColumn(eps->V,1.0,0.0,k,X+k*ld);
133:       DSRestoreArray(eps->ds,DS_MAT_X,&X);
134:       DSGetMat(eps->ds,DS_MAT_Q,&U);
135:       BVMultInPlace(eps->V,U,eps->nconv,nv);
136:       MatDestroy(&U);
137:       BVOrthogonalizeColumn(eps->V,k,NULL,NULL,NULL);
138:     } else {
139:       DSGetMat(eps->ds,DS_MAT_Q,&U);
140:       BVMultInPlace(eps->V,U,eps->nconv,nv);
141:       MatDestroy(&U);
142:     }
143:     (*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx);
144:     if (eps->reason == EPS_CONVERGED_ITERATING && breakdown) {
145:       PetscInfo2(eps,"Breakdown in Arnoldi method (it=%D norm=%g)\n",eps->its,(double)beta);
146:       EPSGetStartVector(eps,k,&breakdown);
147:       if (breakdown) {
148:         eps->reason = EPS_DIVERGED_BREAKDOWN;
149:         PetscInfo(eps,"Unable to generate more start vectors\n");
150:       }
151:     }
152:     eps->nconv = k;
153:     EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,nv);
154:   }

156:   /* truncate Schur decomposition and change the state to raw so that
157:      DSVectors() computes eigenvectors from scratch */
158:   DSSetDimensions(eps->ds,eps->nconv,0,0,0);
159:   DSSetState(eps->ds,DS_STATE_RAW);
160:   return(0);
161: }

165: PetscErrorCode EPSSetFromOptions_Arnoldi(PetscOptionItems *PetscOptionsObject,EPS eps)
166: {
168:   PetscBool      set,val;
169:   EPS_ARNOLDI    *arnoldi = (EPS_ARNOLDI*)eps->data;

172:   PetscOptionsHead(PetscOptionsObject,"EPS Arnoldi Options");
173:   PetscOptionsBool("-eps_arnoldi_delayed","Arnoldi with delayed reorthogonalization","EPSArnoldiSetDelayed",arnoldi->delayed,&val,&set);
174:   if (set) {
175:     EPSArnoldiSetDelayed(eps,val);
176:   }
177:   PetscOptionsTail();
178:   return(0);
179: }

183: static PetscErrorCode EPSArnoldiSetDelayed_Arnoldi(EPS eps,PetscBool delayed)
184: {
185:   EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;

188:   arnoldi->delayed = delayed;
189:   return(0);
190: }

194: /*@
195:    EPSArnoldiSetDelayed - Activates or deactivates delayed reorthogonalization
196:    in the Arnoldi iteration.

198:    Logically Collective on EPS

200:    Input Parameters:
201: +  eps - the eigenproblem solver context
202: -  delayed - boolean flag

204:    Options Database Key:
205: .  -eps_arnoldi_delayed - Activates delayed reorthogonalization in Arnoldi

207:    Note:
208:    Delayed reorthogonalization is an aggressive optimization for the Arnoldi
209:    eigensolver than may provide better scalability, but sometimes makes the
210:    solver converge less than the default algorithm.

212:    Level: advanced

214: .seealso: EPSArnoldiGetDelayed()
215: @*/
216: PetscErrorCode EPSArnoldiSetDelayed(EPS eps,PetscBool delayed)
217: {

223:   PetscTryMethod(eps,"EPSArnoldiSetDelayed_C",(EPS,PetscBool),(eps,delayed));
224:   return(0);
225: }

229: static PetscErrorCode EPSArnoldiGetDelayed_Arnoldi(EPS eps,PetscBool *delayed)
230: {
231:   EPS_ARNOLDI *arnoldi = (EPS_ARNOLDI*)eps->data;

234:   *delayed = arnoldi->delayed;
235:   return(0);
236: }

240: /*@
241:    EPSArnoldiGetDelayed - Gets the type of reorthogonalization used during the Arnoldi
242:    iteration.

244:    Not Collective

246:    Input Parameter:
247: .  eps - the eigenproblem solver context

249:    Input Parameter:
250: .  delayed - boolean flag indicating if delayed reorthogonalization has been enabled

252:    Level: advanced

254: .seealso: EPSArnoldiSetDelayed()
255: @*/
256: PetscErrorCode EPSArnoldiGetDelayed(EPS eps,PetscBool *delayed)
257: {

263:   PetscUseMethod(eps,"EPSArnoldiGetDelayed_C",(EPS,PetscBool*),(eps,delayed));
264:   return(0);
265: }

269: PetscErrorCode EPSDestroy_Arnoldi(EPS eps)
270: {

274:   PetscFree(eps->data);
275:   PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiSetDelayed_C",NULL);
276:   PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiGetDelayed_C",NULL);
277:   return(0);
278: }

282: PetscErrorCode EPSView_Arnoldi(EPS eps,PetscViewer viewer)
283: {
285:   PetscBool      isascii;
286:   EPS_ARNOLDI    *arnoldi = (EPS_ARNOLDI*)eps->data;

289:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
290:   if (isascii) {
291:     if (arnoldi->delayed) {
292:       PetscViewerASCIIPrintf(viewer,"  Arnoldi: using delayed reorthogonalization\n");
293:     }
294:   }
295:   return(0);
296: }

300: PETSC_EXTERN PetscErrorCode EPSCreate_Arnoldi(EPS eps)
301: {
302:   EPS_ARNOLDI    *ctx;

306:   PetscNewLog(eps,&ctx);
307:   eps->data = (void*)ctx;

309:   eps->ops->setup                = EPSSetUp_Arnoldi;
310:   eps->ops->setfromoptions       = EPSSetFromOptions_Arnoldi;
311:   eps->ops->destroy              = EPSDestroy_Arnoldi;
312:   eps->ops->view                 = EPSView_Arnoldi;
313:   eps->ops->backtransform        = EPSBackTransform_Default;
314:   eps->ops->computevectors       = EPSComputeVectors_Schur;
315:   PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiSetDelayed_C",EPSArnoldiSetDelayed_Arnoldi);
316:   PetscObjectComposeFunction((PetscObject)eps,"EPSArnoldiGetDelayed_C",EPSArnoldiGetDelayed_Arnoldi);
317:   return(0);
318: }