Date: 2022-08-09T09:05:42+00:00

Actual source code: ex34.c
slepc-3.17.2 2022-08-09
Report Typos and Errors

      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:    This is a nonlinear eigenvalue problem. When p=2, it is reduced to a linear Laplace eigenvalue
     12:    problem.

     14:    -\nabla\cdot(|\nabla u|^{p-2} \nabla u) = k |u|^{p-2} u in (0,1)x(0,1),

     16:    u = 0 on the entire boundary.

     18:    The code is implemented based on DMPlex using Q1 FEM on a quadrilateral mesh. In this code, we consider p=3.

     20:    Contributed  by Fande Kong fdkong.jd@gmail.com
     21: */

     23: static char help[] = "Nonlinear inverse iteration for A(x)*x=lambda*B(x)*x.\n\n";

     25: #include <slepceps.h>
     26: #include <petscdmplex.h>
     27: #include <petscds.h>

     29: PetscErrorCode CreateSquareMesh(MPI_Comm,DM*);
     30: PetscErrorCode SetupDiscretization(DM);
     31: PetscErrorCode FormJacobianA(SNES,Vec,Mat,Mat,void*);
     32: PetscErrorCode FormFunctionA(SNES,Vec,Vec,void*);
     33: PetscErrorCode MatMult_A(Mat A,Vec x,Vec y);
     34: PetscErrorCode FormJacobianB(SNES,Vec,Mat,Mat,void*);
     35: PetscErrorCode FormFunctionB(SNES,Vec,Vec,void*);
     36: PetscErrorCode MatMult_B(Mat A,Vec x,Vec y);
     37: PetscErrorCode FormFunctionAB(SNES,Vec,Vec,Vec,void*);
     38: PetscErrorCode BoundaryGlobalIndex(DM,const char*,IS*);

     40: typedef struct {
     41:   IS    bdis; /* global indices for boundary DoFs */
     42:   SNES  snes;
     43: } AppCtx;

     45: int main(int argc,char **argv)
     46: {
     47:   DM             dm;
     48:   MPI_Comm       comm;
     49:   AppCtx         user;
     50:   EPS            eps;  /* eigenproblem solver context */
     51:   ST             st;
     52:   EPSType        type;
     53:   Mat            A,B,P;
     54:   Vec            v0;
     55:   PetscContainer container;
     56:   PetscInt       nev,nconv,m,n,M,N;
     57:   PetscBool      nonlin,flg=PETSC_FALSE,update;
     58:   SNES           snes;
     59:   PetscReal      tol,relerr;
     60:   PetscBool      use_shell_matrix=PETSC_FALSE,test_init_sol=PETSC_FALSE;

     62:   SlepcInitialize(&argc,&argv,(char*)0,help);
     63:   comm = PETSC_COMM_WORLD;
     64:   /* Create a quadrilateral mesh on domain (0,1)x(0,1) */
     65:   CreateSquareMesh(comm,&dm);
     66:   /* Setup basis function */
     67:   SetupDiscretization(dm);
     68:   BoundaryGlobalIndex(dm,"marker",&user.bdis);
     69:   /* Check if we are going to use shell matrices */
     70:   PetscOptionsGetBool(NULL,NULL,"-use_shell_matrix",&use_shell_matrix,NULL);
     71:   if (use_shell_matrix) {
     72:     DMCreateMatrix(dm,&P);
     73:     MatGetLocalSize(P,&m,&n);
     74:     MatGetSize(P,&M,&N);
     75:     MatCreateShell(comm,m,n,M,N,&user,&A);
     76:     MatShellSetOperation(A,MATOP_MULT,(void(*)(void))MatMult_A);
     77:     MatCreateShell(comm,m,n,M,N,&user,&B);
     78:     MatShellSetOperation(B,MATOP_MULT,(void(*)(void))MatMult_B);
     79:   } else {
     80:     DMCreateMatrix(dm,&A);
     81:     MatDuplicate(A,MAT_COPY_VALUES,&B);
     82:   }

     84:   /*
     85:      Compose callback functions and context that will be needed by the solver
     86:   */
     87:   PetscObjectComposeFunction((PetscObject)A,"formFunction",FormFunctionA);
     88:   PetscOptionsGetBool(NULL,NULL,"-form_function_ab",&flg,NULL);
     89:   if (flg) PetscObjectComposeFunction((PetscObject)A,"formFunctionAB",FormFunctionAB);
     90:   PetscObjectComposeFunction((PetscObject)A,"formJacobian",FormJacobianA);
     91:   PetscObjectComposeFunction((PetscObject)B,"formFunction",FormFunctionB);
     92:   PetscContainerCreate(comm,&container);
     93:   PetscContainerSetPointer(container,&user);
     94:   PetscObjectCompose((PetscObject)A,"formFunctionCtx",(PetscObject)container);
     95:   PetscObjectCompose((PetscObject)A,"formJacobianCtx",(PetscObject)container);
     96:   PetscObjectCompose((PetscObject)B,"formFunctionCtx",(PetscObject)container);
     97:   PetscContainerDestroy(&container);

     99:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    100:                 Create the eigensolver and set various options
    101:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    103:   EPSCreate(comm,&eps);
    104:   EPSSetOperators(eps,A,B);
    105:   EPSSetProblemType(eps,EPS_GNHEP);
    106:   /*
    107:      Use nonlinear inverse iteration
    108:   */
    109:   EPSSetType(eps,EPSPOWER);
    110:   EPSPowerSetNonlinear(eps,PETSC_TRUE);
    111:   /*
    112:     Attach DM to SNES
    113:   */
    114:   EPSPowerGetSNES(eps,&snes);
    115:   user.snes = snes;
    116:   SNESSetDM(snes,dm);
    117:   EPSSetFromOptions(eps);

    119:   /* Set a preconditioning matrix to ST */
    120:   if (use_shell_matrix) {
    121:     EPSGetST(eps,&st);
    122:     STSetPreconditionerMat(st,P);
    123:   }

    125:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    126:                       Solve the eigensystem
    127:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    129:   EPSSolve(eps);

    131:   EPSGetConverged(eps,&nconv);
    132:   PetscOptionsGetBool(NULL,NULL,"-test_init_sol",&test_init_sol,NULL);
    133:   if (nconv && test_init_sol) {
    134:     PetscScalar   k;
    135:     PetscReal     norm0;
    136:     PetscInt      nits;

    138:     MatCreateVecs(A,&v0,NULL);
    139:     EPSGetEigenpair(eps,0,&k,NULL,v0,NULL);
    140:     EPSSetInitialSpace(eps,1,&v0);
    141:     VecDestroy(&v0);
    142:     /* Norm of the previous residual */
    143:     SNESGetFunctionNorm(snes,&norm0);
    144:     /* Make the tolerance smaller than the last residual
    145:        SNES will converge right away if the initial is setup correctly */
    146:     SNESSetTolerances(snes,norm0*1.2,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
    147:     EPSSolve(eps);
    148:     /* Number of Newton iterations supposes to be zero */
    149:     SNESGetIterationNumber(snes,&nits);
    150:     if (nits) PetscPrintf(comm," Number of Newton iterations %" PetscInt_FMT " should be zero \n",nits);
    151:   }

    153:   /*
    154:      Optional: Get some information from the solver and display it
    155:   */
    156:   EPSGetType(eps,&type);
    157:   EPSGetTolerances(eps,&tol,NULL);
    158:   EPSPowerGetNonlinear(eps,&nonlin);
    159:   EPSPowerGetUpdate(eps,&update);
    160:   PetscPrintf(comm," Solution method: %s%s\n\n",type,nonlin?(update?" (nonlinear with monolithic update)":" (nonlinear)"):"");
    161:   EPSGetDimensions(eps,&nev,NULL,NULL);
    162:   PetscPrintf(comm," Number of requested eigenvalues: %" PetscInt_FMT "\n",nev);

    164:   /* print eigenvalue and error */
    165:   EPSGetConverged(eps,&nconv);
    166:   if (nconv>0) {
    167:     PetscScalar   k;
    168:     PetscReal     na,nb;
    169:     Vec           a,b,eigen;
    170:     DMCreateGlobalVector(dm,&a);
    171:     VecDuplicate(a,&b);
    172:     VecDuplicate(a,&eigen);
    173:     EPSGetEigenpair(eps,0,&k,NULL,eigen,NULL);
    174:     FormFunctionA(snes,eigen,a,&user);
    175:     FormFunctionB(snes,eigen,b,&user);
    176:     VecAXPY(a,-k,b);
    177:     VecNorm(a,NORM_2,&na);
    178:     VecNorm(b,NORM_2,&nb);
    179:     relerr = na/(nb*PetscAbsScalar(k));
    180:     if (relerr<10*tol) PetscPrintf(comm,"k: %g, relative error below tol\n",(double)PetscRealPart(k));
    181:     else PetscPrintf(comm,"k: %g, relative error: %g\n",(double)PetscRealPart(k),(double)relerr);
    182:     VecDestroy(&a);
    183:     VecDestroy(&b);
    184:     VecDestroy(&eigen);
    185:   } else PetscPrintf(comm,"Solver did not converge\n");

    187:   MatDestroy(&A);
    188:   MatDestroy(&B);
    189:   if (use_shell_matrix) MatDestroy(&P);
    190:   DMDestroy(&dm);
    191:   EPSDestroy(&eps);
    192:   ISDestroy(&user.bdis);
    193:   SlepcFinalize();
    194:   return 0;
    195: }

    197: /* <|u|u, v> */
    198: static void f0_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    199:                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    200:                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    201:                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
    202: {
    203:   PetscScalar cof = PetscAbsScalar(u[0]);

    205:   f0[0] = cof*u[0];
    206: }

    208: /* <|\nabla u| \nabla u, \nabla v> */
    209: static void f1_u(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    210:                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    211:                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    212:                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[])
    213: {
    214:   PetscInt    d;
    215:   PetscScalar cof = 0;
    216:   for (d = 0; d < dim; ++d)  cof += u_x[d]*u_x[d];

    218:   cof = PetscSqrtScalar(cof);

    220:   for (d = 0; d < dim; ++d) f1[d] = u_x[d]*cof;
    221: }

    223: /* approximate  Jacobian for   <|u|u, v> */
    224: static void g0_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    225:                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    226:                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    227:                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
    228: {
    229:   g0[0] = 1.0*PetscAbsScalar(u[0]);
    230: }

    232: /* approximate  Jacobian for   <|\nabla u| \nabla u, \nabla v> */
    233: static void g3_uu(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    234:                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    235:                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    236:                   PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[])
    237: {
    238:   PetscInt d;

    240:   for (d = 0; d < dim; ++d) g3[d*dim+d] = 1.0;
    241: }

    243: PetscErrorCode SetupDiscretization(DM dm)
    244: {
    245:   PetscFE        fe;
    246:   MPI_Comm       comm;

    249:   /* Create finite element */
    250:   PetscObjectGetComm((PetscObject)dm,&comm);
    251:   PetscFECreateDefault(comm,2,1,PETSC_FALSE,NULL,-1,&fe);
    252:   PetscObjectSetName((PetscObject)fe,"u");
    253:   DMSetField(dm,0,NULL,(PetscObject)fe);
    254:   DMCreateDS(dm);
    255:   PetscFEDestroy(&fe);
    256:   PetscFunctionReturn(0);
    257: }

    259: PetscErrorCode CreateSquareMesh(MPI_Comm comm,DM *dm)
    260: {
    261:   PetscInt       cells[] = {8,8};
    262:   PetscInt       dim = 2;
    263:   DM             pdm;
    264:   PetscMPIInt    size;

    266:   DMPlexCreateBoxMesh(comm,dim,PETSC_FALSE,cells,NULL,NULL,NULL,PETSC_TRUE,dm);
    267:   DMSetFromOptions(*dm);
    268:   DMSetUp(*dm);
    269:   MPI_Comm_size(comm,&size);
    270:   if (size > 1) {
    271:     DMPlexDistribute(*dm,0,NULL,&pdm);
    272:     DMDestroy(dm);
    273:     *dm = pdm;
    274:   }
    275:   PetscFunctionReturn(0);
    276: }

    278: PetscErrorCode BoundaryGlobalIndex(DM dm,const char labelname[],IS *bdis)
    279: {
    280:   IS             bdpoints;
    281:   PetscInt       nindices,*indices,numDof,offset,npoints,i,j;
    282:   const PetscInt *bdpoints_indices;
    283:   DMLabel        bdmarker;
    284:   PetscSection   gsection;

    286:   DMGetGlobalSection(dm,&gsection);
    287:   DMGetLabel(dm,labelname,&bdmarker);
    288:   DMLabelGetStratumIS(bdmarker,1,&bdpoints);
    289:   ISGetLocalSize(bdpoints,&npoints);
    290:   ISGetIndices(bdpoints,&bdpoints_indices);
    291:   nindices = 0;
    292:   for (i=0;i<npoints;i++) {
    293:     PetscSectionGetDof(gsection,bdpoints_indices[i],&numDof);
    294:     if (numDof<=0) continue;
    295:     nindices += numDof;
    296:   }
    297:   PetscCalloc1(nindices,&indices);
    298:   nindices = 0;
    299:   for (i=0;i<npoints;i++) {
    300:     PetscSectionGetDof(gsection,bdpoints_indices[i],&numDof);
    301:     if (numDof<=0) continue;
    302:     PetscSectionGetOffset(gsection,bdpoints_indices[i],&offset);
    303:     for (j=0;j<numDof;j++) indices[nindices++] = offset+j;
    304:   }
    305:   ISRestoreIndices(bdpoints,&bdpoints_indices);
    306:   ISDestroy(&bdpoints);
    307:   ISCreateGeneral(PetscObjectComm((PetscObject)dm),nindices,indices,PETSC_OWN_POINTER,bdis);
    308:   PetscFunctionReturn(0);
    309: }

    311: static PetscErrorCode FormJacobian(SNES snes,Vec X,Mat A,Mat B,void *ctx)
    312: {
    313:   DM             dm;
    314:   Vec            Xloc;

    316:   SNESGetDM(snes,&dm);
    317:   DMGetLocalVector(dm,&Xloc);
    318:   VecZeroEntries(Xloc);
    319:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    320:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    321:   CHKMEMQ;
    322:   DMPlexSNESComputeJacobianFEM(dm,Xloc,A,B,ctx);
    323:   if (A!=B) {
    324:     MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    325:     MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    326:   }
    327:   CHKMEMQ;
    328:   DMRestoreLocalVector(dm,&Xloc);
    329:   PetscFunctionReturn(0);
    330: }

    332: PetscErrorCode FormJacobianA(SNES snes,Vec X,Mat A,Mat B,void *ctx)
    333: {
    334:   DM             dm;
    335:   PetscDS        prob;
    336:   PetscWeakForm  wf;
    337:   AppCtx         *userctx = (AppCtx *)ctx;

    339:   MatSetOption(B,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE);
    340:   SNESGetDM(snes,&dm);
    341:   DMGetDS(dm,&prob);
    342:   PetscDSGetWeakForm(prob, &wf);
    343:   PetscWeakFormClearIndex(wf, NULL, 0, 0, 0, PETSC_WF_G3, 0);
    344:   PetscWeakFormSetIndexJacobian(wf, NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0, NULL, 0, g3_uu);
    345:   FormJacobian(snes,X,A,B,ctx);
    346:   MatZeroRowsIS(B,userctx->bdis,1.0,NULL,NULL);
    347:   PetscFunctionReturn(0);
    348: }

    350: PetscErrorCode FormJacobianB(SNES snes,Vec X,Mat A,Mat B,void *ctx)
    351: {
    352:   DM             dm;
    353:   PetscDS        prob;
    354:   PetscWeakForm  wf;
    355:   AppCtx         *userctx = (AppCtx *)ctx;

    357:   MatSetOption(B,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE);
    358:   SNESGetDM(snes,&dm);
    359:   DMGetDS(dm,&prob);
    360:   PetscDSGetWeakForm(prob, &wf);
    361:   PetscWeakFormClearIndex(wf, NULL, 0, 0, 0, PETSC_WF_G3, 0);
    362:   PetscWeakFormSetIndexJacobian(wf, NULL, 0, 0, 0, 0, 0, g0_uu, 0, NULL, 0, NULL, 0, NULL);
    363:   FormJacobian(snes,X,A,B,ctx);
    364:   MatZeroRowsIS(B,userctx->bdis,0.0,NULL,NULL);
    365:   PetscFunctionReturn(0);
    366: }

    368: PetscErrorCode FormFunctionAB(SNES snes,Vec x,Vec Ax,Vec Bx,void *ctx)
    369: {
    370:   /*
    371:    * In real applications, users should have a generic formFunctionAB which
    372:    * forms Ax and Bx simultaneously for an more efficient calculation.
    373:    * In this example, we just call FormFunctionA+FormFunctionB to mimic how
    374:    * to use FormFunctionAB
    375:    */
    376:   FormFunctionA(snes,x,Ax,ctx);
    377:   FormFunctionB(snes,x,Bx,ctx);
    378:   PetscFunctionReturn(0);
    379: }

    381: static PetscErrorCode FormFunction(SNES snes,Vec X,Vec F,void *ctx)
    382: {
    383:   DM             dm;
    384:   Vec            Xloc,Floc;

    386:   SNESGetDM(snes,&dm);
    387:   DMGetLocalVector(dm,&Xloc);
    388:   DMGetLocalVector(dm,&Floc);
    389:   VecZeroEntries(Xloc);
    390:   VecZeroEntries(Floc);
    391:   DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);
    392:   DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);
    393:   CHKMEMQ;
    394:   DMPlexSNESComputeResidualFEM(dm,Xloc,Floc,ctx);
    395:   CHKMEMQ;
    396:   VecZeroEntries(F);
    397:   DMLocalToGlobalBegin(dm,Floc,ADD_VALUES,F);
    398:   DMLocalToGlobalEnd(dm,Floc,ADD_VALUES,F);
    399:   DMRestoreLocalVector(dm,&Xloc);
    400:   DMRestoreLocalVector(dm,&Floc);
    401:   PetscFunctionReturn(0);
    402: }

    404: PetscErrorCode FormFunctionA(SNES snes,Vec X,Vec F,void *ctx)
    405: {
    406:   DM             dm;
    407:   PetscDS        prob;
    408:   PetscWeakForm  wf;
    409:   PetscInt       nindices,iStart,iEnd,i;
    410:   AppCtx         *userctx = (AppCtx *)ctx;
    411:   PetscScalar    *array,value;
    412:   const PetscInt *indices;
    413:   PetscInt       vecstate;

    415:   SNESGetDM(snes,&dm);
    416:   DMGetDS(dm,&prob);
    417:   /* hook functions */
    418:   PetscDSGetWeakForm(prob, &wf);
    419:   PetscWeakFormClearIndex(wf, NULL, 0, 0, 0, PETSC_WF_F0, 0);
    420:   PetscWeakFormSetIndexResidual(wf, NULL, 0, 0, 0, 0, NULL, 0, f1_u);
    421:   FormFunction(snes,X,F,ctx);
    422:   /* Boundary condition */
    423:   VecLockGet(X,&vecstate);
    424:   if (vecstate>0) VecLockReadPop(X);
    425:   VecGetOwnershipRange(X,&iStart,&iEnd);
    426:   VecGetArray(X,&array);
    427:   ISGetLocalSize(userctx->bdis,&nindices);
    428:   ISGetIndices(userctx->bdis,&indices);
    429:   for (i=0;i<nindices;i++) {
    430:     value = array[indices[i]-iStart] - 0.0;
    431:     VecSetValue(F,indices[i],value,INSERT_VALUES);
    432:   }
    433:   ISRestoreIndices(userctx->bdis,&indices);
    434:   VecRestoreArray(X,&array);
    435:   if (vecstate>0) VecLockReadPush(X);
    436:   VecAssemblyBegin(F);
    437:   VecAssemblyEnd(F);
    438:   PetscFunctionReturn(0);
    439: }

    441: PetscErrorCode MatMult_A(Mat A,Vec x,Vec y)
    442: {
    443:   AppCtx         *userctx;

    445:   MatShellGetContext(A,&userctx);
    446:   FormFunctionA(userctx->snes,x,y,userctx);
    447:   PetscFunctionReturn(0);
    448: }

    450: PetscErrorCode FormFunctionB(SNES snes,Vec X,Vec F,void *ctx)
    451: {
    452:   DM             dm;
    453:   PetscDS        prob;
    454:   PetscWeakForm  wf;
    455:   PetscInt       nindices,iStart,iEnd,i;
    456:   AppCtx         *userctx = (AppCtx *)ctx;
    457:   PetscScalar    value;
    458:   const PetscInt *indices;

    460:   SNESGetDM(snes,&dm);
    461:   DMGetDS(dm,&prob);
    462:   /* hook functions */
    463:   PetscDSGetWeakForm(prob, &wf);
    464:   PetscWeakFormClearIndex(wf, NULL, 0, 0, 0, PETSC_WF_F1, 0);
    465:   PetscWeakFormSetIndexResidual(wf, NULL, 0, 0, 0, 0, f0_u, 0, NULL);
    466:   FormFunction(snes,X,F,ctx);
    467:   /* Boundary condition */
    468:   VecGetOwnershipRange(F,&iStart,&iEnd);
    469:   ISGetLocalSize(userctx->bdis,&nindices);
    470:   ISGetIndices(userctx->bdis,&indices);
    471:   for (i=0;i<nindices;i++) {
    472:     value = 0.0;
    473:     VecSetValue(F,indices[i],value,INSERT_VALUES);
    474:   }
    475:   ISRestoreIndices(userctx->bdis,&indices);
    476:   VecAssemblyBegin(F);
    477:   VecAssemblyEnd(F);
    478:   PetscFunctionReturn(0);
    479: }

    481: PetscErrorCode MatMult_B(Mat B,Vec x,Vec y)
    482: {
    483:   AppCtx         *userctx;

    485:   MatShellGetContext(B,&userctx);
    486:   FormFunctionB(userctx->snes,x,y,userctx);
    487:   PetscFunctionReturn(0);
    488: }

    490: /*TEST

    492:    testset:
    493:       requires: double
    494:       args: -petscspace_degree 1 -petscspace_poly_tensor
    495:       output_file: output/ex34_1.out
    496:       test:
    497:          suffix: 1
    498:       test:
    499:          suffix: 2
    500:          args: -eps_power_update -form_function_ab {{0 1}}
    501:          filter: sed -e "s/ with monolithic update//"
    502:       test:
    503:          suffix: 3
    504:          args: -use_shell_matrix -eps_power_snes_mf_operator 1
    505:       test:
    506:          suffix: 4
    507:          args: -use_shell_matrix -eps_power_update -init_eps_power_snes_mf_operator 1 -eps_power_snes_mf_operator 1 -form_function_ab {{0 1}}
    508:          filter: sed -e "s/ with monolithic update//"
    509:       test:
    510:          suffix: 5
    511:          args: -use_shell_matrix -eps_power_update -init_eps_power_snes_mf_operator 1 -eps_power_snes_mf_operator 1 -form_function_ab {{0 1}} -test_init_sol 1
    512:          filter: sed -e "s/ with monolithic update//"

    514:       test:
    515:          suffix: 6
    516:          args: -use_shell_matrix -eps_power_update -init_eps_power_snes_mf_operator 1 -eps_power_snes_mf_operator 1 -form_function_ab {{0 1}} -eps_monitor_all
    517:          output_file: output/ex34_6.out
    518:          filter: sed -e "s/\([+-].*i\)//g" -e "1,3s/[0-9]//g" -e "/[45] EPS/d"
    519: TEST*/