Actual source code: pepsetup.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:    PEP routines related to problem setup
     12: */

     14: #include <slepc/private/pepimpl.h>

     16: /*
     17:    Let the solver choose the ST type that should be used by default,
     18:    otherwise set it to SHIFT.
     19:    This is called at PEPSetFromOptions (before STSetFromOptions)
     20:    and also at PEPSetUp (in case PEPSetFromOptions was not called).
     21: */
     22: PetscErrorCode PEPSetDefaultST(PEP pep)
     23: {
     24:   PetscFunctionBegin;
     25:   PetscTryTypeMethod(pep,setdefaultst);
     26:   if (!((PetscObject)pep->st)->type_name) PetscCall(STSetType(pep->st,STSHIFT));
     27:   PetscFunctionReturn(PETSC_SUCCESS);
     28: }

     30: /*
     31:    This is used in Q-Arnoldi and STOAR to set the transform flag by
     32:    default, otherwise the user has to explicitly run with -st_transform
     33: */
     34: PetscErrorCode PEPSetDefaultST_Transform(PEP pep)
     35: {
     36:   PetscFunctionBegin;
     37:   PetscCall(STSetTransform(pep->st,PETSC_TRUE));
     38:   PetscFunctionReturn(PETSC_SUCCESS);
     39: }

     41: /*@
     42:    PEPSetDSType - Sets the type of the internal `DS` object based on the current
     43:    settings of the polynomial eigensolver.

     45:    Collective

     47:    Input Parameter:
     48: .  pep - the polynomial eigensolver context

     50:    Note:
     51:    This function need not be called explicitly, since it will be called at
     52:    both `PEPSetFromOptions()` and `PEPSetUp()`.

     54:    Level: developer

     56: .seealso: [](ch:pep), `PEPSetFromOptions()`, `PEPSetUp()`
     57: @*/
     58: PetscErrorCode PEPSetDSType(PEP pep)
     59: {
     60:   PetscFunctionBegin;
     62:   PetscTryTypeMethod(pep,setdstype);
     63:   PetscFunctionReturn(PETSC_SUCCESS);
     64: }

     66: /*@
     67:    PEPSetUp - Sets up all the internal data structures necessary for the
     68:    execution of the polynomial eigensolver.

     70:    Collective

     72:    Input Parameter:
     73: .  pep - the polynomial eigensolver context

     75:    Notes:
     76:    This function need not be called explicitly in most cases, since `PEPSolve()`
     77:    calls it. It can be useful when one wants to measure the set-up time
     78:    separately from the solve time.

     80:    Level: developer

     82: .seealso: [](ch:pep), `PEPCreate()`, `PEPSolve()`, `PEPDestroy()`
     83: @*/
     84: PetscErrorCode PEPSetUp(PEP pep)
     85: {
     86:   SlepcSC        sc;
     87:   PetscBool      istrivial,flg;
     88:   PetscInt       k;
     89:   KSP            ksp;
     90:   PC             pc;
     91:   PetscMPIInt    size;
     92:   MatSolverType  stype;

     94:   PetscFunctionBegin;
     96:   if (pep->state) PetscFunctionReturn(PETSC_SUCCESS);
     97:   PetscCall(PetscLogEventBegin(PEP_SetUp,pep,0,0,0));

     99:   /* reset the convergence flag from the previous solves */
    100:   pep->reason = PEP_CONVERGED_ITERATING;

    102:   /* set default solver type (PEPSetFromOptions was not called) */
    103:   if (!((PetscObject)pep)->type_name) PetscCall(PEPSetType(pep,PEPTOAR));
    104:   if (!pep->st) PetscCall(PEPGetST(pep,&pep->st));
    105:   PetscCall(PEPSetDefaultST(pep));
    106:   if (!pep->ds) PetscCall(PEPGetDS(pep,&pep->ds));
    107:   PetscCall(PEPSetDSType(pep));
    108:   if (!pep->rg) PetscCall(PEPGetRG(pep,&pep->rg));
    109:   if (!((PetscObject)pep->rg)->type_name) PetscCall(RGSetType(pep->rg,RGINTERVAL));

    111:   /* check matrices, transfer them to ST */
    112:   PetscCheck(pep->A,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONGSTATE,"PEPSetOperators must be called first");
    113:   PetscCall(STSetMatrices(pep->st,pep->nmat,pep->A));

    115:   /* set problem dimensions */
    116:   PetscCall(MatGetSize(pep->A[0],&pep->n,NULL));
    117:   PetscCall(MatGetLocalSize(pep->A[0],&pep->nloc,NULL));

    119:   /* set default problem type */
    120:   if (!pep->problem_type) PetscCall(PEPSetProblemType(pep,PEP_GENERAL));
    121:   if (pep->nev > (pep->nmat-1)*pep->n) pep->nev = (pep->nmat-1)*pep->n;
    122:   if (pep->ncv > (pep->nmat-1)*pep->n) pep->ncv = (pep->nmat-1)*pep->n;

    124:   /* check consistency of refinement options */
    125:   if (pep->refine) {
    126:     if (!pep->scheme) {  /* set default scheme */
    127:       PetscCall(PEPRefineGetKSP(pep,&ksp));
    128:       PetscCall(KSPGetPC(ksp,&pc));
    129:       PetscCall(PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg));
    130:       if (flg) PetscCall(PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,""));
    131:       pep->scheme = flg? PEP_REFINE_SCHEME_MBE: PEP_REFINE_SCHEME_SCHUR;
    132:     }
    133:     if (pep->scheme==PEP_REFINE_SCHEME_MBE) {
    134:       PetscCall(PEPRefineGetKSP(pep,&ksp));
    135:       PetscCall(KSPGetPC(ksp,&pc));
    136:       PetscCall(PetscObjectTypeCompare((PetscObject)ksp,KSPPREONLY,&flg));
    137:       if (flg) PetscCall(PetscObjectTypeCompareAny((PetscObject)pc,&flg,PCLU,PCCHOLESKY,""));
    138:       PetscCheck(flg,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"The MBE scheme for refinement requires a direct solver in KSP");
    139:       PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size));
    140:       if (size>1) {   /* currently selected PC is a factorization */
    141:         PetscCall(PCFactorGetMatSolverType(pc,&stype));
    142:         PetscCall(PetscStrcmp(stype,MATSOLVERPETSC,&flg));
    143:         PetscCheck(!flg,PetscObjectComm((PetscObject)pep),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");
    144:       }
    145:     }
    146:     if (pep->scheme==PEP_REFINE_SCHEME_SCHUR) {
    147:       PetscCheck(pep->npart==1,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"The Schur scheme for refinement does not support subcommunicators");
    148:     }
    149:   }
    150:   /* call specific solver setup */
    151:   PetscUseTypeMethod(pep,setup);

    153:   /* set tolerance if not yet set */
    154:   if (pep->tol==(PetscReal)PETSC_DETERMINE) pep->tol = SLEPC_DEFAULT_TOL;
    155:   if (pep->refine) {
    156:     if (pep->rtol==(PetscReal)PETSC_DETERMINE) pep->rtol = PetscMax(pep->tol/1000,PETSC_MACHINE_EPSILON);
    157:     if (pep->rits==PETSC_DETERMINE) pep->rits = (pep->refine==PEP_REFINE_SIMPLE)? 10: 1;
    158:   }

    160:   /* set default extraction */
    161:   if (!pep->extract) {
    162:     pep->extract = (pep->basis==PEP_BASIS_MONOMIAL)? PEP_EXTRACT_NORM: PEP_EXTRACT_NONE;
    163:   }

    165:   /* fill sorting criterion context */
    166:   switch (pep->which) {
    167:     case PEP_LARGEST_MAGNITUDE:
    168:       pep->sc->comparison    = SlepcCompareLargestMagnitude;
    169:       pep->sc->comparisonctx = NULL;
    170:       break;
    171:     case PEP_SMALLEST_MAGNITUDE:
    172:       pep->sc->comparison    = SlepcCompareSmallestMagnitude;
    173:       pep->sc->comparisonctx = NULL;
    174:       break;
    175:     case PEP_LARGEST_REAL:
    176:       pep->sc->comparison    = SlepcCompareLargestReal;
    177:       pep->sc->comparisonctx = NULL;
    178:       break;
    179:     case PEP_SMALLEST_REAL:
    180:       pep->sc->comparison    = SlepcCompareSmallestReal;
    181:       pep->sc->comparisonctx = NULL;
    182:       break;
    183:     case PEP_LARGEST_IMAGINARY:
    184:       pep->sc->comparison    = SlepcCompareLargestImaginary;
    185:       pep->sc->comparisonctx = NULL;
    186:       break;
    187:     case PEP_SMALLEST_IMAGINARY:
    188:       pep->sc->comparison    = SlepcCompareSmallestImaginary;
    189:       pep->sc->comparisonctx = NULL;
    190:       break;
    191:     case PEP_TARGET_MAGNITUDE:
    192:       pep->sc->comparison    = SlepcCompareTargetMagnitude;
    193:       pep->sc->comparisonctx = &pep->target;
    194:       break;
    195:     case PEP_TARGET_REAL:
    196:       pep->sc->comparison    = SlepcCompareTargetReal;
    197:       pep->sc->comparisonctx = &pep->target;
    198:       break;
    199:     case PEP_TARGET_IMAGINARY:
    200:       pep->sc->comparison    = SlepcCompareTargetImaginary;
    201:       pep->sc->comparisonctx = &pep->target;
    202:       break;
    203:     case PEP_ALL:
    204:       pep->sc->comparison    = SlepcCompareSmallestReal;
    205:       pep->sc->comparisonctx = NULL;
    206:       break;
    207:     case PEP_WHICH_USER:
    208:       break;
    209:   }
    210:   pep->sc->map    = NULL;
    211:   pep->sc->mapobj = NULL;

    213:   /* fill sorting criterion for DS */
    214:   if (pep->which!=PEP_ALL) {
    215:     PetscCall(DSGetSlepcSC(pep->ds,&sc));
    216:     PetscCall(RGIsTrivial(pep->rg,&istrivial));
    217:     sc->rg            = istrivial? NULL: pep->rg;
    218:     sc->comparison    = pep->sc->comparison;
    219:     sc->comparisonctx = pep->sc->comparisonctx;
    220:     sc->map           = SlepcMap_ST;
    221:     sc->mapobj        = (PetscObject)pep->st;
    222:   }
    223:   /* setup ST */
    224:   PetscCall(STSetUp(pep->st));

    226:   /* compute matrix coefficients */
    227:   PetscCall(STGetTransform(pep->st,&flg));
    228:   if (!flg) {
    229:     if (pep->which!=PEP_ALL && pep->solvematcoeffs) PetscCall(STMatSetUp(pep->st,1.0,pep->solvematcoeffs));
    230:   } else {
    231:     PetscCheck(pep->basis==PEP_BASIS_MONOMIAL,PetscObjectComm((PetscObject)pep),PETSC_ERR_SUP,"Cannot use ST-transform with non-monomial basis in PEP");
    232:   }

    234:   /* compute scale factor if no set by user */
    235:   PetscCall(PEPComputeScaleFactor(pep));

    237:   /* build balancing matrix if required */
    238:   if (pep->scale==PEP_SCALE_DIAGONAL || pep->scale==PEP_SCALE_BOTH) {
    239:     if (!pep->Dl) PetscCall(BVCreateVec(pep->V,&pep->Dl));
    240:     if (!pep->Dr) PetscCall(BVCreateVec(pep->V,&pep->Dr));
    241:     PetscCall(PEPBuildDiagonalScaling(pep));
    242:   }

    244:   /* process initial vectors */
    245:   if (pep->nini<0) {
    246:     k = -pep->nini;
    247:     PetscCheck(k<=pep->ncv,PetscObjectComm((PetscObject)pep),PETSC_ERR_USER_INPUT,"The number of initial vectors is larger than ncv");
    248:     PetscCall(BVInsertVecs(pep->V,0,&k,pep->IS,PETSC_TRUE));
    249:     PetscCall(SlepcBasisDestroy_Private(&pep->nini,&pep->IS));
    250:     pep->nini = k;
    251:   }
    252:   PetscCall(PetscLogEventEnd(PEP_SetUp,pep,0,0,0));
    253:   pep->state = PEP_STATE_SETUP;
    254:   PetscFunctionReturn(PETSC_SUCCESS);
    255: }

    257: /*@
    258:    PEPSetOperators - Sets the coefficient matrices associated with the polynomial
    259:    eigenvalue problem.

    261:    Collective

    263:    Input Parameters:
    264: +  pep  - the polynomial eigensolver context
    265: .  nmat - number of matrices in array `A`
    266: -  A    - the array of matrices associated with the eigenproblem

    268:    Notes:
    269:    The polynomial eigenproblem is defined as $P(\lambda)x=0$, where $\lambda$
    270:    is the eigenvalue, $x$ is the eigenvector, and $P$ is defined as
    271:    $P(\lambda) = A_0 + \lambda A_1 + \dots + \lambda^d A_d$, with $d$=`nmat`-1
    272:    (the degree of $P$). For non-monomial bases, this expression is different.

    274:    Level: beginner

    276: .seealso: [](ch:pep), `PEPSolve()`, `PEPGetOperators()`, `PEPGetNumMatrices()`, `PEPSetBasis()`
    277: @*/
    278: PetscErrorCode PEPSetOperators(PEP pep,PetscInt nmat,Mat A[])
    279: {
    280:   PetscInt       i,n=0,m,m0=0,mloc,nloc,mloc0=0;

    282:   PetscFunctionBegin;
    285:   PetscCheck(nmat>0,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Non-positive value of nmat: %" PetscInt_FMT,nmat);
    286:   PetscCheck(nmat>2,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Cannot solve linear eigenproblems with PEP; use EPS instead");
    287:   PetscAssertPointer(A,3);

    289:   for (i=0;i<nmat;i++) {
    291:     PetscCheckSameComm(pep,1,A[i],3);
    292:     PetscCall(MatGetSize(A[i],&m,&n));
    293:     PetscCall(MatGetLocalSize(A[i],&mloc,&nloc));
    294:     PetscCheck(m==n,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"A[%" PetscInt_FMT "] is a non-square matrix (%" PetscInt_FMT " rows, %" PetscInt_FMT " cols)",i,m,n);
    295:     PetscCheck(mloc==nloc,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"A[%" PetscInt_FMT "] does not have equal row and column local sizes (%" PetscInt_FMT ", %" PetscInt_FMT ")",i,mloc,nloc);
    296:     if (!i) { m0 = m; mloc0 = mloc; }
    297:     PetscCheck(m==m0,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_INCOMP,"Dimensions of A[%" PetscInt_FMT "] do not match with previous matrices (%" PetscInt_FMT ", %" PetscInt_FMT ")",i,m,m0);
    298:     PetscCheck(mloc==mloc0,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_INCOMP,"Local dimensions of A[%" PetscInt_FMT "] do not match with previous matrices (%" PetscInt_FMT ", %" PetscInt_FMT ")",i,mloc,mloc0);
    299:     PetscCall(PetscObjectReference((PetscObject)A[i]));
    300:   }

    302:   if (pep->state && (n!=pep->n || nloc!=pep->nloc)) PetscCall(PEPReset(pep));
    303:   else if (pep->nmat) {
    304:     PetscCall(MatDestroyMatrices(pep->nmat,&pep->A));
    305:     PetscCall(PetscFree2(pep->pbc,pep->nrma));
    306:     PetscCall(PetscFree(pep->solvematcoeffs));
    307:   }

    309:   PetscCall(PetscMalloc1(nmat,&pep->A));
    310:   PetscCall(PetscCalloc2(3*nmat,&pep->pbc,nmat,&pep->nrma));
    311:   for (i=0;i<nmat;i++) {
    312:     pep->A[i]   = A[i];
    313:     pep->pbc[i] = 1.0;  /* default to monomial basis */
    314:   }
    315:   pep->nmat = nmat;
    316:   pep->state = PEP_STATE_INITIAL;
    317:   PetscFunctionReturn(PETSC_SUCCESS);
    318: }

    320: /*@
    321:    PEPGetOperators - Gets the matrices associated with the polynomial eigensystem.

    323:    Collective

    325:    Input Parameters:
    326: +  pep - the polynomial eigensolver context
    327: -  k   - the index of the requested matrix (starting in 0)

    329:    Output Parameter:
    330: .  A - the requested matrix

    332:    Level: intermediate

    334: .seealso: [](ch:pep), `PEPSolve()`, `PEPSetOperators()`, `PEPGetNumMatrices()`
    335: @*/
    336: PetscErrorCode PEPGetOperators(PEP pep,PetscInt k,Mat *A)
    337: {
    338:   PetscFunctionBegin;
    340:   PetscAssertPointer(A,3);
    341:   PetscCheck(k>=0 && k<pep->nmat,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"k must be between 0 and %" PetscInt_FMT,pep->nmat-1);
    342:   *A = pep->A[k];
    343:   PetscFunctionReturn(PETSC_SUCCESS);
    344: }

    346: /*@
    347:    PEPGetNumMatrices - Returns the number of matrices stored in the `PEP`.

    349:    Not Collective

    351:    Input Parameter:
    352: .  pep - the polynomial eigensolver context

    354:    Output Parameter:
    355: .  nmat - the number of matrices passed in `PEPSetOperators()`

    357:    Level: intermediate

    359: .seealso: [](ch:pep), `PEPSetOperators()`
    360: @*/
    361: PetscErrorCode PEPGetNumMatrices(PEP pep,PetscInt *nmat)
    362: {
    363:   PetscFunctionBegin;
    365:   PetscAssertPointer(nmat,2);
    366:   *nmat = pep->nmat;
    367:   PetscFunctionReturn(PETSC_SUCCESS);
    368: }

    370: /*@
    371:    PEPSetInitialSpace - Specify a basis of vectors that constitute the initial
    372:    space, that is, the subspace from which the solver starts to iterate.

    374:    Collective

    376:    Input Parameters:
    377: +  pep   - the polynomial eigensolver context
    378: .  n     - number of vectors
    379: -  is    - set of basis vectors of the initial space

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

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

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

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

    394:    Level: intermediate

    396: .seealso: [](ch:pep), `PEPSetUp()`
    397: @*/
    398: PetscErrorCode PEPSetInitialSpace(PEP pep,PetscInt n,Vec is[])
    399: {
    400:   PetscFunctionBegin;
    403:   PetscCheck(n>=0,PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument n cannot be negative");
    404:   if (n>0) {
    405:     PetscAssertPointer(is,3);
    407:   }
    408:   PetscCall(SlepcBasisReference_Private(n,is,&pep->nini,&pep->IS));
    409:   if (n>0) pep->state = PEP_STATE_INITIAL;
    410:   PetscFunctionReturn(PETSC_SUCCESS);
    411: }

    413: /*
    414:   PEPSetDimensions_Default - Set reasonable values for ncv, mpd if not set
    415:   by the user. This is called at setup.
    416:  */
    417: PetscErrorCode PEPSetDimensions_Default(PEP pep,PetscInt nev,PetscInt *ncv,PetscInt *mpd)
    418: {
    419:   PetscBool      krylov;
    420:   PetscInt       dim;

    422:   PetscFunctionBegin;
    423:   PetscCall(PetscObjectTypeCompareAny((PetscObject)pep,&krylov,PEPTOAR,PEPSTOAR,PEPQARNOLDI,""));
    424:   dim = (pep->nmat-1)*pep->n;
    425:   if (*ncv!=PETSC_DETERMINE) { /* ncv set */
    426:     if (krylov) {
    427:       PetscCheck(*ncv>nev || (*ncv==nev && *ncv==dim),PetscObjectComm((PetscObject)pep),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev+1");
    428:     } else {
    429:       PetscCheck(*ncv>=nev,PetscObjectComm((PetscObject)pep),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev");
    430:     }
    431:   } else if (*mpd!=PETSC_DETERMINE) { /* mpd set */
    432:     *ncv = PetscMin(dim,nev+(*mpd));
    433:   } else { /* neither set: defaults depend on nev being small or large */
    434:     if (nev<500) *ncv = PetscMin(dim,PetscMax(2*nev,nev+15));
    435:     else {
    436:       *mpd = 500;
    437:       *ncv = PetscMin(dim,nev+(*mpd));
    438:     }
    439:   }
    440:   if (*mpd==PETSC_DETERMINE) *mpd = *ncv;
    441:   PetscFunctionReturn(PETSC_SUCCESS);
    442: }

    444: /*@
    445:    PEPAllocateSolution - Allocate memory storage for common variables such
    446:    as eigenvalues and eigenvectors.

    448:    Collective

    450:    Input Parameters:
    451: +  pep   - the polynomial eigensolver context
    452: -  extra - number of additional positions, used for methods that require a
    453:            working basis slightly larger than `ncv`

    455:    Developer Note:
    456:    This is `SLEPC_EXTERN` because it may be required by user plugin `PEP`
    457:    implementations.

    459:    Level: developer

    461: .seealso: [](ch:pep), `PEPSetUp()`, `PEPSetDimensions()`
    462: @*/
    463: PetscErrorCode PEPAllocateSolution(PEP pep,PetscInt extra)
    464: {
    465:   PetscInt       oldsize,requested,requestedbv;
    466:   Vec            t;

    468:   PetscFunctionBegin;
    469:   requested = (pep->lineariz? pep->ncv: pep->ncv*(pep->nmat-1)) + extra;
    470:   requestedbv = pep->ncv + extra;

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

    475:   /* allocate space for eigenvalues and friends */
    476:   if (requested != oldsize || !pep->eigr) {
    477:     PetscCall(PetscFree4(pep->eigr,pep->eigi,pep->errest,pep->perm));
    478:     PetscCall(PetscMalloc4(requested,&pep->eigr,requested,&pep->eigi,requested,&pep->errest,requested,&pep->perm));
    479:   }

    481:   /* allocate V */
    482:   if (!pep->V) PetscCall(PEPGetBV(pep,&pep->V));
    483:   if (!oldsize) {
    484:     if (!((PetscObject)pep->V)->type_name) PetscCall(BVSetType(pep->V,BVMAT));
    485:     PetscCall(STMatCreateVecsEmpty(pep->st,&t,NULL));
    486:     PetscCall(BVSetSizesFromVec(pep->V,t,requestedbv));
    487:     PetscCall(VecDestroy(&t));
    488:   } else PetscCall(BVResize(pep->V,requestedbv,PETSC_FALSE));
    489:   PetscFunctionReturn(PETSC_SUCCESS);
    490: }