Date: 2026-03-09T09:12:21+00:00

Actual source code: nepsetup.c

      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 - the 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: [](ch:nep), `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 nonlinear eigensolver.

     45:    Collective

     47:    Input Parameter:
     48: .  nep - the nonlinear eigensolver 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: [](ch:nep), `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:       nep->sc->comparison    = SlepcCompareTargetImaginary;
    178:       nep->sc->comparisonctx = &nep->target;
    179:       break;
    180:     case NEP_ALL:
    181:       nep->sc->comparison    = SlepcCompareSmallestReal;
    182:       nep->sc->comparisonctx = NULL;
    183:       break;
    184:     case NEP_WHICH_USER:
    185:       break;
    186:   }

    188:   nep->sc->map    = NULL;
    189:   nep->sc->mapobj = NULL;

    191:   /* fill sorting criterion for DS */
    192:   if (nep->useds) {
    193:     PetscCall(DSGetSlepcSC(nep->ds,&sc));
    194:     sc->comparison    = nep->sc->comparison;
    195:     sc->comparisonctx = nep->sc->comparisonctx;
    196:     PetscCall(PetscObjectTypeCompare((PetscObject)nep,NEPNLEIGS,&flg));
    197:     if (!flg) {
    198:       sc->map    = NULL;
    199:       sc->mapobj = NULL;
    200:     }
    201:   }
    202:   PetscCheck(nep->nev<=nep->ncv,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"nev bigger than ncv");

    204:   /* process initial vectors */
    205:   if (nep->nini<0) {
    206:     k = -nep->nini;
    207:     PetscCheck(k<=nep->ncv,PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"The number of initial vectors is larger than ncv");
    208:     PetscCall(BVInsertVecs(nep->V,0,&k,nep->IS,PETSC_TRUE));
    209:     PetscCall(SlepcBasisDestroy_Private(&nep->nini,&nep->IS));
    210:     nep->nini = k;
    211:   }
    212:   PetscCall(PetscLogEventEnd(NEP_SetUp,nep,0,0,0));
    213:   nep->state = NEP_STATE_SETUP;
    214:   PetscFunctionReturn(PETSC_SUCCESS);
    215: }

    217: /*@
    218:    NEPSetInitialSpace - Specify a basis of vectors that constitute the initial
    219:    space, that is, the subspace from which the solver starts to iterate.

    221:    Collective

    223:    Input Parameters:
    224: +  nep   - the nonlinear eigensolver context
    225: .  n     - number of vectors
    226: -  is    - set of basis vectors of the initial space

    228:    Notes:
    229:    Some solvers start to iterate on a single vector (initial vector). In that case,
    230:    the other vectors are ignored.

    232:    These vectors do not persist from one `NEPSolve()` call to the other, so the
    233:    initial space should be set every time.

    235:    The vectors do not need to be mutually orthonormal, since they are explicitly
    236:    orthonormalized internally.

    238:    Common usage of this function is when the user can provide a rough approximation
    239:    of the wanted eigenspace. Then, convergence may be faster.

    241:    Level: intermediate

    243: .seealso: [](ch:nep), `NEPSetUp()`
    244: @*/
    245: PetscErrorCode NEPSetInitialSpace(NEP nep,PetscInt n,Vec is[])
    246: {
    247:   PetscFunctionBegin;
    250:   PetscCheck(n>=0,PetscObjectComm((PetscObject)nep),PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
    251:   if (n>0) {
    252:     PetscAssertPointer(is,3);
    254:   }
    255:   PetscCall(SlepcBasisReference_Private(n,is,&nep->nini,&nep->IS));
    256:   if (n>0) nep->state = NEP_STATE_INITIAL;
    257:   PetscFunctionReturn(PETSC_SUCCESS);
    258: }

    260: /*
    261:   NEPSetDimensions_Default - Set reasonable values for ncv, mpd if not set
    262:   by the user. This is called at setup.
    263:  */
    264: PetscErrorCode NEPSetDimensions_Default(NEP nep,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
    265: {
    266:   PetscFunctionBegin;
    267:   if (*ncv!=PETSC_DETERMINE) { /* ncv set */
    268:     PetscCheck(*ncv>=nev,PetscObjectComm((PetscObject)nep),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev");
    269:   } else if (*mpd!=PETSC_DETERMINE) { /* mpd set */
    270:     *ncv = PetscMin(nep->n,nev+(*mpd));
    271:   } else { /* neither set: defaults depend on nev being small or large */
    272:     if (nev<500) *ncv = PetscMin(nep->n,PetscMax(2*nev,nev+15));
    273:     else {
    274:       *mpd = 500;
    275:       *ncv = PetscMin(nep->n,nev+(*mpd));
    276:     }
    277:   }
    278:   if (*mpd==PETSC_DETERMINE) *mpd = *ncv;
    279:   PetscFunctionReturn(PETSC_SUCCESS);
    280: }

    282: /*@
    283:    NEPAllocateSolution - Allocate memory storage for common variables such
    284:    as eigenvalues and eigenvectors.

    286:    Collective

    288:    Input Parameters:
    289: +  nep   - the nonlinear eigensolver context
    290: -  extra - number of additional positions, used for methods that require a
    291:            working basis slightly larger than `ncv`

    293:    Developer Note:
    294:    This is `SLEPC_EXTERN` because it may be required by user plugin `NEP`
    295:    implementations.

    297:    Level: developer

    299: .seealso: [](ch:nep), `PEPSetUp()`, `PEPSetDimensions()`
    300: @*/
    301: PetscErrorCode NEPAllocateSolution(NEP nep,PetscInt extra)
    302: {
    303:   PetscInt       oldsize,requested;
    304:   PetscRandom    rand;
    305:   Mat            T;
    306:   Vec            t;

    308:   PetscFunctionBegin;
    309:   requested = nep->ncv + extra;

    311:   /* oldsize is zero if this is the first time setup is called */
    312:   PetscCall(BVGetSizes(nep->V,NULL,NULL,&oldsize));

    314:   /* allocate space for eigenvalues and friends */
    315:   if (requested != oldsize || !nep->eigr) {
    316:     PetscCall(PetscFree4(nep->eigr,nep->eigi,nep->errest,nep->perm));
    317:     PetscCall(PetscMalloc4(requested,&nep->eigr,requested,&nep->eigi,requested,&nep->errest,requested,&nep->perm));
    318:   }

    320:   /* allocate V */
    321:   if (!nep->V) PetscCall(NEPGetBV(nep,&nep->V));
    322:   if (!oldsize) {
    323:     if (!((PetscObject)nep->V)->type_name) PetscCall(BVSetType(nep->V,BVMAT));
    324:     if (nep->fui==NEP_USER_INTERFACE_SPLIT) T = nep->A[0];
    325:     else PetscCall(NEPGetFunction(nep,&T,NULL,NULL,NULL));
    326:     PetscCall(MatCreateVecsEmpty(T,&t,NULL));
    327:     PetscCall(BVSetSizesFromVec(nep->V,t,requested));
    328:     PetscCall(VecDestroy(&t));
    329:   } else PetscCall(BVResize(nep->V,requested,PETSC_FALSE));

    331:   /* allocate W */
    332:   if (nep->twosided) {
    333:     PetscCall(BVGetRandomContext(nep->V,&rand));  /* make sure the random context is available when duplicating */
    334:     PetscCall(BVDestroy(&nep->W));
    335:     PetscCall(BVDuplicate(nep->V,&nep->W));
    336:   }
    337:   PetscFunctionReturn(PETSC_SUCCESS);
    338: }