Actual source code: nepsetup.c
slepc-main 2024-12-17
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: NEP routines related to problem setup
12: */
14: #include <slepc/private/nepimpl.h>
16: /*@
17: NEPSetDSType - Sets the type of the internal DS object based on the current
18: settings of the nonlinear eigensolver.
20: Collective
22: Input Parameter:
23: . nep - nonlinear eigensolver context
25: Note:
26: This function need not be called explicitly, since it will be called at
27: both NEPSetFromOptions() and NEPSetUp().
29: Level: developer
31: .seealso: NEPSetFromOptions(), NEPSetUp()
32: @*/
33: PetscErrorCode NEPSetDSType(NEP nep)
34: {
35: PetscFunctionBegin;
37: PetscTryTypeMethod(nep,setdstype);
38: PetscFunctionReturn(PETSC_SUCCESS);
39: }
41: /*@
42: NEPSetUp - Sets up all the internal data structures necessary for the
43: execution of the NEP solver.
45: Collective
47: Input Parameter:
48: . nep - solver context
50: Notes:
51: This function need not be called explicitly in most cases, since NEPSolve()
52: calls it. It can be useful when one wants to measure the set-up time
53: separately from the solve time.
55: Level: developer
57: .seealso: NEPCreate(), NEPSolve(), NEPDestroy()
58: @*/
59: PetscErrorCode NEPSetUp(NEP nep)
60: {
61: PetscInt k;
62: SlepcSC sc;
63: Mat T;
64: PetscBool flg;
65: KSP ksp;
66: PC pc;
67: PetscMPIInt size;
68: MatSolverType stype;
70: PetscFunctionBegin;
72: NEPCheckProblem(nep,1);
73: if (nep->state) PetscFunctionReturn(PETSC_SUCCESS);
74: PetscCall(PetscLogEventBegin(NEP_SetUp,nep,0,0,0));
76: /* reset the convergence flag from the previous solves */
77: nep->reason = NEP_CONVERGED_ITERATING;
79: /* set default solver type (NEPSetFromOptions was not called) */
80: if (!((PetscObject)nep)->type_name) PetscCall(NEPSetType(nep,NEPRII));
81: if (nep->useds && !nep->ds) PetscCall(NEPGetDS(nep,&nep->ds));
82: if (nep->useds) PetscCall(NEPSetDSType(nep));
83: if (!nep->rg) PetscCall(NEPGetRG(nep,&nep->rg));
84: if (!((PetscObject)nep->rg)->type_name) PetscCall(RGSetType(nep->rg,RGINTERVAL));
86: /* set problem dimensions */
87: switch (nep->fui) {
88: case NEP_USER_INTERFACE_CALLBACK:
89: PetscCall(NEPGetFunction(nep,&T,NULL,NULL,NULL));
90: PetscCall(MatGetSize(T,&nep->n,NULL));
91: PetscCall(MatGetLocalSize(T,&nep->nloc,NULL));
92: break;
93: case NEP_USER_INTERFACE_SPLIT:
94: PetscCall(MatDuplicate(nep->A[0],MAT_DO_NOT_COPY_VALUES,&nep->function));
95: if (nep->P) PetscCall(MatDuplicate(nep->P[0],MAT_DO_NOT_COPY_VALUES,&nep->function_pre));
96: PetscCall(MatDuplicate(nep->A[0],MAT_DO_NOT_COPY_VALUES,&nep->jacobian));
97: PetscCall(MatGetSize(nep->A[0],&nep->n,NULL));
98: PetscCall(MatGetLocalSize(nep->A[0],&nep->nloc,NULL));
99: break;
100: }
102: /* set default problem type */
103: if (!nep->problem_type) PetscCall(NEPSetProblemType(nep,NEP_GENERAL));
105: /* check consistency of refinement options */
106: if (nep->refine) {
107: PetscCheck(nep->fui==NEP_USER_INTERFACE_SPLIT,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"Iterative refinement only implemented in split form");
108: if (!nep->scheme) { /* set default scheme */
109: PetscCall(NEPRefineGetKSP(nep,&ksp));
110: PetscCall(KSPGetPC(ksp,&pc));
111: PetscCall(PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg));
112: if (flg) PetscCall(PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,""));
113: nep->scheme = flg? NEP_REFINE_SCHEME_MBE: NEP_REFINE_SCHEME_SCHUR;
114: }
115: if (nep->scheme==NEP_REFINE_SCHEME_MBE) {
116: PetscCall(NEPRefineGetKSP(nep,&ksp));
117: PetscCall(KSPGetPC(ksp,&pc));
118: PetscCall(PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg));
119: if (flg) PetscCall(PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,""));
120: PetscCheck(flg,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"The MBE scheme for refinement requires a direct solver in KSP");
121: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size));
122: if (size>1) { /* currently selected PC is a factorization */
123: PetscCall(PCFactorGetMatSolverType(pc,&stype));
124: PetscCall(PetscStrcmp(stype,MATSOLVERPETSC,&flg));
125: PetscCheck(!flg,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"For Newton refinement, you chose to solve linear systems with a factorization, but in parallel runs you need to select an external package");
126: }
127: }
128: if (nep->scheme==NEP_REFINE_SCHEME_SCHUR) {
129: PetscCheck(nep->npart==1,PetscObjectComm((PetscObject)nep),PETSC_ERR_SUP,"The Schur scheme for refinement does not support subcommunicators");
130: }
131: }
132: /* call specific solver setup */
133: PetscUseTypeMethod(nep,setup);
135: /* set tolerance if not yet set */
136: if (nep->tol==(PetscReal)PETSC_DETERMINE) nep->tol = SLEPC_DEFAULT_TOL;
137: if (nep->refine) {
138: if (nep->rtol==(PetscReal)PETSC_DETERMINE) nep->rtol = PetscMax(nep->tol/1000,PETSC_MACHINE_EPSILON);
139: if (nep->rits==(PetscReal)PETSC_DETERMINE) nep->rits = (nep->refine==NEP_REFINE_SIMPLE)? 10: 1;
140: }
142: /* fill sorting criterion context */
143: switch (nep->which) {
144: case NEP_LARGEST_MAGNITUDE:
145: nep->sc->comparison = SlepcCompareLargestMagnitude;
146: nep->sc->comparisonctx = NULL;
147: break;
148: case NEP_SMALLEST_MAGNITUDE:
149: nep->sc->comparison = SlepcCompareSmallestMagnitude;
150: nep->sc->comparisonctx = NULL;
151: break;
152: case NEP_LARGEST_REAL:
153: nep->sc->comparison = SlepcCompareLargestReal;
154: nep->sc->comparisonctx = NULL;
155: break;
156: case NEP_SMALLEST_REAL:
157: nep->sc->comparison = SlepcCompareSmallestReal;
158: nep->sc->comparisonctx = NULL;
159: break;
160: case NEP_LARGEST_IMAGINARY:
161: nep->sc->comparison = SlepcCompareLargestImaginary;
162: nep->sc->comparisonctx = NULL;
163: break;
164: case NEP_SMALLEST_IMAGINARY:
165: nep->sc->comparison = SlepcCompareSmallestImaginary;
166: nep->sc->comparisonctx = NULL;
167: break;
168: case NEP_TARGET_MAGNITUDE:
169: nep->sc->comparison = SlepcCompareTargetMagnitude;
170: nep->sc->comparisonctx = &nep->target;
171: break;
172: case NEP_TARGET_REAL:
173: nep->sc->comparison = SlepcCompareTargetReal;
174: nep->sc->comparisonctx = &nep->target;
175: break;
176: case NEP_TARGET_IMAGINARY:
177: #if defined(PETSC_USE_COMPLEX)
178: nep->sc->comparison = SlepcCompareTargetImaginary;
179: nep->sc->comparisonctx = &nep->target;
180: #endif
181: break;
182: case NEP_ALL:
183: nep->sc->comparison = SlepcCompareSmallestReal;
184: nep->sc->comparisonctx = NULL;
185: break;
186: case NEP_WHICH_USER:
187: break;
188: }
190: nep->sc->map = NULL;
191: nep->sc->mapobj = NULL;
193: /* fill sorting criterion for DS */
194: if (nep->useds) {
195: PetscCall(DSGetSlepcSC(nep->ds,&sc));
196: sc->comparison = nep->sc->comparison;
197: sc->comparisonctx = nep->sc->comparisonctx;
198: PetscCall(PetscObjectTypeCompare((PetscObject)nep,NEPNLEIGS,&flg));
199: if (!flg) {
200: sc->map = NULL;
201: sc->mapobj = NULL;
202: }
203: }
204: PetscCheck(nep->nev<=nep->ncv,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"nev bigger than ncv");
206: /* process initial vectors */
207: if (nep->nini<0) {
208: k = -nep->nini;
209: PetscCheck(k<=nep->ncv,PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"The number of initial vectors is larger than ncv");
210: PetscCall(BVInsertVecs(nep->V,0,&k,nep->IS,PETSC_TRUE));
211: PetscCall(SlepcBasisDestroy_Private(&nep->nini,&nep->IS));
212: nep->nini = k;
213: }
214: PetscCall(PetscLogEventEnd(NEP_SetUp,nep,0,0,0));
215: nep->state = NEP_STATE_SETUP;
216: PetscFunctionReturn(PETSC_SUCCESS);
217: }
219: /*@
220: NEPSetInitialSpace - Specify a basis of vectors that constitute the initial
221: space, that is, the subspace from which the solver starts to iterate.
223: Collective
225: Input Parameters:
226: + nep - the nonlinear eigensolver context
227: . n - number of vectors
228: - is - set of basis vectors of the initial space
230: Notes:
231: Some solvers start to iterate on a single vector (initial vector). In that case,
232: the other vectors are ignored.
234: These vectors do not persist from one NEPSolve() call to the other, so the
235: initial space should be set every time.
237: The vectors do not need to be mutually orthonormal, since they are explicitly
238: orthonormalized internally.
240: Common usage of this function is when the user can provide a rough approximation
241: of the wanted eigenspace. Then, convergence may be faster.
243: Level: intermediate
245: .seealso: NEPSetUp()
246: @*/
247: PetscErrorCode NEPSetInitialSpace(NEP nep,PetscInt n,Vec is[])
248: {
249: PetscFunctionBegin;
252: PetscCheck(n>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
253: if (n>0) {
254: PetscAssertPointer(is,3);
256: }
257: PetscCall(SlepcBasisReference_Private(n,is,&nep->nini,&nep->IS));
258: if (n>0) nep->state = NEP_STATE_INITIAL;
259: PetscFunctionReturn(PETSC_SUCCESS);
260: }
262: /*
263: NEPSetDimensions_Default - Set reasonable values for ncv, mpd if not set
264: by the user. This is called at setup.
265: */
266: PetscErrorCode NEPSetDimensions_Default(NEP nep,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
267: {
268: PetscFunctionBegin;
269: if (*ncv!=PETSC_DETERMINE) { /* ncv set */
270: PetscCheck(*ncv>=nev,PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev");
271: } else if (*mpd!=PETSC_DETERMINE) { /* mpd set */
272: *ncv = PetscMin(nep->n,nev+(*mpd));
273: } else { /* neither set: defaults depend on nev being small or large */
274: if (nev<500) *ncv = PetscMin(nep->n,PetscMax(2*nev,nev+15));
275: else {
276: *mpd = 500;
277: *ncv = PetscMin(nep->n,nev+(*mpd));
278: }
279: }
280: if (*mpd==PETSC_DETERMINE) *mpd = *ncv;
281: PetscFunctionReturn(PETSC_SUCCESS);
282: }
284: /*@
285: NEPAllocateSolution - Allocate memory storage for common variables such
286: as eigenvalues and eigenvectors.
288: Collective
290: Input Parameters:
291: + nep - eigensolver context
292: - extra - number of additional positions, used for methods that require a
293: working basis slightly larger than ncv
295: Developer Notes:
296: This is SLEPC_EXTERN because it may be required by user plugin NEP
297: implementations.
299: Level: developer
301: .seealso: PEPSetUp()
302: @*/
303: PetscErrorCode NEPAllocateSolution(NEP nep,PetscInt extra)
304: {
305: PetscInt oldsize,requested;
306: PetscRandom rand;
307: Mat T;
308: Vec t;
310: PetscFunctionBegin;
311: requested = nep->ncv + extra;
313: /* oldsize is zero if this is the first time setup is called */
314: PetscCall(BVGetSizes(nep->V,NULL,NULL,&oldsize));
316: /* allocate space for eigenvalues and friends */
317: if (requested != oldsize || !nep->eigr) {
318: PetscCall(PetscFree4(nep->eigr,nep->eigi,nep->errest,nep->perm));
319: PetscCall(PetscMalloc4(requested,&nep->eigr,requested,&nep->eigi,requested,&nep->errest,requested,&nep->perm));
320: }
322: /* allocate V */
323: if (!nep->V) PetscCall(NEPGetBV(nep,&nep->V));
324: if (!oldsize) {
325: if (!((PetscObject)nep->V)->type_name) PetscCall(BVSetType(nep->V,BVMAT));
326: if (nep->fui==NEP_USER_INTERFACE_SPLIT) T = nep->A[0];
327: else PetscCall(NEPGetFunction(nep,&T,NULL,NULL,NULL));
328: PetscCall(MatCreateVecsEmpty(T,&t,NULL));
329: PetscCall(BVSetSizesFromVec(nep->V,t,requested));
330: PetscCall(VecDestroy(&t));
331: } else PetscCall(BVResize(nep->V,requested,PETSC_FALSE));
333: /* allocate W */
334: if (nep->twosided) {
335: PetscCall(BVGetRandomContext(nep->V,&rand)); /* make sure the random context is available when duplicating */
336: PetscCall(BVDestroy(&nep->W));
337: PetscCall(BVDuplicate(nep->V,&nep->W));
338: }
339: PetscFunctionReturn(PETSC_SUCCESS);
340: }