Line data Source code
1 : /*
2 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3 : SLEPc - Scalable Library for Eigenvalue Problem Computations
4 : Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
5 :
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: "ciss"
12 :
13 : Method: Contour Integral Spectral Slicing
14 :
15 : Algorithm:
16 :
17 : Contour integral based on Sakurai-Sugiura method to construct a
18 : subspace, with various eigenpair extractions (Rayleigh-Ritz,
19 : explicit moment).
20 :
21 : Based on code contributed by Y. Maeda, T. Sakurai.
22 :
23 : References:
24 :
25 : [1] J. Asakura, T. Sakurai, H. Tadano, T. Ikegami, K. Kimura, "A
26 : numerical method for nonlinear eigenvalue problems using contour
27 : integrals", JSIAM Lett. 1:52-55, 2009.
28 :
29 : [2] S. Yokota and T. Sakurai, "A projection method for nonlinear
30 : eigenvalue problems using contour integrals", JSIAM Lett.
31 : 5:41-44, 2013.
32 : */
33 :
34 : #include <slepc/private/nepimpl.h> /*I "slepcnep.h" I*/
35 : #include <slepc/private/slepccontour.h>
36 :
37 : typedef struct _n_nep_ciss_project *NEP_CISS_PROJECT;
38 : typedef struct {
39 : /* parameters */
40 : PetscInt N; /* number of integration points (32) */
41 : PetscInt L; /* block size (16) */
42 : PetscInt M; /* moment degree (N/4 = 4) */
43 : PetscReal delta; /* threshold of singular value (1e-12) */
44 : PetscInt L_max; /* maximum number of columns of the source matrix V */
45 : PetscReal spurious_threshold; /* discard spurious eigenpairs */
46 : PetscBool isreal; /* T(z) is real for real z */
47 : PetscInt npart; /* number of partitions */
48 : PetscInt refine_inner;
49 : PetscInt refine_blocksize;
50 : NEPCISSExtraction extraction;
51 : /* private data */
52 : SlepcContourData contour;
53 : PetscReal *sigma; /* threshold for numerical rank */
54 : PetscScalar *weight;
55 : PetscScalar *omega;
56 : PetscScalar *pp;
57 : BV V;
58 : BV S;
59 : BV Y;
60 : PetscBool useconj;
61 : Mat J; /* auxiliary matrix when using subcomm */
62 : BV pV;
63 : NEP_CISS_PROJECT dsctxf;
64 : PetscObjectId rgid;
65 : PetscObjectState rgstate;
66 : } NEP_CISS;
67 :
68 : struct _n_nep_ciss_project {
69 : NEP nep;
70 : BV Q;
71 : };
72 :
73 408 : static PetscErrorCode NEPContourDSComputeMatrix(DS ds,PetscScalar lambda,PetscBool deriv,DSMatType mat,void *ctx)
74 : {
75 408 : NEP_CISS_PROJECT proj = (NEP_CISS_PROJECT)ctx;
76 408 : Mat M,fun;
77 :
78 408 : PetscFunctionBegin;
79 408 : if (!deriv) {
80 408 : PetscCall(NEPComputeFunction(proj->nep,lambda,proj->nep->function,proj->nep->function));
81 408 : fun = proj->nep->function;
82 : } else {
83 0 : PetscCall(NEPComputeJacobian(proj->nep,lambda,proj->nep->jacobian));
84 0 : fun = proj->nep->jacobian;
85 : }
86 408 : PetscCall(DSGetMat(ds,mat,&M));
87 408 : PetscCall(BVMatProject(proj->Q,fun,proj->Q,M));
88 408 : PetscCall(DSRestoreMat(ds,mat,&M));
89 408 : PetscFunctionReturn(PETSC_SUCCESS);
90 : }
91 :
92 224 : static PetscErrorCode NEPComputeFunctionSubcomm(NEP nep,PetscScalar lambda,Mat T,Mat P,PetscBool deriv)
93 : {
94 224 : PetscInt i;
95 224 : PetscScalar alpha;
96 224 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
97 :
98 224 : PetscFunctionBegin;
99 224 : PetscAssert(nep->fui!=NEP_USER_INTERFACE_CALLBACK,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_WRONGSTATE,"Should not arrive here with callbacks");
100 224 : PetscCall(MatZeroEntries(T));
101 224 : if (!deriv && T != P) PetscCall(MatZeroEntries(P));
102 832 : for (i=0;i<nep->nt;i++) {
103 608 : if (!deriv) PetscCall(FNEvaluateFunction(nep->f[i],lambda,&alpha));
104 304 : else PetscCall(FNEvaluateDerivative(nep->f[i],lambda,&alpha));
105 608 : PetscCall(MatAXPY(T,alpha,ctx->contour->pA[i],nep->mstr));
106 608 : if (!deriv && T != P) PetscCall(MatAXPY(P,alpha,ctx->contour->pP[i],nep->mstrp));
107 : }
108 224 : PetscFunctionReturn(PETSC_SUCCESS);
109 : }
110 :
111 : /*
112 : Set up KSP solvers for every integration point
113 : */
114 40 : static PetscErrorCode NEPCISSSetUp(NEP nep,Mat T,Mat P)
115 : {
116 40 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
117 40 : SlepcContourData contour;
118 40 : PetscInt i,p_id;
119 40 : Mat Amat,Pmat;
120 :
121 40 : PetscFunctionBegin;
122 40 : if (!ctx->contour || !ctx->contour->ksp) PetscCall(NEPCISSGetKSPs(nep,NULL,NULL));
123 40 : contour = ctx->contour;
124 40 : PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Something went wrong with NEPCISSGetKSPs()");
125 840 : for (i=0;i<contour->npoints;i++) {
126 800 : p_id = i*contour->subcomm->n + contour->subcomm->color;
127 800 : PetscCall(MatDuplicate(T,MAT_DO_NOT_COPY_VALUES,&Amat));
128 800 : if (T != P) PetscCall(MatDuplicate(P,MAT_DO_NOT_COPY_VALUES,&Pmat)); else Pmat = Amat;
129 800 : if (contour->subcomm->n == 1 || nep->fui==NEP_USER_INTERFACE_CALLBACK) PetscCall(NEPComputeFunction(nep,ctx->omega[p_id],Amat,Pmat));
130 112 : else PetscCall(NEPComputeFunctionSubcomm(nep,ctx->omega[p_id],Amat,Pmat,PETSC_FALSE));
131 800 : PetscCall(NEP_KSPSetOperators(contour->ksp[i],Amat,Pmat));
132 800 : PetscCall(MatDestroy(&Amat));
133 800 : if (T != P) PetscCall(MatDestroy(&Pmat));
134 : }
135 40 : PetscFunctionReturn(PETSC_SUCCESS);
136 : }
137 :
138 : /*
139 : Y_i = F(z_i)^{-1}Fp(z_i)V for every integration point, Y=[Y_i] is in the context
140 : */
141 41 : static PetscErrorCode NEPCISSSolve(NEP nep,Mat dT,BV V,PetscInt L_start,PetscInt L_end)
142 : {
143 41 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
144 41 : SlepcContourData contour = ctx->contour;
145 41 : PetscInt i,p_id;
146 41 : Mat MV,BMV=NULL,MC;
147 :
148 41 : PetscFunctionBegin;
149 41 : PetscCall(BVSetActiveColumns(V,L_start,L_end));
150 41 : PetscCall(BVGetMat(V,&MV));
151 873 : for (i=0;i<contour->npoints;i++) {
152 832 : p_id = i*contour->subcomm->n + contour->subcomm->color;
153 832 : if (contour->subcomm->n==1 || nep->fui==NEP_USER_INTERFACE_CALLBACK) PetscCall(NEPComputeJacobian(nep,ctx->omega[p_id],dT));
154 112 : else PetscCall(NEPComputeFunctionSubcomm(nep,ctx->omega[p_id],dT,NULL,PETSC_TRUE));
155 832 : PetscCall(BVSetActiveColumns(ctx->Y,i*ctx->L+L_start,i*ctx->L+L_end));
156 832 : PetscCall(BVGetMat(ctx->Y,&MC));
157 832 : if (!i) {
158 41 : PetscCall(MatProductCreate(dT,MV,NULL,&BMV));
159 41 : PetscCall(MatProductSetType(BMV,MATPRODUCT_AB));
160 41 : PetscCall(MatProductSetFromOptions(BMV));
161 41 : PetscCall(MatProductSymbolic(BMV));
162 : }
163 832 : PetscCall(MatProductNumeric(BMV));
164 832 : PetscCall(KSPMatSolve(contour->ksp[i],BMV,MC));
165 832 : PetscCall(BVRestoreMat(ctx->Y,&MC));
166 : }
167 41 : PetscCall(MatDestroy(&BMV));
168 41 : PetscCall(BVRestoreMat(V,&MV));
169 41 : PetscFunctionReturn(PETSC_SUCCESS);
170 : }
171 :
172 40 : static PetscErrorCode NEPSetUp_CISS(NEP nep)
173 : {
174 40 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
175 40 : SlepcContourData contour;
176 40 : PetscInt nwork;
177 40 : PetscBool istrivial,isellipse,flg;
178 40 : NEP_CISS_PROJECT dsctxf;
179 40 : PetscObjectId id;
180 40 : PetscObjectState state;
181 40 : Vec v0;
182 :
183 40 : PetscFunctionBegin;
184 40 : if (nep->ncv==PETSC_DETERMINE) nep->ncv = ctx->L_max*ctx->M;
185 : else {
186 18 : ctx->L_max = nep->ncv/ctx->M;
187 18 : if (!ctx->L_max) {
188 0 : ctx->L_max = 1;
189 0 : nep->ncv = ctx->L_max*ctx->M;
190 : }
191 : }
192 40 : ctx->L = PetscMin(ctx->L,ctx->L_max);
193 40 : if (nep->max_it==PETSC_DETERMINE) nep->max_it = 5;
194 40 : if (nep->mpd==PETSC_DETERMINE) nep->mpd = nep->ncv;
195 40 : if (!nep->which) nep->which = NEP_ALL;
196 40 : PetscCheck(nep->which==NEP_ALL,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"This solver supports only computing all eigenvalues");
197 40 : NEPCheckUnsupported(nep,NEP_FEATURE_STOPPING | NEP_FEATURE_TWOSIDED);
198 :
199 : /* check region */
200 40 : PetscCall(RGIsTrivial(nep->rg,&istrivial));
201 40 : PetscCheck(!istrivial,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"CISS requires a nontrivial region, e.g. -rg_type ellipse ...");
202 40 : PetscCall(RGGetComplement(nep->rg,&flg));
203 40 : PetscCheck(!flg,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"A region with complement flag set is not allowed");
204 40 : PetscCall(PetscObjectTypeCompare((PetscObject)nep->rg,RGELLIPSE,&isellipse));
205 40 : PetscCheck(isellipse,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Currently only implemented for elliptic regions");
206 :
207 : /* if the region has changed, then reset contour data */
208 40 : PetscCall(PetscObjectGetId((PetscObject)nep->rg,&id));
209 40 : PetscCall(PetscObjectStateGet((PetscObject)nep->rg,&state));
210 40 : if (ctx->rgid && (id != ctx->rgid || state != ctx->rgstate)) {
211 0 : PetscCall(SlepcContourDataDestroy(&ctx->contour));
212 0 : PetscCall(PetscInfo(nep,"Resetting the contour data structure due to a change of region\n"));
213 0 : ctx->rgid = id; ctx->rgstate = state;
214 : }
215 :
216 : /* create contour data structure */
217 40 : if (!ctx->contour) {
218 0 : PetscCall(RGCanUseConjugates(nep->rg,ctx->isreal,&ctx->useconj));
219 0 : PetscCall(SlepcContourDataCreate(ctx->useconj?ctx->N/2:ctx->N,ctx->npart,(PetscObject)nep,&ctx->contour));
220 : }
221 :
222 40 : PetscCall(NEPAllocateSolution(nep,0));
223 40 : if (ctx->weight) PetscCall(PetscFree4(ctx->weight,ctx->omega,ctx->pp,ctx->sigma));
224 40 : PetscCall(PetscMalloc4(ctx->N,&ctx->weight,ctx->N,&ctx->omega,ctx->N,&ctx->pp,ctx->L_max*ctx->M,&ctx->sigma));
225 :
226 : /* allocate basis vectors */
227 40 : PetscCall(BVDestroy(&ctx->S));
228 40 : PetscCall(BVDuplicateResize(nep->V,ctx->L*ctx->M,&ctx->S));
229 40 : PetscCall(BVDestroy(&ctx->V));
230 40 : PetscCall(BVDuplicateResize(nep->V,ctx->L,&ctx->V));
231 :
232 40 : contour = ctx->contour;
233 40 : if (contour->subcomm && contour->subcomm->n != 1 && nep->fui==NEP_USER_INTERFACE_CALLBACK) {
234 6 : PetscCall(NEPComputeFunction(nep,0,nep->function,nep->function_pre));
235 6 : PetscCall(SlepcContourRedundantMat(contour,1,&nep->function,(nep->function!=nep->function_pre)?&nep->function_pre:NULL));
236 34 : } else PetscCall(SlepcContourRedundantMat(contour,nep->nt,nep->A,nep->P));
237 40 : if (contour->pA) {
238 18 : if (!ctx->J) PetscCall(MatDuplicate(contour->pA[0],MAT_DO_NOT_COPY_VALUES,&ctx->J));
239 18 : PetscCall(BVGetColumn(ctx->V,0,&v0));
240 18 : PetscCall(SlepcContourScatterCreate(contour,v0));
241 18 : PetscCall(BVRestoreColumn(ctx->V,0,&v0));
242 18 : PetscCall(BVDestroy(&ctx->pV));
243 18 : PetscCall(BVCreate(PetscObjectComm((PetscObject)contour->xsub),&ctx->pV));
244 18 : PetscCall(BVSetSizesFromVec(ctx->pV,contour->xsub,nep->n));
245 18 : PetscCall(BVSetFromOptions(ctx->pV));
246 18 : PetscCall(BVResize(ctx->pV,ctx->L,PETSC_FALSE));
247 : }
248 :
249 40 : PetscCall(BVDestroy(&ctx->Y));
250 40 : if (contour->pA) {
251 18 : PetscCall(BVCreate(PetscObjectComm((PetscObject)contour->xsub),&ctx->Y));
252 18 : PetscCall(BVSetSizesFromVec(ctx->Y,contour->xsub,nep->n));
253 18 : PetscCall(BVSetFromOptions(ctx->Y));
254 18 : PetscCall(BVResize(ctx->Y,contour->npoints*ctx->L,PETSC_FALSE));
255 22 : } else PetscCall(BVDuplicateResize(nep->V,contour->npoints*ctx->L,&ctx->Y));
256 :
257 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_RITZ) {
258 24 : PetscCall(DSSetMethod(nep->ds,1));
259 24 : PetscCall(DSNEPSetRG(nep->ds,nep->rg));
260 24 : if (nep->fui==NEP_USER_INTERFACE_SPLIT) PetscCall(DSNEPSetFN(nep->ds,nep->nt,nep->f));
261 : else {
262 6 : PetscCall(PetscNew(&dsctxf));
263 6 : PetscCall(DSNEPSetComputeMatrixFunction(nep->ds,NEPContourDSComputeMatrix,dsctxf));
264 6 : dsctxf->nep = nep;
265 6 : ctx->dsctxf = dsctxf;
266 : }
267 : }
268 40 : PetscCall(DSAllocate(nep->ds,nep->ncv));
269 40 : nwork = (nep->fui==NEP_USER_INTERFACE_SPLIT)? 2: 1;
270 40 : PetscCall(NEPSetWorkVecs(nep,nwork));
271 40 : PetscFunctionReturn(PETSC_SUCCESS);
272 : }
273 :
274 40 : static PetscErrorCode NEPSolve_CISS(NEP nep)
275 : {
276 40 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
277 40 : SlepcContourData contour = ctx->contour;
278 40 : Mat X,M,E,T,P,J;
279 40 : BV V;
280 40 : PetscInt i,j,ld,L_add=0,nv=0,L_base=ctx->L,inner,*inside;
281 40 : PetscScalar *Mu,*H0,*H1,*rr,*temp,center;
282 40 : PetscReal error,max_error,radius,rgscale,est_eig,eta;
283 40 : PetscBool isellipse,*fl1;
284 40 : Vec si;
285 40 : SlepcSC sc;
286 40 : PetscRandom rand;
287 :
288 40 : PetscFunctionBegin;
289 40 : PetscCall(DSGetSlepcSC(nep->ds,&sc));
290 40 : sc->comparison = SlepcCompareLargestMagnitude;
291 40 : sc->comparisonctx = NULL;
292 40 : sc->map = NULL;
293 40 : sc->mapobj = NULL;
294 40 : PetscCall(DSGetLeadingDimension(nep->ds,&ld));
295 40 : PetscCall(RGComputeQuadrature(nep->rg,RG_QUADRULE_TRAPEZOIDAL,ctx->N,ctx->omega,ctx->pp,ctx->weight));
296 40 : if (contour->pA) {
297 18 : T = contour->pA[0];
298 18 : P = ((nep->fui==NEP_USER_INTERFACE_SPLIT && nep->P) || (nep->fui==NEP_USER_INTERFACE_CALLBACK && contour->pP))? contour->pP[0]: T;
299 : } else {
300 22 : T = nep->function;
301 22 : P = nep->function_pre? nep->function_pre: nep->function;
302 : }
303 40 : PetscCall(NEPCISSSetUp(nep,T,P));
304 40 : PetscCall(BVSetActiveColumns(ctx->V,0,ctx->L));
305 40 : PetscCall(BVSetRandomSign(ctx->V));
306 40 : PetscCall(BVGetRandomContext(ctx->V,&rand));
307 40 : if (contour->pA) {
308 18 : J = ctx->J;
309 18 : V = ctx->pV;
310 18 : PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
311 : } else {
312 22 : J = nep->jacobian;
313 22 : V = ctx->V;
314 : }
315 40 : PetscCall(NEPCISSSolve(nep,J,V,0,ctx->L));
316 40 : PetscCall(PetscObjectTypeCompare((PetscObject)nep->rg,RGELLIPSE,&isellipse));
317 40 : if (isellipse) {
318 40 : PetscCall(BVTraceQuadrature(ctx->Y,ctx->V,ctx->L,ctx->L,ctx->weight,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj,&est_eig));
319 40 : PetscCall(PetscInfo(nep,"Estimated eigenvalue count: %f\n",(double)est_eig));
320 40 : eta = PetscPowReal(10.0,-PetscLog10Real(nep->tol)/ctx->N);
321 40 : L_add = PetscMax(0,(PetscInt)PetscCeilReal((est_eig*eta)/ctx->M)-ctx->L);
322 40 : if (L_add>ctx->L_max-ctx->L) {
323 0 : PetscCall(PetscInfo(nep,"Number of eigenvalues inside the contour path may be too large\n"));
324 0 : L_add = ctx->L_max-ctx->L;
325 : }
326 : }
327 : /* Updates L after estimate the number of eigenvalue */
328 40 : if (L_add>0) {
329 1 : PetscCall(PetscInfo(nep,"Changing L %" PetscInt_FMT " -> %" PetscInt_FMT " by Estimate #Eig\n",ctx->L,ctx->L+L_add));
330 1 : PetscCall(BVCISSResizeBases(ctx->S,contour->pA?ctx->pV:ctx->V,ctx->Y,ctx->L,ctx->L+L_add,ctx->M,contour->npoints));
331 1 : PetscCall(BVSetActiveColumns(ctx->V,ctx->L,ctx->L+L_add));
332 1 : PetscCall(BVSetRandomSign(ctx->V));
333 1 : if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
334 1 : ctx->L += L_add;
335 1 : PetscCall(NEPCISSSolve(nep,J,V,ctx->L-L_add,ctx->L));
336 : }
337 :
338 40 : PetscCall(PetscMalloc2(ctx->L*ctx->L*ctx->M*2,&Mu,ctx->L*ctx->M*ctx->L*ctx->M,&H0));
339 40 : for (i=0;i<ctx->refine_blocksize;i++) {
340 3 : PetscCall(BVDotQuadrature(ctx->Y,V,Mu,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->subcomm,contour->npoints,ctx->useconj));
341 3 : PetscCall(CISS_BlockHankel(Mu,0,ctx->L,ctx->M,H0));
342 3 : PetscCall(PetscLogEventBegin(NEP_CISS_SVD,nep,0,0,0));
343 3 : PetscCall(SlepcCISS_BH_SVD(H0,ctx->L*ctx->M,ctx->delta,ctx->sigma,&nv));
344 3 : PetscCall(PetscLogEventEnd(NEP_CISS_SVD,nep,0,0,0));
345 3 : if (ctx->sigma[0]<=ctx->delta || nv < ctx->L*ctx->M || ctx->L == ctx->L_max) break;
346 0 : L_add = L_base;
347 0 : if (ctx->L+L_add>ctx->L_max) L_add = ctx->L_max-ctx->L;
348 0 : PetscCall(PetscInfo(nep,"Changing L %" PetscInt_FMT " -> %" PetscInt_FMT " by SVD(H0)\n",ctx->L,ctx->L+L_add));
349 0 : PetscCall(BVCISSResizeBases(ctx->S,contour->pA?ctx->pV:ctx->V,ctx->Y,ctx->L,ctx->L+L_add,ctx->M,contour->npoints));
350 0 : PetscCall(BVSetActiveColumns(ctx->V,ctx->L,ctx->L+L_add));
351 0 : PetscCall(BVSetRandomSign(ctx->V));
352 0 : if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
353 0 : ctx->L += L_add;
354 0 : PetscCall(NEPCISSSolve(nep,J,V,ctx->L-L_add,ctx->L));
355 0 : if (L_add) {
356 0 : PetscCall(PetscFree2(Mu,H0));
357 0 : PetscCall(PetscMalloc2(ctx->L*ctx->L*ctx->M*2,&Mu,ctx->L*ctx->M*ctx->L*ctx->M,&H0));
358 : }
359 : }
360 :
361 40 : PetscCall(RGGetScale(nep->rg,&rgscale));
362 40 : PetscCall(RGEllipseGetParameters(nep->rg,¢er,&radius,NULL));
363 :
364 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) PetscCall(PetscMalloc1(ctx->L*ctx->M*ctx->L*ctx->M,&H1));
365 :
366 80 : while (nep->reason == NEP_CONVERGED_ITERATING) {
367 40 : nep->its++;
368 40 : for (inner=0;inner<=ctx->refine_inner;inner++) {
369 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) {
370 8 : PetscCall(BVDotQuadrature(ctx->Y,V,Mu,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->subcomm,contour->npoints,ctx->useconj));
371 8 : PetscCall(CISS_BlockHankel(Mu,0,ctx->L,ctx->M,H0));
372 8 : PetscCall(PetscLogEventBegin(NEP_CISS_SVD,nep,0,0,0));
373 8 : PetscCall(SlepcCISS_BH_SVD(H0,ctx->L*ctx->M,ctx->delta,ctx->sigma,&nv));
374 8 : PetscCall(PetscLogEventEnd(NEP_CISS_SVD,nep,0,0,0));
375 : } else {
376 32 : PetscCall(BVSumQuadrature(ctx->S,ctx->Y,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj));
377 : /* compute SVD of S */
378 56 : PetscCall(BVSVDAndRank(ctx->S,ctx->M,ctx->L,ctx->delta,(ctx->extraction==NEP_CISS_EXTRACTION_CAA)?BV_SVD_METHOD_QR_CAA:BV_SVD_METHOD_QR,H0,ctx->sigma,&nv));
379 : }
380 40 : PetscCall(PetscInfo(nep,"Estimated rank: nv = %" PetscInt_FMT "\n",nv));
381 40 : if (ctx->sigma[0]>ctx->delta && nv==ctx->L*ctx->M && inner!=ctx->refine_inner) {
382 0 : PetscCall(BVSumQuadrature(ctx->S,ctx->Y,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj));
383 0 : PetscCall(BVSetActiveColumns(ctx->S,0,ctx->L));
384 0 : PetscCall(BVSetActiveColumns(ctx->V,0,ctx->L));
385 0 : PetscCall(BVCopy(ctx->S,ctx->V));
386 0 : if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
387 0 : PetscCall(NEPCISSSolve(nep,J,V,0,ctx->L));
388 : } else break;
389 : }
390 40 : nep->nconv = 0;
391 40 : if (nv == 0) { nep->reason = NEP_CONVERGED_TOL; break; }
392 : else {
393 : /* Extracting eigenpairs */
394 40 : PetscCall(DSSetDimensions(nep->ds,nv,0,0));
395 40 : PetscCall(DSSetState(nep->ds,DS_STATE_RAW));
396 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) {
397 8 : PetscCall(CISS_BlockHankel(Mu,0,ctx->L,ctx->M,H0));
398 8 : PetscCall(CISS_BlockHankel(Mu,1,ctx->L,ctx->M,H1));
399 8 : PetscCall(DSGetArray(nep->ds,DS_MAT_A,&temp));
400 51 : for (j=0;j<nv;j++)
401 290 : for (i=0;i<nv;i++)
402 247 : temp[i+j*ld] = H1[i+j*ctx->L*ctx->M];
403 8 : PetscCall(DSRestoreArray(nep->ds,DS_MAT_A,&temp));
404 8 : PetscCall(DSGetArray(nep->ds,DS_MAT_B,&temp));
405 51 : for (j=0;j<nv;j++)
406 290 : for (i=0;i<nv;i++)
407 247 : temp[i+j*ld] = H0[i+j*ctx->L*ctx->M];
408 8 : PetscCall(DSRestoreArray(nep->ds,DS_MAT_B,&temp));
409 32 : } else if (ctx->extraction == NEP_CISS_EXTRACTION_CAA) {
410 8 : PetscCall(BVSetActiveColumns(ctx->S,0,nv));
411 8 : PetscCall(DSGetArray(nep->ds,DS_MAT_A,&temp));
412 50 : for (i=0;i<nv;i++) PetscCall(PetscArraycpy(temp+i*ld,H0+i*nv,nv));
413 8 : PetscCall(DSRestoreArray(nep->ds,DS_MAT_A,&temp));
414 : } else {
415 24 : PetscCall(BVSetActiveColumns(ctx->S,0,nv));
416 24 : if (nep->fui==NEP_USER_INTERFACE_SPLIT) {
417 66 : for (i=0;i<nep->nt;i++) {
418 48 : PetscCall(DSGetMat(nep->ds,DSMatExtra[i],&E));
419 48 : PetscCall(BVMatProject(ctx->S,nep->A[i],ctx->S,E));
420 48 : PetscCall(DSRestoreMat(nep->ds,DSMatExtra[i],&E));
421 : }
422 6 : } else { ctx->dsctxf->Q = ctx->S; }
423 : }
424 40 : PetscCall(DSSolve(nep->ds,nep->eigr,nep->eigi));
425 40 : PetscCall(DSSynchronize(nep->ds,nep->eigr,nep->eigi));
426 40 : PetscCall(DSGetDimensions(nep->ds,NULL,NULL,NULL,&nv));
427 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_CAA || ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) {
428 101 : for (i=0;i<nv;i++) {
429 85 : nep->eigr[i] = (nep->eigr[i]*radius+center)*rgscale;
430 : }
431 : }
432 40 : PetscCall(PetscMalloc3(nv,&fl1,nv,&inside,nv,&rr));
433 40 : PetscCall(DSVectors(nep->ds,DS_MAT_X,NULL,NULL));
434 40 : PetscCall(DSGetMat(nep->ds,DS_MAT_X,&X));
435 40 : PetscCall(SlepcCISS_isGhost(X,nv,ctx->sigma,ctx->spurious_threshold,fl1));
436 40 : PetscCall(DSRestoreMat(nep->ds,DS_MAT_X,&X));
437 40 : PetscCall(RGCheckInside(nep->rg,nv,nep->eigr,nep->eigi,inside));
438 228 : for (i=0;i<nv;i++) {
439 188 : if (fl1[i] && inside[i]>=0) {
440 167 : rr[i] = 1.0;
441 167 : nep->nconv++;
442 21 : } else rr[i] = 0.0;
443 : }
444 40 : PetscCall(DSSort(nep->ds,nep->eigr,nep->eigi,rr,NULL,&nep->nconv));
445 40 : PetscCall(DSSynchronize(nep->ds,nep->eigr,nep->eigi));
446 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_CAA || ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) {
447 101 : for (i=0;i<nv;i++) nep->eigr[i] = (nep->eigr[i]*radius+center)*rgscale;
448 : }
449 40 : PetscCall(PetscFree3(fl1,inside,rr));
450 40 : PetscCall(BVSetActiveColumns(nep->V,0,nv));
451 40 : PetscCall(DSVectors(nep->ds,DS_MAT_X,NULL,NULL));
452 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) {
453 8 : PetscCall(BVSumQuadrature(ctx->S,ctx->Y,ctx->M,ctx->L,ctx->L,ctx->weight,ctx->pp,contour->scatterin,contour->subcomm,contour->npoints,ctx->useconj));
454 8 : PetscCall(BVSetActiveColumns(ctx->S,0,nv));
455 8 : PetscCall(BVCopy(ctx->S,nep->V));
456 8 : PetscCall(DSGetMat(nep->ds,DS_MAT_X,&X));
457 8 : PetscCall(BVMultInPlace(ctx->S,X,0,nep->nconv));
458 8 : PetscCall(BVMultInPlace(nep->V,X,0,nep->nconv));
459 8 : PetscCall(DSRestoreMat(nep->ds,DS_MAT_X,&X));
460 : } else {
461 32 : PetscCall(DSGetMat(nep->ds,DS_MAT_X,&X));
462 32 : PetscCall(BVMultInPlace(ctx->S,X,0,nep->nconv));
463 32 : PetscCall(DSRestoreMat(nep->ds,DS_MAT_X,&X));
464 32 : PetscCall(BVSetActiveColumns(ctx->S,0,nep->nconv));
465 32 : PetscCall(BVCopy(ctx->S,nep->V));
466 : }
467 : max_error = 0.0;
468 207 : for (i=0;i<nep->nconv;i++) {
469 167 : PetscCall(BVGetColumn(nep->V,i,&si));
470 167 : PetscCall(VecNormalize(si,NULL));
471 167 : PetscCall(NEPComputeResidualNorm_Private(nep,PETSC_FALSE,nep->eigr[i],si,nep->work,&error));
472 167 : PetscCall((*nep->converged)(nep,nep->eigr[i],0,error,&error,nep->convergedctx));
473 167 : PetscCall(BVRestoreColumn(nep->V,i,&si));
474 225 : max_error = PetscMax(max_error,error);
475 : }
476 40 : if (max_error <= nep->tol) nep->reason = NEP_CONVERGED_TOL;
477 0 : else if (nep->its > nep->max_it) nep->reason = NEP_DIVERGED_ITS;
478 : else {
479 0 : if (nep->nconv > ctx->L) nv = nep->nconv;
480 0 : else if (ctx->L > nv) nv = ctx->L;
481 0 : nv = PetscMin(nv,ctx->L*ctx->M);
482 0 : PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,nv,ctx->L,NULL,&M));
483 0 : PetscCall(MatSetRandom(M,rand));
484 0 : PetscCall(BVSetActiveColumns(ctx->S,0,nv));
485 0 : PetscCall(BVMultInPlace(ctx->S,M,0,ctx->L));
486 0 : PetscCall(MatDestroy(&M));
487 0 : PetscCall(BVSetActiveColumns(ctx->S,0,ctx->L));
488 0 : PetscCall(BVSetActiveColumns(ctx->V,0,ctx->L));
489 0 : PetscCall(BVCopy(ctx->S,ctx->V));
490 0 : if (contour->pA) PetscCall(BVScatter(ctx->V,ctx->pV,contour->scatterin,contour->xdup));
491 80 : PetscCall(NEPCISSSolve(nep,J,V,0,ctx->L));
492 : }
493 : }
494 : }
495 40 : PetscCall(PetscFree2(Mu,H0));
496 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_HANKEL) PetscCall(PetscFree(H1));
497 40 : PetscFunctionReturn(PETSC_SUCCESS);
498 : }
499 :
500 38 : static PetscErrorCode NEPCISSSetSizes_CISS(NEP nep,PetscInt ip,PetscInt bs,PetscInt ms,PetscInt npart,PetscInt bsmax,PetscBool realmats)
501 : {
502 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
503 38 : PetscInt oN,oL,oM,oLmax,onpart;
504 38 : PetscMPIInt size;
505 :
506 38 : PetscFunctionBegin;
507 38 : oN = ctx->N;
508 38 : if (ip == PETSC_DETERMINE) {
509 13 : if (ctx->N!=32) { ctx->N =32; ctx->M = ctx->N/4; }
510 25 : } else if (ip != PETSC_CURRENT) {
511 25 : PetscCheck(ip>0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The ip argument must be > 0");
512 25 : PetscCheck(ip%2==0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The ip argument must be an even number");
513 25 : if (ctx->N!=ip) { ctx->N = ip; ctx->M = ctx->N/4; }
514 : }
515 38 : oL = ctx->L;
516 38 : if (bs == PETSC_DETERMINE) {
517 13 : ctx->L = 16;
518 25 : } else if (bs != PETSC_CURRENT) {
519 25 : PetscCheck(bs>0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The bs argument must be > 0");
520 25 : ctx->L = bs;
521 : }
522 38 : oM = ctx->M;
523 38 : if (ms == PETSC_DETERMINE) {
524 13 : ctx->M = ctx->N/4;
525 25 : } else if (ms != PETSC_CURRENT) {
526 25 : PetscCheck(ms>0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The ms argument must be > 0");
527 25 : PetscCheck(ms<=ctx->N,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The ms argument must be less than or equal to the number of integration points");
528 25 : ctx->M = ms;
529 : }
530 38 : onpart = ctx->npart;
531 38 : if (npart == PETSC_DETERMINE) {
532 0 : ctx->npart = 1;
533 38 : } else if (npart != PETSC_CURRENT) {
534 38 : PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)nep),&size));
535 38 : PetscCheck(npart>0 && npart<=size,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of npart");
536 38 : ctx->npart = npart;
537 : }
538 38 : oLmax = ctx->L_max;
539 38 : if (bsmax == PETSC_DETERMINE) {
540 13 : ctx->L_max = 64;
541 25 : } else if (bsmax != PETSC_CURRENT) {
542 25 : PetscCheck(bsmax>0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The bsmax argument must be > 0");
543 25 : ctx->L_max = PetscMax(bsmax,ctx->L);
544 : }
545 38 : if (onpart != ctx->npart || oN != ctx->N || realmats != ctx->isreal) {
546 31 : PetscCall(SlepcContourDataDestroy(&ctx->contour));
547 31 : PetscCall(PetscInfo(nep,"Resetting the contour data structure due to a change of parameters\n"));
548 31 : nep->state = NEP_STATE_INITIAL;
549 : }
550 38 : ctx->isreal = realmats;
551 38 : if (oL != ctx->L || oM != ctx->M || oLmax != ctx->L_max) nep->state = NEP_STATE_INITIAL;
552 38 : PetscFunctionReturn(PETSC_SUCCESS);
553 : }
554 :
555 : /*@
556 : NEPCISSSetSizes - Sets the values of various size parameters in the CISS solver.
557 :
558 : Logically Collective
559 :
560 : Input Parameters:
561 : + nep - the nonlinear eigensolver context
562 : . ip - number of integration points
563 : . bs - block size
564 : . ms - moment size
565 : . npart - number of partitions when splitting the communicator
566 : . bsmax - max block size
567 : - realmats - T(z) is real for real z
568 :
569 : Options Database Keys:
570 : + -nep_ciss_integration_points - Sets the number of integration points
571 : . -nep_ciss_blocksize - Sets the block size
572 : . -nep_ciss_moments - Sets the moment size
573 : . -nep_ciss_partitions - Sets the number of partitions
574 : . -nep_ciss_maxblocksize - Sets the maximum block size
575 : - -nep_ciss_realmats - T(z) is real for real z
576 :
577 : Notes:
578 : For all integer arguments, you can use PETSC_CURRENT to keep the current value, and
579 : PETSC_DETERMINE to set them to a default value.
580 :
581 : The default number of partitions is 1. This means the internal KSP object is shared
582 : among all processes of the NEP communicator. Otherwise, the communicator is split
583 : into npart communicators, so that npart KSP solves proceed simultaneously.
584 :
585 : The realmats flag can be set to true when T(.) is guaranteed to be real
586 : when the argument is a real value, for example, when all matrices in
587 : the split form are real. When set to true, the solver avoids some computations.
588 :
589 : Level: advanced
590 :
591 : .seealso: NEPCISSGetSizes()
592 : @*/
593 38 : PetscErrorCode NEPCISSSetSizes(NEP nep,PetscInt ip,PetscInt bs,PetscInt ms,PetscInt npart,PetscInt bsmax,PetscBool realmats)
594 : {
595 38 : PetscFunctionBegin;
596 38 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
597 114 : PetscValidLogicalCollectiveInt(nep,ip,2);
598 114 : PetscValidLogicalCollectiveInt(nep,bs,3);
599 114 : PetscValidLogicalCollectiveInt(nep,ms,4);
600 114 : PetscValidLogicalCollectiveInt(nep,npart,5);
601 114 : PetscValidLogicalCollectiveInt(nep,bsmax,6);
602 114 : PetscValidLogicalCollectiveBool(nep,realmats,7);
603 38 : PetscTryMethod(nep,"NEPCISSSetSizes_C",(NEP,PetscInt,PetscInt,PetscInt,PetscInt,PetscInt,PetscBool),(nep,ip,bs,ms,npart,bsmax,realmats));
604 38 : PetscFunctionReturn(PETSC_SUCCESS);
605 : }
606 :
607 38 : static PetscErrorCode NEPCISSGetSizes_CISS(NEP nep,PetscInt *ip,PetscInt *bs,PetscInt *ms,PetscInt *npart,PetscInt *bsmax,PetscBool *realmats)
608 : {
609 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
610 :
611 38 : PetscFunctionBegin;
612 38 : if (ip) *ip = ctx->N;
613 38 : if (bs) *bs = ctx->L;
614 38 : if (ms) *ms = ctx->M;
615 38 : if (npart) *npart = ctx->npart;
616 38 : if (bsmax) *bsmax = ctx->L_max;
617 38 : if (realmats) *realmats = ctx->isreal;
618 38 : PetscFunctionReturn(PETSC_SUCCESS);
619 : }
620 :
621 : /*@
622 : NEPCISSGetSizes - Gets the values of various size parameters in the CISS solver.
623 :
624 : Not Collective
625 :
626 : Input Parameter:
627 : . nep - the nonlinear eigensolver context
628 :
629 : Output Parameters:
630 : + ip - number of integration points
631 : . bs - block size
632 : . ms - moment size
633 : . npart - number of partitions when splitting the communicator
634 : . bsmax - max block size
635 : - realmats - T(z) is real for real z
636 :
637 : Level: advanced
638 :
639 : .seealso: NEPCISSSetSizes()
640 : @*/
641 38 : PetscErrorCode NEPCISSGetSizes(NEP nep,PetscInt *ip,PetscInt *bs,PetscInt *ms,PetscInt *npart,PetscInt *bsmax,PetscBool *realmats)
642 : {
643 38 : PetscFunctionBegin;
644 38 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
645 38 : PetscUseMethod(nep,"NEPCISSGetSizes_C",(NEP,PetscInt*,PetscInt*,PetscInt*,PetscInt*,PetscInt*,PetscBool*),(nep,ip,bs,ms,npart,bsmax,realmats));
646 38 : PetscFunctionReturn(PETSC_SUCCESS);
647 : }
648 :
649 3 : static PetscErrorCode NEPCISSSetThreshold_CISS(NEP nep,PetscReal delta,PetscReal spur)
650 : {
651 3 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
652 :
653 3 : PetscFunctionBegin;
654 3 : if (delta == (PetscReal)PETSC_DETERMINE) {
655 0 : ctx->delta = SLEPC_DEFAULT_TOL*1e-4;
656 3 : } else if (delta != (PetscReal)PETSC_CURRENT) {
657 3 : PetscCheck(delta>0.0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The delta argument must be > 0.0");
658 3 : ctx->delta = delta;
659 : }
660 3 : if (spur == (PetscReal)PETSC_DETERMINE) {
661 0 : ctx->spurious_threshold = PetscSqrtReal(SLEPC_DEFAULT_TOL);
662 3 : } else if (spur != (PetscReal)PETSC_CURRENT) {
663 3 : PetscCheck(spur>0.0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The spurious threshold argument must be > 0.0");
664 3 : ctx->spurious_threshold = spur;
665 : }
666 3 : PetscFunctionReturn(PETSC_SUCCESS);
667 : }
668 :
669 : /*@
670 : NEPCISSSetThreshold - Sets the values of various threshold parameters in
671 : the CISS solver.
672 :
673 : Logically Collective
674 :
675 : Input Parameters:
676 : + nep - the nonlinear eigensolver context
677 : . delta - threshold for numerical rank
678 : - spur - spurious threshold (to discard spurious eigenpairs)
679 :
680 : Options Database Keys:
681 : + -nep_ciss_delta - Sets the delta
682 : - -nep_ciss_spurious_threshold - Sets the spurious threshold
683 :
684 : Note:
685 : PETSC_CURRENT can be used to preserve the current value of any of the
686 : arguments, and PETSC_DETERMINE to set them to a default value.
687 :
688 : Level: advanced
689 :
690 : .seealso: NEPCISSGetThreshold()
691 : @*/
692 3 : PetscErrorCode NEPCISSSetThreshold(NEP nep,PetscReal delta,PetscReal spur)
693 : {
694 3 : PetscFunctionBegin;
695 3 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
696 9 : PetscValidLogicalCollectiveReal(nep,delta,2);
697 9 : PetscValidLogicalCollectiveReal(nep,spur,3);
698 3 : PetscTryMethod(nep,"NEPCISSSetThreshold_C",(NEP,PetscReal,PetscReal),(nep,delta,spur));
699 3 : PetscFunctionReturn(PETSC_SUCCESS);
700 : }
701 :
702 38 : static PetscErrorCode NEPCISSGetThreshold_CISS(NEP nep,PetscReal *delta,PetscReal *spur)
703 : {
704 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
705 :
706 38 : PetscFunctionBegin;
707 38 : if (delta) *delta = ctx->delta;
708 38 : if (spur) *spur = ctx->spurious_threshold;
709 38 : PetscFunctionReturn(PETSC_SUCCESS);
710 : }
711 :
712 : /*@
713 : NEPCISSGetThreshold - Gets the values of various threshold parameters in
714 : the CISS solver.
715 :
716 : Not Collective
717 :
718 : Input Parameter:
719 : . nep - the nonlinear eigensolver context
720 :
721 : Output Parameters:
722 : + delta - threshold for numerical rank
723 : - spur - spurious threshold (to discard spurious eigenpairs)
724 :
725 : Level: advanced
726 :
727 : .seealso: NEPCISSSetThreshold()
728 : @*/
729 38 : PetscErrorCode NEPCISSGetThreshold(NEP nep,PetscReal *delta,PetscReal *spur)
730 : {
731 38 : PetscFunctionBegin;
732 38 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
733 38 : PetscUseMethod(nep,"NEPCISSGetThreshold_C",(NEP,PetscReal*,PetscReal*),(nep,delta,spur));
734 38 : PetscFunctionReturn(PETSC_SUCCESS);
735 : }
736 :
737 3 : static PetscErrorCode NEPCISSSetRefinement_CISS(NEP nep,PetscInt inner,PetscInt blsize)
738 : {
739 3 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
740 :
741 3 : PetscFunctionBegin;
742 3 : if (inner == PETSC_DETERMINE) {
743 0 : ctx->refine_inner = 0;
744 3 : } else if (inner != PETSC_CURRENT) {
745 3 : PetscCheck(inner>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The refine inner argument must be >= 0");
746 3 : ctx->refine_inner = inner;
747 : }
748 3 : if (blsize == PETSC_DETERMINE) {
749 0 : ctx->refine_blocksize = 0;
750 3 : } else if (blsize != PETSC_CURRENT) {
751 3 : PetscCheck(blsize>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"The refine blocksize argument must be >= 0");
752 3 : ctx->refine_blocksize = blsize;
753 : }
754 3 : PetscFunctionReturn(PETSC_SUCCESS);
755 : }
756 :
757 : /*@
758 : NEPCISSSetRefinement - Sets the values of various refinement parameters
759 : in the CISS solver.
760 :
761 : Logically Collective
762 :
763 : Input Parameters:
764 : + nep - the nonlinear eigensolver context
765 : . inner - number of iterative refinement iterations (inner loop)
766 : - blsize - number of iterative refinement iterations (blocksize loop)
767 :
768 : Options Database Keys:
769 : + -nep_ciss_refine_inner - Sets number of inner iterations
770 : - -nep_ciss_refine_blocksize - Sets number of blocksize iterations
771 :
772 : Note:
773 : PETSC_CURRENT can be used to preserve the current value of any of the
774 : arguments, and PETSC_DETERMINE to set them to a default value.
775 :
776 : Level: advanced
777 :
778 : .seealso: NEPCISSGetRefinement()
779 : @*/
780 3 : PetscErrorCode NEPCISSSetRefinement(NEP nep,PetscInt inner,PetscInt blsize)
781 : {
782 3 : PetscFunctionBegin;
783 3 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
784 9 : PetscValidLogicalCollectiveInt(nep,inner,2);
785 9 : PetscValidLogicalCollectiveInt(nep,blsize,3);
786 3 : PetscTryMethod(nep,"NEPCISSSetRefinement_C",(NEP,PetscInt,PetscInt),(nep,inner,blsize));
787 3 : PetscFunctionReturn(PETSC_SUCCESS);
788 : }
789 :
790 38 : static PetscErrorCode NEPCISSGetRefinement_CISS(NEP nep,PetscInt *inner,PetscInt *blsize)
791 : {
792 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
793 :
794 38 : PetscFunctionBegin;
795 38 : if (inner) *inner = ctx->refine_inner;
796 38 : if (blsize) *blsize = ctx->refine_blocksize;
797 38 : PetscFunctionReturn(PETSC_SUCCESS);
798 : }
799 :
800 : /*@
801 : NEPCISSGetRefinement - Gets the values of various refinement parameters
802 : in the CISS solver.
803 :
804 : Not Collective
805 :
806 : Input Parameter:
807 : . nep - the nonlinear eigensolver context
808 :
809 : Output Parameters:
810 : + inner - number of iterative refinement iterations (inner loop)
811 : - blsize - number of iterative refinement iterations (blocksize loop)
812 :
813 : Level: advanced
814 :
815 : .seealso: NEPCISSSetRefinement()
816 : @*/
817 38 : PetscErrorCode NEPCISSGetRefinement(NEP nep, PetscInt *inner, PetscInt *blsize)
818 : {
819 38 : PetscFunctionBegin;
820 38 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
821 38 : PetscUseMethod(nep,"NEPCISSGetRefinement_C",(NEP,PetscInt*,PetscInt*),(nep,inner,blsize));
822 38 : PetscFunctionReturn(PETSC_SUCCESS);
823 : }
824 :
825 24 : static PetscErrorCode NEPCISSSetExtraction_CISS(NEP nep,NEPCISSExtraction extraction)
826 : {
827 24 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
828 :
829 24 : PetscFunctionBegin;
830 24 : if (ctx->extraction != extraction) {
831 16 : ctx->extraction = extraction;
832 16 : nep->state = NEP_STATE_INITIAL;
833 : }
834 24 : PetscFunctionReturn(PETSC_SUCCESS);
835 : }
836 :
837 : /*@
838 : NEPCISSSetExtraction - Sets the extraction technique used in the CISS solver.
839 :
840 : Logically Collective
841 :
842 : Input Parameters:
843 : + nep - the nonlinear eigensolver context
844 : - extraction - the extraction technique
845 :
846 : Options Database Key:
847 : . -nep_ciss_extraction - Sets the extraction technique (either 'ritz', 'hankel' or 'caa')
848 :
849 : Notes:
850 : By default, the Rayleigh-Ritz extraction is used (NEP_CISS_EXTRACTION_RITZ).
851 :
852 : If the 'hankel' or the 'caa' option is specified (NEP_CISS_EXTRACTION_HANKEL or
853 : NEP_CISS_EXTRACTION_CAA), then the Block Hankel method, or the Communication-avoiding
854 : Arnoldi method, respectively, is used for extracting eigenpairs.
855 :
856 : Level: advanced
857 :
858 : .seealso: NEPCISSGetExtraction(), NEPCISSExtraction
859 : @*/
860 24 : PetscErrorCode NEPCISSSetExtraction(NEP nep,NEPCISSExtraction extraction)
861 : {
862 24 : PetscFunctionBegin;
863 24 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
864 72 : PetscValidLogicalCollectiveEnum(nep,extraction,2);
865 24 : PetscTryMethod(nep,"NEPCISSSetExtraction_C",(NEP,NEPCISSExtraction),(nep,extraction));
866 24 : PetscFunctionReturn(PETSC_SUCCESS);
867 : }
868 :
869 13 : static PetscErrorCode NEPCISSGetExtraction_CISS(NEP nep,NEPCISSExtraction *extraction)
870 : {
871 13 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
872 :
873 13 : PetscFunctionBegin;
874 13 : *extraction = ctx->extraction;
875 13 : PetscFunctionReturn(PETSC_SUCCESS);
876 : }
877 :
878 : /*@
879 : NEPCISSGetExtraction - Gets the extraction technique used in the CISS solver.
880 :
881 : Not Collective
882 :
883 : Input Parameter:
884 : . nep - the nonlinear eigensolver context
885 :
886 : Output Parameters:
887 : . extraction - extraction technique
888 :
889 : Level: advanced
890 :
891 : .seealso: NEPCISSSetExtraction() NEPCISSExtraction
892 : @*/
893 13 : PetscErrorCode NEPCISSGetExtraction(NEP nep,NEPCISSExtraction *extraction)
894 : {
895 13 : PetscFunctionBegin;
896 13 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
897 13 : PetscAssertPointer(extraction,2);
898 13 : PetscUseMethod(nep,"NEPCISSGetExtraction_C",(NEP,NEPCISSExtraction*),(nep,extraction));
899 13 : PetscFunctionReturn(PETSC_SUCCESS);
900 : }
901 :
902 44 : static PetscErrorCode NEPCISSGetKSPs_CISS(NEP nep,PetscInt *nsolve,KSP **ksp)
903 : {
904 44 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
905 44 : SlepcContourData contour;
906 44 : PetscInt i;
907 44 : PC pc;
908 44 : MPI_Comm child;
909 :
910 44 : PetscFunctionBegin;
911 44 : if (!ctx->contour) { /* initialize contour data structure first */
912 44 : PetscCall(RGCanUseConjugates(nep->rg,ctx->isreal,&ctx->useconj));
913 44 : PetscCall(SlepcContourDataCreate(ctx->useconj?ctx->N/2:ctx->N,ctx->npart,(PetscObject)nep,&ctx->contour));
914 : }
915 44 : contour = ctx->contour;
916 44 : if (!contour->ksp) {
917 44 : PetscCall(PetscMalloc1(contour->npoints,&contour->ksp));
918 44 : PetscCall(PetscSubcommGetChild(contour->subcomm,&child));
919 876 : for (i=0;i<contour->npoints;i++) {
920 832 : PetscCall(KSPCreate(child,&contour->ksp[i]));
921 832 : PetscCall(PetscObjectIncrementTabLevel((PetscObject)contour->ksp[i],(PetscObject)nep,1));
922 832 : PetscCall(KSPSetOptionsPrefix(contour->ksp[i],((PetscObject)nep)->prefix));
923 832 : PetscCall(KSPAppendOptionsPrefix(contour->ksp[i],"nep_ciss_"));
924 832 : PetscCall(PetscObjectSetOptions((PetscObject)contour->ksp[i],((PetscObject)nep)->options));
925 832 : PetscCall(KSPSetErrorIfNotConverged(contour->ksp[i],PETSC_TRUE));
926 1248 : PetscCall(KSPSetTolerances(contour->ksp[i],SlepcDefaultTol(nep->tol),PETSC_CURRENT,PETSC_CURRENT,PETSC_CURRENT));
927 832 : PetscCall(KSPGetPC(contour->ksp[i],&pc));
928 832 : if ((nep->fui==NEP_USER_INTERFACE_SPLIT && nep->P) || (nep->fui==NEP_USER_INTERFACE_CALLBACK && nep->function_pre!=nep->function)) {
929 96 : PetscCall(KSPSetType(contour->ksp[i],KSPBCGS));
930 96 : PetscCall(PCSetType(pc,PCBJACOBI));
931 : } else {
932 736 : PetscCall(KSPSetType(contour->ksp[i],KSPPREONLY));
933 832 : PetscCall(PCSetType(pc,PCLU));
934 : }
935 : }
936 : }
937 44 : if (nsolve) *nsolve = contour->npoints;
938 44 : if (ksp) *ksp = contour->ksp;
939 44 : PetscFunctionReturn(PETSC_SUCCESS);
940 : }
941 :
942 : /*@C
943 : NEPCISSGetKSPs - Retrieve the array of linear solver objects associated with
944 : the CISS solver.
945 :
946 : Collective
947 :
948 : Input Parameter:
949 : . nep - nonlinear eigenvalue solver
950 :
951 : Output Parameters:
952 : + nsolve - number of solver objects
953 : - ksp - array of linear solver object
954 :
955 : Notes:
956 : The number of KSP solvers is equal to the number of integration points divided by
957 : the number of partitions. This value is halved in the case of real matrices with
958 : a region centered at the real axis.
959 :
960 : Level: advanced
961 :
962 : .seealso: NEPCISSSetSizes()
963 : @*/
964 44 : PetscErrorCode NEPCISSGetKSPs(NEP nep,PetscInt *nsolve,KSP **ksp)
965 : {
966 44 : PetscFunctionBegin;
967 44 : PetscValidHeaderSpecific(nep,NEP_CLASSID,1);
968 44 : PetscUseMethod(nep,"NEPCISSGetKSPs_C",(NEP,PetscInt*,KSP**),(nep,nsolve,ksp));
969 44 : PetscFunctionReturn(PETSC_SUCCESS);
970 : }
971 :
972 40 : static PetscErrorCode NEPReset_CISS(NEP nep)
973 : {
974 40 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
975 :
976 40 : PetscFunctionBegin;
977 40 : PetscCall(BVDestroy(&ctx->S));
978 40 : PetscCall(BVDestroy(&ctx->V));
979 40 : PetscCall(BVDestroy(&ctx->Y));
980 40 : PetscCall(SlepcContourDataReset(ctx->contour));
981 40 : PetscCall(MatDestroy(&ctx->J));
982 40 : PetscCall(BVDestroy(&ctx->pV));
983 40 : if (ctx->extraction == NEP_CISS_EXTRACTION_RITZ && nep->fui==NEP_USER_INTERFACE_CALLBACK) PetscCall(PetscFree(ctx->dsctxf));
984 40 : PetscFunctionReturn(PETSC_SUCCESS);
985 : }
986 :
987 38 : static PetscErrorCode NEPSetFromOptions_CISS(NEP nep,PetscOptionItems *PetscOptionsObject)
988 : {
989 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
990 38 : PetscReal r1,r2;
991 38 : PetscInt i,i1,i2,i3,i4,i5,i6,i7;
992 38 : PetscBool b1,flg,flg2,flg3,flg4,flg5,flg6;
993 38 : NEPCISSExtraction extraction;
994 :
995 38 : PetscFunctionBegin;
996 38 : PetscOptionsHeadBegin(PetscOptionsObject,"NEP CISS Options");
997 :
998 38 : PetscCall(NEPCISSGetSizes(nep,&i1,&i2,&i3,&i4,&i5,&b1));
999 38 : PetscCall(PetscOptionsInt("-nep_ciss_integration_points","Number of integration points","NEPCISSSetSizes",i1,&i1,&flg));
1000 38 : PetscCall(PetscOptionsInt("-nep_ciss_blocksize","Block size","NEPCISSSetSizes",i2,&i2,&flg2));
1001 38 : PetscCall(PetscOptionsInt("-nep_ciss_moments","Moment size","NEPCISSSetSizes",i3,&i3,&flg3));
1002 38 : PetscCall(PetscOptionsInt("-nep_ciss_partitions","Number of partitions","NEPCISSSetSizes",i4,&i4,&flg4));
1003 38 : PetscCall(PetscOptionsInt("-nep_ciss_maxblocksize","Maximum block size","NEPCISSSetSizes",i5,&i5,&flg5));
1004 38 : PetscCall(PetscOptionsBool("-nep_ciss_realmats","True if T(z) is real for real z","NEPCISSSetSizes",b1,&b1,&flg6));
1005 38 : if (flg || flg2 || flg3 || flg4 || flg5 || flg6) PetscCall(NEPCISSSetSizes(nep,i1,i2,i3,i4,i5,b1));
1006 :
1007 38 : PetscCall(NEPCISSGetThreshold(nep,&r1,&r2));
1008 38 : PetscCall(PetscOptionsReal("-nep_ciss_delta","Threshold for numerical rank","NEPCISSSetThreshold",r1,&r1,&flg));
1009 38 : PetscCall(PetscOptionsReal("-nep_ciss_spurious_threshold","Threshold for the spurious eigenpairs","NEPCISSSetThreshold",r2,&r2,&flg2));
1010 38 : if (flg || flg2) PetscCall(NEPCISSSetThreshold(nep,r1,r2));
1011 :
1012 38 : PetscCall(NEPCISSGetRefinement(nep,&i6,&i7));
1013 38 : PetscCall(PetscOptionsInt("-nep_ciss_refine_inner","Number of inner iterative refinement iterations","NEPCISSSetRefinement",i6,&i6,&flg));
1014 38 : PetscCall(PetscOptionsInt("-nep_ciss_refine_blocksize","Number of blocksize iterative refinement iterations","NEPCISSSetRefinement",i7,&i7,&flg2));
1015 38 : if (flg || flg2) PetscCall(NEPCISSSetRefinement(nep,i6,i7));
1016 :
1017 38 : PetscCall(PetscOptionsEnum("-nep_ciss_extraction","Extraction technique","NEPCISSSetExtraction",NEPCISSExtractions,(PetscEnum)ctx->extraction,(PetscEnum*)&extraction,&flg));
1018 38 : if (flg) PetscCall(NEPCISSSetExtraction(nep,extraction));
1019 :
1020 38 : PetscOptionsHeadEnd();
1021 :
1022 38 : if (!nep->rg) PetscCall(NEPGetRG(nep,&nep->rg));
1023 38 : PetscCall(RGSetFromOptions(nep->rg)); /* this is necessary here to set useconj */
1024 38 : if (!ctx->contour || !ctx->contour->ksp) PetscCall(NEPCISSGetKSPs(nep,NULL,NULL));
1025 38 : PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Something went wrong with NEPCISSGetKSPs()");
1026 774 : for (i=0;i<ctx->contour->npoints;i++) PetscCall(KSPSetFromOptions(ctx->contour->ksp[i]));
1027 38 : PetscCall(PetscSubcommSetFromOptions(ctx->contour->subcomm));
1028 38 : PetscFunctionReturn(PETSC_SUCCESS);
1029 : }
1030 :
1031 38 : static PetscErrorCode NEPDestroy_CISS(NEP nep)
1032 : {
1033 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
1034 :
1035 38 : PetscFunctionBegin;
1036 38 : PetscCall(SlepcContourDataDestroy(&ctx->contour));
1037 38 : PetscCall(PetscFree4(ctx->weight,ctx->omega,ctx->pp,ctx->sigma));
1038 38 : PetscCall(PetscFree(nep->data));
1039 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetSizes_C",NULL));
1040 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetSizes_C",NULL));
1041 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetThreshold_C",NULL));
1042 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetThreshold_C",NULL));
1043 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetRefinement_C",NULL));
1044 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetRefinement_C",NULL));
1045 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetExtraction_C",NULL));
1046 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetExtraction_C",NULL));
1047 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetKSPs_C",NULL));
1048 38 : PetscFunctionReturn(PETSC_SUCCESS);
1049 : }
1050 :
1051 1 : static PetscErrorCode NEPView_CISS(NEP nep,PetscViewer viewer)
1052 : {
1053 1 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
1054 1 : PetscBool isascii;
1055 1 : PetscViewer sviewer;
1056 :
1057 1 : PetscFunctionBegin;
1058 1 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
1059 1 : if (isascii) {
1060 1 : PetscCall(PetscViewerASCIIPrintf(viewer," sizes { integration points: %" PetscInt_FMT ", block size: %" PetscInt_FMT ", moment size: %" PetscInt_FMT ", partitions: %" PetscInt_FMT ", maximum block size: %" PetscInt_FMT " }\n",ctx->N,ctx->L,ctx->M,ctx->npart,ctx->L_max));
1061 1 : if (ctx->isreal) PetscCall(PetscViewerASCIIPrintf(viewer," exploiting symmetry of integration points\n"));
1062 1 : PetscCall(PetscViewerASCIIPrintf(viewer," threshold { delta: %g, spurious threshold: %g }\n",(double)ctx->delta,(double)ctx->spurious_threshold));
1063 1 : PetscCall(PetscViewerASCIIPrintf(viewer," iterative refinement { inner: %" PetscInt_FMT ", blocksize: %" PetscInt_FMT " }\n",ctx->refine_inner, ctx->refine_blocksize));
1064 1 : PetscCall(PetscViewerASCIIPrintf(viewer," extraction: %s\n",NEPCISSExtractions[ctx->extraction]));
1065 1 : if (!ctx->contour || !ctx->contour->ksp) PetscCall(NEPCISSGetKSPs(nep,NULL,NULL));
1066 1 : PetscAssert(ctx->contour && ctx->contour->ksp,PetscObjectComm((PetscObject)nep),PETSC_ERR_PLIB,"Something went wrong with NEPCISSGetKSPs()");
1067 1 : PetscCall(PetscViewerASCIIPushTab(viewer));
1068 1 : if (ctx->npart>1 && ctx->contour->subcomm) {
1069 0 : PetscCall(PetscViewerGetSubViewer(viewer,ctx->contour->subcomm->child,&sviewer));
1070 0 : if (!ctx->contour->subcomm->color) PetscCall(KSPView(ctx->contour->ksp[0],sviewer));
1071 0 : PetscCall(PetscViewerFlush(sviewer));
1072 0 : PetscCall(PetscViewerRestoreSubViewer(viewer,ctx->contour->subcomm->child,&sviewer));
1073 : /* extra call needed because of the two calls to PetscViewerASCIIPushSynchronized() in PetscViewerGetSubViewer() */
1074 0 : PetscCall(PetscViewerASCIIPopSynchronized(viewer));
1075 1 : } else PetscCall(KSPView(ctx->contour->ksp[0],viewer));
1076 1 : PetscCall(PetscViewerASCIIPopTab(viewer));
1077 : }
1078 1 : PetscFunctionReturn(PETSC_SUCCESS);
1079 : }
1080 :
1081 78 : static PetscErrorCode NEPSetDSType_CISS(NEP nep)
1082 : {
1083 78 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
1084 :
1085 78 : PetscFunctionBegin;
1086 78 : switch (ctx->extraction) {
1087 46 : case NEP_CISS_EXTRACTION_RITZ: PetscCall(DSSetType(nep->ds,DSNEP)); break;
1088 16 : case NEP_CISS_EXTRACTION_HANKEL: PetscCall(DSSetType(nep->ds,DSGNHEP)); break;
1089 16 : case NEP_CISS_EXTRACTION_CAA: PetscCall(DSSetType(nep->ds,DSNHEP)); break;
1090 : }
1091 78 : PetscFunctionReturn(PETSC_SUCCESS);
1092 : }
1093 :
1094 38 : SLEPC_EXTERN PetscErrorCode NEPCreate_CISS(NEP nep)
1095 : {
1096 38 : NEP_CISS *ctx = (NEP_CISS*)nep->data;
1097 :
1098 38 : PetscFunctionBegin;
1099 38 : PetscCall(PetscNew(&ctx));
1100 38 : nep->data = ctx;
1101 : /* set default values of parameters */
1102 38 : ctx->N = 32;
1103 38 : ctx->L = 16;
1104 38 : ctx->M = ctx->N/4;
1105 38 : ctx->delta = SLEPC_DEFAULT_TOL*1e-4;
1106 38 : ctx->L_max = 64;
1107 38 : ctx->spurious_threshold = PetscSqrtReal(SLEPC_DEFAULT_TOL);
1108 38 : ctx->isreal = PETSC_FALSE;
1109 38 : ctx->npart = 1;
1110 :
1111 38 : nep->useds = PETSC_TRUE;
1112 :
1113 38 : nep->ops->solve = NEPSolve_CISS;
1114 38 : nep->ops->setup = NEPSetUp_CISS;
1115 38 : nep->ops->setfromoptions = NEPSetFromOptions_CISS;
1116 38 : nep->ops->reset = NEPReset_CISS;
1117 38 : nep->ops->destroy = NEPDestroy_CISS;
1118 38 : nep->ops->view = NEPView_CISS;
1119 38 : nep->ops->setdstype = NEPSetDSType_CISS;
1120 :
1121 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetSizes_C",NEPCISSSetSizes_CISS));
1122 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetSizes_C",NEPCISSGetSizes_CISS));
1123 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetThreshold_C",NEPCISSSetThreshold_CISS));
1124 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetThreshold_C",NEPCISSGetThreshold_CISS));
1125 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetRefinement_C",NEPCISSSetRefinement_CISS));
1126 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetRefinement_C",NEPCISSGetRefinement_CISS));
1127 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSSetExtraction_C",NEPCISSSetExtraction_CISS));
1128 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetExtraction_C",NEPCISSGetExtraction_CISS));
1129 38 : PetscCall(PetscObjectComposeFunction((PetscObject)nep,"NEPCISSGetKSPs_C",NEPCISSGetKSPs_CISS));
1130 38 : PetscFunctionReturn(PETSC_SUCCESS);
1131 : }
|