Actual source code: nleigs.c
slepc-3.16.3 2022-04-11
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 nonlinear eigensolver: "nleigs"
13: Method: NLEIGS
15: Algorithm:
17: Fully rational Krylov method for nonlinear eigenvalue problems.
19: References:
21: [1] S. Guttel et al., "NLEIGS: A class of robust fully rational Krylov
22: method for nonlinear eigenvalue problems", SIAM J. Sci. Comput.
23: 36(6):A2842-A2864, 2014.
24: */
26: #include <slepc/private/nepimpl.h>
27: #include <slepcblaslapack.h>
28: #include "nleigs.h"
30: PetscErrorCode NEPNLEIGSBackTransform(PetscObject ob,PetscInt n,PetscScalar *valr,PetscScalar *vali)
31: {
32: NEP nep;
33: PetscInt j;
34: #if !defined(PETSC_USE_COMPLEX)
35: PetscScalar t;
36: #endif
39: nep = (NEP)ob;
40: #if !defined(PETSC_USE_COMPLEX)
41: for (j=0;j<n;j++) {
42: if (vali[j] == 0) valr[j] = 1.0 / valr[j] + nep->target;
43: else {
44: t = valr[j] * valr[j] + vali[j] * vali[j];
45: valr[j] = valr[j] / t + nep->target;
46: vali[j] = - vali[j] / t;
47: }
48: }
49: #else
50: for (j=0;j<n;j++) {
51: valr[j] = 1.0 / valr[j] + nep->target;
52: }
53: #endif
54: return(0);
55: }
57: /* Computes the roots of a polynomial */
58: static PetscErrorCode NEPNLEIGSAuxiliarPRootFinder(PetscInt deg,PetscScalar *polcoeffs,PetscScalar *wr,PetscScalar *wi,PetscBool *avail)
59: {
61: PetscScalar *C;
62: PetscBLASInt n_,lwork;
63: PetscInt i;
64: #if defined(PETSC_USE_COMPLEX)
65: PetscReal *rwork=NULL;
66: #endif
67: PetscScalar *work;
68: PetscBLASInt info;
71: *avail = PETSC_TRUE;
72: if (deg>0) {
73: PetscCalloc1(deg*deg,&C);
74: PetscBLASIntCast(deg,&n_);
75: for (i=0;i<deg-1;i++) {
76: C[(deg+1)*i+1] = 1.0;
77: C[(deg-1)*deg+i] = -polcoeffs[deg-i]/polcoeffs[0];
78: }
79: C[deg*deg+-1] = -polcoeffs[1]/polcoeffs[0];
80: PetscBLASIntCast(3*deg,&lwork);
82: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
83: #if !defined(PETSC_USE_COMPLEX)
84: PetscMalloc1(lwork,&work);
85: PetscStackCallBLAS("LAPACKgeev",LAPACKgeev_("N","N",&n_,C,&n_,wr,wi,NULL,&n_,NULL,&n_,work,&lwork,&info));
86: if (info) *avail = PETSC_FALSE;
87: PetscFree(work);
88: #else
89: PetscMalloc2(2*deg,&rwork,lwork,&work);
90: PetscStackCallBLAS("LAPACKgeev",LAPACKgeev_("N","N",&n_,C,&n_,wr,NULL,&n_,NULL,&n_,work,&lwork,rwork,&info));
91: if (info) *avail = PETSC_FALSE;
92: PetscFree2(rwork,work);
93: #endif
94: PetscFPTrapPop();
95: PetscFree(C);
96: }
97: return(0);
98: }
100: static PetscErrorCode NEPNLEIGSAuxiliarRmDuplicates(PetscInt nin,PetscScalar *pin,PetscInt *nout,PetscScalar *pout,PetscInt max)
101: {
102: PetscInt i,j;
105: for (i=0;i<nin;i++) {
106: if (max && *nout>=max) break;
107: pout[(*nout)++] = pin[i];
108: for (j=0;j<*nout-1;j++)
109: if (PetscAbsScalar(pin[i]-pout[j])<PETSC_MACHINE_EPSILON*100) {
110: (*nout)--;
111: break;
112: }
113: }
114: return(0);
115: }
117: static PetscErrorCode NEPNLEIGSFNSingularities(FN f,PetscInt *nisol,PetscScalar **isol,PetscBool *rational)
118: {
120: FNCombineType ctype;
121: FN f1,f2;
122: PetscInt i,nq,nisol1,nisol2;
123: PetscScalar *qcoeff,*wr,*wi,*isol1,*isol2;
124: PetscBool flg,avail,rat1,rat2;
127: *rational = PETSC_FALSE;
128: PetscObjectTypeCompare((PetscObject)f,FNRATIONAL,&flg);
129: if (flg) {
130: *rational = PETSC_TRUE;
131: FNRationalGetDenominator(f,&nq,&qcoeff);
132: if (nq>1) {
133: PetscMalloc2(nq-1,&wr,nq-1,&wi);
134: NEPNLEIGSAuxiliarPRootFinder(nq-1,qcoeff,wr,wi,&avail);
135: if (avail) {
136: PetscCalloc1(nq-1,isol);
137: *nisol = 0;
138: for (i=0;i<nq-1;i++)
139: #if !defined(PETSC_USE_COMPLEX)
140: if (wi[i]==0)
141: #endif
142: (*isol)[(*nisol)++] = wr[i];
143: nq = *nisol; *nisol = 0;
144: for (i=0;i<nq;i++) wr[i] = (*isol)[i];
145: NEPNLEIGSAuxiliarRmDuplicates(nq,wr,nisol,*isol,0);
146: PetscFree2(wr,wi);
147: } else { *nisol=0; *isol = NULL; }
148: } else { *nisol = 0; *isol = NULL; }
149: PetscFree(qcoeff);
150: }
151: PetscObjectTypeCompare((PetscObject)f,FNCOMBINE,&flg);
152: if (flg) {
153: FNCombineGetChildren(f,&ctype,&f1,&f2);
154: if (ctype != FN_COMBINE_COMPOSE && ctype != FN_COMBINE_DIVIDE) {
155: NEPNLEIGSFNSingularities(f1,&nisol1,&isol1,&rat1);
156: NEPNLEIGSFNSingularities(f2,&nisol2,&isol2,&rat2);
157: if (nisol1+nisol2>0) {
158: PetscCalloc1(nisol1+nisol2,isol);
159: *nisol = 0;
160: NEPNLEIGSAuxiliarRmDuplicates(nisol1,isol1,nisol,*isol,0);
161: NEPNLEIGSAuxiliarRmDuplicates(nisol2,isol2,nisol,*isol,0);
162: }
163: *rational = (rat1&&rat2)?PETSC_TRUE:PETSC_FALSE;
164: PetscFree(isol1);
165: PetscFree(isol2);
166: }
167: }
168: return(0);
169: }
171: static PetscErrorCode NEPNLEIGSRationalSingularities(NEP nep,PetscInt *ndptx,PetscScalar *dxi,PetscBool *rational)
172: {
174: PetscInt nt,i,nisol;
175: FN f;
176: PetscScalar *isol;
177: PetscBool rat;
180: *rational = PETSC_TRUE;
181: *ndptx = 0;
182: NEPGetSplitOperatorInfo(nep,&nt,NULL);
183: for (i=0;i<nt;i++) {
184: NEPGetSplitOperatorTerm(nep,i,NULL,&f);
185: NEPNLEIGSFNSingularities(f,&nisol,&isol,&rat);
186: if (nisol) {
187: NEPNLEIGSAuxiliarRmDuplicates(nisol,isol,ndptx,dxi,0);
188: PetscFree(isol);
189: }
190: *rational = ((*rational)&&rat)?PETSC_TRUE:PETSC_FALSE;
191: }
192: return(0);
193: }
195: /* Adaptive Anderson-Antoulas algorithm */
196: static PetscErrorCode NEPNLEIGSAAAComputation(NEP nep,PetscInt ndpt,PetscScalar *ds,PetscScalar *F,PetscInt *ndptx,PetscScalar *dxi)
197: {
199: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
200: PetscScalar mean=0.0,*z,*f,*C,*A,*VT,*work,*ww,szero=0.0,sone=1.0;
201: PetscScalar *N,*D;
202: PetscReal *S,norm,err,*R;
203: PetscInt i,k,j,idx=0,cont;
204: PetscBLASInt n_,m_,lda_,lwork,info,one=1;
205: #if defined(PETSC_USE_COMPLEX)
206: PetscReal *rwork;
207: #endif
210: PetscBLASIntCast(8*ndpt,&lwork);
211: PetscMalloc5(ndpt,&R,ndpt,&z,ndpt,&f,ndpt*ndpt,&C,ndpt,&ww);
212: PetscMalloc6(ndpt*ndpt,&A,ndpt,&S,ndpt*ndpt,&VT,lwork,&work,ndpt,&D,ndpt,&N);
213: #if defined(PETSC_USE_COMPLEX)
214: PetscMalloc1(8*ndpt,&rwork);
215: #endif
216: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
217: norm = 0.0;
218: for (i=0;i<ndpt;i++) {
219: mean += F[i];
220: norm = PetscMax(PetscAbsScalar(F[i]),norm);
221: }
222: mean /= ndpt;
223: PetscBLASIntCast(ndpt,&lda_);
224: for (i=0;i<ndpt;i++) R[i] = PetscAbsScalar(F[i]-mean);
225: /* next support point */
226: err = 0.0;
227: for (i=0;i<ndpt;i++) if (R[i]>=err) {idx = i; err = R[i];}
228: for (k=0;k<ndpt-1;k++) {
229: z[k] = ds[idx]; f[k] = F[idx]; R[idx] = -1.0;
230: /* next column of Cauchy matrix */
231: for (i=0;i<ndpt;i++) {
232: C[i+k*ndpt] = 1.0/(ds[i]-ds[idx]);
233: }
235: PetscArrayzero(A,ndpt*ndpt);
236: cont = 0;
237: for (i=0;i<ndpt;i++) {
238: if (R[i]!=-1.0) {
239: for (j=0;j<=k;j++)A[cont+j*ndpt] = C[i+j*ndpt]*F[i]-C[i+j*ndpt]*f[j];
240: cont++;
241: }
242: }
243: PetscBLASIntCast(cont,&m_);
244: PetscBLASIntCast(k+1,&n_);
245: #if defined(PETSC_USE_COMPLEX)
246: PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","A",&m_,&n_,A,&lda_,S,NULL,&lda_,VT,&lda_,work,&lwork,rwork,&info));
247: #else
248: PetscStackCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","A",&m_,&n_,A,&lda_,S,NULL,&lda_,VT,&lda_,work,&lwork,&info));
249: #endif
250: SlepcCheckLapackInfo("gesvd",info);
251: for (i=0;i<=k;i++) {
252: ww[i] = PetscConj(VT[i*ndpt+k]);
253: D[i] = ww[i]*f[i];
254: }
255: PetscStackCallBLAS("BLASgemv",BLASgemv_("N",&lda_,&n_,&sone,C,&lda_,D,&one,&szero,N,&one));
256: PetscStackCallBLAS("BLASgemv",BLASgemv_("N",&lda_,&n_,&sone,C,&lda_,ww,&one,&szero,D,&one));
257: for (i=0;i<ndpt;i++) if (R[i]>=0) R[i] = PetscAbsScalar(F[i]-N[i]/D[i]);
258: /* next support point */
259: err = 0.0;
260: for (i=0;i<ndpt;i++) if (R[i]>=err) {idx = i; err = R[i];}
261: if (err <= ctx->ddtol*norm) break;
262: }
264: if (k==ndpt-1) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_CONV_FAILED,"Failed to determine singularities automatically in general problem");
265: /* poles */
266: PetscArrayzero(C,ndpt*ndpt);
267: PetscArrayzero(A,ndpt*ndpt);
268: for (i=0;i<=k;i++) {
269: C[i+ndpt*i] = 1.0;
270: A[(i+1)*ndpt] = ww[i];
271: A[i+1] = 1.0;
272: A[i+1+(i+1)*ndpt] = z[i];
273: }
274: C[0] = 0.0; C[k+1+(k+1)*ndpt] = 1.0;
275: n_++;
276: #if defined(PETSC_USE_COMPLEX)
277: PetscStackCallBLAS("LAPACKggev",LAPACKggev_("N","N",&n_,A,&lda_,C,&lda_,D,N,NULL,&lda_,NULL,&lda_,work,&lwork,rwork,&info));
278: #else
279: PetscStackCallBLAS("LAPACKggev",LAPACKggev_("N","N",&n_,A,&lda_,C,&lda_,D,VT,N,NULL,&lda_,NULL,&lda_,work,&lwork,&info));
280: #endif
281: SlepcCheckLapackInfo("ggev",info);
282: cont = 0.0;
283: for (i=0;i<n_;i++) if (N[i]!=0.0) {
284: dxi[cont++] = D[i]/N[i];
285: }
286: *ndptx = cont;
287: PetscFPTrapPop();
288: PetscFree5(R,z,f,C,ww);
289: PetscFree6(A,S,VT,work,D,N);
290: #if defined(PETSC_USE_COMPLEX)
291: PetscFree(rwork);
292: #endif
293: return(0);
294: }
296: /* Singularities using Adaptive Anderson-Antoulas algorithm */
297: static PetscErrorCode NEPNLEIGSAAASingularities(NEP nep,PetscInt ndpt,PetscScalar *ds,PetscInt *ndptx,PetscScalar *dxi)
298: {
300: Vec u,v,w;
301: PetscRandom rand=NULL;
302: PetscScalar *F,*isol;
303: PetscInt i,k,nisol,nt;
304: Mat T;
305: FN f;
308: PetscMalloc1(ndpt,&F);
309: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
310: PetscMalloc1(ndpt,&isol);
311: *ndptx = 0;
312: NEPGetSplitOperatorInfo(nep,&nt,NULL);
313: nisol = *ndptx;
314: for (k=0;k<nt;k++) {
315: NEPGetSplitOperatorTerm(nep,k,NULL,&f);
316: for (i=0;i<ndpt;i++) {
317: FNEvaluateFunction(f,ds[i],&F[i]);
318: }
319: NEPNLEIGSAAAComputation(nep,ndpt,ds,F,&nisol,isol);
320: if (nisol) {
321: NEPNLEIGSAuxiliarRmDuplicates(nisol,isol,ndptx,dxi,ndpt);
322: }
323: }
324: PetscFree(isol);
325: } else {
326: MatCreateVecs(nep->function,&u,NULL);
327: VecDuplicate(u,&v);
328: VecDuplicate(u,&w);
329: if (nep->V) { BVGetRandomContext(nep->V,&rand); }
330: VecSetRandom(u,rand);
331: VecNormalize(u,NULL);
332: VecSetRandom(v,rand);
333: VecNormalize(v,NULL);
334: T = nep->function;
335: for (i=0;i<ndpt;i++) {
336: NEPComputeFunction(nep,ds[i],T,T);
337: MatMult(T,v,w);
338: VecDot(w,u,&F[i]);
339: }
340: NEPNLEIGSAAAComputation(nep,ndpt,ds,F,ndptx,dxi);
341: VecDestroy(&u);
342: VecDestroy(&v);
343: VecDestroy(&w);
344: }
345: PetscFree(F);
346: return(0);
347: }
349: static PetscErrorCode NEPNLEIGSLejaBagbyPoints(NEP nep)
350: {
352: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
353: PetscInt i,k,ndpt=NDPOINTS,ndptx=NDPOINTS;
354: PetscScalar *ds,*dsi,*dxi,*nrs,*nrxi,*s=ctx->s,*xi=ctx->xi,*beta=ctx->beta;
355: PetscReal maxnrs,minnrxi;
356: PetscBool rational;
357: #if !defined(PETSC_USE_COMPLEX)
358: PetscReal a,b,h;
359: #endif
362: if (!ctx->computesingularities && nep->problem_type!=NEP_RATIONAL) ndpt = ndptx = LBPOINTS;
363: PetscMalloc5(ndpt+1,&ds,ndpt+1,&dsi,ndpt,&dxi,ndpt+1,&nrs,ndpt,&nrxi);
365: /* Discretize the target region boundary */
366: RGComputeContour(nep->rg,ndpt,ds,dsi);
367: #if !defined(PETSC_USE_COMPLEX)
368: for (i=0;i<ndpt;i++) if (dsi[i]!=0.0) break;
369: if (i<ndpt) {
370: if (nep->problem_type==NEP_RATIONAL) {
371: /* Select a segment in the real axis */
372: RGComputeBoundingBox(nep->rg,&a,&b,NULL,NULL);
373: if (a<=-PETSC_MAX_REAL || b>=PETSC_MAX_REAL) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"NLEIGS requires a bounded target set");
374: h = (b-a)/ndpt;
375: for (i=0;i<ndpt;i++) {ds[i] = a+h*i; dsi[i] = 0.0;}
376: } else SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"NLEIGS with real arithmetic requires the target set to be included in the real axis");
377: }
378: #endif
379: /* Discretize the singularity region */
380: if (ctx->computesingularities) {
381: (ctx->computesingularities)(nep,&ndptx,dxi,ctx->singularitiesctx);
382: } else {
383: if (nep->problem_type==NEP_RATIONAL) {
384: NEPNLEIGSRationalSingularities(nep,&ndptx,dxi,&rational);
385: if (!rational) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_CONV_FAILED,"Failed to determine singularities automatically in rational problem; consider solving the problem as general");
386: } else {
387: /* AAA algorithm */
388: NEPNLEIGSAAASingularities(nep,ndpt,ds,&ndptx,dxi);
389: }
390: }
391: /* Look for Leja-Bagby points in the discretization sets */
392: s[0] = ds[0];
393: xi[0] = (ndptx>0)?dxi[0]:PETSC_INFINITY;
394: if (PetscAbsScalar(xi[0])<10*PETSC_MACHINE_EPSILON) SETERRQ2(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"Singularity point %D is nearly zero: %g; consider removing the singularity or shifting the problem",0,(double)PetscAbsScalar(xi[0]));
395: beta[0] = 1.0; /* scaling factors are also computed here */
396: for (i=0;i<ndpt;i++) {
397: nrs[i] = 1.0;
398: nrxi[i] = 1.0;
399: }
400: for (k=1;k<ctx->ddmaxit;k++) {
401: maxnrs = 0.0;
402: minnrxi = PETSC_MAX_REAL;
403: for (i=0;i<ndpt;i++) {
404: nrs[i] *= ((ds[i]-s[k-1])/(1.0-ds[i]/xi[k-1]))/beta[k-1];
405: if (PetscAbsScalar(nrs[i])>maxnrs) {maxnrs = PetscAbsScalar(nrs[i]); s[k] = ds[i];}
406: }
407: if (ndptx>k) {
408: for (i=1;i<ndptx;i++) {
409: nrxi[i] *= ((dxi[i]-s[k-1])/(1.0-dxi[i]/xi[k-1]))/beta[k-1];
410: if (PetscAbsScalar(nrxi[i])<minnrxi) {minnrxi = PetscAbsScalar(nrxi[i]); xi[k] = dxi[i];}
411: }
412: if (PetscAbsScalar(xi[k])<10*PETSC_MACHINE_EPSILON) SETERRQ2(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"Singularity point %D is nearly zero: %g; consider removing the singularity or shifting the problem",k,(double)PetscAbsScalar(xi[k]));
413: } else xi[k] = PETSC_INFINITY;
414: beta[k] = maxnrs;
415: }
416: PetscFree5(ds,dsi,dxi,nrs,nrxi);
417: return(0);
418: }
420: PetscErrorCode NEPNLEIGSEvalNRTFunct(NEP nep,PetscInt k,PetscScalar sigma,PetscScalar *b)
421: {
422: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
423: PetscInt i;
424: PetscScalar *beta=ctx->beta,*s=ctx->s,*xi=ctx->xi;
427: b[0] = 1.0/beta[0];
428: for (i=0;i<k;i++) {
429: b[i+1] = ((sigma-s[i])*b[i])/(beta[i+1]*(1.0-sigma/xi[i]));
430: }
431: return(0);
432: }
434: static PetscErrorCode MatMult_Fun(Mat A,Vec x,Vec y)
435: {
436: PetscErrorCode ierr;
437: NEP_NLEIGS_MATSHELL *ctx;
438: PetscInt i;
441: MatShellGetContext(A,&ctx);
442: MatMult(ctx->A[0],x,y);
443: if (ctx->coeff[0]!=1.0) { VecScale(y,ctx->coeff[0]); }
444: for (i=1;i<ctx->nmat;i++) {
445: MatMult(ctx->A[i],x,ctx->t);
446: VecAXPY(y,ctx->coeff[i],ctx->t);
447: }
448: return(0);
449: }
451: static PetscErrorCode MatMultTranspose_Fun(Mat A,Vec x,Vec y)
452: {
453: PetscErrorCode ierr;
454: NEP_NLEIGS_MATSHELL *ctx;
455: PetscInt i;
458: MatShellGetContext(A,&ctx);
459: MatMultTranspose(ctx->A[0],x,y);
460: if (ctx->coeff[0]!=1.0) { VecScale(y,ctx->coeff[0]); }
461: for (i=1;i<ctx->nmat;i++) {
462: MatMultTranspose(ctx->A[i],x,ctx->t);
463: VecAXPY(y,ctx->coeff[i],ctx->t);
464: }
465: return(0);
466: }
468: static PetscErrorCode MatGetDiagonal_Fun(Mat A,Vec diag)
469: {
470: PetscErrorCode ierr;
471: NEP_NLEIGS_MATSHELL *ctx;
472: PetscInt i;
475: MatShellGetContext(A,&ctx);
476: MatGetDiagonal(ctx->A[0],diag);
477: if (ctx->coeff[0]!=1.0) { VecScale(diag,ctx->coeff[0]); }
478: for (i=1;i<ctx->nmat;i++) {
479: MatGetDiagonal(ctx->A[i],ctx->t);
480: VecAXPY(diag,ctx->coeff[i],ctx->t);
481: }
482: return(0);
483: }
485: static PetscErrorCode MatDuplicate_Fun(Mat A,MatDuplicateOption op,Mat *B)
486: {
487: PetscInt m,n,M,N,i;
488: NEP_NLEIGS_MATSHELL *ctxnew,*ctx;
489: void (*fun)(void);
490: PetscErrorCode ierr;
493: MatShellGetContext(A,&ctx);
494: PetscNew(&ctxnew);
495: ctxnew->nmat = ctx->nmat;
496: ctxnew->maxnmat = ctx->maxnmat;
497: PetscMalloc2(ctxnew->maxnmat,&ctxnew->A,ctxnew->maxnmat,&ctxnew->coeff);
498: for (i=0;i<ctx->nmat;i++) {
499: PetscObjectReference((PetscObject)ctx->A[i]);
500: ctxnew->A[i] = ctx->A[i];
501: ctxnew->coeff[i] = ctx->coeff[i];
502: }
503: MatGetSize(ctx->A[0],&M,&N);
504: MatGetLocalSize(ctx->A[0],&m,&n);
505: VecDuplicate(ctx->t,&ctxnew->t);
506: MatCreateShell(PetscObjectComm((PetscObject)A),m,n,M,N,(void*)ctxnew,B);
507: MatShellSetManageScalingShifts(*B);
508: MatShellGetOperation(A,MATOP_MULT,&fun);
509: MatShellSetOperation(*B,MATOP_MULT,fun);
510: MatShellGetOperation(A,MATOP_MULT_TRANSPOSE,&fun);
511: MatShellSetOperation(*B,MATOP_MULT_TRANSPOSE,fun);
512: MatShellGetOperation(A,MATOP_GET_DIAGONAL,&fun);
513: MatShellSetOperation(*B,MATOP_GET_DIAGONAL,fun);
514: MatShellGetOperation(A,MATOP_DUPLICATE,&fun);
515: MatShellSetOperation(*B,MATOP_DUPLICATE,fun);
516: MatShellGetOperation(A,MATOP_DESTROY,&fun);
517: MatShellSetOperation(*B,MATOP_DESTROY,fun);
518: MatShellGetOperation(A,MATOP_AXPY,&fun);
519: MatShellSetOperation(*B,MATOP_AXPY,fun);
520: return(0);
521: }
523: static PetscErrorCode MatDestroy_Fun(Mat A)
524: {
525: NEP_NLEIGS_MATSHELL *ctx;
526: PetscErrorCode ierr;
527: PetscInt i;
530: if (A) {
531: MatShellGetContext(A,&ctx);
532: for (i=0;i<ctx->nmat;i++) {
533: MatDestroy(&ctx->A[i]);
534: }
535: VecDestroy(&ctx->t);
536: PetscFree2(ctx->A,ctx->coeff);
537: PetscFree(ctx);
538: }
539: return(0);
540: }
542: static PetscErrorCode MatAXPY_Fun(Mat Y,PetscScalar a,Mat X,MatStructure str)
543: {
544: NEP_NLEIGS_MATSHELL *ctxY,*ctxX;
545: PetscErrorCode ierr;
546: PetscInt i,j;
547: PetscBool found;
550: MatShellGetContext(Y,&ctxY);
551: MatShellGetContext(X,&ctxX);
552: for (i=0;i<ctxX->nmat;i++) {
553: found = PETSC_FALSE;
554: for (j=0;!found&&j<ctxY->nmat;j++) {
555: if (ctxX->A[i]==ctxY->A[j]) {
556: found = PETSC_TRUE;
557: ctxY->coeff[j] += a*ctxX->coeff[i];
558: }
559: }
560: if (!found) {
561: ctxY->coeff[ctxY->nmat] = a*ctxX->coeff[i];
562: ctxY->A[ctxY->nmat++] = ctxX->A[i];
563: PetscObjectReference((PetscObject)ctxX->A[i]);
564: }
565: }
566: return(0);
567: }
569: static PetscErrorCode MatScale_Fun(Mat M,PetscScalar a)
570: {
571: NEP_NLEIGS_MATSHELL *ctx;
572: PetscErrorCode ierr;
573: PetscInt i;
576: MatShellGetContext(M,&ctx);
577: for (i=0;i<ctx->nmat;i++) ctx->coeff[i] *= a;
578: return(0);
579: }
581: static PetscErrorCode NLEIGSMatToMatShellArray(Mat A,Mat *Ms,PetscInt maxnmat)
582: {
583: PetscErrorCode ierr;
584: NEP_NLEIGS_MATSHELL *ctx;
585: PetscInt m,n,M,N;
586: PetscBool has;
589: MatHasOperation(A,MATOP_DUPLICATE,&has);
590: if (!has) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"MatDuplicate operation required");
591: PetscNew(&ctx);
592: ctx->maxnmat = maxnmat;
593: PetscMalloc2(ctx->maxnmat,&ctx->A,ctx->maxnmat,&ctx->coeff);
594: MatDuplicate(A,MAT_COPY_VALUES,&ctx->A[0]);
595: ctx->nmat = 1;
596: ctx->coeff[0] = 1.0;
597: MatCreateVecs(A,&ctx->t,NULL);
598: MatGetSize(A,&M,&N);
599: MatGetLocalSize(A,&m,&n);
600: MatCreateShell(PetscObjectComm((PetscObject)A),m,n,M,N,(void*)ctx,Ms);
601: MatShellSetManageScalingShifts(*Ms);
602: MatShellSetOperation(*Ms,MATOP_MULT,(void(*)(void))MatMult_Fun);
603: MatShellSetOperation(*Ms,MATOP_MULT_TRANSPOSE,(void(*)(void))MatMultTranspose_Fun);
604: MatShellSetOperation(*Ms,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Fun);
605: MatShellSetOperation(*Ms,MATOP_DUPLICATE,(void(*)(void))MatDuplicate_Fun);
606: MatShellSetOperation(*Ms,MATOP_DESTROY,(void(*)(void))MatDestroy_Fun);
607: MatShellSetOperation(*Ms,MATOP_AXPY,(void(*)(void))MatAXPY_Fun);
608: MatShellSetOperation(*Ms,MATOP_SCALE,(void(*)(void))MatScale_Fun);
609: return(0);
610: }
612: /*
613: MatIsShellAny - returns true if any of the n matrices is a shell matrix
614: */
615: static PetscErrorCode MatIsShellAny(Mat *A,PetscInt n,PetscBool *shell)
616: {
618: PetscInt i;
619: PetscBool flg;
622: *shell = PETSC_FALSE;
623: for (i=0;i<n;i++) {
624: MatIsShell(A[i],&flg);
625: if (flg) { *shell = PETSC_TRUE; break; }
626: }
627: return(0);
628: }
630: static PetscErrorCode NEPNLEIGSDividedDifferences_split(NEP nep)
631: {
633: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
634: PetscInt k,j,i,maxnmat,nmax;
635: PetscReal norm0,norm,*matnorm;
636: PetscScalar *s=ctx->s,*beta=ctx->beta,*xi=ctx->xi,*b,alpha,*coeffs,*pK,*pH,sone=1.0;
637: Mat T,Ts,K,H;
638: PetscBool shell,hasmnorm=PETSC_FALSE,matrix=PETSC_TRUE;
639: PetscBLASInt n_;
642: nmax = ctx->ddmaxit;
643: PetscMalloc1(nep->nt*nmax,&ctx->coeffD);
644: PetscMalloc3(nmax+1,&b,nmax+1,&coeffs,nep->nt,&matnorm);
645: for (j=0;j<nep->nt;j++) {
646: MatHasOperation(nep->A[j],MATOP_NORM,&hasmnorm);
647: if (!hasmnorm) break;
648: MatNorm(nep->A[j],NORM_INFINITY,matnorm+j);
649: }
650: /* Try matrix functions scheme */
651: PetscCalloc2(nmax*nmax,&pK,nmax*nmax,&pH);
652: for (i=0;i<nmax-1;i++) {
653: pK[(nmax+1)*i] = 1.0;
654: pK[(nmax+1)*i+1] = beta[i+1]/xi[i];
655: pH[(nmax+1)*i] = s[i];
656: pH[(nmax+1)*i+1] = beta[i+1];
657: }
658: pH[nmax*nmax-1] = s[nmax-1];
659: pK[nmax*nmax-1] = 1.0;
660: PetscBLASIntCast(nmax,&n_);
661: PetscStackCallBLAS("BLAStrsm",BLAStrsm_("R","L","N","U",&n_,&n_,&sone,pK,&n_,pH,&n_));
662: /* The matrix to be used is in H. K will be a work-space matrix */
663: MatCreateSeqDense(PETSC_COMM_SELF,nmax,nmax,pH,&H);
664: MatCreateSeqDense(PETSC_COMM_SELF,nmax,nmax,pK,&K);
665: for (j=0;matrix&&j<nep->nt;j++) {
666: PetscPushErrorHandler(PetscReturnErrorHandler,NULL);
667: FNEvaluateFunctionMat(nep->f[j],H,K);
668: PetscPopErrorHandler();
669: if (!ierr) {
670: for (i=0;i<nmax;i++) ctx->coeffD[j+i*nep->nt] = pK[i]*beta[0];
671: } else {
672: matrix = PETSC_FALSE;
673: PetscFPTrapPop();
674: }
675: }
676: MatDestroy(&H);
677: MatDestroy(&K);
678: if (!matrix) {
679: for (j=0;j<nep->nt;j++) {
680: FNEvaluateFunction(nep->f[j],s[0],ctx->coeffD+j);
681: ctx->coeffD[j] *= beta[0];
682: }
683: }
684: if (hasmnorm) {
685: norm0 = 0.0;
686: for (j=0;j<nep->nt;j++) norm0 += matnorm[j]*PetscAbsScalar(ctx->coeffD[j]);
687: } else {
688: norm0 = 0.0;
689: for (j=0;j<nep->nt;j++) norm0 = PetscMax(PetscAbsScalar(ctx->coeffD[j]),norm0);
690: }
691: ctx->nmat = ctx->ddmaxit;
692: for (k=1;k<ctx->ddmaxit;k++) {
693: if (!matrix) {
694: NEPNLEIGSEvalNRTFunct(nep,k,s[k],b);
695: for (i=0;i<nep->nt;i++) {
696: FNEvaluateFunction(nep->f[i],s[k],ctx->coeffD+k*nep->nt+i);
697: for (j=0;j<k;j++) {
698: ctx->coeffD[k*nep->nt+i] -= b[j]*ctx->coeffD[i+nep->nt*j];
699: }
700: ctx->coeffD[k*nep->nt+i] /= b[k];
701: }
702: }
703: if (hasmnorm) {
704: norm = 0.0;
705: for (j=0;j<nep->nt;j++) norm += matnorm[j]*PetscAbsScalar(ctx->coeffD[k*nep->nt+j]);
706: } else {
707: norm = 0.0;
708: for (j=0;j<nep->nt;j++) norm = PetscMax(PetscAbsScalar(ctx->coeffD[k*nep->nt+j]),norm);
709: }
710: if (k>1 && norm/norm0 < ctx->ddtol) {
711: ctx->nmat = k+1;
712: break;
713: }
714: }
715: if (!ctx->ksp) { NEPNLEIGSGetKSPs(nep,&ctx->nshiftsw,&ctx->ksp); }
716: MatIsShellAny(nep->A,nep->nt,&shell);
717: maxnmat = PetscMax(ctx->ddmaxit,nep->nt);
718: for (i=0;i<ctx->nshiftsw;i++) {
719: NEPNLEIGSEvalNRTFunct(nep,ctx->nmat-1,ctx->shifts[i],coeffs);
720: if (!shell) {
721: MatDuplicate(nep->A[0],MAT_COPY_VALUES,&T);
722: } else {
723: NLEIGSMatToMatShellArray(nep->A[0],&T,maxnmat);
724: }
725: alpha = 0.0;
726: for (j=0;j<ctx->nmat;j++) alpha += coeffs[j]*ctx->coeffD[j*nep->nt];
727: MatScale(T,alpha);
728: for (k=1;k<nep->nt;k++) {
729: alpha = 0.0;
730: for (j=0;j<ctx->nmat;j++) alpha += coeffs[j]*ctx->coeffD[j*nep->nt+k];
731: if (shell) {
732: NLEIGSMatToMatShellArray(nep->A[k],&Ts,maxnmat);
733: }
734: MatAXPY(T,alpha,shell?Ts:nep->A[k],nep->mstr);
735: if (shell) {
736: MatDestroy(&Ts);
737: }
738: }
739: KSPSetOperators(ctx->ksp[i],T,T);
740: KSPSetUp(ctx->ksp[i]);
741: MatDestroy(&T);
742: }
743: PetscFree3(b,coeffs,matnorm);
744: PetscFree2(pK,pH);
745: return(0);
746: }
748: static PetscErrorCode NEPNLEIGSDividedDifferences_callback(NEP nep)
749: {
751: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
752: PetscInt k,j,i,maxnmat;
753: PetscReal norm0,norm;
754: PetscScalar *s=ctx->s,*beta=ctx->beta,*b,*coeffs;
755: Mat *D=ctx->D,T;
756: PetscBool shell,has,vec=PETSC_FALSE;
757: PetscRandom rand=NULL;
758: Vec w[2];
761: PetscMalloc2(ctx->ddmaxit+1,&b,ctx->ddmaxit+1,&coeffs);
762: if (nep->V) { BVGetRandomContext(nep->V,&rand); }
763: T = nep->function;
764: NEPComputeFunction(nep,s[0],T,T);
765: MatIsShell(T,&shell);
766: maxnmat = PetscMax(ctx->ddmaxit,nep->nt);
767: if (!shell) {
768: MatDuplicate(T,MAT_COPY_VALUES,&D[0]);
769: } else {
770: NLEIGSMatToMatShellArray(T,&D[0],maxnmat);
771: }
772: if (beta[0]!=1.0) {
773: MatScale(D[0],1.0/beta[0]);
774: }
775: MatHasOperation(D[0],MATOP_NORM,&has);
776: if (has) {
777: MatNorm(D[0],NORM_FROBENIUS,&norm0);
778: } else {
779: MatCreateVecs(D[0],NULL,&w[0]);
780: VecDuplicate(w[0],&w[1]);
781: VecDuplicate(w[0],&ctx->vrn);
782: VecSetRandomNormal(ctx->vrn,rand,w[0],w[1]);
783: VecNormalize(ctx->vrn,NULL);
784: vec = PETSC_TRUE;
785: MatNormEstimate(D[0],ctx->vrn,w[0],&norm0);
786: }
787: ctx->nmat = ctx->ddmaxit;
788: for (k=1;k<ctx->ddmaxit;k++) {
789: NEPNLEIGSEvalNRTFunct(nep,k,s[k],b);
790: NEPComputeFunction(nep,s[k],T,T);
791: if (!shell) {
792: MatDuplicate(T,MAT_COPY_VALUES,&D[k]);
793: } else {
794: NLEIGSMatToMatShellArray(T,&D[k],maxnmat);
795: }
796: for (j=0;j<k;j++) {
797: MatAXPY(D[k],-b[j],D[j],nep->mstr);
798: }
799: MatScale(D[k],1.0/b[k]);
800: MatHasOperation(D[k],MATOP_NORM,&has);
801: if (has) {
802: MatNorm(D[k],NORM_FROBENIUS,&norm);
803: } else {
804: if (!vec) {
805: MatCreateVecs(D[k],NULL,&w[0]);
806: VecDuplicate(w[0],&w[1]);
807: VecDuplicate(w[0],&ctx->vrn);
808: VecSetRandomNormal(ctx->vrn,rand,w[0],w[1]);
809: VecNormalize(ctx->vrn,NULL);
810: vec = PETSC_TRUE;
811: }
812: MatNormEstimate(D[k],ctx->vrn,w[0],&norm);
813: }
814: if (k>1 && norm/norm0 < ctx->ddtol && k>1) {
815: ctx->nmat = k+1;
816: break;
817: }
818: }
819: if (!ctx->ksp) { NEPNLEIGSGetKSPs(nep,&ctx->nshiftsw,&ctx->ksp); }
820: for (i=0;i<ctx->nshiftsw;i++) {
821: NEPNLEIGSEvalNRTFunct(nep,ctx->nmat-1,ctx->shifts[i],coeffs);
822: MatDuplicate(ctx->D[0],MAT_COPY_VALUES,&T);
823: if (coeffs[0]!=1.0) { MatScale(T,coeffs[0]); }
824: for (j=1;j<ctx->nmat;j++) {
825: MatAXPY(T,coeffs[j],ctx->D[j],nep->mstr);
826: }
827: KSPSetOperators(ctx->ksp[i],T,T);
828: KSPSetUp(ctx->ksp[i]);
829: MatDestroy(&T);
830: }
831: PetscFree2(b,coeffs);
832: if (vec) {
833: VecDestroy(&w[0]);
834: VecDestroy(&w[1]);
835: }
836: return(0);
837: }
839: /*
840: NEPKrylovConvergence - This is the analogue to EPSKrylovConvergence.
841: */
842: PetscErrorCode NEPNLEIGSKrylovConvergence(NEP nep,PetscBool getall,PetscInt kini,PetscInt nits,PetscReal betah,PetscScalar betak,PetscInt *kout,Vec *w)
843: {
845: PetscInt k,newk,marker,inside;
846: PetscScalar re,im;
847: PetscReal resnorm,tt;
848: PetscBool istrivial;
849: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
852: RGIsTrivial(nep->rg,&istrivial);
853: marker = -1;
854: if (nep->trackall) getall = PETSC_TRUE;
855: for (k=kini;k<kini+nits;k++) {
856: /* eigenvalue */
857: re = nep->eigr[k];
858: im = nep->eigi[k];
859: if (!istrivial) {
860: if (!ctx->nshifts) {
861: NEPNLEIGSBackTransform((PetscObject)nep,1,&re,&im);
862: }
863: RGCheckInside(nep->rg,1,&re,&im,&inside);
864: if (marker==-1 && inside<0) marker = k;
865: }
866: newk = k;
867: DSVectors(nep->ds,DS_MAT_X,&newk,&resnorm);
868: tt = (ctx->nshifts)?SlepcAbsEigenvalue(betak-nep->eigr[k]*betah,nep->eigi[k]*betah):betah;
869: resnorm *= PetscAbsReal(tt);
870: /* error estimate */
871: (*nep->converged)(nep,nep->eigr[k],nep->eigi[k],resnorm,&nep->errest[k],nep->convergedctx);
872: if (marker==-1 && nep->errest[k] >= nep->tol) marker = k;
873: if (newk==k+1) {
874: nep->errest[k+1] = nep->errest[k];
875: k++;
876: }
877: if (marker!=-1 && !getall) break;
878: }
879: if (marker!=-1) k = marker;
880: *kout = k;
881: return(0);
882: }
884: PetscErrorCode NEPSetUp_NLEIGS(NEP nep)
885: {
887: PetscInt k,in;
888: PetscScalar zero=0.0;
889: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
890: SlepcSC sc;
891: PetscBool istrivial;
894: NEPSetDimensions_Default(nep,nep->nev,&nep->ncv,&nep->mpd);
895: if (nep->ncv>nep->nev+nep->mpd) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"The value of ncv must not be larger than nev+mpd");
896: if (nep->max_it==PETSC_DEFAULT) nep->max_it = PetscMax(5000,2*nep->n/nep->ncv);
897: if (!ctx->ddmaxit) ctx->ddmaxit = LBPOINTS;
898: RGIsTrivial(nep->rg,&istrivial);
899: if (istrivial) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"NEPNLEIGS requires a nontrivial region defining the target set");
900: if (!nep->which) nep->which = NEP_TARGET_MAGNITUDE;
901: if (nep->which!=NEP_TARGET_MAGNITUDE && nep->which!=NEP_TARGET_REAL && nep->which!=NEP_TARGET_IMAGINARY && nep->which!=NEP_WHICH_USER) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver supports only target selection of eigenvalues");
903: /* Initialize the NLEIGS context structure */
904: k = ctx->ddmaxit;
905: PetscMalloc4(k,&ctx->s,k,&ctx->xi,k,&ctx->beta,k,&ctx->D);
906: nep->data = ctx;
907: if (nep->tol==PETSC_DEFAULT) nep->tol = SLEPC_DEFAULT_TOL;
908: if (ctx->ddtol==PETSC_DEFAULT) ctx->ddtol = nep->tol/10.0;
909: if (!ctx->keep) ctx->keep = 0.5;
911: /* Compute Leja-Bagby points and scaling values */
912: NEPNLEIGSLejaBagbyPoints(nep);
913: if (nep->problem_type!=NEP_RATIONAL) {
914: RGCheckInside(nep->rg,1,&nep->target,&zero,&in);
915: if (in<0) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"The target is not inside the target set");
916: }
918: /* Compute the divided difference matrices */
919: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
920: NEPNLEIGSDividedDifferences_split(nep);
921: } else {
922: NEPNLEIGSDividedDifferences_callback(nep);
923: }
924: NEPAllocateSolution(nep,ctx->nmat-1);
925: NEPSetWorkVecs(nep,4);
926: if (!ctx->fullbasis) {
927: if (nep->twosided) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Two-sided variant requires the full-basis option, rerun with -nep_nleigs_full_basis");
928: /* set-up DS and transfer split operator functions */
929: DSSetType(nep->ds,ctx->nshifts?DSGNHEP:DSNHEP);
930: DSAllocate(nep->ds,nep->ncv+1);
931: DSGetSlepcSC(nep->ds,&sc);
932: if (!ctx->nshifts) sc->map = NEPNLEIGSBackTransform;
933: DSSetExtraRow(nep->ds,PETSC_TRUE);
934: sc->mapobj = (PetscObject)nep;
935: sc->rg = nep->rg;
936: sc->comparison = nep->sc->comparison;
937: sc->comparisonctx = nep->sc->comparisonctx;
938: BVDestroy(&ctx->V);
939: BVCreateTensor(nep->V,ctx->nmat-1,&ctx->V);
940: nep->ops->solve = NEPSolve_NLEIGS;
941: nep->ops->computevectors = NEPComputeVectors_Schur;
942: } else {
943: NEPSetUp_NLEIGS_FullBasis(nep);
944: nep->ops->solve = NEPSolve_NLEIGS_FullBasis;
945: nep->ops->computevectors = NULL;
946: }
947: return(0);
948: }
950: /*
951: Extend the TOAR basis by applying the the matrix operator
952: over a vector which is decomposed on the TOAR way
953: Input:
954: - S,V: define the latest Arnoldi vector (nv vectors in V)
955: Output:
956: - t: new vector extending the TOAR basis
957: - r: temporally coefficients to compute the TOAR coefficients
958: for the new Arnoldi vector
959: Workspace: t_ (two vectors)
960: */
961: static PetscErrorCode NEPTOARExtendBasis(NEP nep,PetscInt idxrktg,PetscScalar *S,PetscInt ls,PetscInt nv,BV W,BV V,Vec t,PetscScalar *r,PetscInt lr,Vec *t_)
962: {
964: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
965: PetscInt deg=ctx->nmat-1,k,j;
966: Vec v=t_[0],q=t_[1],w;
967: PetscScalar *beta=ctx->beta,*s=ctx->s,*xi=ctx->xi,*coeffs,sigma;
970: if (!ctx->ksp) { NEPNLEIGSGetKSPs(nep,&ctx->nshiftsw,&ctx->ksp); }
971: sigma = ctx->shifts[idxrktg];
972: BVSetActiveColumns(nep->V,0,nv);
973: PetscMalloc1(ctx->nmat,&coeffs);
974: if (PetscAbsScalar(s[deg-2]-sigma)<100*PETSC_MACHINE_EPSILON) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_CONV_FAILED,"Breakdown in NLEIGS");
975: /* i-part stored in (i-1) position */
976: for (j=0;j<nv;j++) {
977: r[(deg-2)*lr+j] = (S[(deg-2)*ls+j]+(beta[deg-1]/xi[deg-2])*S[(deg-1)*ls+j])/(s[deg-2]-sigma);
978: }
979: BVSetActiveColumns(W,0,deg);
980: BVGetColumn(W,deg-1,&w);
981: BVMultVec(V,1.0/beta[deg],0,w,S+(deg-1)*ls);
982: BVRestoreColumn(W,deg-1,&w);
983: BVGetColumn(W,deg-2,&w);
984: BVMultVec(V,1.0,0.0,w,r+(deg-2)*lr);
985: BVRestoreColumn(W,deg-2,&w);
986: for (k=deg-2;k>0;k--) {
987: if (PetscAbsScalar(s[k-1]-sigma)<100*PETSC_MACHINE_EPSILON) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_CONV_FAILED,"Breakdown in NLEIGS");
988: for (j=0;j<nv;j++) r[(k-1)*lr+j] = (S[(k-1)*ls+j]+(beta[k]/xi[k-1])*S[k*ls+j]-beta[k]*(1.0-sigma/xi[k-1])*r[(k)*lr+j])/(s[k-1]-sigma);
989: BVGetColumn(W,k-1,&w);
990: BVMultVec(V,1.0,0.0,w,r+(k-1)*lr);
991: BVRestoreColumn(W,k-1,&w);
992: }
993: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
994: for (j=0;j<ctx->nmat-2;j++) coeffs[j] = ctx->coeffD[nep->nt*j];
995: coeffs[ctx->nmat-2] = ctx->coeffD[nep->nt*(ctx->nmat-1)];
996: BVMultVec(W,1.0,0.0,v,coeffs);
997: MatMult(nep->A[0],v,q);
998: for (k=1;k<nep->nt;k++) {
999: for (j=0;j<ctx->nmat-2;j++) coeffs[j] = ctx->coeffD[nep->nt*j+k];
1000: coeffs[ctx->nmat-2] = ctx->coeffD[nep->nt*(ctx->nmat-1)+k];
1001: BVMultVec(W,1.0,0,v,coeffs);
1002: MatMult(nep->A[k],v,t);
1003: VecAXPY(q,1.0,t);
1004: }
1005: KSPSolve(ctx->ksp[idxrktg],q,t);
1006: VecScale(t,-1.0);
1007: } else {
1008: for (k=0;k<deg-1;k++) {
1009: BVGetColumn(W,k,&w);
1010: MatMult(ctx->D[k],w,q);
1011: BVRestoreColumn(W,k,&w);
1012: BVInsertVec(W,k,q);
1013: }
1014: BVGetColumn(W,deg-1,&w);
1015: MatMult(ctx->D[deg],w,q);
1016: BVRestoreColumn(W,k,&w);
1017: BVInsertVec(W,k,q);
1018: for (j=0;j<ctx->nmat-1;j++) coeffs[j] = 1.0;
1019: BVMultVec(W,1.0,0.0,q,coeffs);
1020: KSPSolve(ctx->ksp[idxrktg],q,t);
1021: VecScale(t,-1.0);
1022: }
1023: PetscFree(coeffs);
1024: return(0);
1025: }
1027: /*
1028: Compute TOAR coefficients of the blocks of the new Arnoldi vector computed
1029: */
1030: static PetscErrorCode NEPTOARCoefficients(NEP nep,PetscScalar sigma,PetscInt nv,PetscScalar *S,PetscInt ls,PetscScalar *r,PetscInt lr,PetscScalar *x,PetscScalar *work)
1031: {
1033: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1034: PetscInt k,j,d=ctx->nmat-1;
1035: PetscScalar *t=work;
1038: NEPNLEIGSEvalNRTFunct(nep,d-1,sigma,t);
1039: for (k=0;k<d-1;k++) {
1040: for (j=0;j<=nv;j++) r[k*lr+j] += t[k]*x[j];
1041: }
1042: for (j=0;j<=nv;j++) r[(d-1)*lr+j] = t[d-1]*x[j];
1043: return(0);
1044: }
1046: /*
1047: Compute continuation vector coefficients for the Rational-Krylov run.
1048: dim(work) >= (end-ini)*(end-ini+1) + end+1 + 2*(end-ini+1), dim(t) = end.
1049: */
1050: static PetscErrorCode NEPNLEIGS_RKcontinuation(NEP nep,PetscInt ini,PetscInt end,PetscScalar *K,PetscScalar *H,PetscInt ld,PetscScalar sigma,PetscScalar *S,PetscInt lds,PetscScalar *cont,PetscScalar *t,PetscScalar *work)
1051: {
1053: PetscScalar *x,*W,*tau,sone=1.0,szero=0.0;
1054: PetscInt i,j,n1,n,nwu=0;
1055: PetscBLASInt info,n_,n1_,one=1,dim,lds_;
1056: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
1059: if (!ctx->nshifts || !end) {
1060: t[0] = 1;
1061: PetscArraycpy(cont,S+end*lds,lds);
1062: } else {
1063: n = end-ini;
1064: n1 = n+1;
1065: x = work+nwu;
1066: nwu += end+1;
1067: tau = work+nwu;
1068: nwu += n;
1069: W = work+nwu;
1070: nwu += n1*n;
1071: for (j=ini;j<end;j++) {
1072: for (i=ini;i<=end;i++) W[(j-ini)*n1+i-ini] = K[j*ld+i] -H[j*ld+i]*sigma;
1073: }
1074: PetscBLASIntCast(n,&n_);
1075: PetscBLASIntCast(n1,&n1_);
1076: PetscBLASIntCast(end+1,&dim);
1077: PetscFPTrapPush(PETSC_FP_TRAP_OFF);
1078: PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&n1_,&n_,W,&n1_,tau,work+nwu,&n1_,&info));
1079: SlepcCheckLapackInfo("geqrf",info);
1080: for (i=0;i<end;i++) t[i] = 0.0;
1081: t[end] = 1.0;
1082: for (j=n-1;j>=0;j--) {
1083: for (i=0;i<ini+j;i++) x[i] = 0.0;
1084: x[ini+j] = 1.0;
1085: for (i=j+1;i<n1;i++) x[i+ini] = W[i+n1*j];
1086: tau[j] = PetscConj(tau[j]);
1087: PetscStackCallBLAS("LAPACKlarf",LAPACKlarf_("L",&dim,&one,x,&one,tau+j,t,&dim,work+nwu));
1088: }
1089: PetscBLASIntCast(lds,&lds_);
1090: PetscStackCallBLAS("BLASgemv",BLASgemv_("N",&lds_,&n1_,&sone,S,&lds_,t,&one,&szero,cont,&one));
1091: PetscFPTrapPop();
1092: }
1093: return(0);
1094: }
1096: /*
1097: Compute a run of Arnoldi iterations
1098: */
1099: PetscErrorCode NEPNLEIGSTOARrun(NEP nep,PetscScalar *K,PetscScalar *H,PetscInt ldh,BV W,PetscInt k,PetscInt *M,PetscBool *breakdown,Vec *t_)
1100: {
1102: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
1103: PetscInt i,j,m=*M,lwa,deg=ctx->nmat-1,lds,nqt,ld,l;
1104: Vec t;
1105: PetscReal norm;
1106: PetscScalar *x,*work,*tt,sigma,*cont,*S;
1107: PetscBool lindep;
1108: Mat MS;
1111: BVTensorGetFactors(ctx->V,NULL,&MS);
1112: MatDenseGetArray(MS,&S);
1113: BVGetSizes(nep->V,NULL,NULL,&ld);
1114: lds = ld*deg;
1115: BVGetActiveColumns(nep->V,&l,&nqt);
1116: lwa = PetscMax(ld,deg)+(m+1)*(m+1)+4*(m+1);
1117: PetscMalloc4(ld,&x,lwa,&work,m+1,&tt,lds,&cont);
1118: BVSetActiveColumns(ctx->V,0,m);
1119: for (j=k;j<m;j++) {
1120: sigma = ctx->shifts[(++(ctx->idxrk))%ctx->nshiftsw];
1122: /* Continuation vector */
1123: NEPNLEIGS_RKcontinuation(nep,0,j,K,H,ldh,sigma,S,lds,cont,tt,work);
1125: /* apply operator */
1126: BVGetColumn(nep->V,nqt,&t);
1127: NEPTOARExtendBasis(nep,(ctx->idxrk)%ctx->nshiftsw,cont,ld,nqt,W,nep->V,t,S+(j+1)*lds,ld,t_);
1128: BVRestoreColumn(nep->V,nqt,&t);
1130: /* orthogonalize */
1131: BVOrthogonalizeColumn(nep->V,nqt,x,&norm,&lindep);
1132: if (!lindep) {
1133: x[nqt] = norm;
1134: BVScaleColumn(nep->V,nqt,1.0/norm);
1135: nqt++;
1136: } else x[nqt] = 0.0;
1138: NEPTOARCoefficients(nep,sigma,nqt-1,cont,ld,S+(j+1)*lds,ld,x,work);
1140: /* Level-2 orthogonalization */
1141: BVOrthogonalizeColumn(ctx->V,j+1,H+j*ldh,&norm,breakdown);
1142: H[j+1+ldh*j] = norm;
1143: if (ctx->nshifts) {
1144: for (i=0;i<=j;i++) K[i+ldh*j] = sigma*H[i+ldh*j] + tt[i];
1145: K[j+1+ldh*j] = sigma*H[j+1+ldh*j];
1146: }
1147: if (*breakdown) {
1148: *M = j+1;
1149: break;
1150: }
1151: BVScaleColumn(ctx->V,j+1,1.0/norm);
1152: BVSetActiveColumns(nep->V,l,nqt);
1153: }
1154: PetscFree4(x,work,tt,cont);
1155: MatDenseRestoreArray(MS,&S);
1156: BVTensorRestoreFactors(ctx->V,NULL,&MS);
1157: return(0);
1158: }
1160: PetscErrorCode NEPSolve_NLEIGS(NEP nep)
1161: {
1162: PetscErrorCode ierr;
1163: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
1164: PetscInt i,k=0,l,nv=0,ld,lds,ldds,nq;
1165: PetscInt deg=ctx->nmat-1,nconv=0,dsn,dsk;
1166: PetscScalar *H,*pU,*K,betak=0,*eigr,*eigi;
1167: const PetscScalar *S;
1168: PetscReal betah;
1169: PetscBool falselock=PETSC_FALSE,breakdown=PETSC_FALSE;
1170: BV W;
1171: Mat MS,MQ,U;
1174: if (ctx->lock) {
1175: /* undocumented option to use a cheaper locking instead of the true locking */
1176: PetscOptionsGetBool(NULL,NULL,"-nep_nleigs_falselocking",&falselock,NULL);
1177: }
1179: BVGetSizes(nep->V,NULL,NULL,&ld);
1180: lds = deg*ld;
1181: DSGetLeadingDimension(nep->ds,&ldds);
1182: if (!ctx->nshifts) {
1183: PetscMalloc2(nep->ncv,&eigr,nep->ncv,&eigi);
1184: } else { eigr = nep->eigr; eigi = nep->eigi; }
1185: BVDuplicateResize(nep->V,PetscMax(nep->nt-1,ctx->nmat-1),&W);
1187: /* clean projected matrix (including the extra-arrow) */
1188: DSGetArray(nep->ds,DS_MAT_A,&H);
1189: PetscArrayzero(H,ldds*ldds);
1190: DSRestoreArray(nep->ds,DS_MAT_A,&H);
1191: if (ctx->nshifts) {
1192: DSGetArray(nep->ds,DS_MAT_B,&H);
1193: PetscArrayzero(H,ldds*ldds);
1194: DSRestoreArray(nep->ds,DS_MAT_B,&H);
1195: }
1197: /* Get the starting Arnoldi vector */
1198: BVTensorBuildFirstColumn(ctx->V,nep->nini);
1200: /* Restart loop */
1201: l = 0;
1202: while (nep->reason == NEP_CONVERGED_ITERATING) {
1203: nep->its++;
1205: /* Compute an nv-step Krylov relation */
1206: nv = PetscMin(nep->nconv+nep->mpd,nep->ncv);
1207: if (ctx->nshifts) { DSGetArray(nep->ds,DS_MAT_A,&K); }
1208: DSGetArray(nep->ds,ctx->nshifts?DS_MAT_B:DS_MAT_A,&H);
1209: NEPNLEIGSTOARrun(nep,K,H,ldds,W,nep->nconv+l,&nv,&breakdown,nep->work);
1210: betah = PetscAbsScalar(H[(nv-1)*ldds+nv]);
1211: DSRestoreArray(nep->ds,ctx->nshifts?DS_MAT_B:DS_MAT_A,&H);
1212: if (ctx->nshifts) {
1213: betak = K[(nv-1)*ldds+nv];
1214: DSRestoreArray(nep->ds,DS_MAT_A,&K);
1215: }
1216: DSSetDimensions(nep->ds,nv,nep->nconv,nep->nconv+l);
1217: if (l==0) {
1218: DSSetState(nep->ds,DS_STATE_INTERMEDIATE);
1219: } else {
1220: DSSetState(nep->ds,DS_STATE_RAW);
1221: }
1223: /* Solve projected problem */
1224: DSSolve(nep->ds,nep->eigr,nep->eigi);
1225: DSSort(nep->ds,nep->eigr,nep->eigi,NULL,NULL,NULL);
1226: DSUpdateExtraRow(nep->ds);
1227: DSSynchronize(nep->ds,nep->eigr,nep->eigi);
1229: /* Check convergence */
1230: NEPNLEIGSKrylovConvergence(nep,PETSC_FALSE,nep->nconv,nv-nep->nconv,betah,betak,&k,nep->work);
1231: (*nep->stopping)(nep,nep->its,nep->max_it,k,nep->nev,&nep->reason,nep->stoppingctx);
1233: /* Update l */
1234: if (nep->reason != NEP_CONVERGED_ITERATING || breakdown) l = 0;
1235: else {
1236: l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
1237: DSGetTruncateSize(nep->ds,k,nv,&l);
1238: if (!breakdown) {
1239: /* Prepare the Rayleigh quotient for restart */
1240: DSGetDimensions(nep->ds,&dsn,NULL,&dsk,NULL);
1241: DSSetDimensions(nep->ds,dsn,k,dsk);
1242: DSTruncate(nep->ds,k+l,PETSC_FALSE);
1243: }
1244: }
1245: nconv = k;
1246: if (!ctx->lock && nep->reason == NEP_CONVERGED_ITERATING && !breakdown) { l += k; k = 0; }
1247: if (l) { PetscInfo1(nep,"Preparing to restart keeping l=%D vectors\n",l); }
1249: /* Update S */
1250: DSGetMat(nep->ds,ctx->nshifts?DS_MAT_Z:DS_MAT_Q,&MQ);
1251: BVMultInPlace(ctx->V,MQ,nep->nconv,k+l);
1252: MatDestroy(&MQ);
1254: /* Copy last column of S */
1255: BVCopyColumn(ctx->V,nv,k+l);
1257: if (breakdown && nep->reason == NEP_CONVERGED_ITERATING) {
1258: /* Stop if breakdown */
1259: PetscInfo2(nep,"Breakdown (it=%D norm=%g)\n",nep->its,(double)betah);
1260: nep->reason = NEP_DIVERGED_BREAKDOWN;
1261: }
1262: if (nep->reason != NEP_CONVERGED_ITERATING) l--;
1263: /* truncate S */
1264: BVGetActiveColumns(nep->V,NULL,&nq);
1265: if (k+l+deg<=nq) {
1266: BVSetActiveColumns(ctx->V,nep->nconv,k+l+1);
1267: if (!falselock && ctx->lock) {
1268: BVTensorCompress(ctx->V,k-nep->nconv);
1269: } else {
1270: BVTensorCompress(ctx->V,0);
1271: }
1272: }
1273: nep->nconv = k;
1274: if (!ctx->nshifts) {
1275: for (i=0;i<nv;i++) { eigr[i] = nep->eigr[i]; eigi[i] = nep->eigi[i]; }
1276: NEPNLEIGSBackTransform((PetscObject)nep,nv,eigr,eigi);
1277: }
1278: NEPMonitor(nep,nep->its,nconv,eigr,eigi,nep->errest,nv);
1279: }
1280: nep->nconv = nconv;
1281: if (nep->nconv>0) {
1282: BVSetActiveColumns(ctx->V,0,nep->nconv);
1283: BVGetActiveColumns(nep->V,NULL,&nq);
1284: BVSetActiveColumns(nep->V,0,nq);
1285: if (nq>nep->nconv) {
1286: BVTensorCompress(ctx->V,nep->nconv);
1287: BVSetActiveColumns(nep->V,0,nep->nconv);
1288: nq = nep->nconv;
1289: }
1290: if (ctx->nshifts) {
1291: DSGetMat(nep->ds,DS_MAT_B,&MQ);
1292: BVMultInPlace(ctx->V,MQ,0,nep->nconv);
1293: MatDestroy(&MQ);
1294: }
1295: BVTensorGetFactors(ctx->V,NULL,&MS);
1296: MatDenseGetArrayRead(MS,&S);
1297: PetscMalloc1(nq*nep->nconv,&pU);
1298: for (i=0;i<nep->nconv;i++) {
1299: PetscArraycpy(pU+i*nq,S+i*lds,nq);
1300: }
1301: MatDenseRestoreArrayRead(MS,&S);
1302: BVTensorRestoreFactors(ctx->V,NULL,&MS);
1303: MatCreateSeqDense(PETSC_COMM_SELF,nq,nep->nconv,pU,&U);
1304: BVSetActiveColumns(nep->V,0,nq);
1305: BVMultInPlace(nep->V,U,0,nep->nconv);
1306: BVSetActiveColumns(nep->V,0,nep->nconv);
1307: MatDestroy(&U);
1308: PetscFree(pU);
1309: DSTruncate(nep->ds,nep->nconv,PETSC_TRUE);
1310: }
1312: /* Map eigenvalues back to the original problem */
1313: if (!ctx->nshifts) {
1314: NEPNLEIGSBackTransform((PetscObject)nep,nep->nconv,nep->eigr,nep->eigi);
1315: PetscFree2(eigr,eigi);
1316: }
1317: BVDestroy(&W);
1318: return(0);
1319: }
1321: static PetscErrorCode NEPNLEIGSSetSingularitiesFunction_NLEIGS(NEP nep,PetscErrorCode (*fun)(NEP,PetscInt*,PetscScalar*,void*),void *ctx)
1322: {
1323: NEP_NLEIGS *nepctx=(NEP_NLEIGS*)nep->data;
1326: if (fun) nepctx->computesingularities = fun;
1327: if (ctx) nepctx->singularitiesctx = ctx;
1328: nep->state = NEP_STATE_INITIAL;
1329: return(0);
1330: }
1332: /*@C
1333: NEPNLEIGSSetSingularitiesFunction - Sets a user function to compute a discretization
1334: of the singularity set (where T(.) is not analytic).
1336: Logically Collective on nep
1338: Input Parameters:
1339: + nep - the NEP context
1340: . fun - user function (if NULL then NEP retains any previously set value)
1341: - ctx - [optional] user-defined context for private data for the function
1342: (may be NULL, in which case NEP retains any previously set value)
1344: Calling Sequence of fun:
1345: $ fun(NEP nep,PetscInt *maxnp,PetscScalar *xi,void *ctx)
1347: + nep - the NEP context
1348: . maxnp - on input number of requested points in the discretization (can be set)
1349: . xi - computed values of the discretization
1350: - ctx - optional context, as set by NEPNLEIGSSetSingularitiesFunction()
1352: Notes:
1353: The user-defined function can set a smaller value of maxnp if necessary.
1354: It is wrong to return a larger value.
1356: If the problem type has been set to rational with NEPSetProblemType(),
1357: then it is not necessary to set the singularities explicitly since the
1358: solver will try to determine them automatically.
1360: Level: intermediate
1362: .seealso: NEPNLEIGSGetSingularitiesFunction(), NEPSetProblemType()
1363: @*/
1364: PetscErrorCode NEPNLEIGSSetSingularitiesFunction(NEP nep,PetscErrorCode (*fun)(NEP,PetscInt*,PetscScalar*,void*),void *ctx)
1365: {
1370: PetscTryMethod(nep,"NEPNLEIGSSetSingularitiesFunction_C",(NEP,PetscErrorCode(*)(NEP,PetscInt*,PetscScalar*,void*),void*),(nep,fun,ctx));
1371: return(0);
1372: }
1374: static PetscErrorCode NEPNLEIGSGetSingularitiesFunction_NLEIGS(NEP nep,PetscErrorCode (**fun)(NEP,PetscInt*,PetscScalar*,void*),void **ctx)
1375: {
1376: NEP_NLEIGS *nepctx=(NEP_NLEIGS*)nep->data;
1379: if (fun) *fun = nepctx->computesingularities;
1380: if (ctx) *ctx = nepctx->singularitiesctx;
1381: return(0);
1382: }
1384: /*@C
1385: NEPNLEIGSGetSingularitiesFunction - Returns the Function and optionally the user
1386: provided context for computing a discretization of the singularity set.
1388: Not Collective
1390: Input Parameter:
1391: . nep - the nonlinear eigensolver context
1393: Output Parameters:
1394: + fun - location to put the function (or NULL)
1395: - ctx - location to stash the function context (or NULL)
1397: Level: advanced
1399: .seealso: NEPNLEIGSSetSingularitiesFunction()
1400: @*/
1401: PetscErrorCode NEPNLEIGSGetSingularitiesFunction(NEP nep,PetscErrorCode (**fun)(NEP,PetscInt*,PetscScalar*,void*),void **ctx)
1402: {
1407: PetscUseMethod(nep,"NEPNLEIGSGetSingularitiesFunction_C",(NEP,PetscErrorCode(**)(NEP,PetscInt*,PetscScalar*,void*),void**),(nep,fun,ctx));
1408: return(0);
1409: }
1411: static PetscErrorCode NEPNLEIGSSetRestart_NLEIGS(NEP nep,PetscReal keep)
1412: {
1413: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1416: if (keep==PETSC_DEFAULT) ctx->keep = 0.5;
1417: else {
1418: if (keep<0.1 || keep>0.9) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The keep argument must be in the range [0.1,0.9]");
1419: ctx->keep = keep;
1420: }
1421: return(0);
1422: }
1424: /*@
1425: NEPNLEIGSSetRestart - Sets the restart parameter for the NLEIGS
1426: method, in particular the proportion of basis vectors that must be kept
1427: after restart.
1429: Logically Collective on nep
1431: Input Parameters:
1432: + nep - the nonlinear eigensolver context
1433: - keep - the number of vectors to be kept at restart
1435: Options Database Key:
1436: . -nep_nleigs_restart - Sets the restart parameter
1438: Notes:
1439: Allowed values are in the range [0.1,0.9]. The default is 0.5.
1441: Level: advanced
1443: .seealso: NEPNLEIGSGetRestart()
1444: @*/
1445: PetscErrorCode NEPNLEIGSSetRestart(NEP nep,PetscReal keep)
1446: {
1452: PetscTryMethod(nep,"NEPNLEIGSSetRestart_C",(NEP,PetscReal),(nep,keep));
1453: return(0);
1454: }
1456: static PetscErrorCode NEPNLEIGSGetRestart_NLEIGS(NEP nep,PetscReal *keep)
1457: {
1458: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1461: *keep = ctx->keep;
1462: return(0);
1463: }
1465: /*@
1466: NEPNLEIGSGetRestart - Gets the restart parameter used in the NLEIGS method.
1468: Not Collective
1470: Input Parameter:
1471: . nep - the nonlinear eigensolver context
1473: Output Parameter:
1474: . keep - the restart parameter
1476: Level: advanced
1478: .seealso: NEPNLEIGSSetRestart()
1479: @*/
1480: PetscErrorCode NEPNLEIGSGetRestart(NEP nep,PetscReal *keep)
1481: {
1487: PetscUseMethod(nep,"NEPNLEIGSGetRestart_C",(NEP,PetscReal*),(nep,keep));
1488: return(0);
1489: }
1491: static PetscErrorCode NEPNLEIGSSetLocking_NLEIGS(NEP nep,PetscBool lock)
1492: {
1493: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1496: ctx->lock = lock;
1497: return(0);
1498: }
1500: /*@
1501: NEPNLEIGSSetLocking - Choose between locking and non-locking variants of
1502: the NLEIGS method.
1504: Logically Collective on nep
1506: Input Parameters:
1507: + nep - the nonlinear eigensolver context
1508: - lock - true if the locking variant must be selected
1510: Options Database Key:
1511: . -nep_nleigs_locking - Sets the locking flag
1513: Notes:
1514: The default is to lock converged eigenpairs when the method restarts.
1515: This behaviour can be changed so that all directions are kept in the
1516: working subspace even if already converged to working accuracy (the
1517: non-locking variant).
1519: Level: advanced
1521: .seealso: NEPNLEIGSGetLocking()
1522: @*/
1523: PetscErrorCode NEPNLEIGSSetLocking(NEP nep,PetscBool lock)
1524: {
1530: PetscTryMethod(nep,"NEPNLEIGSSetLocking_C",(NEP,PetscBool),(nep,lock));
1531: return(0);
1532: }
1534: static PetscErrorCode NEPNLEIGSGetLocking_NLEIGS(NEP nep,PetscBool *lock)
1535: {
1536: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1539: *lock = ctx->lock;
1540: return(0);
1541: }
1543: /*@
1544: NEPNLEIGSGetLocking - Gets the locking flag used in the NLEIGS method.
1546: Not Collective
1548: Input Parameter:
1549: . nep - the nonlinear eigensolver context
1551: Output Parameter:
1552: . lock - the locking flag
1554: Level: advanced
1556: .seealso: NEPNLEIGSSetLocking()
1557: @*/
1558: PetscErrorCode NEPNLEIGSGetLocking(NEP nep,PetscBool *lock)
1559: {
1565: PetscUseMethod(nep,"NEPNLEIGSGetLocking_C",(NEP,PetscBool*),(nep,lock));
1566: return(0);
1567: }
1569: static PetscErrorCode NEPNLEIGSSetInterpolation_NLEIGS(NEP nep,PetscReal tol,PetscInt degree)
1570: {
1572: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1575: if (tol == PETSC_DEFAULT) {
1576: ctx->ddtol = PETSC_DEFAULT;
1577: nep->state = NEP_STATE_INITIAL;
1578: } else {
1579: if (tol <= 0.0) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of tol. Must be > 0");
1580: ctx->ddtol = tol;
1581: }
1582: if (degree == PETSC_DEFAULT || degree == PETSC_DECIDE) {
1583: ctx->ddmaxit = 0;
1584: if (nep->state) { NEPReset(nep); }
1585: nep->state = NEP_STATE_INITIAL;
1586: } else {
1587: if (degree <= 0) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of degree. Must be > 0");
1588: if (ctx->ddmaxit != degree) {
1589: ctx->ddmaxit = degree;
1590: if (nep->state) { NEPReset(nep); }
1591: nep->state = NEP_STATE_INITIAL;
1592: }
1593: }
1594: return(0);
1595: }
1597: /*@
1598: NEPNLEIGSSetInterpolation - Sets the tolerance and maximum degree
1599: when building the interpolation via divided differences.
1601: Logically Collective on nep
1603: Input Parameters:
1604: + nep - the nonlinear eigensolver context
1605: . tol - tolerance to stop computing divided differences
1606: - degree - maximum degree of interpolation
1608: Options Database Key:
1609: + -nep_nleigs_interpolation_tol <tol> - Sets the tolerance to stop computing divided differences
1610: - -nep_nleigs_interpolation_degree <degree> - Sets the maximum degree of interpolation
1612: Notes:
1613: Use PETSC_DEFAULT for either argument to assign a reasonably good value.
1615: Level: advanced
1617: .seealso: NEPNLEIGSGetInterpolation()
1618: @*/
1619: PetscErrorCode NEPNLEIGSSetInterpolation(NEP nep,PetscReal tol,PetscInt degree)
1620: {
1627: PetscTryMethod(nep,"NEPNLEIGSSetInterpolation_C",(NEP,PetscReal,PetscInt),(nep,tol,degree));
1628: return(0);
1629: }
1631: static PetscErrorCode NEPNLEIGSGetInterpolation_NLEIGS(NEP nep,PetscReal *tol,PetscInt *degree)
1632: {
1633: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1636: if (tol) *tol = ctx->ddtol;
1637: if (degree) *degree = ctx->ddmaxit;
1638: return(0);
1639: }
1641: /*@
1642: NEPNLEIGSGetInterpolation - Gets the tolerance and maximum degree
1643: when building the interpolation via divided differences.
1645: Not Collective
1647: Input Parameter:
1648: . nep - the nonlinear eigensolver context
1650: Output Parameters:
1651: + tol - tolerance to stop computing divided differences
1652: - degree - maximum degree of interpolation
1654: Level: advanced
1656: .seealso: NEPNLEIGSSetInterpolation()
1657: @*/
1658: PetscErrorCode NEPNLEIGSGetInterpolation(NEP nep,PetscReal *tol,PetscInt *degree)
1659: {
1664: PetscTryMethod(nep,"NEPNLEIGSGetInterpolation_C",(NEP,PetscReal*,PetscInt*),(nep,tol,degree));
1665: return(0);
1666: }
1668: static PetscErrorCode NEPNLEIGSSetRKShifts_NLEIGS(NEP nep,PetscInt ns,PetscScalar *shifts)
1669: {
1671: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1672: PetscInt i;
1675: if (ns<0) SETERRQ(PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONG,"Number of shifts must be non-negative");
1676: if (ctx->nshifts) { PetscFree(ctx->shifts); }
1677: for (i=0;i<ctx->nshiftsw;i++) { KSPDestroy(&ctx->ksp[i]); }
1678: PetscFree(ctx->ksp);
1679: ctx->ksp = NULL;
1680: if (ns) {
1681: PetscMalloc1(ns,&ctx->shifts);
1682: for (i=0;i<ns;i++) ctx->shifts[i] = shifts[i];
1683: }
1684: ctx->nshifts = ns;
1685: nep->state = NEP_STATE_INITIAL;
1686: return(0);
1687: }
1689: /*@
1690: NEPNLEIGSSetRKShifts - Sets a list of shifts to be used in the Rational
1691: Krylov method.
1693: Logically Collective on nep
1695: Input Parameters:
1696: + nep - the nonlinear eigensolver context
1697: . ns - number of shifts
1698: - shifts - array of scalar values specifying the shifts
1700: Options Database Key:
1701: . -nep_nleigs_rk_shifts - Sets the list of shifts
1703: Notes:
1704: If only one shift is provided, the built subspace built is equivalent to
1705: shift-and-invert Krylov-Schur (provided that the absolute convergence
1706: criterion is used).
1708: In the case of real scalars, complex shifts are not allowed. In the
1709: command line, a comma-separated list of complex values can be provided with
1710: the format [+/-][realnumber][+/-]realnumberi with no spaces, e.g.
1711: -nep_nleigs_rk_shifts 1.0+2.0i,1.5+2.0i,1.0+1.5i
1713: Use ns=0 to remove previously set shifts.
1715: Level: advanced
1717: .seealso: NEPNLEIGSGetRKShifts()
1718: @*/
1719: PetscErrorCode NEPNLEIGSSetRKShifts(NEP nep,PetscInt ns,PetscScalar shifts[])
1720: {
1727: PetscTryMethod(nep,"NEPNLEIGSSetRKShifts_C",(NEP,PetscInt,PetscScalar*),(nep,ns,shifts));
1728: return(0);
1729: }
1731: static PetscErrorCode NEPNLEIGSGetRKShifts_NLEIGS(NEP nep,PetscInt *ns,PetscScalar **shifts)
1732: {
1734: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1735: PetscInt i;
1738: *ns = ctx->nshifts;
1739: if (ctx->nshifts) {
1740: PetscMalloc1(ctx->nshifts,shifts);
1741: for (i=0;i<ctx->nshifts;i++) (*shifts)[i] = ctx->shifts[i];
1742: }
1743: return(0);
1744: }
1746: /*@C
1747: NEPNLEIGSGetRKShifts - Gets the list of shifts used in the Rational
1748: Krylov method.
1750: Not Collective
1752: Input Parameter:
1753: . nep - the nonlinear eigensolver context
1755: Output Parameters:
1756: + ns - number of shifts
1757: - shifts - array of shifts
1759: Note:
1760: The user is responsible for deallocating the returned array.
1762: Level: advanced
1764: .seealso: NEPNLEIGSSetRKShifts()
1765: @*/
1766: PetscErrorCode NEPNLEIGSGetRKShifts(NEP nep,PetscInt *ns,PetscScalar *shifts[])
1767: {
1774: PetscTryMethod(nep,"NEPNLEIGSGetRKShifts_C",(NEP,PetscInt*,PetscScalar**),(nep,ns,shifts));
1775: return(0);
1776: }
1778: static PetscErrorCode NEPNLEIGSGetKSPs_NLEIGS(NEP nep,PetscInt *nsolve,KSP **ksp)
1779: {
1781: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
1782: PetscInt i;
1783: PC pc;
1786: if (!ctx->ksp) {
1787: NEPNLEIGSSetShifts(nep,&ctx->nshiftsw);
1788: PetscMalloc1(ctx->nshiftsw,&ctx->ksp);
1789: for (i=0;i<ctx->nshiftsw;i++) {
1790: KSPCreate(PetscObjectComm((PetscObject)nep),&ctx->ksp[i]);
1791: PetscObjectIncrementTabLevel((PetscObject)ctx->ksp[i],(PetscObject)nep,1);
1792: KSPSetOptionsPrefix(ctx->ksp[i],((PetscObject)nep)->prefix);
1793: KSPAppendOptionsPrefix(ctx->ksp[i],"nep_nleigs_");
1794: PetscLogObjectParent((PetscObject)nep,(PetscObject)ctx->ksp[i]);
1795: PetscObjectSetOptions((PetscObject)ctx->ksp[i],((PetscObject)nep)->options);
1796: KSPSetErrorIfNotConverged(ctx->ksp[i],PETSC_TRUE);
1797: KSPSetTolerances(ctx->ksp[i],SlepcDefaultTol(nep->tol),PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
1798: KSPGetPC(ctx->ksp[i],&pc);
1799: KSPSetType(ctx->ksp[i],KSPPREONLY);
1800: PCSetType(pc,PCLU);
1801: }
1802: }
1803: if (nsolve) *nsolve = ctx->nshiftsw;
1804: if (ksp) *ksp = ctx->ksp;
1805: return(0);
1806: }
1808: /*@C
1809: NEPNLEIGSGetKSPs - Retrieve the array of linear solver objects associated with
1810: the nonlinear eigenvalue solver.
1812: Not Collective
1814: Input Parameter:
1815: . nep - nonlinear eigenvalue solver
1817: Output Parameters:
1818: + nsolve - number of returned KSP objects
1819: - ksp - array of linear solver object
1821: Notes:
1822: The number of KSP objects is equal to the number of shifts provided by the user,
1823: or 1 if the user did not provide shifts.
1825: Level: advanced
1827: .seealso: NEPNLEIGSSetRKShifts()
1828: @*/
1829: PetscErrorCode NEPNLEIGSGetKSPs(NEP nep,PetscInt *nsolve,KSP **ksp)
1830: {
1835: PetscUseMethod(nep,"NEPNLEIGSGetKSPs_C",(NEP,PetscInt*,KSP**),(nep,nsolve,ksp));
1836: return(0);
1837: }
1839: static PetscErrorCode NEPNLEIGSSetFullBasis_NLEIGS(NEP nep,PetscBool fullbasis)
1840: {
1841: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1844: if (fullbasis!=ctx->fullbasis) {
1845: ctx->fullbasis = fullbasis;
1846: nep->state = NEP_STATE_INITIAL;
1847: nep->useds = PetscNot(fullbasis);
1848: }
1849: return(0);
1850: }
1852: /*@
1853: NEPNLEIGSSetFullBasis - Choose between TOAR-basis (default) and full-basis
1854: variants of the NLEIGS method.
1856: Logically Collective on nep
1858: Input Parameters:
1859: + nep - the nonlinear eigensolver context
1860: - fullbasis - true if the full-basis variant must be selected
1862: Options Database Key:
1863: . -nep_nleigs_full_basis - Sets the full-basis flag
1865: Notes:
1866: The default is to use a compact representation of the Krylov basis, that is,
1867: V = (I otimes U) S, with a tensor BV. This behaviour can be changed so that
1868: the full basis V is explicitly stored and operated with. This variant is more
1869: expensive in terms of memory and computation, but is necessary in some cases,
1870: particularly for two-sided computations, see NEPSetTwoSided().
1872: In the full-basis variant, the NLEIGS solver uses an EPS object to explicitly
1873: solve the linearized eigenproblem, see NEPNLEIGSGetEPS().
1875: Level: advanced
1877: .seealso: NEPNLEIGSGetFullBasis(), NEPNLEIGSGetEPS(), NEPSetTwoSided(), BVCreateTensor()
1878: @*/
1879: PetscErrorCode NEPNLEIGSSetFullBasis(NEP nep,PetscBool fullbasis)
1880: {
1886: PetscTryMethod(nep,"NEPNLEIGSSetFullBasis_C",(NEP,PetscBool),(nep,fullbasis));
1887: return(0);
1888: }
1890: static PetscErrorCode NEPNLEIGSGetFullBasis_NLEIGS(NEP nep,PetscBool *fullbasis)
1891: {
1892: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1895: *fullbasis = ctx->fullbasis;
1896: return(0);
1897: }
1899: /*@
1900: NEPNLEIGSGetFullBasis - Gets the flag that indicates if NLEIGS is using the
1901: full-basis variant.
1903: Not Collective
1905: Input Parameter:
1906: . nep - the nonlinear eigensolver context
1908: Output Parameter:
1909: . fullbasis - the flag
1911: Level: advanced
1913: .seealso: NEPNLEIGSSetFullBasis()
1914: @*/
1915: PetscErrorCode NEPNLEIGSGetFullBasis(NEP nep,PetscBool *fullbasis)
1916: {
1922: PetscUseMethod(nep,"NEPNLEIGSGetFullBasis_C",(NEP,PetscBool*),(nep,fullbasis));
1923: return(0);
1924: }
1926: #define SHIFTMAX 30
1928: PetscErrorCode NEPSetFromOptions_NLEIGS(PetscOptionItems *PetscOptionsObject,NEP nep)
1929: {
1931: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
1932: PetscInt i=0,k;
1933: PetscBool flg1,flg2,b;
1934: PetscReal r;
1935: PetscScalar array[SHIFTMAX];
1938: PetscOptionsHead(PetscOptionsObject,"NEP NLEIGS Options");
1940: PetscOptionsReal("-nep_nleigs_restart","Proportion of vectors kept after restart","NEPNLEIGSSetRestart",0.5,&r,&flg1);
1941: if (flg1) { NEPNLEIGSSetRestart(nep,r); }
1943: PetscOptionsBool("-nep_nleigs_locking","Choose between locking and non-locking variants","NEPNLEIGSSetLocking",PETSC_FALSE,&b,&flg1);
1944: if (flg1) { NEPNLEIGSSetLocking(nep,b); }
1946: PetscOptionsBool("-nep_nleigs_full_basis","Choose between TOAR and full-basis variants","NEPNLEIGSSetFullBasis",PETSC_FALSE,&b,&flg1);
1947: if (flg1) { NEPNLEIGSSetFullBasis(nep,b); }
1949: NEPNLEIGSGetInterpolation(nep,&r,&i);
1950: if (!i) i = PETSC_DEFAULT;
1951: PetscOptionsInt("-nep_nleigs_interpolation_degree","Maximum number of terms for interpolation via divided differences","NEPNLEIGSSetInterpolation",i,&i,&flg1);
1952: PetscOptionsReal("-nep_nleigs_interpolation_tol","Tolerance for interpolation via divided differences","NEPNLEIGSSetInterpolation",r,&r,&flg2);
1953: if (flg1 || flg2) { NEPNLEIGSSetInterpolation(nep,r,i); }
1955: k = SHIFTMAX;
1956: for (i=0;i<k;i++) array[i] = 0;
1957: PetscOptionsScalarArray("-nep_nleigs_rk_shifts","Shifts for Rational Krylov","NEPNLEIGSSetRKShifts",array,&k,&flg1);
1958: if (flg1) { NEPNLEIGSSetRKShifts(nep,k,array); }
1960: PetscOptionsTail();
1962: if (!ctx->ksp) { NEPNLEIGSGetKSPs(nep,&ctx->nshiftsw,&ctx->ksp); }
1963: for (i=0;i<ctx->nshiftsw;i++) {
1964: KSPSetFromOptions(ctx->ksp[i]);
1965: }
1967: if (ctx->fullbasis) {
1968: if (!ctx->eps) { NEPNLEIGSGetEPS(nep,&ctx->eps); }
1969: EPSSetFromOptions(ctx->eps);
1970: }
1971: return(0);
1972: }
1974: PetscErrorCode NEPView_NLEIGS(NEP nep,PetscViewer viewer)
1975: {
1977: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
1978: PetscBool isascii;
1979: PetscInt i;
1980: char str[50];
1983: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
1984: if (isascii) {
1985: PetscViewerASCIIPrintf(viewer," %d%% of basis vectors kept after restart\n",(int)(100*ctx->keep));
1986: if (ctx->fullbasis) {
1987: PetscViewerASCIIPrintf(viewer," using the full-basis variant\n");
1988: } else {
1989: PetscViewerASCIIPrintf(viewer," using the %slocking variant\n",ctx->lock?"":"non-");
1990: }
1991: PetscViewerASCIIPrintf(viewer," divided difference terms: used=%D, max=%D\n",ctx->nmat,ctx->ddmaxit);
1992: PetscViewerASCIIPrintf(viewer," tolerance for divided difference convergence: %g\n",(double)ctx->ddtol);
1993: if (ctx->nshifts) {
1994: PetscViewerASCIIPrintf(viewer," RK shifts: ");
1995: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
1996: for (i=0;i<ctx->nshifts;i++) {
1997: SlepcSNPrintfScalar(str,sizeof(str),ctx->shifts[i],PETSC_FALSE);
1998: PetscViewerASCIIPrintf(viewer,"%s%s",str,(i<ctx->nshifts-1)?",":"");
1999: }
2000: PetscViewerASCIIPrintf(viewer,"\n");
2001: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
2002: }
2003: if (!ctx->ksp) { NEPNLEIGSGetKSPs(nep,&ctx->nshiftsw,&ctx->ksp); }
2004: PetscViewerASCIIPushTab(viewer);
2005: KSPView(ctx->ksp[0],viewer);
2006: PetscViewerASCIIPopTab(viewer);
2007: if (ctx->fullbasis) {
2008: if (!ctx->eps) { NEPNLEIGSGetEPS(nep,&ctx->eps); }
2009: PetscViewerASCIIPushTab(viewer);
2010: EPSView(ctx->eps,viewer);
2011: PetscViewerASCIIPopTab(viewer);
2012: }
2013: }
2014: return(0);
2015: }
2017: PetscErrorCode NEPReset_NLEIGS(NEP nep)
2018: {
2020: PetscInt k;
2021: NEP_NLEIGS *ctx=(NEP_NLEIGS*)nep->data;
2024: if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
2025: PetscFree(ctx->coeffD);
2026: } else {
2027: for (k=0;k<ctx->nmat;k++) { MatDestroy(&ctx->D[k]); }
2028: }
2029: PetscFree4(ctx->s,ctx->xi,ctx->beta,ctx->D);
2030: for (k=0;k<ctx->nshiftsw;k++) { KSPReset(ctx->ksp[k]); }
2031: if (ctx->vrn) {
2032: VecDestroy(&ctx->vrn);
2033: }
2034: if (ctx->fullbasis) {
2035: MatDestroy(&ctx->A);
2036: EPSReset(ctx->eps);
2037: for (k=0;k<4;k++) { VecDestroy(&ctx->w[k]); }
2038: }
2039: return(0);
2040: }
2042: PetscErrorCode NEPDestroy_NLEIGS(NEP nep)
2043: {
2045: PetscInt k;
2046: NEP_NLEIGS *ctx = (NEP_NLEIGS*)nep->data;
2049: BVDestroy(&ctx->V);
2050: for (k=0;k<ctx->nshiftsw;k++) { KSPDestroy(&ctx->ksp[k]); }
2051: PetscFree(ctx->ksp);
2052: if (ctx->nshifts) { PetscFree(ctx->shifts); }
2053: if (ctx->fullbasis) { EPSDestroy(&ctx->eps); }
2054: PetscFree(nep->data);
2055: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetSingularitiesFunction_C",NULL);
2056: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetSingularitiesFunction_C",NULL);
2057: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetRestart_C",NULL);
2058: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetRestart_C",NULL);
2059: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetLocking_C",NULL);
2060: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetLocking_C",NULL);
2061: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetInterpolation_C",NULL);
2062: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetInterpolation_C",NULL);
2063: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetRKShifts_C",NULL);
2064: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetRKShifts_C",NULL);
2065: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetKSPs_C",NULL);
2066: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetFullBasis_C",NULL);
2067: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetFullBasis_C",NULL);
2068: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetEPS_C",NULL);
2069: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetEPS_C",NULL);
2070: return(0);
2071: }
2073: SLEPC_EXTERN PetscErrorCode NEPCreate_NLEIGS(NEP nep)
2074: {
2076: NEP_NLEIGS *ctx;
2079: PetscNewLog(nep,&ctx);
2080: nep->data = (void*)ctx;
2081: ctx->lock = PETSC_TRUE;
2082: ctx->ddtol = PETSC_DEFAULT;
2084: nep->useds = PETSC_TRUE;
2086: nep->ops->setup = NEPSetUp_NLEIGS;
2087: nep->ops->setfromoptions = NEPSetFromOptions_NLEIGS;
2088: nep->ops->view = NEPView_NLEIGS;
2089: nep->ops->destroy = NEPDestroy_NLEIGS;
2090: nep->ops->reset = NEPReset_NLEIGS;
2092: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetSingularitiesFunction_C",NEPNLEIGSSetSingularitiesFunction_NLEIGS);
2093: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetSingularitiesFunction_C",NEPNLEIGSGetSingularitiesFunction_NLEIGS);
2094: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetRestart_C",NEPNLEIGSSetRestart_NLEIGS);
2095: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetRestart_C",NEPNLEIGSGetRestart_NLEIGS);
2096: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetLocking_C",NEPNLEIGSSetLocking_NLEIGS);
2097: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetLocking_C",NEPNLEIGSGetLocking_NLEIGS);
2098: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetInterpolation_C",NEPNLEIGSSetInterpolation_NLEIGS);
2099: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetInterpolation_C",NEPNLEIGSGetInterpolation_NLEIGS);
2100: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetRKShifts_C",NEPNLEIGSSetRKShifts_NLEIGS);
2101: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetRKShifts_C",NEPNLEIGSGetRKShifts_NLEIGS);
2102: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetKSPs_C",NEPNLEIGSGetKSPs_NLEIGS);
2103: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetFullBasis_C",NEPNLEIGSSetFullBasis_NLEIGS);
2104: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetFullBasis_C",NEPNLEIGSGetFullBasis_NLEIGS);
2105: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSSetEPS_C",NEPNLEIGSSetEPS_NLEIGS);
2106: PetscObjectComposeFunction((PetscObject)nep,"NEPNLEIGSGetEPS_C",NEPNLEIGSGetEPS_NLEIGS);
2107: return(0);
2108: }