Actual source code: power.c
slepc-3.19.0 2023-03-31
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: SLEPc eigensolver: "power"
13: Method: Power Iteration
15: Algorithm:
17: This solver implements the power iteration for finding dominant
18: eigenpairs. It also includes the following well-known methods:
19: - Inverse Iteration: when used in combination with shift-and-invert
20: spectral transformation.
21: - Rayleigh Quotient Iteration (RQI): also with shift-and-invert plus
22: a variable shift.
24: It can also be used for nonlinear inverse iteration on the problem
25: A(x)*x=lambda*B(x)*x, where A and B are not constant but depend on x.
27: References:
29: [1] "Single Vector Iteration Methods in SLEPc", SLEPc Technical Report
30: STR-2, available at https://slepc.upv.es.
31: */
33: #include <slepc/private/epsimpl.h>
34: #include <slepcblaslapack.h>
35: /* petsc headers */
36: #include <petscdm.h>
37: #include <petscsnes.h>
39: static PetscErrorCode EPSPowerFormFunction_Update(SNES,Vec,Vec,void*);
40: PetscErrorCode EPSSolve_Power(EPS);
41: PetscErrorCode EPSSolve_TS_Power(EPS);
43: typedef struct {
44: EPSPowerShiftType shift_type;
45: PetscBool nonlinear;
46: PetscBool update;
47: SNES snes;
48: PetscErrorCode (*formFunctionB)(SNES,Vec,Vec,void*);
49: void *formFunctionBctx;
50: PetscErrorCode (*formFunctionA)(SNES,Vec,Vec,void*);
51: void *formFunctionActx;
52: PetscErrorCode (*formFunctionAB)(SNES,Vec,Vec,Vec,void*);
53: PetscInt idx; /* index of the first nonzero entry in the iteration vector */
54: PetscMPIInt p; /* process id of the owner of idx */
55: PetscReal norm0; /* norm of initial vector */
56: } EPS_POWER;
58: static PetscErrorCode SNESMonitor_PowerUpdate(SNES snes,PetscInt its,PetscReal fnorm,void *ctx)
59: {
60: EPS eps;
62: PetscFunctionBegin;
63: PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
64: PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
65: /* Call EPS monitor on each SNES iteration */
66: PetscCall(EPSMonitor(eps,its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
67: PetscFunctionReturn(PETSC_SUCCESS);
68: }
70: PetscErrorCode EPSSetUp_Power(EPS eps)
71: {
72: EPS_POWER *power = (EPS_POWER*)eps->data;
73: STMatMode mode;
74: Mat A,B,P;
75: Vec res;
76: PetscContainer container;
77: PetscErrorCode (*formFunctionA)(SNES,Vec,Vec,void*);
78: PetscErrorCode (*formJacobianA)(SNES,Vec,Mat,Mat,void*);
79: void *ctx;
81: PetscFunctionBegin;
82: if (eps->ncv!=PETSC_DEFAULT) {
83: PetscCheck(eps->ncv>=eps->nev,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev");
84: } else eps->ncv = eps->nev;
85: if (eps->mpd!=PETSC_DEFAULT) PetscCall(PetscInfo(eps,"Warning: parameter mpd ignored\n"));
86: if (eps->max_it==PETSC_DEFAULT) {
87: /* SNES will directly return the solution for us, and we need to do only one iteration */
88: if (power->nonlinear && power->update) eps->max_it = 1;
89: else eps->max_it = PetscMax(1000*eps->nev,100*eps->n);
90: }
91: if (!eps->which) PetscCall(EPSSetWhichEigenpairs_Default(eps));
92: PetscCheck(eps->which==EPS_LARGEST_MAGNITUDE || eps->which==EPS_TARGET_MAGNITUDE,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only largest magnitude or target magnitude eigenvalues");
93: if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) {
94: PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Variable shifts not allowed in nonlinear problems");
95: EPSCheckSinvertCayleyCondition(eps,PETSC_TRUE," (with variable shifts)");
96: PetscCall(STGetMatMode(eps->st,&mode));
97: PetscCheck(mode!=ST_MATMODE_INPLACE,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"ST matrix mode inplace does not work with variable shifts");
98: }
99: EPSCheckUnsupported(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_CONVERGENCE);
100: EPSCheckIgnored(eps,EPS_FEATURE_EXTRACTION);
101: PetscCall(EPSAllocateSolution(eps,0));
102: PetscCall(EPS_SetInnerProduct(eps));
104: if (power->nonlinear) {
105: PetscCheck(eps->nev==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration cannot compute more than one eigenvalue");
106: PetscCall(EPSSetWorkVecs(eps,3));
107: PetscCheck(!power->update || eps->max_it==1,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"More than one iteration is not allowed for Newton eigensolver (SNES)");
109: /* Set up SNES solver */
110: /* If SNES was setup, we need to reset it so that it will be consistent with the current EPS */
111: if (power->snes) PetscCall(SNESReset(power->snes));
112: else PetscCall(EPSPowerGetSNES(eps,&power->snes));
114: /* For nonlinear solver (Newton), we should scale the initial vector back.
115: The initial vector will be scaled in EPSSetUp. */
116: if (eps->IS) PetscCall(VecNorm((eps->IS)[0],NORM_2,&power->norm0));
118: PetscCall(EPSGetOperators(eps,&A,&B));
120: PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunction",&formFunctionA));
121: PetscCheck(formFunctionA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formFunction' in matrix A");
122: PetscCall(PetscObjectQuery((PetscObject)A,"formFunctionCtx",(PetscObject*)&container));
123: if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
124: else ctx = NULL;
125: PetscCall(MatCreateVecs(A,&res,NULL));
126: power->formFunctionA = formFunctionA;
127: power->formFunctionActx = ctx;
128: if (power->update) {
129: PetscCall(SNESSetFunction(power->snes,res,EPSPowerFormFunction_Update,ctx));
130: PetscCall(PetscObjectQueryFunction((PetscObject)A,"formFunctionAB",&power->formFunctionAB));
131: PetscCall(SNESMonitorSet(power->snes,SNESMonitor_PowerUpdate,NULL,NULL));
132: }
133: else PetscCall(SNESSetFunction(power->snes,res,formFunctionA,ctx));
134: PetscCall(VecDestroy(&res));
136: PetscCall(PetscObjectQueryFunction((PetscObject)A,"formJacobian",&formJacobianA));
137: PetscCheck(formJacobianA,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER,"For nonlinear inverse iteration you must compose a callback function 'formJacobian' in matrix A");
138: PetscCall(PetscObjectQuery((PetscObject)A,"formJacobianCtx",(PetscObject*)&container));
139: if (container) PetscCall(PetscContainerGetPointer(container,&ctx));
140: else ctx = NULL;
141: /* This allows users to compute a different preconditioning matrix than A.
142: * It is useful when A and B are shell matrices.
143: */
144: PetscCall(STGetPreconditionerMat(eps->st,&P));
145: /* If users do not provide a matrix, we simply use A */
146: PetscCall(SNESSetJacobian(power->snes,A,P? P:A,formJacobianA,ctx));
147: PetscCall(SNESSetFromOptions(power->snes));
148: PetscCall(SNESSetUp(power->snes));
149: if (B) {
150: PetscCall(PetscObjectQueryFunction((PetscObject)B,"formFunction",&power->formFunctionB));
151: PetscCall(PetscObjectQuery((PetscObject)B,"formFunctionCtx",(PetscObject*)&container));
152: if (power->formFunctionB && container) PetscCall(PetscContainerGetPointer(container,&power->formFunctionBctx));
153: else power->formFunctionBctx = NULL;
154: }
155: } else {
156: if (eps->twosided) PetscCall(EPSSetWorkVecs(eps,3));
157: else PetscCall(EPSSetWorkVecs(eps,2));
158: PetscCall(DSSetType(eps->ds,DSNHEP));
159: PetscCall(DSAllocate(eps->ds,eps->nev));
160: }
161: /* dispatch solve method */
162: if (eps->twosided) {
163: PetscCheck(!power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Nonlinear inverse iteration does not have two-sided variant");
164: PetscCheck(power->shift_type!=EPS_POWER_SHIFT_WILKINSON,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"Two-sided variant does not support Wilkinson shifts");
165: eps->ops->solve = EPSSolve_TS_Power;
166: } else eps->ops->solve = EPSSolve_Power;
167: PetscFunctionReturn(PETSC_SUCCESS);
168: }
170: /*
171: Find the index of the first nonzero entry of x, and the process that owns it.
172: */
173: static PetscErrorCode FirstNonzeroIdx(Vec x,PetscInt *idx,PetscMPIInt *p)
174: {
175: PetscInt i,first,last,N;
176: PetscLayout map;
177: const PetscScalar *xx;
179: PetscFunctionBegin;
180: PetscCall(VecGetSize(x,&N));
181: PetscCall(VecGetOwnershipRange(x,&first,&last));
182: PetscCall(VecGetArrayRead(x,&xx));
183: for (i=first;i<last;i++) {
184: if (PetscAbsScalar(xx[i-first])>10*PETSC_MACHINE_EPSILON) break;
185: }
186: PetscCall(VecRestoreArrayRead(x,&xx));
187: if (i==last) i=N;
188: PetscCall(MPIU_Allreduce(&i,idx,1,MPIU_INT,MPI_MIN,PetscObjectComm((PetscObject)x)));
189: PetscCheck(*idx!=N,PetscObjectComm((PetscObject)x),PETSC_ERR_PLIB,"Zero vector found");
190: PetscCall(VecGetLayout(x,&map));
191: PetscCall(PetscLayoutFindOwner(map,*idx,p));
192: PetscFunctionReturn(PETSC_SUCCESS);
193: }
195: /*
196: Normalize a vector x with respect to a given norm as well as the
197: sign of the first nonzero entry (assumed to be idx in process p).
198: */
199: static PetscErrorCode Normalize(Vec x,PetscReal norm,PetscInt idx,PetscMPIInt p,PetscScalar *sign)
200: {
201: PetscScalar alpha=1.0;
202: PetscInt first,last;
203: PetscReal absv;
204: const PetscScalar *xx;
206: PetscFunctionBegin;
207: PetscCall(VecGetOwnershipRange(x,&first,&last));
208: if (idx>=first && idx<last) {
209: PetscCall(VecGetArrayRead(x,&xx));
210: absv = PetscAbsScalar(xx[idx-first]);
211: if (absv>10*PETSC_MACHINE_EPSILON) alpha = xx[idx-first]/absv;
212: PetscCall(VecRestoreArrayRead(x,&xx));
213: }
214: PetscCallMPI(MPI_Bcast(&alpha,1,MPIU_SCALAR,p,PetscObjectComm((PetscObject)x)));
215: if (sign) *sign = alpha;
216: alpha *= norm;
217: PetscCall(VecScale(x,1.0/alpha));
218: PetscFunctionReturn(PETSC_SUCCESS);
219: }
221: static PetscErrorCode EPSPowerUpdateFunctionB(EPS eps,Vec x,Vec Bx)
222: {
223: EPS_POWER *power = (EPS_POWER*)eps->data;
224: Mat B;
226: PetscFunctionBegin;
227: PetscCall(STResetMatrixState(eps->st));
228: PetscCall(EPSGetOperators(eps,NULL,&B));
229: if (B) {
230: if (power->formFunctionB) PetscCall((*power->formFunctionB)(power->snes,x,Bx,power->formFunctionBctx));
231: else PetscCall(MatMult(B,x,Bx));
232: } else PetscCall(VecCopy(x,Bx));
233: PetscFunctionReturn(PETSC_SUCCESS);
234: }
236: static PetscErrorCode EPSPowerUpdateFunctionA(EPS eps,Vec x,Vec Ax)
237: {
238: EPS_POWER *power = (EPS_POWER*)eps->data;
239: Mat A;
241: PetscFunctionBegin;
242: PetscCall(STResetMatrixState(eps->st));
243: PetscCall(EPSGetOperators(eps,&A,NULL));
244: PetscCheck(A,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_NULL,"Matrix A is required for an eigenvalue problem");
245: if (power->formFunctionA) PetscCall((*power->formFunctionA)(power->snes,x,Ax,power->formFunctionActx));
246: else PetscCall(MatMult(A,x,Ax));
247: PetscFunctionReturn(PETSC_SUCCESS);
248: }
250: static PetscErrorCode EPSPowerFormFunction_Update(SNES snes,Vec x,Vec y,void *ctx)
251: {
252: EPS eps;
253: PetscReal bx;
254: Vec Bx;
255: PetscScalar sign;
256: EPS_POWER *power;
258: PetscFunctionBegin;
259: PetscCall(PetscObjectQuery((PetscObject)snes,"eps",(PetscObject *)&eps));
260: PetscCheck(eps,PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_NULL,"No composed EPS");
261: PetscCall(STResetMatrixState(eps->st));
262: power = (EPS_POWER*)eps->data;
263: Bx = eps->work[2];
264: if (power->formFunctionAB) PetscCall((*power->formFunctionAB)(snes,x,y,Bx,ctx));
265: else {
266: PetscCall(EPSPowerUpdateFunctionA(eps,x,y));
267: PetscCall(EPSPowerUpdateFunctionB(eps,x,Bx));
268: }
269: PetscCall(VecNorm(Bx,NORM_2,&bx));
270: PetscCall(Normalize(Bx,bx,power->idx,power->p,&sign));
271: PetscCall(VecAXPY(y,-1.0,Bx));
272: /* Keep tracking eigenvalue update. It would be useful when we want to monitor solver progress via snes monitor. */
273: eps->eigr[(eps->nconv < eps->nev)? eps->nconv:(eps->nconv-1)] = 1.0/(bx*sign);
274: PetscFunctionReturn(PETSC_SUCCESS);
275: }
277: /*
278: Use SNES to compute y = A^{-1}*B*x for the nonlinear problem
279: */
280: static PetscErrorCode EPSPowerApply_SNES(EPS eps,Vec x,Vec y)
281: {
282: EPS_POWER *power = (EPS_POWER*)eps->data;
283: Vec Bx;
285: PetscFunctionBegin;
286: PetscCall(VecCopy(x,y));
287: if (power->update) PetscCall(SNESSolve(power->snes,NULL,y));
288: else {
289: Bx = eps->work[2];
290: PetscCall(SNESSolve(power->snes,Bx,y));
291: }
292: PetscFunctionReturn(PETSC_SUCCESS);
293: }
295: /*
296: Use nonlinear inverse power to compute an initial guess
297: */
298: static PetscErrorCode EPSPowerComputeInitialGuess_Update(EPS eps)
299: {
300: EPS powereps;
301: Mat A,B,P;
302: Vec v1,v2;
303: SNES snes;
304: DM dm,newdm;
306: PetscFunctionBegin;
307: PetscCall(EPSCreate(PetscObjectComm((PetscObject)eps),&powereps));
308: PetscCall(EPSGetOperators(eps,&A,&B));
309: PetscCall(EPSSetType(powereps,EPSPOWER));
310: PetscCall(EPSSetOperators(powereps,A,B));
311: PetscCall(EPSSetTolerances(powereps,1e-6,4));
312: PetscCall(EPSSetOptionsPrefix(powereps,((PetscObject)eps)->prefix));
313: PetscCall(EPSAppendOptionsPrefix(powereps,"init_"));
314: PetscCall(EPSSetProblemType(powereps,EPS_GNHEP));
315: PetscCall(EPSSetWhichEigenpairs(powereps,EPS_TARGET_MAGNITUDE));
316: PetscCall(EPSPowerSetNonlinear(powereps,PETSC_TRUE));
317: PetscCall(STGetPreconditionerMat(eps->st,&P));
318: /* attach dm to initial solve */
319: PetscCall(EPSPowerGetSNES(eps,&snes));
320: PetscCall(SNESGetDM(snes,&dm));
321: /* use dmshell to temporarily store snes context */
322: PetscCall(DMCreate(PetscObjectComm((PetscObject)eps),&newdm));
323: PetscCall(DMSetType(newdm,DMSHELL));
324: PetscCall(DMSetUp(newdm));
325: PetscCall(DMCopyDMSNES(dm,newdm));
326: PetscCall(EPSPowerGetSNES(powereps,&snes));
327: PetscCall(SNESSetDM(snes,dm));
328: PetscCall(EPSSetFromOptions(powereps));
329: if (P) PetscCall(STSetPreconditionerMat(powereps->st,P));
330: PetscCall(EPSSolve(powereps));
331: PetscCall(BVGetColumn(eps->V,0,&v2));
332: PetscCall(BVGetColumn(powereps->V,0,&v1));
333: PetscCall(VecCopy(v1,v2));
334: PetscCall(BVRestoreColumn(powereps->V,0,&v1));
335: PetscCall(BVRestoreColumn(eps->V,0,&v2));
336: PetscCall(EPSDestroy(&powereps));
337: /* restore context back to the old nonlinear solver */
338: PetscCall(DMCopyDMSNES(newdm,dm));
339: PetscCall(DMDestroy(&newdm));
340: PetscFunctionReturn(PETSC_SUCCESS);
341: }
343: PetscErrorCode EPSSolve_Power(EPS eps)
344: {
345: EPS_POWER *power = (EPS_POWER*)eps->data;
346: PetscInt k,ld;
347: Vec v,y,e,Bx;
348: Mat A;
349: KSP ksp;
350: PetscReal relerr,norm,norm1,rt1,rt2,cs1;
351: PetscScalar theta,rho,delta,sigma,alpha2,beta1,sn1,*T,sign;
352: PetscBool breakdown;
353: KSPConvergedReason reason;
354: SNESConvergedReason snesreason;
356: PetscFunctionBegin;
357: e = eps->work[0];
358: y = eps->work[1];
359: if (power->nonlinear) Bx = eps->work[2];
360: else Bx = NULL;
362: if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
363: if (power->nonlinear) {
364: PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",(PetscObject)eps));
365: /* Compute an initial guess only when users do not provide one */
366: if (power->update && !eps->nini) PetscCall(EPSPowerComputeInitialGuess_Update(eps));
367: } else PetscCall(DSGetLeadingDimension(eps->ds,&ld));
368: if (!power->update) PetscCall(EPSGetStartVector(eps,0,NULL));
369: if (power->nonlinear) {
370: PetscCall(BVGetColumn(eps->V,0,&v));
371: if (eps->nini) {
372: /* We scale the initial vector back if the initial vector was provided by users */
373: PetscCall(VecScale(v,power->norm0));
374: }
375: PetscCall(EPSPowerUpdateFunctionB(eps,v,Bx));
376: PetscCall(VecNorm(Bx,NORM_2,&norm));
377: PetscCall(FirstNonzeroIdx(Bx,&power->idx,&power->p));
378: PetscCall(Normalize(Bx,norm,power->idx,power->p,NULL));
379: PetscCall(BVRestoreColumn(eps->V,0,&v));
380: }
382: PetscCall(STGetShift(eps->st,&sigma)); /* original shift */
383: rho = sigma;
385: while (eps->reason == EPS_CONVERGED_ITERATING) {
386: eps->its++;
387: k = eps->nconv;
389: /* y = OP v */
390: PetscCall(BVGetColumn(eps->V,k,&v));
391: if (power->nonlinear) PetscCall(EPSPowerApply_SNES(eps,v,y));
392: else PetscCall(STApply(eps->st,v,y));
393: PetscCall(BVRestoreColumn(eps->V,k,&v));
395: /* purge previously converged eigenvectors */
396: if (PetscUnlikely(power->nonlinear)) {
397: /* We do not need to call this for Newton eigensolver since eigenvalue is
398: * updated in function evaluations.
399: */
400: if (!power->update) {
401: PetscCall(EPSPowerUpdateFunctionB(eps,y,Bx));
402: PetscCall(VecNorm(Bx,NORM_2,&norm));
403: PetscCall(Normalize(Bx,norm,power->idx,power->p,&sign));
404: }
405: } else {
406: PetscCall(DSGetArray(eps->ds,DS_MAT_A,&T));
407: PetscCall(BVSetActiveColumns(eps->V,0,k));
408: PetscCall(BVOrthogonalizeVec(eps->V,y,T+k*ld,&norm,NULL));
409: }
411: /* theta = (v,y)_B */
412: PetscCall(BVSetActiveColumns(eps->V,k,k+1));
413: PetscCall(BVDotVec(eps->V,y,&theta));
414: if (!power->nonlinear) {
415: T[k+k*ld] = theta;
416: PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&T));
417: }
419: /* Eigenvalue is already stored in function evaluations.
420: * Assign eigenvalue to theta to make the rest of the code consistent
421: */
422: if (power->update) theta = eps->eigr[eps->nconv];
423: else if (power->nonlinear) theta = 1.0/norm*sign; /* Eigenvalue: 1/|Bx| */
425: if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
427: /* approximate eigenvalue is the Rayleigh quotient */
428: eps->eigr[eps->nconv] = theta;
430: /**
431: * If the Newton method (update, SNES) is used, we do not compute "relerr"
432: * since SNES determines the convergence.
433: */
434: if (PetscUnlikely(power->update)) relerr = 0.;
435: else {
436: /* compute relative error as ||y-theta v||_2/|theta| */
437: PetscCall(VecCopy(y,e));
438: PetscCall(BVGetColumn(eps->V,k,&v));
439: PetscCall(VecAXPY(e,power->nonlinear?-1.0:-theta,v));
440: PetscCall(BVRestoreColumn(eps->V,k,&v));
441: PetscCall(VecNorm(e,NORM_2,&relerr));
442: if (PetscUnlikely(power->nonlinear)) relerr *= PetscAbsScalar(theta);
443: else relerr /= PetscAbsScalar(theta);
444: }
446: } else { /* RQI */
448: /* delta = ||y||_B */
449: delta = norm;
451: /* compute relative error */
452: if (rho == 0.0) relerr = PETSC_MAX_REAL;
453: else relerr = 1.0 / (norm*PetscAbsScalar(rho));
455: /* approximate eigenvalue is the shift */
456: eps->eigr[eps->nconv] = rho;
458: /* compute new shift */
459: if (relerr<eps->tol) {
460: rho = sigma; /* if converged, restore original shift */
461: PetscCall(STSetShift(eps->st,rho));
462: } else {
463: rho = rho + PetscConj(theta)/(delta*delta); /* Rayleigh quotient R(v) */
464: if (power->shift_type == EPS_POWER_SHIFT_WILKINSON) {
465: /* beta1 is the norm of the residual associated with R(v) */
466: PetscCall(BVGetColumn(eps->V,k,&v));
467: PetscCall(VecAXPY(v,-PetscConj(theta)/(delta*delta),y));
468: PetscCall(BVRestoreColumn(eps->V,k,&v));
469: PetscCall(BVScaleColumn(eps->V,k,1.0/delta));
470: PetscCall(BVNormColumn(eps->V,k,NORM_2,&norm1));
471: beta1 = norm1;
473: /* alpha2 = (e'*A*e)/(beta1*beta1), where e is the residual */
474: PetscCall(STGetMatrix(eps->st,0,&A));
475: PetscCall(BVGetColumn(eps->V,k,&v));
476: PetscCall(MatMult(A,v,e));
477: PetscCall(VecDot(v,e,&alpha2));
478: PetscCall(BVRestoreColumn(eps->V,k,&v));
479: alpha2 = alpha2 / (beta1 * beta1);
481: /* choose the eigenvalue of [rho beta1; beta1 alpha2] closest to rho */
482: PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
483: PetscCallBLAS("LAPACKlaev2",LAPACKlaev2_(&rho,&beta1,&alpha2,&rt1,&rt2,&cs1,&sn1));
484: PetscCall(PetscFPTrapPop());
485: if (PetscAbsScalar(rt1-rho) < PetscAbsScalar(rt2-rho)) rho = rt1;
486: else rho = rt2;
487: }
488: /* update operator according to new shift */
489: PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
490: PetscCall(STSetShift(eps->st,rho));
491: PetscCall(KSPGetConvergedReason(ksp,&reason));
492: if (reason) {
493: PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
494: rho *= 1+10*PETSC_MACHINE_EPSILON;
495: PetscCall(STSetShift(eps->st,rho));
496: PetscCall(KSPGetConvergedReason(ksp,&reason));
497: PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
498: }
499: PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
500: }
501: }
502: eps->errest[eps->nconv] = relerr;
504: /* normalize */
505: if (!power->nonlinear) PetscCall(Normalize(y,norm,power->idx,power->p,NULL));
506: PetscCall(BVInsertVec(eps->V,k,y));
508: if (PetscUnlikely(power->update)) {
509: PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
510: /* For Newton eigensolver, we are ready to return once SNES converged. */
511: if (snesreason>0) eps->nconv = 1;
512: } else if (PetscUnlikely(relerr<eps->tol)) { /* accept eigenpair */
513: eps->nconv = eps->nconv + 1;
514: if (eps->nconv<eps->nev) {
515: PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
516: if (breakdown) {
517: eps->reason = EPS_DIVERGED_BREAKDOWN;
518: PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
519: break;
520: }
521: }
522: }
523: /* For Newton eigensolver, monitor will be called from SNES monitor */
524: if (!power->update) PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
525: PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
527: /**
528: * When a customized stopping test is used, and reason can be set to be converged (EPS_CONVERGED_USER).
529: * In this case, we need to increase eps->nconv to "1" so users can retrieve the solution.
530: */
531: if (PetscUnlikely(power->nonlinear && eps->reason>0)) eps->nconv = 1;
532: }
534: if (power->nonlinear) PetscCall(PetscObjectCompose((PetscObject)power->snes,"eps",NULL));
535: else {
536: PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
537: PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
538: }
539: PetscFunctionReturn(PETSC_SUCCESS);
540: }
542: PetscErrorCode EPSSolve_TS_Power(EPS eps)
543: {
544: EPS_POWER *power = (EPS_POWER*)eps->data;
545: PetscInt k,ld;
546: Vec v,w,y,e,z;
547: KSP ksp;
548: PetscReal relerr=1.0,relerrl,delta;
549: PetscScalar theta,rho,alpha,sigma;
550: PetscBool breakdown,breakdownl;
551: KSPConvergedReason reason;
553: PetscFunctionBegin;
554: e = eps->work[0];
555: v = eps->work[1];
556: w = eps->work[2];
558: if (power->shift_type != EPS_POWER_SHIFT_CONSTANT) PetscCall(STGetKSP(eps->st,&ksp));
559: PetscCall(DSGetLeadingDimension(eps->ds,&ld));
560: PetscCall(EPSGetStartVector(eps,0,NULL));
561: PetscCall(EPSGetLeftStartVector(eps,0,NULL));
562: PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,0,NULL));
563: PetscCall(BVCopyVec(eps->V,0,v));
564: PetscCall(BVCopyVec(eps->W,0,w));
565: PetscCall(STGetShift(eps->st,&sigma)); /* original shift */
566: rho = sigma;
568: while (eps->reason == EPS_CONVERGED_ITERATING) {
569: eps->its++;
570: k = eps->nconv;
572: /* y = OP v, z = OP' w */
573: PetscCall(BVGetColumn(eps->V,k,&y));
574: PetscCall(STApply(eps->st,v,y));
575: PetscCall(BVRestoreColumn(eps->V,k,&y));
576: PetscCall(BVGetColumn(eps->W,k,&z));
577: PetscCall(STApplyHermitianTranspose(eps->st,w,z));
578: PetscCall(BVRestoreColumn(eps->W,k,&z));
580: /* purge previously converged eigenvectors */
581: PetscCall(BVBiorthogonalizeColumn(eps->V,eps->W,k));
583: /* theta = (w,y)_B */
584: PetscCall(BVSetActiveColumns(eps->V,k,k+1));
585: PetscCall(BVDotVec(eps->V,w,&theta));
586: theta = PetscConj(theta);
588: if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) { /* direct & inverse iteration */
590: /* approximate eigenvalue is the Rayleigh quotient */
591: eps->eigr[eps->nconv] = theta;
593: /* compute relative errors as ||y-theta v||_2/|theta| and ||z-conj(theta) w||_2/|theta|*/
594: PetscCall(BVCopyVec(eps->V,k,e));
595: PetscCall(VecAXPY(e,-theta,v));
596: PetscCall(VecNorm(e,NORM_2,&relerr));
597: PetscCall(BVCopyVec(eps->W,k,e));
598: PetscCall(VecAXPY(e,-PetscConj(theta),w));
599: PetscCall(VecNorm(e,NORM_2,&relerrl));
600: relerr = PetscMax(relerr,relerrl)/PetscAbsScalar(theta);
601: }
603: /* normalize */
604: PetscCall(BVSetActiveColumns(eps->V,k,k+1));
605: PetscCall(BVGetColumn(eps->W,k,&z));
606: PetscCall(BVDotVec(eps->V,z,&alpha));
607: PetscCall(BVRestoreColumn(eps->W,k,&z));
608: delta = PetscSqrtReal(PetscAbsScalar(alpha));
609: PetscCheck(delta!=0.0,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Breakdown in two-sided Power/RQI");
610: PetscCall(BVScaleColumn(eps->V,k,1.0/PetscConj(alpha/delta)));
611: PetscCall(BVScaleColumn(eps->W,k,1.0/delta));
612: PetscCall(BVCopyVec(eps->V,k,v));
613: PetscCall(BVCopyVec(eps->W,k,w));
615: if (power->shift_type == EPS_POWER_SHIFT_RAYLEIGH) { /* RQI */
617: /* compute relative error */
618: if (rho == 0.0) relerr = PETSC_MAX_REAL;
619: else relerr = 1.0 / PetscAbsScalar(delta*rho);
621: /* approximate eigenvalue is the shift */
622: eps->eigr[eps->nconv] = rho;
624: /* compute new shift */
625: if (relerr<eps->tol) {
626: rho = sigma; /* if converged, restore original shift */
627: PetscCall(STSetShift(eps->st,rho));
628: } else {
629: rho = rho + PetscConj(theta)/(delta*delta); /* Rayleigh quotient R(v) */
630: /* update operator according to new shift */
631: PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_FALSE));
632: PetscCall(STSetShift(eps->st,rho));
633: PetscCall(KSPGetConvergedReason(ksp,&reason));
634: if (reason) {
635: PetscCall(PetscInfo(eps,"Factorization failed, repeat with a perturbed shift\n"));
636: rho *= 1+10*PETSC_MACHINE_EPSILON;
637: PetscCall(STSetShift(eps->st,rho));
638: PetscCall(KSPGetConvergedReason(ksp,&reason));
639: PetscCheck(!reason,PetscObjectComm((PetscObject)ksp),PETSC_ERR_CONV_FAILED,"Second factorization failed");
640: }
641: PetscCall(KSPSetErrorIfNotConverged(ksp,PETSC_TRUE));
642: }
643: }
644: eps->errest[eps->nconv] = relerr;
646: /* if relerr<tol, accept eigenpair */
647: if (relerr<eps->tol) {
648: eps->nconv = eps->nconv + 1;
649: if (eps->nconv<eps->nev) {
650: PetscCall(EPSGetStartVector(eps,eps->nconv,&breakdown));
651: PetscCall(EPSGetLeftStartVector(eps,eps->nconv,&breakdownl));
652: if (breakdown || breakdownl) {
653: eps->reason = EPS_DIVERGED_BREAKDOWN;
654: PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
655: break;
656: }
657: PetscCall(BVBiorthonormalizeColumn(eps->V,eps->W,eps->nconv,NULL));
658: }
659: }
660: PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,PetscMin(eps->nconv+1,eps->nev)));
661: PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
662: }
664: PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
665: PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
666: PetscFunctionReturn(PETSC_SUCCESS);
667: }
669: PetscErrorCode EPSStopping_Power(EPS eps,PetscInt its,PetscInt max_it,PetscInt nconv,PetscInt nev,EPSConvergedReason *reason,void *ctx)
670: {
671: EPS_POWER *power = (EPS_POWER*)eps->data;
672: SNESConvergedReason snesreason;
674: PetscFunctionBegin;
675: if (PetscUnlikely(power->update)) {
676: PetscCall(SNESGetConvergedReason(power->snes,&snesreason));
677: if (snesreason < 0) {
678: *reason = EPS_DIVERGED_BREAKDOWN;
679: PetscFunctionReturn(PETSC_SUCCESS);
680: }
681: }
682: PetscCall(EPSStoppingBasic(eps,its,max_it,nconv,nev,reason,ctx));
683: PetscFunctionReturn(PETSC_SUCCESS);
684: }
686: PetscErrorCode EPSBackTransform_Power(EPS eps)
687: {
688: EPS_POWER *power = (EPS_POWER*)eps->data;
690: PetscFunctionBegin;
691: if (power->nonlinear) eps->eigr[0] = 1.0/eps->eigr[0];
692: else if (power->shift_type == EPS_POWER_SHIFT_CONSTANT) PetscCall(EPSBackTransform_Default(eps));
693: PetscFunctionReturn(PETSC_SUCCESS);
694: }
696: PetscErrorCode EPSSetFromOptions_Power(EPS eps,PetscOptionItems *PetscOptionsObject)
697: {
698: EPS_POWER *power = (EPS_POWER*)eps->data;
699: PetscBool flg,val;
700: EPSPowerShiftType shift;
702: PetscFunctionBegin;
703: PetscOptionsHeadBegin(PetscOptionsObject,"EPS Power Options");
705: PetscCall(PetscOptionsEnum("-eps_power_shift_type","Shift type","EPSPowerSetShiftType",EPSPowerShiftTypes,(PetscEnum)power->shift_type,(PetscEnum*)&shift,&flg));
706: if (flg) PetscCall(EPSPowerSetShiftType(eps,shift));
708: PetscCall(PetscOptionsBool("-eps_power_nonlinear","Use nonlinear inverse iteration","EPSPowerSetNonlinear",power->nonlinear,&val,&flg));
709: if (flg) PetscCall(EPSPowerSetNonlinear(eps,val));
711: PetscCall(PetscOptionsBool("-eps_power_update","Update residual monolithically","EPSPowerSetUpdate",power->update,&val,&flg));
712: if (flg) PetscCall(EPSPowerSetUpdate(eps,val));
714: PetscOptionsHeadEnd();
715: PetscFunctionReturn(PETSC_SUCCESS);
716: }
718: static PetscErrorCode EPSPowerSetShiftType_Power(EPS eps,EPSPowerShiftType shift)
719: {
720: EPS_POWER *power = (EPS_POWER*)eps->data;
722: PetscFunctionBegin;
723: switch (shift) {
724: case EPS_POWER_SHIFT_CONSTANT:
725: case EPS_POWER_SHIFT_RAYLEIGH:
726: case EPS_POWER_SHIFT_WILKINSON:
727: if (power->shift_type != shift) {
728: power->shift_type = shift;
729: eps->state = EPS_STATE_INITIAL;
730: }
731: break;
732: default:
733: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid shift type");
734: }
735: PetscFunctionReturn(PETSC_SUCCESS);
736: }
738: /*@
739: EPSPowerSetShiftType - Sets the type of shifts used during the power
740: iteration. This can be used to emulate the Rayleigh Quotient Iteration
741: (RQI) method.
743: Logically Collective
745: Input Parameters:
746: + eps - the eigenproblem solver context
747: - shift - the type of shift
749: Options Database Key:
750: . -eps_power_shift_type - Sets the shift type (either 'constant' or
751: 'rayleigh' or 'wilkinson')
753: Notes:
754: By default, shifts are constant (EPS_POWER_SHIFT_CONSTANT) and the iteration
755: is the simple power method (or inverse iteration if a shift-and-invert
756: transformation is being used).
758: A variable shift can be specified (EPS_POWER_SHIFT_RAYLEIGH or
759: EPS_POWER_SHIFT_WILKINSON). In this case, the iteration behaves rather like
760: a cubic converging method such as RQI.
762: Level: advanced
764: .seealso: EPSPowerGetShiftType(), STSetShift(), EPSPowerShiftType
765: @*/
766: PetscErrorCode EPSPowerSetShiftType(EPS eps,EPSPowerShiftType shift)
767: {
768: PetscFunctionBegin;
771: PetscTryMethod(eps,"EPSPowerSetShiftType_C",(EPS,EPSPowerShiftType),(eps,shift));
772: PetscFunctionReturn(PETSC_SUCCESS);
773: }
775: static PetscErrorCode EPSPowerGetShiftType_Power(EPS eps,EPSPowerShiftType *shift)
776: {
777: EPS_POWER *power = (EPS_POWER*)eps->data;
779: PetscFunctionBegin;
780: *shift = power->shift_type;
781: PetscFunctionReturn(PETSC_SUCCESS);
782: }
784: /*@
785: EPSPowerGetShiftType - Gets the type of shifts used during the power
786: iteration.
788: Not Collective
790: Input Parameter:
791: . eps - the eigenproblem solver context
793: Output Parameter:
794: . shift - the type of shift
796: Level: advanced
798: .seealso: EPSPowerSetShiftType(), EPSPowerShiftType
799: @*/
800: PetscErrorCode EPSPowerGetShiftType(EPS eps,EPSPowerShiftType *shift)
801: {
802: PetscFunctionBegin;
805: PetscUseMethod(eps,"EPSPowerGetShiftType_C",(EPS,EPSPowerShiftType*),(eps,shift));
806: PetscFunctionReturn(PETSC_SUCCESS);
807: }
809: static PetscErrorCode EPSPowerSetNonlinear_Power(EPS eps,PetscBool nonlinear)
810: {
811: EPS_POWER *power = (EPS_POWER*)eps->data;
813: PetscFunctionBegin;
814: if (power->nonlinear != nonlinear) {
815: power->nonlinear = nonlinear;
816: eps->useds = PetscNot(nonlinear);
817: eps->ops->setupsort = nonlinear? NULL: EPSSetUpSort_Default;
818: eps->state = EPS_STATE_INITIAL;
819: }
820: PetscFunctionReturn(PETSC_SUCCESS);
821: }
823: /*@
824: EPSPowerSetNonlinear - Sets a flag to indicate that the problem is nonlinear.
826: Logically Collective
828: Input Parameters:
829: + eps - the eigenproblem solver context
830: - nonlinear - whether the problem is nonlinear or not
832: Options Database Key:
833: . -eps_power_nonlinear - Sets the nonlinear flag
835: Notes:
836: If this flag is set, the solver assumes that the problem is nonlinear,
837: that is, the operators that define the eigenproblem are not constant
838: matrices, but depend on the eigenvector, A(x)*x=lambda*B(x)*x. This is
839: different from the case of nonlinearity with respect to the eigenvalue
840: (use the NEP solver class for this kind of problems).
842: The way in which nonlinear operators are specified is very similar to
843: the case of PETSc's SNES solver. The difference is that the callback
844: functions are provided via composed functions "formFunction" and
845: "formJacobian" in each of the matrix objects passed as arguments of
846: EPSSetOperators(). The application context required for these functions
847: can be attached via a composed PetscContainer.
849: Level: advanced
851: .seealso: EPSPowerGetNonlinear(), EPSSetOperators()
852: @*/
853: PetscErrorCode EPSPowerSetNonlinear(EPS eps,PetscBool nonlinear)
854: {
855: PetscFunctionBegin;
858: PetscTryMethod(eps,"EPSPowerSetNonlinear_C",(EPS,PetscBool),(eps,nonlinear));
859: PetscFunctionReturn(PETSC_SUCCESS);
860: }
862: static PetscErrorCode EPSPowerGetNonlinear_Power(EPS eps,PetscBool *nonlinear)
863: {
864: EPS_POWER *power = (EPS_POWER*)eps->data;
866: PetscFunctionBegin;
867: *nonlinear = power->nonlinear;
868: PetscFunctionReturn(PETSC_SUCCESS);
869: }
871: /*@
872: EPSPowerGetNonlinear - Returns a flag indicating if the problem is nonlinear.
874: Not Collective
876: Input Parameter:
877: . eps - the eigenproblem solver context
879: Output Parameter:
880: . nonlinear - the nonlinear flag
882: Level: advanced
884: .seealso: EPSPowerSetUpdate(), EPSPowerSetNonlinear()
885: @*/
886: PetscErrorCode EPSPowerGetNonlinear(EPS eps,PetscBool *nonlinear)
887: {
888: PetscFunctionBegin;
891: PetscUseMethod(eps,"EPSPowerGetNonlinear_C",(EPS,PetscBool*),(eps,nonlinear));
892: PetscFunctionReturn(PETSC_SUCCESS);
893: }
895: static PetscErrorCode EPSPowerSetUpdate_Power(EPS eps,PetscBool update)
896: {
897: EPS_POWER *power = (EPS_POWER*)eps->data;
899: PetscFunctionBegin;
900: PetscCheck(power->nonlinear,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_INCOMP,"This option does not make sense for linear problems");
901: power->update = update;
902: eps->state = EPS_STATE_INITIAL;
903: PetscFunctionReturn(PETSC_SUCCESS);
904: }
906: /*@
907: EPSPowerSetUpdate - Sets a flag to indicate that the residual is updated monolithically
908: for nonlinear problems. This potentially has a better convergence.
910: Logically Collective
912: Input Parameters:
913: + eps - the eigenproblem solver context
914: - update - whether the residual is updated monolithically or not
916: Options Database Key:
917: . -eps_power_update - Sets the update flag
919: Level: advanced
921: .seealso: EPSPowerGetUpdate(), EPSPowerGetNonlinear(), EPSSetOperators()
922: @*/
923: PetscErrorCode EPSPowerSetUpdate(EPS eps,PetscBool update)
924: {
925: PetscFunctionBegin;
928: PetscTryMethod(eps,"EPSPowerSetUpdate_C",(EPS,PetscBool),(eps,update));
929: PetscFunctionReturn(PETSC_SUCCESS);
930: }
932: static PetscErrorCode EPSPowerGetUpdate_Power(EPS eps,PetscBool *update)
933: {
934: EPS_POWER *power = (EPS_POWER*)eps->data;
936: PetscFunctionBegin;
937: *update = power->update;
938: PetscFunctionReturn(PETSC_SUCCESS);
939: }
941: /*@
942: EPSPowerGetUpdate - Returns a flag indicating if the residual is updated monolithically
943: for nonlinear problems.
945: Not Collective
947: Input Parameter:
948: . eps - the eigenproblem solver context
950: Output Parameter:
951: . update - the update flag
953: Level: advanced
955: .seealso: EPSPowerSetUpdate(), EPSPowerSetNonlinear()
956: @*/
957: PetscErrorCode EPSPowerGetUpdate(EPS eps,PetscBool *update)
958: {
959: PetscFunctionBegin;
962: PetscUseMethod(eps,"EPSPowerGetUpdate_C",(EPS,PetscBool*),(eps,update));
963: PetscFunctionReturn(PETSC_SUCCESS);
964: }
966: static PetscErrorCode EPSPowerSetSNES_Power(EPS eps,SNES snes)
967: {
968: EPS_POWER *power = (EPS_POWER*)eps->data;
970: PetscFunctionBegin;
971: PetscCall(PetscObjectReference((PetscObject)snes));
972: PetscCall(SNESDestroy(&power->snes));
973: power->snes = snes;
974: eps->state = EPS_STATE_INITIAL;
975: PetscFunctionReturn(PETSC_SUCCESS);
976: }
978: /*@
979: EPSPowerSetSNES - Associate a nonlinear solver object (SNES) to the
980: eigenvalue solver (to be used in nonlinear inverse iteration).
982: Collective
984: Input Parameters:
985: + eps - the eigenvalue solver
986: - snes - the nonlinear solver object
988: Level: advanced
990: .seealso: EPSPowerGetSNES()
991: @*/
992: PetscErrorCode EPSPowerSetSNES(EPS eps,SNES snes)
993: {
994: PetscFunctionBegin;
997: PetscCheckSameComm(eps,1,snes,2);
998: PetscTryMethod(eps,"EPSPowerSetSNES_C",(EPS,SNES),(eps,snes));
999: PetscFunctionReturn(PETSC_SUCCESS);
1000: }
1002: static PetscErrorCode EPSPowerGetSNES_Power(EPS eps,SNES *snes)
1003: {
1004: EPS_POWER *power = (EPS_POWER*)eps->data;
1006: PetscFunctionBegin;
1007: if (!power->snes) {
1008: PetscCall(SNESCreate(PetscObjectComm((PetscObject)eps),&power->snes));
1009: PetscCall(PetscObjectIncrementTabLevel((PetscObject)power->snes,(PetscObject)eps,1));
1010: PetscCall(SNESSetOptionsPrefix(power->snes,((PetscObject)eps)->prefix));
1011: PetscCall(SNESAppendOptionsPrefix(power->snes,"eps_power_"));
1012: PetscCall(PetscObjectSetOptions((PetscObject)power->snes,((PetscObject)eps)->options));
1013: }
1014: *snes = power->snes;
1015: PetscFunctionReturn(PETSC_SUCCESS);
1016: }
1018: /*@
1019: EPSPowerGetSNES - Retrieve the nonlinear solver object (SNES) associated
1020: with the eigenvalue solver.
1022: Not Collective
1024: Input Parameter:
1025: . eps - the eigenvalue solver
1027: Output Parameter:
1028: . snes - the nonlinear solver object
1030: Level: advanced
1032: .seealso: EPSPowerSetSNES()
1033: @*/
1034: PetscErrorCode EPSPowerGetSNES(EPS eps,SNES *snes)
1035: {
1036: PetscFunctionBegin;
1039: PetscUseMethod(eps,"EPSPowerGetSNES_C",(EPS,SNES*),(eps,snes));
1040: PetscFunctionReturn(PETSC_SUCCESS);
1041: }
1043: PetscErrorCode EPSReset_Power(EPS eps)
1044: {
1045: EPS_POWER *power = (EPS_POWER*)eps->data;
1047: PetscFunctionBegin;
1048: if (power->snes) PetscCall(SNESReset(power->snes));
1049: PetscFunctionReturn(PETSC_SUCCESS);
1050: }
1052: PetscErrorCode EPSDestroy_Power(EPS eps)
1053: {
1054: EPS_POWER *power = (EPS_POWER*)eps->data;
1056: PetscFunctionBegin;
1057: if (power->nonlinear) PetscCall(SNESDestroy(&power->snes));
1058: PetscCall(PetscFree(eps->data));
1059: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",NULL));
1060: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",NULL));
1061: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",NULL));
1062: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",NULL));
1063: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",NULL));
1064: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",NULL));
1065: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",NULL));
1066: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",NULL));
1067: PetscFunctionReturn(PETSC_SUCCESS);
1068: }
1070: PetscErrorCode EPSView_Power(EPS eps,PetscViewer viewer)
1071: {
1072: EPS_POWER *power = (EPS_POWER*)eps->data;
1073: PetscBool isascii;
1075: PetscFunctionBegin;
1076: PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
1077: if (isascii) {
1078: if (power->nonlinear) {
1079: PetscCall(PetscViewerASCIIPrintf(viewer," using nonlinear inverse iteration\n"));
1080: if (power->update) PetscCall(PetscViewerASCIIPrintf(viewer," updating the residual monolithically\n"));
1081: if (!power->snes) PetscCall(EPSPowerGetSNES(eps,&power->snes));
1082: PetscCall(PetscViewerASCIIPushTab(viewer));
1083: PetscCall(SNESView(power->snes,viewer));
1084: PetscCall(PetscViewerASCIIPopTab(viewer));
1085: } else PetscCall(PetscViewerASCIIPrintf(viewer," %s shifts\n",EPSPowerShiftTypes[power->shift_type]));
1086: }
1087: PetscFunctionReturn(PETSC_SUCCESS);
1088: }
1090: PetscErrorCode EPSComputeVectors_Power(EPS eps)
1091: {
1092: EPS_POWER *power = (EPS_POWER*)eps->data;
1094: PetscFunctionBegin;
1095: if (eps->twosided) {
1096: PetscCall(EPSComputeVectors_Twosided(eps));
1097: PetscCall(BVNormalize(eps->V,NULL));
1098: PetscCall(BVNormalize(eps->W,NULL));
1099: } else if (!power->nonlinear) PetscCall(EPSComputeVectors_Schur(eps));
1100: PetscFunctionReturn(PETSC_SUCCESS);
1101: }
1103: PetscErrorCode EPSSetDefaultST_Power(EPS eps)
1104: {
1105: EPS_POWER *power = (EPS_POWER*)eps->data;
1106: KSP ksp;
1107: PC pc;
1109: PetscFunctionBegin;
1110: if (power->nonlinear) {
1111: eps->categ=EPS_CATEGORY_PRECOND;
1112: PetscCall(STGetKSP(eps->st,&ksp));
1113: /* Set ST as STPRECOND so it can carry one preconditioning matrix
1114: * It is useful when A and B are shell matrices
1115: */
1116: PetscCall(STSetType(eps->st,STPRECOND));
1117: PetscCall(KSPGetPC(ksp,&pc));
1118: PetscCall(PCSetType(pc,PCNONE));
1119: }
1120: PetscFunctionReturn(PETSC_SUCCESS);
1121: }
1123: SLEPC_EXTERN PetscErrorCode EPSCreate_Power(EPS eps)
1124: {
1125: EPS_POWER *ctx;
1127: PetscFunctionBegin;
1128: PetscCall(PetscNew(&ctx));
1129: eps->data = (void*)ctx;
1131: eps->useds = PETSC_TRUE;
1132: eps->categ = EPS_CATEGORY_OTHER;
1134: eps->ops->setup = EPSSetUp_Power;
1135: eps->ops->setupsort = EPSSetUpSort_Default;
1136: eps->ops->setfromoptions = EPSSetFromOptions_Power;
1137: eps->ops->reset = EPSReset_Power;
1138: eps->ops->destroy = EPSDestroy_Power;
1139: eps->ops->view = EPSView_Power;
1140: eps->ops->backtransform = EPSBackTransform_Power;
1141: eps->ops->computevectors = EPSComputeVectors_Power;
1142: eps->ops->setdefaultst = EPSSetDefaultST_Power;
1143: eps->stopping = EPSStopping_Power;
1145: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetShiftType_C",EPSPowerSetShiftType_Power));
1146: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetShiftType_C",EPSPowerGetShiftType_Power));
1147: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetNonlinear_C",EPSPowerSetNonlinear_Power));
1148: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetNonlinear_C",EPSPowerGetNonlinear_Power));
1149: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetUpdate_C",EPSPowerSetUpdate_Power));
1150: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetUpdate_C",EPSPowerGetUpdate_Power));
1151: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerSetSNES_C",EPSPowerSetSNES_Power));
1152: PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSPowerGetSNES_C",EPSPowerGetSNES_Power));
1153: PetscFunctionReturn(PETSC_SUCCESS);
1154: }