Actual source code: plexfem.c

petsc-dev 2014-02-02
Report Typos and Errors
  1: #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/

  3: #include <petscfe.h>

  7: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
  8: {
  9:   DM_Plex *mesh = (DM_Plex*) dm->data;

 14:   *scale = mesh->scale[unit];
 15:   return(0);
 16: }

 20: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
 21: {
 22:   DM_Plex *mesh = (DM_Plex*) dm->data;

 26:   mesh->scale[unit] = scale;
 27:   return(0);
 28: }

 30: PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
 31: {
 32:   switch (i) {
 33:   case 0:
 34:     switch (j) {
 35:     case 0: return 0;
 36:     case 1:
 37:       switch (k) {
 38:       case 0: return 0;
 39:       case 1: return 0;
 40:       case 2: return 1;
 41:       }
 42:     case 2:
 43:       switch (k) {
 44:       case 0: return 0;
 45:       case 1: return -1;
 46:       case 2: return 0;
 47:       }
 48:     }
 49:   case 1:
 50:     switch (j) {
 51:     case 0:
 52:       switch (k) {
 53:       case 0: return 0;
 54:       case 1: return 0;
 55:       case 2: return -1;
 56:       }
 57:     case 1: return 0;
 58:     case 2:
 59:       switch (k) {
 60:       case 0: return 1;
 61:       case 1: return 0;
 62:       case 2: return 0;
 63:       }
 64:     }
 65:   case 2:
 66:     switch (j) {
 67:     case 0:
 68:       switch (k) {
 69:       case 0: return 0;
 70:       case 1: return 1;
 71:       case 2: return 0;
 72:       }
 73:     case 1:
 74:       switch (k) {
 75:       case 0: return -1;
 76:       case 1: return 0;
 77:       case 2: return 0;
 78:       }
 79:     case 2: return 0;
 80:     }
 81:   }
 82:   return 0;
 83: }

 87: /*@C
 88:   DMPlexCreateRigidBody - create rigid body modes from coordinates

 90:   Collective on DM

 92:   Input Arguments:
 93: + dm - the DM
 94: . section - the local section associated with the rigid field, or NULL for the default section
 95: - globalSection - the global section associated with the rigid field, or NULL for the default section

 97:   Output Argument:
 98: . sp - the null space

100:   Note: This is necessary to take account of Dirichlet conditions on the displacements

102:   Level: advanced

104: .seealso: MatNullSpaceCreate()
105: @*/
106: PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
107: {
108:   MPI_Comm       comm;
109:   Vec            coordinates, localMode, mode[6];
110:   PetscSection   coordSection;
111:   PetscScalar   *coords;
112:   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;

116:   PetscObjectGetComm((PetscObject)dm,&comm);
117:   DMPlexGetDimension(dm, &dim);
118:   if (dim == 1) {
119:     MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
120:     return(0);
121:   }
122:   if (!section)       {DMGetDefaultSection(dm, &section);}
123:   if (!globalSection) {DMGetDefaultGlobalSection(dm, &globalSection);}
124:   PetscSectionGetConstrainedStorageSize(globalSection, &n);
125:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
126:   DMGetCoordinateSection(dm, &coordSection);
127:   DMGetCoordinatesLocal(dm, &coordinates);
128:   m    = (dim*(dim+1))/2;
129:   VecCreate(comm, &mode[0]);
130:   VecSetSizes(mode[0], n, PETSC_DETERMINE);
131:   VecSetUp(mode[0]);
132:   for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
133:   /* Assume P1 */
134:   DMGetLocalVector(dm, &localMode);
135:   for (d = 0; d < dim; ++d) {
136:     PetscScalar values[3] = {0.0, 0.0, 0.0};

138:     values[d] = 1.0;
139:     VecSet(localMode, 0.0);
140:     for (v = vStart; v < vEnd; ++v) {
141:       DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);
142:     }
143:     DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);
144:     DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);
145:   }
146:   VecGetArray(coordinates, &coords);
147:   for (d = dim; d < dim*(dim+1)/2; ++d) {
148:     PetscInt i, j, k = dim > 2 ? d - dim : d;

150:     VecSet(localMode, 0.0);
151:     for (v = vStart; v < vEnd; ++v) {
152:       PetscScalar values[3] = {0.0, 0.0, 0.0};
153:       PetscInt    off;

155:       PetscSectionGetOffset(coordSection, v, &off);
156:       for (i = 0; i < dim; ++i) {
157:         for (j = 0; j < dim; ++j) {
158:           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
159:         }
160:       }
161:       DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);
162:     }
163:     DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);
164:     DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);
165:   }
166:   VecRestoreArray(coordinates, &coords);
167:   DMRestoreLocalVector(dm, &localMode);
168:   for (i = 0; i < dim; ++i) {VecNormalize(mode[i], NULL);}
169:   /* Orthonormalize system */
170:   for (i = dim; i < m; ++i) {
171:     PetscScalar dots[6];

173:     VecMDot(mode[i], i, mode, dots);
174:     for (j = 0; j < i; ++j) dots[j] *= -1.0;
175:     VecMAXPY(mode[i], i, dots, mode);
176:     VecNormalize(mode[i], NULL);
177:   }
178:   MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
179:   for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
180:   return(0);
181: }

185: PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
186: {
187:   PetscDualSpace *sp;
188:   PetscSection    section;
189:   PetscScalar    *values;
190:   PetscReal      *v0, *J, detJ;
191:   PetscInt        numFields, numComp, dim, spDim, totDim = 0, numValues, cStart, cEnd, c, f, d, v;
192:   PetscErrorCode  ierr;

195:   DMGetDefaultSection(dm, &section);
196:   PetscSectionGetNumFields(section, &numFields);
197:   PetscMalloc1(numFields, &sp);
198:   for (f = 0; f < numFields; ++f) {
199:     PetscFEGetDualSpace(fe[f], &sp[f]);
200:     PetscFEGetNumComponents(fe[f], &numComp);
201:     PetscDualSpaceGetDimension(sp[f], &spDim);
202:     totDim += spDim*numComp;
203:   }
204:   DMPlexGetDimension(dm, &dim);
205:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
206:   DMPlexVecGetClosure(dm, section, localX, cStart, &numValues, NULL);
207:   if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section cell closure size %d != dual space dimension %d", numValues, totDim);
208:   DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);
209:   PetscMalloc2(dim,&v0,dim*dim,&J);
210:   for (c = cStart; c < cEnd; ++c) {
211:     PetscCellGeometry geom;

213:     DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);
214:     geom.v0   = v0;
215:     geom.J    = J;
216:     geom.detJ = &detJ;
217:     for (f = 0, v = 0; f < numFields; ++f) {
218:       void * const ctx = ctxs ? ctxs[f] : NULL;
219:       PetscFEGetNumComponents(fe[f], &numComp);
220:       PetscDualSpaceGetDimension(sp[f], &spDim);
221:       for (d = 0; d < spDim; ++d) {
222:         PetscDualSpaceApply(sp[f], d, geom, numComp, funcs[f], ctx, &values[v]);
223:         v += numComp;
224:       }
225:     }
226:     DMPlexVecSetClosure(dm, section, localX, c, values, mode);
227:   }
228:   DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);
229:   PetscFree2(v0,J);
230:   PetscFree(sp);
231:   return(0);
232: }

236: /*@C
237:   DMPlexProjectFunction - This projects the given function into the function space provided.

239:   Input Parameters:
240: + dm      - The DM
241: . fe      - The PetscFE associated with the field
242: . funcs   - The coordinate functions to evaluate, one per field
243: . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
244: - mode    - The insertion mode for values

246:   Output Parameter:
247: . X - vector

249:   Level: developer

251: .seealso: DMPlexComputeL2Diff()
252: @*/
253: PetscErrorCode DMPlexProjectFunction(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
254: {
255:   Vec            localX;

260:   DMGetLocalVector(dm, &localX);
261:   DMPlexProjectFunctionLocal(dm, fe, funcs, ctxs, mode, localX);
262:   DMLocalToGlobalBegin(dm, localX, mode, X);
263:   DMLocalToGlobalEnd(dm, localX, mode, X);
264:   DMRestoreLocalVector(dm, &localX);
265:   return(0);
266: }

270: /*@C
271:   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

273:   Input Parameters:
274: + dm    - The DM
275: . fe    - The PetscFE object for each field
276: . funcs - The functions to evaluate for each field component
277: . ctxs  - Optional array of contexts to pass to each function, or NULL.
278: - X     - The coefficient vector u_h

280:   Output Parameter:
281: . diff - The diff ||u - u_h||_2

283:   Level: developer

285: .seealso: DMPlexProjectFunction()
286: @*/
287: PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
288: {
289:   const PetscInt  debug = 0;
290:   PetscSection    section;
291:   PetscQuadrature quad;
292:   Vec             localX;
293:   PetscScalar    *funcVal;
294:   PetscReal      *coords, *v0, *J, *invJ, detJ;
295:   PetscReal       localDiff = 0.0;
296:   PetscInt        dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
297:   PetscErrorCode  ierr;

300:   DMPlexGetDimension(dm, &dim);
301:   DMGetDefaultSection(dm, &section);
302:   PetscSectionGetNumFields(section, &numFields);
303:   DMGetLocalVector(dm, &localX);
304:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
305:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
306:   for (field = 0; field < numFields; ++field) {
307:     PetscInt Nc;

309:     PetscFEGetNumComponents(fe[field], &Nc);
310:     numComponents += Nc;
311:   }
312:   DMPlexProjectFunctionLocal(dm, fe, funcs, ctxs, INSERT_BC_VALUES, localX);
313:   PetscMalloc5(numComponents,&funcVal,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);
314:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
315:   PetscFEGetQuadrature(fe[0], &quad);
316:   for (c = cStart; c < cEnd; ++c) {
317:     PetscScalar *x = NULL;
318:     PetscReal    elemDiff = 0.0;

320:     DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);
321:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
322:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

324:     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
325:       void * const     ctx           = ctxs ? ctxs[field] : NULL;
326:       const PetscInt   numQuadPoints = quad.numPoints;
327:       const PetscReal *quadPoints    = quad.points;
328:       const PetscReal *quadWeights   = quad.weights;
329:       PetscReal       *basis;
330:       PetscInt         numBasisFuncs, numBasisComps, q, d, e, fc, f;

332:       PetscFEGetDimension(fe[field], &numBasisFuncs);
333:       PetscFEGetNumComponents(fe[field], &numBasisComps);
334:       PetscFEGetDefaultTabulation(fe[field], &basis, NULL, NULL);
335:       if (debug) {
336:         char title[1024];
337:         PetscSNPrintf(title, 1023, "Solution for Field %d", field);
338:         DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);
339:       }
340:       for (q = 0; q < numQuadPoints; ++q) {
341:         for (d = 0; d < dim; d++) {
342:           coords[d] = v0[d];
343:           for (e = 0; e < dim; e++) {
344:             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
345:           }
346:         }
347:         (*funcs[field])(coords, funcVal, ctx);
348:         for (fc = 0; fc < numBasisComps; ++fc) {
349:           PetscScalar interpolant = 0.0;

351:           for (f = 0; f < numBasisFuncs; ++f) {
352:             const PetscInt fidx = f*numBasisComps+fc;
353:             interpolant += x[fieldOffset+fidx]*basis[q*numBasisFuncs*numBasisComps+fidx];
354:           }
355:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ);}
356:           elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ;
357:         }
358:       }
359:       comp        += numBasisComps;
360:       fieldOffset += numBasisFuncs*numBasisComps;
361:     }
362:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
363:     if (debug) {PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);}
364:     localDiff += elemDiff;
365:   }
366:   PetscFree5(funcVal,coords,v0,J,invJ);
367:   DMRestoreLocalVector(dm, &localX);
368:   MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));
369:   *diff = PetscSqrtReal(*diff);
370:   return(0);
371: }

375: /*@C
376:   DMPlexComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.

378:   Input Parameters:
379: + dm    - The DM
380: . fe    - The PetscFE object for each field
381: . funcs - The gradient functions to evaluate for each field component
382: . ctxs  - Optional array of contexts to pass to each function, or NULL.
383: . X     - The coefficient vector u_h
384: - n     - The vector to project along

386:   Output Parameter:
387: . diff - The diff ||(grad u - grad u_h) . n||_2

389:   Level: developer

391: .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff()
392: @*/
393: PetscErrorCode DMPlexComputeL2GradientDiff(DM dm, PetscFE fe[], void (**funcs)(const PetscReal [], const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
394: {
395:   const PetscInt  debug = 0;
396:   PetscSection    section;
397:   PetscQuadrature quad;
398:   Vec             localX;
399:   PetscScalar    *funcVal, *interpolantVec;
400:   PetscReal      *coords, *realSpaceDer, *v0, *J, *invJ, detJ;
401:   PetscReal       localDiff = 0.0;
402:   PetscInt        dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
403:   PetscErrorCode  ierr;

406:   DMPlexGetDimension(dm, &dim);
407:   DMGetDefaultSection(dm, &section);
408:   PetscSectionGetNumFields(section, &numFields);
409:   DMGetLocalVector(dm, &localX);
410:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
411:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
412:   for (field = 0; field < numFields; ++field) {
413:     PetscInt Nc;

415:     PetscFEGetNumComponents(fe[field], &Nc);
416:     numComponents += Nc;
417:   }
418:   /* DMPlexProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
419:   PetscMalloc7(numComponents,&funcVal,dim,&coords,dim,&realSpaceDer,dim,&v0,dim*dim,&J,dim*dim,&invJ,dim,&interpolantVec);
420:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
421:   PetscFEGetQuadrature(fe[0], &quad);
422:   for (c = cStart; c < cEnd; ++c) {
423:     PetscScalar *x = NULL;
424:     PetscReal    elemDiff = 0.0;

426:     DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);
427:     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
428:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

430:     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
431:       void * const     ctx           = ctxs ? ctxs[field] : NULL;
432:       const PetscInt   numQuadPoints = quad.numPoints;
433:       const PetscReal *quadPoints    = quad.points;
434:       const PetscReal *quadWeights   = quad.weights;
435:       PetscReal       *basisDer;
436:       PetscInt         Nb, Ncomp, q, d, e, fc, f, g;

438:       PetscFEGetDimension(fe[field], &Nb);
439:       PetscFEGetNumComponents(fe[field], &Ncomp);
440:       PetscFEGetDefaultTabulation(fe[field], NULL, &basisDer, NULL);
441:       if (debug) {
442:         char title[1024];
443:         PetscSNPrintf(title, 1023, "Solution for Field %d", field);
444:         DMPrintCellVector(c, title, Nb*Ncomp, &x[fieldOffset]);
445:       }
446:       for (q = 0; q < numQuadPoints; ++q) {
447:         for (d = 0; d < dim; d++) {
448:           coords[d] = v0[d];
449:           for (e = 0; e < dim; e++) {
450:             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
451:           }
452:         }
453:         (*funcs[field])(coords, n, funcVal, ctx);
454:         for (fc = 0; fc < Ncomp; ++fc) {
455:           PetscScalar interpolant = 0.0;

457:           for (d = 0; d < dim; ++d) interpolantVec[d] = 0.0;
458:           for (f = 0; f < Nb; ++f) {
459:             const PetscInt fidx = f*Ncomp+fc;

461:             for (d = 0; d < dim; ++d) {
462:               realSpaceDer[d] = 0.0;
463:               for (g = 0; g < dim; ++g) {
464:                 realSpaceDer[d] += invJ[g*dim+d]*basisDer[(q*Nb*Ncomp+fidx)*dim+g];
465:               }
466:               interpolantVec[d] += x[fieldOffset+fidx]*realSpaceDer[d];
467:             }
468:           }
469:           for (d = 0; d < dim; ++d) interpolant += interpolantVec[d]*n[d];
470:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %d fieldDer %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ);}
471:           elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ;
472:         }
473:       }
474:       comp        += Ncomp;
475:       fieldOffset += Nb*Ncomp;
476:     }
477:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
478:     if (debug) {PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);}
479:     localDiff += elemDiff;
480:   }
481:     PetscFree7(funcVal,coords,realSpaceDer,v0,J,invJ,interpolantVec);
482:   DMRestoreLocalVector(dm, &localX);
483:   MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));
484:   *diff = PetscSqrtReal(*diff);
485:   return(0);
486: }

490: /*@
491:   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user

493:   Input Parameters:
494: + dm - The mesh
495: . X  - Local input vector
496: - user - The user context

498:   Output Parameter:
499: . F  - Local output vector

501:   Note:
502:   The second member of the user context must be an FEMContext.

504:   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
505:   like a GPU, or vectorize on a multicore machine.

507:   Level: developer

509: .seealso: DMPlexComputeJacobianActionFEM()
510: @*/
511: PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
512: {
513:   DM_Plex          *mesh  = (DM_Plex *) dm->data;
514:   PetscFEM         *fem   = (PetscFEM *) user;
515:   PetscFE          *fe    = fem->fe;
516:   PetscFE          *feAux = fem->feAux;
517:   PetscFE          *feBd  = fem->feBd;
518:   const char       *name  = "Residual";
519:   DM                dmAux;
520:   Vec               A;
521:   PetscQuadrature   q;
522:   PetscCellGeometry geom;
523:   PetscSection      section, sectionAux;
524:   PetscReal        *v0, *J, *invJ, *detJ;
525:   PetscScalar      *elemVec, *u, *a = NULL;
526:   PetscInt          dim, Nf, NfAux = 0, f, numCells, cStart, cEnd, c;
527:   PetscInt          cellDof = 0, numComponents = 0;
528:   PetscInt          cellDofAux = 0, numComponentsAux = 0;
529:   PetscErrorCode    ierr;

532:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
533:   DMPlexGetDimension(dm, &dim);
534:   DMGetDefaultSection(dm, &section);
535:   PetscSectionGetNumFields(section, &Nf);
536:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
537:   numCells = cEnd - cStart;
538:   for (f = 0; f < Nf; ++f) {
539:     PetscInt Nb, Nc;

541:     PetscFEGetDimension(fe[f], &Nb);
542:     PetscFEGetNumComponents(fe[f], &Nc);
543:     cellDof       += Nb*Nc;
544:     numComponents += Nc;
545:   }
546:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
547:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
548:   if (dmAux) {
549:     DMGetDefaultSection(dmAux, &sectionAux);
550:     PetscSectionGetNumFields(sectionAux, &NfAux);
551:   }
552:   for (f = 0; f < NfAux; ++f) {
553:     PetscInt Nb, Nc;

555:     PetscFEGetDimension(feAux[f], &Nb);
556:     PetscFEGetNumComponents(feAux[f], &Nc);
557:     cellDofAux       += Nb*Nc;
558:     numComponentsAux += Nc;
559:   }
560:   DMPlexProjectFunctionLocal(dm, fe, fem->bcFuncs, fem->bcCtxs, INSERT_BC_VALUES, X);
561:   VecSet(F, 0.0);
562:   PetscMalloc6(numCells*cellDof,&u,numCells*dim,&v0,numCells*dim*dim,&J,numCells*dim*dim,&invJ,numCells,&detJ,numCells*cellDof,&elemVec);
563:   if (dmAux) {PetscMalloc1(numCells*cellDofAux, &a);}
564:   for (c = cStart; c < cEnd; ++c) {
565:     PetscScalar *x = NULL;
566:     PetscInt     i;

568:     DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);
569:     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
570:     DMPlexVecGetClosure(dm, section, X, c, NULL, &x);
571:     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
572:     DMPlexVecRestoreClosure(dm, section, X, c, NULL, &x);
573:     if (dmAux) {
574:       DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);
575:       for (i = 0; i < cellDofAux; ++i) a[c*cellDofAux+i] = x[i];
576:       DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);
577:     }
578:   }
579:   for (f = 0; f < Nf; ++f) {
580:     void   (*f0)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->f0Funcs[f];
581:     void   (*f1)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->f1Funcs[f];
582:     PetscInt Nb;
583:     /* Conforming batches */
584:     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
585:     /* Remainder */
586:     PetscInt Nr, offset;

588:     PetscFEGetQuadrature(fe[f], &q);
589:     PetscFEGetDimension(fe[f], &Nb);
590:     PetscFEGetTileSizes(fe[f], NULL, &numBlocks, NULL, &numBatches);
591:     blockSize = Nb*q.numPoints;
592:     batchSize = numBlocks * blockSize;
593:      PetscFESetTileSizes(fe[f], blockSize, numBlocks, batchSize, numBatches);
594:     numChunks = numCells / (numBatches*batchSize);
595:     Ne        = numChunks*numBatches*batchSize;
596:     Nr        = numCells % (numBatches*batchSize);
597:     offset    = numCells - Nr;
598:     geom.v0   = v0;
599:     geom.J    = J;
600:     geom.invJ = invJ;
601:     geom.detJ = detJ;
602:     PetscFEIntegrateResidual(fe[f], Ne, Nf, fe, f, geom, u, NfAux, feAux, a, f0, f1, elemVec);
603:     geom.v0   = &v0[offset*dim];
604:     geom.J    = &J[offset*dim*dim];
605:     geom.invJ = &invJ[offset*dim*dim];
606:     geom.detJ = &detJ[offset];
607:     PetscFEIntegrateResidual(fe[f], Nr, Nf, fe, f, geom, &u[offset*cellDof], NfAux, feAux, &a[offset*cellDofAux], f0, f1, &elemVec[offset*cellDof]);
608:   }
609:   for (c = cStart; c < cEnd; ++c) {
610:     if (mesh->printFEM > 1) {DMPrintCellVector(c, name, cellDof, &elemVec[c*cellDof]);}
611:     DMPlexVecSetClosure(dm, section, F, c, &elemVec[c*cellDof], ADD_VALUES);
612:   }
613:   PetscFree6(u,v0,J,invJ,detJ,elemVec);
614:   if (dmAux) {PetscFree(a);}
615:   if (feBd) {
616:     DMLabel         label, depth;
617:     IS              pointIS;
618:     const PetscInt *points;
619:     PetscInt        dep, numPoints, p, numFaces;
620:     PetscReal      *n;

622:     DMPlexGetLabel(dm, "boundary", &label);
623:     DMPlexGetDepthLabel(dm, &depth);
624:     DMLabelGetStratumSize(label, 1, &numPoints);
625:     DMLabelGetStratumIS(label, 1, &pointIS);
626:     ISGetIndices(pointIS, &points);
627:     for (f = 0, cellDof = 0, numComponents = 0; f < Nf; ++f) {
628:       PetscInt Nb, Nc;

630:       PetscFEGetDimension(feBd[f], &Nb);
631:       PetscFEGetNumComponents(feBd[f], &Nc);
632:       cellDof       += Nb*Nc;
633:       numComponents += Nc;
634:     }
635:     for (p = 0, numFaces = 0; p < numPoints; ++p) {
636:       DMLabelGetValue(depth, points[p], &dep);
637:       if (dep == dim-1) ++numFaces;
638:     }
639:     PetscMalloc7(numFaces*cellDof,&u,numFaces*dim,&v0,numFaces*dim,&n,numFaces*dim*dim,&J,numFaces*dim*dim,&invJ,numFaces,&detJ,numFaces*cellDof,&elemVec);
640:     for (p = 0, f = 0; p < numPoints; ++p) {
641:       const PetscInt point = points[p];
642:       PetscScalar   *x     = NULL;
643:       PetscInt       i;

645:       DMLabelGetValue(depth, points[p], &dep);
646:       if (dep != dim-1) continue;
647:       DMPlexComputeCellGeometry(dm, point, &v0[f*dim], &J[f*dim*dim], &invJ[f*dim*dim], &detJ[f]);
648:       DMPlexComputeCellGeometryFVM(dm, point, NULL, NULL, &n[f*dim]);
649:       if (detJ[f] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for face %d", detJ[f], point);
650:       DMPlexVecGetClosure(dm, section, X, point, NULL, &x);
651:       for (i = 0; i < cellDof; ++i) u[f*cellDof+i] = x[i];
652:       DMPlexVecRestoreClosure(dm, section, X, point, NULL, &x);
653:       ++f;
654:     }
655:     for (f = 0; f < Nf; ++f) {
656:       void   (*f0)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], const PetscReal[], PetscScalar[]) = fem->f0BdFuncs[f];
657:       void   (*f1)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], const PetscReal[], PetscScalar[]) = fem->f1BdFuncs[f];
658:       PetscInt Nb;
659:       /* Conforming batches */
660:       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
661:       /* Remainder */
662:       PetscInt Nr, offset;

664:       PetscFEGetQuadrature(feBd[f], &q);
665:       PetscFEGetDimension(feBd[f], &Nb);
666:       PetscFEGetTileSizes(feBd[f], NULL, &numBlocks, NULL, &numBatches);
667:       blockSize = Nb*q.numPoints;
668:       batchSize = numBlocks * blockSize;
669:        PetscFESetTileSizes(feBd[f], blockSize, numBlocks, batchSize, numBatches);
670:       numChunks = numFaces / (numBatches*batchSize);
671:       Ne        = numChunks*numBatches*batchSize;
672:       Nr        = numFaces % (numBatches*batchSize);
673:       offset    = numFaces - Nr;
674:       geom.v0   = v0;
675:       geom.n    = n;
676:       geom.J    = J;
677:       geom.invJ = invJ;
678:       geom.detJ = detJ;
679:       PetscFEIntegrateBdResidual(feBd[f], Ne, Nf, feBd, f, geom, u, 0, NULL, NULL, f0, f1, elemVec);
680:       geom.v0   = &v0[offset*dim];
681:       geom.n    = &n[offset*dim];
682:       geom.J    = &J[offset*dim*dim];
683:       geom.invJ = &invJ[offset*dim*dim];
684:       geom.detJ = &detJ[offset];
685:       PetscFEIntegrateBdResidual(feBd[f], Nr, Nf, feBd, f, geom, &u[offset*cellDof], 0, NULL, NULL, f0, f1, &elemVec[offset*cellDof]);
686:     }
687:     for (p = 0, f = 0; p < numPoints; ++p) {
688:       const PetscInt point = points[p];

690:       DMLabelGetValue(depth, point, &dep);
691:       if (dep != dim-1) continue;
692:       if (mesh->printFEM > 1) {DMPrintCellVector(point, "BdResidual", cellDof, &elemVec[f*cellDof]);}
693:       DMPlexVecSetClosure(dm, NULL, F, point, &elemVec[f*cellDof], ADD_VALUES);
694:       ++f;
695:     }
696:     ISRestoreIndices(pointIS, &points);
697:     ISDestroy(&pointIS);
698:     PetscFree7(u,v0,n,J,invJ,detJ,elemVec);
699:   }
700:   if (mesh->printFEM) {DMPrintLocalVec(dm, name, mesh->printTol, F);}
701:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
702:   return(0);
703: }

707: /*@C
708:   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user

710:   Input Parameters:
711: + dm - The mesh
712: . J  - The Jacobian shell matrix
713: . X  - Local input vector
714: - user - The user context

716:   Output Parameter:
717: . F  - Local output vector

719:   Note:
720:   The second member of the user context must be an FEMContext.

722:   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
723:   like a GPU, or vectorize on a multicore machine.

725:   Level: developer

727: .seealso: DMPlexComputeResidualFEM()
728: @*/
729: PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
730: {
731:   DM_Plex          *mesh = (DM_Plex *) dm->data;
732:   PetscFEM         *fem  = (PetscFEM *) user;
733:   PetscFE          *fe   = fem->fe;
734:   PetscQuadrature   quad;
735:   PetscCellGeometry geom;
736:   PetscSection      section;
737:   JacActionCtx     *jctx;
738:   PetscReal        *v0, *J, *invJ, *detJ;
739:   PetscScalar      *elemVec, *u, *a;
740:   PetscInt          dim, numFields, field, numCells, cStart, cEnd, c;
741:   PetscInt          cellDof = 0;
742:   PetscErrorCode    ierr;

745:   /* PetscLogEventBegin(DMPLEX_JacobianActionFEM,dm,0,0,0); */
746:   MatShellGetContext(Jac, &jctx);
747:   DMPlexGetDimension(dm, &dim);
748:   DMGetDefaultSection(dm, &section);
749:   PetscSectionGetNumFields(section, &numFields);
750:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
751:   numCells = cEnd - cStart;
752:   for (field = 0; field < numFields; ++field) {
753:     PetscInt Nb, Nc;

755:     PetscFEGetDimension(fe[field], &Nb);
756:     PetscFEGetNumComponents(fe[field], &Nc);
757:     cellDof += Nb*Nc;
758:   }
759:   VecSet(F, 0.0);
760:   PetscMalloc7(numCells*cellDof,&u,numCells*cellDof,&a,numCells*dim,&v0,numCells*dim*dim,&J,numCells*dim*dim,&invJ,numCells,&detJ,numCells*cellDof,&elemVec);
761:   for (c = cStart; c < cEnd; ++c) {
762:     PetscScalar *x = NULL;
763:     PetscInt     i;

765:     DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);
766:     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
767:     DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);
768:     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
769:     DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);
770:     DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);
771:     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
772:     DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);
773:   }
774:   for (field = 0; field < numFields; ++field) {
775:     PetscInt Nb;
776:     /* Conforming batches */
777:     PetscInt numBlocks  = 1;
778:     PetscInt numBatches = 1;
779:     PetscInt numChunks, Ne, blockSize, batchSize;
780:     /* Remainder */
781:     PetscInt Nr, offset;

783:     PetscFEGetQuadrature(fe[field], &quad);
784:     PetscFEGetDimension(fe[field], &Nb);
785:     blockSize = Nb*quad.numPoints;
786:     batchSize = numBlocks * blockSize;
787:     numChunks = numCells / (numBatches*batchSize);
788:     Ne        = numChunks*numBatches*batchSize;
789:     Nr        = numCells % (numBatches*batchSize);
790:     offset    = numCells - Nr;
791:     geom.v0   = v0;
792:     geom.J    = J;
793:     geom.invJ = invJ;
794:     geom.detJ = detJ;
795:     PetscFEIntegrateJacobianAction(fe[field], Ne, numFields, fe, field, geom, u, a, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);
796:     geom.v0   = &v0[offset*dim];
797:     geom.J    = &J[offset*dim*dim];
798:     geom.invJ = &invJ[offset*dim*dim];
799:     geom.detJ = &detJ[offset];
800:     PetscFEIntegrateJacobianAction(fe[field], Nr, numFields, fe, field, geom, &u[offset*cellDof], &a[offset*cellDof],
801:                                           fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);
802:   }
803:   for (c = cStart; c < cEnd; ++c) {
804:     if (mesh->printFEM > 1) {DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);}
805:     DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);
806:   }
807:   PetscFree7(u,a,v0,J,invJ,detJ,elemVec);
808:   if (mesh->printFEM) {
809:     PetscMPIInt rank, numProcs;
810:     PetscInt    p;

812:     MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);
813:     MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);
814:     PetscPrintf(PetscObjectComm((PetscObject)dm), "Jacobian Action:\n");
815:     for (p = 0; p < numProcs; ++p) {
816:       if (p == rank) {VecView(F, PETSC_VIEWER_STDOUT_SELF);}
817:       PetscBarrier((PetscObject) dm);
818:     }
819:   }
820:   /* PetscLogEventEnd(DMPLEX_JacobianActionFEM,dm,0,0,0); */
821:   return(0);
822: }

826: /*@
827:   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.

829:   Input Parameters:
830: + dm - The mesh
831: . X  - Local input vector
832: - user - The user context

834:   Output Parameter:
835: . Jac  - Jacobian matrix

837:   Note:
838:   The second member of the user context must be an FEMContext.

840:   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
841:   like a GPU, or vectorize on a multicore machine.

843:   Level: developer

845: .seealso: FormFunctionLocal()
846: @*/
847: PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
848: {
849:   DM_Plex          *mesh  = (DM_Plex *) dm->data;
850:   PetscFEM         *fem   = (PetscFEM *) user;
851:   PetscFE          *fe    = fem->fe;
852:   PetscFE          *feAux = fem->feAux;
853:   const char       *name  = "Jacobian";
854:   DM                dmAux;
855:   Vec               A;
856:   PetscQuadrature   quad;
857:   PetscCellGeometry geom;
858:   PetscSection      section, globalSection, sectionAux;
859:   PetscReal        *v0, *J, *invJ, *detJ;
860:   PetscScalar      *elemMat, *u, *a;
861:   PetscInt          dim, Nf, NfAux = 0, f, fieldI, fieldJ, numCells, cStart, cEnd, c;
862:   PetscInt          cellDof = 0, numComponents = 0;
863:   PetscInt          cellDofAux = 0, numComponentsAux = 0;
864:   PetscBool         isShell;
865:   PetscErrorCode    ierr;

868:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
869:   DMPlexGetDimension(dm, &dim);
870:   DMGetDefaultSection(dm, &section);
871:   DMGetDefaultGlobalSection(dm, &globalSection);
872:   PetscSectionGetNumFields(section, &Nf);
873:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
874:   numCells = cEnd - cStart;
875:   for (f = 0; f < Nf; ++f) {
876:     PetscInt Nb, Nc;

878:     PetscFEGetDimension(fe[f], &Nb);
879:     PetscFEGetNumComponents(fe[f], &Nc);
880:     cellDof       += Nb*Nc;
881:     numComponents += Nc;
882:   }
883:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
884:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
885:   if (dmAux) {
886:     DMGetDefaultSection(dmAux, &sectionAux);
887:     PetscSectionGetNumFields(sectionAux, &NfAux);
888:   }
889:   for (f = 0; f < NfAux; ++f) {
890:     PetscInt Nb, Nc;

892:     PetscFEGetDimension(feAux[f], &Nb);
893:     PetscFEGetNumComponents(feAux[f], &Nc);
894:     cellDofAux       += Nb*Nc;
895:     numComponentsAux += Nc;
896:   }
897:   DMPlexProjectFunctionLocal(dm, fe, fem->bcFuncs, fem->bcCtxs, INSERT_BC_VALUES, X);
898:   MatZeroEntries(JacP);
899:   PetscMalloc6(numCells*cellDof,&u,numCells*dim,&v0,numCells*dim*dim,&J,numCells*dim*dim,&invJ,numCells,&detJ,numCells*cellDof*cellDof,&elemMat);
900:   if (dmAux) {PetscMalloc1(numCells*cellDofAux, &a);}
901:   for (c = cStart; c < cEnd; ++c) {
902:     PetscScalar *x = NULL;
903:     PetscInt     i;

905:     DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);
906:     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
907:     DMPlexVecGetClosure(dm, section, X, c, NULL, &x);
908:     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
909:     DMPlexVecRestoreClosure(dm, section, X, c, NULL, &x);
910:     if (dmAux) {
911:       DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);
912:       for (i = 0; i < cellDofAux; ++i) a[c*cellDofAux+i] = x[i];
913:       DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);
914:     }
915:   }
916:   PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));
917:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
918:     PetscInt Nb;
919:     /* Conforming batches */
920:     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
921:     /* Remainder */
922:     PetscInt Nr, offset;

924:     PetscFEGetQuadrature(fe[fieldI], &quad);
925:     PetscFEGetDimension(fe[fieldI], &Nb);
926:     PetscFEGetTileSizes(fe[fieldI], NULL, &numBlocks, NULL, &numBatches);
927:     blockSize = Nb*quad.numPoints;
928:     batchSize = numBlocks * blockSize;
929:     PetscFESetTileSizes(fe[fieldI], blockSize, numBlocks, batchSize, numBatches);
930:     numChunks = numCells / (numBatches*batchSize);
931:     Ne        = numChunks*numBatches*batchSize;
932:     Nr        = numCells % (numBatches*batchSize);
933:     offset    = numCells - Nr;
934:     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
935:       void   (*g0)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g0Funcs[fieldI*Nf+fieldJ];
936:       void   (*g1)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g1Funcs[fieldI*Nf+fieldJ];
937:       void   (*g2)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g2Funcs[fieldI*Nf+fieldJ];
938:       void   (*g3)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]) = fem->g3Funcs[fieldI*Nf+fieldJ];

940:       geom.v0   = v0;
941:       geom.J    = J;
942:       geom.invJ = invJ;
943:       geom.detJ = detJ;
944:       PetscFEIntegrateJacobian(fe[fieldI], Ne, Nf, fe, fieldI, fieldJ, geom, u, NfAux, feAux, a, g0, g1, g2, g3, elemMat);
945:       geom.v0   = &v0[offset*dim];
946:       geom.J    = &J[offset*dim*dim];
947:       geom.invJ = &invJ[offset*dim*dim];
948:       geom.detJ = &detJ[offset];
949:       PetscFEIntegrateJacobian(fe[fieldI], Nr, Nf, fe, fieldI, fieldJ, geom, &u[offset*cellDof], NfAux, feAux, &a[offset*cellDofAux], g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);
950:     }
951:   }
952:   for (c = cStart; c < cEnd; ++c) {
953:     if (mesh->printFEM > 1) {DMPrintCellMatrix(c, name, cellDof, cellDof, &elemMat[c*cellDof*cellDof]);}
954:     DMPlexMatSetClosure(dm, section, globalSection, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);
955:   }
956:   PetscFree6(u,v0,J,invJ,detJ,elemMat);
957:   if (dmAux) {PetscFree(a);}
958:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
959:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
960:   if (mesh->printFEM) {
961:     PetscPrintf(PETSC_COMM_WORLD, "%s:\n", name);
962:     MatChop(JacP, 1.0e-10);
963:     MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);
964:   }
965:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
966:   PetscObjectTypeCompare((PetscObject) Jac, MATSHELL, &isShell);
967:   if (isShell) {
968:     JacActionCtx *jctx;

970:     MatShellGetContext(Jac, &jctx);
971:     VecCopy(X, jctx->u);
972:   }
973:   *str = SAME_NONZERO_PATTERN;
974:   return(0);
975: }