Actual source code: plexfem.c

petsc-3.11.1 2019-04-12
Report Typos and Errors
  1:  #include <petsc/private/dmpleximpl.h>
  2:  #include <petscsf.h>
  3:  #include <petscsnes.h>

  5:  #include <petsc/private/hashsetij.h>
  6:  #include <petsc/private/petscfeimpl.h>
  7:  #include <petsc/private/petscfvimpl.h>

  9: static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy)
 10: {
 11:   PetscBool      isPlex;

 15:   PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
 16:   if (isPlex) {
 17:     *plex = dm;
 18:     PetscObjectReference((PetscObject) dm);
 19:   } else {
 20:     PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
 21:     if (!*plex) {
 22:       DMConvert(dm,DMPLEX,plex);
 23:       PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
 24:       if (copy) {
 25:         const char *comps[3] = {"A", "dmAux"};
 26:         PetscObject obj;
 27:         PetscInt    i;

 29:         {
 30:           /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
 31:           DMSubDomainHookLink link;
 32:           for (link = dm->subdomainhook; link; link = link->next) {
 33:             if (link->ddhook) {(*link->ddhook)(dm, *plex, link->ctx);}
 34:           }
 35:         }
 36:         for (i = 0; i < 3; i++) {
 37:           PetscObjectQuery((PetscObject) dm, comps[i], &obj);
 38:           PetscObjectCompose((PetscObject) *plex, comps[i], obj);
 39:         }
 40:       }
 41:     } else {
 42:       PetscObjectReference((PetscObject) *plex);
 43:     }
 44:   }
 45:   return(0);
 46: }

 48: static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom (void *ctx)
 49: {
 50:   PetscFEGeom *geom = (PetscFEGeom *) ctx;

 54:   PetscFEGeomDestroy(&geom);
 55:   return(0);
 56: }

 58: static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
 59: {
 60:   char            composeStr[33] = {0};
 61:   PetscObjectId   id;
 62:   PetscContainer  container;
 63:   PetscErrorCode  ierr;

 66:   PetscObjectGetId((PetscObject)quad,&id);
 67:   PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%x\n", id);
 68:   PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
 69:   if (container) {
 70:     PetscContainerGetPointer(container, (void **) geom);
 71:   } else {
 72:     DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
 73:     PetscContainerCreate(PETSC_COMM_SELF,&container);
 74:     PetscContainerSetPointer(container, (void *) *geom);
 75:     PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
 76:     PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
 77:     PetscContainerDestroy(&container);
 78:   }
 79:   return(0);
 80: }

 82: static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
 83: {
 85:   *geom = NULL;
 86:   return(0);
 87: }

 89: /*@
 90:   DMPlexGetScale - Get the scale for the specified fundamental unit

 92:   Not collective

 94:   Input Arguments:
 95: + dm   - the DM
 96: - unit - The SI unit

 98:   Output Argument:
 99: . scale - The value used to scale all quantities with this unit

101:   Level: advanced

103: .seealso: DMPlexSetScale(), PetscUnit
104: @*/
105: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
106: {
107:   DM_Plex *mesh = (DM_Plex*) dm->data;

112:   *scale = mesh->scale[unit];
113:   return(0);
114: }

116: /*@
117:   DMPlexSetScale - Set the scale for the specified fundamental unit

119:   Not collective

121:   Input Arguments:
122: + dm   - the DM
123: . unit - The SI unit
124: - scale - The value used to scale all quantities with this unit

126:   Level: advanced

128: .seealso: DMPlexGetScale(), PetscUnit
129: @*/
130: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
131: {
132:   DM_Plex *mesh = (DM_Plex*) dm->data;

136:   mesh->scale[unit] = scale;
137:   return(0);
138: }

140: static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *mode, void *ctx)
141: {
142:   const PetscInt eps[3][3][3] = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}};
143:   PetscInt *ctxInt  = (PetscInt *) ctx;
144:   PetscInt  dim2    = ctxInt[0];
145:   PetscInt  d       = ctxInt[1];
146:   PetscInt  i, j, k = dim > 2 ? d - dim : d;

149:   if (dim != dim2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %d does not match context dimension %d", dim, dim2);
150:   for (i = 0; i < dim; i++) mode[i] = 0.;
151:   if (d < dim) {
152:     mode[d] = 1.; /* Translation along axis d */
153:   } else {
154:     for (i = 0; i < dim; i++) {
155:       for (j = 0; j < dim; j++) {
156:         mode[j] += eps[i][j][k]*X[i]; /* Rotation about axis d */
157:       }
158:     }
159:   }
160:   return(0);
161: }

163: /*@
164:   DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation

166:   Collective on DM

168:   Input Arguments:
169: . dm - the DM

171:   Output Argument:
172: . sp - the null space

174:   Note: This is necessary to provide a suitable coarse space for algebraic multigrid

176:   Level: advanced

178: .seealso: MatNullSpaceCreate(), PCGAMG
179: @*/
180: PetscErrorCode DMPlexCreateRigidBody(DM dm, MatNullSpace *sp)
181: {
182:   MPI_Comm       comm;
183:   Vec            mode[6];
184:   PetscSection   section, globalSection;
185:   PetscInt       dim, dimEmbed, n, m, mmin, d, i, j;

189:   PetscObjectGetComm((PetscObject)dm,&comm);
190:   DMGetDimension(dm, &dim);
191:   DMGetCoordinateDim(dm, &dimEmbed);
192:   if (dim == 1) {
193:     MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
194:     return(0);
195:   }
196:   DMGetSection(dm, &section);
197:   DMGetGlobalSection(dm, &globalSection);
198:   PetscSectionGetConstrainedStorageSize(globalSection, &n);
199:   m    = (dim*(dim+1))/2;
200:   VecCreate(comm, &mode[0]);
201:   VecSetSizes(mode[0], n, PETSC_DETERMINE);
202:   VecSetUp(mode[0]);
203:   VecGetSize(mode[0], &n);
204:   mmin = PetscMin(m, n);
205:   for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
206:   for (d = 0; d < m; d++) {
207:     PetscInt         ctx[2];
208:     PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
209:     void            *voidctx = (void *) (&ctx[0]);

211:     ctx[0] = dimEmbed;
212:     ctx[1] = d;
213:     DMProjectFunction(dm, 0.0, &func, &voidctx, INSERT_VALUES, mode[d]);
214:   }
215:   for (i = 0; i < PetscMin(dim, mmin); ++i) {VecNormalize(mode[i], NULL);}
216:   /* Orthonormalize system */
217:   for (i = dim; i < mmin; ++i) {
218:     PetscScalar dots[6];

220:     VecMDot(mode[i], i, mode, dots);
221:     for (j = 0; j < i; ++j) dots[j] *= -1.0;
222:     VecMAXPY(mode[i], i, dots, mode);
223:     VecNormalize(mode[i], NULL);
224:   }
225:   MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp);
226:   for (i = 0; i < m; ++i) {VecDestroy(&mode[i]);}
227:   return(0);
228: }

230: /*@
231:   DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation

233:   Collective on DM

235:   Input Arguments:
236: + dm    - the DM
237: . nb    - The number of bodies
238: . label - The DMLabel marking each domain
239: . nids  - The number of ids per body
240: - ids   - An array of the label ids in sequence for each domain

242:   Output Argument:
243: . sp - the null space

245:   Note: This is necessary to provide a suitable coarse space for algebraic multigrid

247:   Level: advanced

249: .seealso: MatNullSpaceCreate()
250: @*/
251: PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
252: {
253:   MPI_Comm       comm;
254:   PetscSection   section, globalSection;
255:   Vec           *mode;
256:   PetscScalar   *dots;
257:   PetscInt       dim, dimEmbed, n, m, b, d, i, j, off;

261:   PetscObjectGetComm((PetscObject)dm,&comm);
262:   DMGetDimension(dm, &dim);
263:   DMGetCoordinateDim(dm, &dimEmbed);
264:   DMGetSection(dm, &section);
265:   DMGetGlobalSection(dm, &globalSection);
266:   PetscSectionGetConstrainedStorageSize(globalSection, &n);
267:   m    = nb * (dim*(dim+1))/2;
268:   PetscMalloc2(m, &mode, m, &dots);
269:   VecCreate(comm, &mode[0]);
270:   VecSetSizes(mode[0], n, PETSC_DETERMINE);
271:   VecSetUp(mode[0]);
272:   for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
273:   for (b = 0, off = 0; b < nb; ++b) {
274:     for (d = 0; d < m/nb; ++d) {
275:       PetscInt         ctx[2];
276:       PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
277:       void            *voidctx = (void *) (&ctx[0]);

279:       ctx[0] = dimEmbed;
280:       ctx[1] = d;
281:       DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);
282:       off   += nids[b];
283:     }
284:   }
285:   for (i = 0; i < dim; ++i) {VecNormalize(mode[i], NULL);}
286:   /* Orthonormalize system */
287:   for (i = 0; i < m; ++i) {
288:     VecMDot(mode[i], i, mode, dots);
289:     for (j = 0; j < i; ++j) dots[j] *= -1.0;
290:     VecMAXPY(mode[i], i, dots, mode);
291:     VecNormalize(mode[i], NULL);
292:   }
293:   MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
294:   for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
295:   PetscFree2(mode, dots);
296:   return(0);
297: }

299: /*@
300:   DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
301:   are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
302:   evaluating the dual space basis of that point.  A basis function is associated with the point in its
303:   transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum
304:   projection height, which is set with this function.  By default, the maximum projection height is zero, which means
305:   that only mesh cells are used to project basis functions.  A height of one, for example, evaluates a cell-interior
306:   basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face.

308:   Input Parameters:
309: + dm - the DMPlex object
310: - height - the maximum projection height >= 0

312:   Level: advanced

314: .seealso: DMPlexGetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
315: @*/
316: PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
317: {
318:   DM_Plex *plex = (DM_Plex *) dm->data;

322:   plex->maxProjectionHeight = height;
323:   return(0);
324: }

326: /*@
327:   DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
328:   DMPlexProjectXXXLocal() functions.

330:   Input Parameters:
331: . dm - the DMPlex object

333:   Output Parameters:
334: . height - the maximum projection height

336:   Level: intermediate

338: .seealso: DMPlexSetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
339: @*/
340: PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
341: {
342:   DM_Plex *plex = (DM_Plex *) dm->data;

346:   *height = plex->maxProjectionHeight;
347:   return(0);
348: }

350: /*@C
351:   DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector

353:   Input Parameters:
354: + dm     - The DM, with a PetscDS that matches the problem being constrained
355: . time   - The time
356: . field  - The field to constrain
357: . Nc     - The number of constrained field components, or 0 for all components
358: . comps  - An array of constrained component numbers, or NULL for all components
359: . label  - The DMLabel defining constrained points
360: . numids - The number of DMLabel ids for constrained points
361: . ids    - An array of ids for constrained points
362: . func   - A pointwise function giving boundary values
363: - ctx    - An optional user context for bcFunc

365:   Output Parameter:
366: . locX   - A local vector to receives the boundary values

368:   Level: developer

370: .seealso: DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
371: @*/
372: PetscErrorCode DMPlexInsertBoundaryValuesEssential(DM dm, PetscReal time, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX)
373: {
374:   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
375:   void            **ctxs;
376:   PetscInt          numFields;
377:   PetscErrorCode    ierr;

380:   DMGetNumFields(dm, &numFields);
381:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
382:   funcs[field] = func;
383:   ctxs[field]  = ctx;
384:   DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);
385:   PetscFree2(funcs,ctxs);
386:   return(0);
387: }

389: /*@C
390:   DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector

392:   Input Parameters:
393: + dm     - The DM, with a PetscDS that matches the problem being constrained
394: . time   - The time
395: . locU   - A local vector with the input solution values
396: . field  - The field to constrain
397: . Nc     - The number of constrained field components, or 0 for all components
398: . comps  - An array of constrained component numbers, or NULL for all components
399: . label  - The DMLabel defining constrained points
400: . numids - The number of DMLabel ids for constrained points
401: . ids    - An array of ids for constrained points
402: . func   - A pointwise function giving boundary values
403: - ctx    - An optional user context for bcFunc

405:   Output Parameter:
406: . locX   - A local vector to receives the boundary values

408:   Level: developer

410: .seealso: DMPlexInsertBoundaryValuesEssential(), DMAddBoundary()
411: @*/
412: PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
413:                                                         void (*func)(PetscInt, PetscInt, PetscInt,
414:                                                                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
415:                                                                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
416:                                                                      PetscReal, const PetscReal[], PetscInt, const PetscScalar[],
417:                                                                      PetscScalar[]),
418:                                                         void *ctx, Vec locX)
419: {
420:   void (**funcs)(PetscInt, PetscInt, PetscInt,
421:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
422:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
423:                  PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
424:   void            **ctxs;
425:   PetscInt          numFields;
426:   PetscErrorCode    ierr;

429:   DMGetNumFields(dm, &numFields);
430:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
431:   funcs[field] = func;
432:   ctxs[field]  = ctx;
433:   DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
434:   PetscFree2(funcs,ctxs);
435:   return(0);
436: }

438: /*@C
439:   DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector

441:   Input Parameters:
442: + dm     - The DM, with a PetscDS that matches the problem being constrained
443: . time   - The time
444: . faceGeometry - A vector with the FVM face geometry information
445: . cellGeometry - A vector with the FVM cell geometry information
446: . Grad         - A vector with the FVM cell gradient information
447: . field  - The field to constrain
448: . Nc     - The number of constrained field components, or 0 for all components
449: . comps  - An array of constrained component numbers, or NULL for all components
450: . label  - The DMLabel defining constrained points
451: . numids - The number of DMLabel ids for constrained points
452: . ids    - An array of ids for constrained points
453: . func   - A pointwise function giving boundary values
454: - ctx    - An optional user context for bcFunc

456:   Output Parameter:
457: . locX   - A local vector to receives the boundary values

459:   Note: This implementation currently ignores the numcomps/comps argument from DMAddBoundary()

461:   Level: developer

463: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
464: @*/
465: PetscErrorCode DMPlexInsertBoundaryValuesRiemann(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
466:                                                  PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX)
467: {
468:   PetscDS            prob;
469:   PetscSF            sf;
470:   DM                 dmFace, dmCell, dmGrad;
471:   const PetscScalar *facegeom, *cellgeom = NULL, *grad;
472:   const PetscInt    *leaves;
473:   PetscScalar       *x, *fx;
474:   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
475:   PetscErrorCode     ierr, ierru = 0;

478:   DMGetPointSF(dm, &sf);
479:   PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
480:   nleaves = PetscMax(0, nleaves);
481:   DMGetDimension(dm, &dim);
482:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
483:   DMGetDS(dm, &prob);
484:   VecGetDM(faceGeometry, &dmFace);
485:   VecGetArrayRead(faceGeometry, &facegeom);
486:   if (cellGeometry) {
487:     VecGetDM(cellGeometry, &dmCell);
488:     VecGetArrayRead(cellGeometry, &cellgeom);
489:   }
490:   if (Grad) {
491:     PetscFV fv;

493:     PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);
494:     VecGetDM(Grad, &dmGrad);
495:     VecGetArrayRead(Grad, &grad);
496:     PetscFVGetNumComponents(fv, &pdim);
497:     DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);
498:   }
499:   VecGetArray(locX, &x);
500:   for (i = 0; i < numids; ++i) {
501:     IS              faceIS;
502:     const PetscInt *faces;
503:     PetscInt        numFaces, f;

505:     DMLabelGetStratumIS(label, ids[i], &faceIS);
506:     if (!faceIS) continue; /* No points with that id on this process */
507:     ISGetLocalSize(faceIS, &numFaces);
508:     ISGetIndices(faceIS, &faces);
509:     for (f = 0; f < numFaces; ++f) {
510:       const PetscInt         face = faces[f], *cells;
511:       PetscFVFaceGeom        *fg;

513:       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
514:       PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);
515:       if (loc >= 0) continue;
516:       DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
517:       DMPlexGetSupport(dm, face, &cells);
518:       if (Grad) {
519:         PetscFVCellGeom       *cg;
520:         PetscScalar           *cx, *cgrad;
521:         PetscScalar           *xG;
522:         PetscReal              dx[3];
523:         PetscInt               d;

525:         DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);
526:         DMPlexPointLocalRead(dm, cells[0], x, &cx);
527:         DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);
528:         DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
529:         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
530:         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx);
531:         ierru = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);
532:         if (ierru) {
533:           ISRestoreIndices(faceIS, &faces);
534:           ISDestroy(&faceIS);
535:           goto cleanup;
536:         }
537:       } else {
538:         PetscScalar       *xI;
539:         PetscScalar       *xG;

541:         DMPlexPointLocalRead(dm, cells[0], x, &xI);
542:         DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
543:         ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
544:         if (ierru) {
545:           ISRestoreIndices(faceIS, &faces);
546:           ISDestroy(&faceIS);
547:           goto cleanup;
548:         }
549:       }
550:     }
551:     ISRestoreIndices(faceIS, &faces);
552:     ISDestroy(&faceIS);
553:   }
554:   cleanup:
555:   VecRestoreArray(locX, &x);
556:   if (Grad) {
557:     DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx);
558:     VecRestoreArrayRead(Grad, &grad);
559:   }
560:   if (cellGeometry) {VecRestoreArrayRead(cellGeometry, &cellgeom);}
561:   VecRestoreArrayRead(faceGeometry, &facegeom);
562:   CHKERRQ(ierru);
563:   return(0);
564: }

566: PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
567: {
568:   PetscDS        prob;
569:   PetscInt       numBd, b;

573:   DMGetDS(dm, &prob);
574:   PetscDSGetNumBoundary(prob, &numBd);
575:   for (b = 0; b < numBd; ++b) {
576:     DMBoundaryConditionType type;
577:     const char             *labelname;
578:     DMLabel                 label;
579:     PetscInt                field, Nc;
580:     const PetscInt         *comps;
581:     PetscObject             obj;
582:     PetscClassId            id;
583:     void                    (*func)(void);
584:     PetscInt                numids;
585:     const PetscInt         *ids;
586:     void                   *ctx;

588:     DMGetBoundary(dm, b, &type, NULL, &labelname, &field, &Nc, &comps, &func, &numids, &ids, &ctx);
589:     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
590:     DMGetLabel(dm, labelname, &label);
591:     DMGetField(dm, field, NULL, &obj);
592:     PetscObjectGetClassId(obj, &id);
593:     if (id == PETSCFE_CLASSID) {
594:       switch (type) {
595:         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
596:       case DM_BC_ESSENTIAL:
597:         DMPlexLabelAddCells(dm,label);
598:         DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);
599:         DMPlexLabelClearCells(dm,label);
600:         break;
601:       case DM_BC_ESSENTIAL_FIELD:
602:         DMPlexLabelAddCells(dm,label);
603:         DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids,
604:                                                         (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
605:                                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
606:                                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func, ctx, locX);
607:         DMPlexLabelClearCells(dm,label);
608:         break;
609:       default: break;
610:       }
611:     } else if (id == PETSCFV_CLASSID) {
612:       if (!faceGeomFVM) continue;
613:       DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids,
614:                                                (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);
615:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
616:   }
617:   return(0);
618: }

620: /*@
621:   DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector

623:   Input Parameters:
624: + dm - The DM
625: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
626: . time - The time
627: . faceGeomFVM - Face geometry data for FV discretizations
628: . cellGeomFVM - Cell geometry data for FV discretizations
629: - gradFVM - Gradient reconstruction data for FV discretizations

631:   Output Parameters:
632: . locX - Solution updated with boundary values

634:   Level: developer

636: .seealso: DMProjectFunctionLabelLocal()
637: @*/
638: PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
639: {

648:   PetscTryMethod(dm,"DMPlexInsertBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX,time,faceGeomFVM,cellGeomFVM,gradFVM));
649:   return(0);
650: }

652: PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
653: {
654:   Vec              localX;
655:   PetscErrorCode   ierr;

658:   DMGetLocalVector(dm, &localX);
659:   DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL);
660:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
661:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
662:   DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff);
663:   DMRestoreLocalVector(dm, &localX);
664:   return(0);
665: }

667: /*@C
668:   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

670:   Input Parameters:
671: + dm     - The DM
672: . time   - The time
673: . funcs  - The functions to evaluate for each field component
674: . ctxs   - Optional array of contexts to pass to each function, or NULL.
675: - localX - The coefficient vector u_h, a local vector

677:   Output Parameter:
678: . diff - The diff ||u - u_h||_2

680:   Level: developer

682: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
683: @*/
684: PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
685: {
686:   const PetscInt   debug = ((DM_Plex*)dm->data)->printL2;
687:   PetscSection     section;
688:   PetscQuadrature  quad;
689:   PetscScalar     *funcVal, *interpolant;
690:   PetscReal       *coords, *detJ, *J;
691:   PetscReal        localDiff = 0.0;
692:   const PetscReal *quadWeights;
693:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, cEndInterior, c, field, fieldOffset;
694:   PetscErrorCode   ierr;

697:   DMGetDimension(dm, &dim);
698:   DMGetCoordinateDim(dm, &coordDim);
699:   DMGetSection(dm, &section);
700:   PetscSectionGetNumFields(section, &numFields);
701:   for (field = 0; field < numFields; ++field) {
702:     PetscObject  obj;
703:     PetscClassId id;
704:     PetscInt     Nc;

706:     DMGetField(dm, field, NULL, &obj);
707:     PetscObjectGetClassId(obj, &id);
708:     if (id == PETSCFE_CLASSID) {
709:       PetscFE fe = (PetscFE) obj;

711:       PetscFEGetQuadrature(fe, &quad);
712:       PetscFEGetNumComponents(fe, &Nc);
713:     } else if (id == PETSCFV_CLASSID) {
714:       PetscFV fv = (PetscFV) obj;

716:       PetscFVGetQuadrature(fv, &quad);
717:       PetscFVGetNumComponents(fv, &Nc);
718:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
719:     numComponents += Nc;
720:   }
721:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
722:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
723:   PetscMalloc5(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J);
724:   DMPlexGetVTKCellHeight(dm, &cellHeight);
725:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
726:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
727:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
728:   for (c = cStart; c < cEnd; ++c) {
729:     PetscScalar *x = NULL;
730:     PetscReal    elemDiff = 0.0;
731:     PetscInt     qc = 0;

733:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, NULL, detJ);
734:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

736:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
737:       PetscObject  obj;
738:       PetscClassId id;
739:       void * const ctx = ctxs ? ctxs[field] : NULL;
740:       PetscInt     Nb, Nc, q, fc;

742:       DMGetField(dm, field, NULL, &obj);
743:       PetscObjectGetClassId(obj, &id);
744:       if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
745:       else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
746:       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
747:       if (debug) {
748:         char title[1024];
749:         PetscSNPrintf(title, 1023, "Solution for Field %d", field);
750:         DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
751:       }
752:       for (q = 0; q < Nq; ++q) {
753:         if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, point %D", detJ[q], c, q);
754:         (*funcs[field])(coordDim, time, &coords[coordDim * q], Nc, funcVal, ctx);
755:         if (ierr) {
756:           PetscErrorCode ierr2;
757:           ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
758:           ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
759:           ierr2 = PetscFree5(funcVal,interpolant,coords,detJ,J);CHKERRQ(ierr2);
760: 
761:         }
762:         if (id == PETSCFE_CLASSID)      {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);}
763:         else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
764:         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
765:         for (fc = 0; fc < Nc; ++fc) {
766:           const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
767:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q]);}
768:           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
769:         }
770:       }
771:       fieldOffset += Nb;
772:       qc += Nc;
773:     }
774:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
775:     if (debug) {PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);}
776:     localDiff += elemDiff;
777:   }
778:   PetscFree5(funcVal,interpolant,coords,detJ,J);
779:   MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
780:   *diff = PetscSqrtReal(*diff);
781:   return(0);
782: }

784: PetscErrorCode DMComputeL2GradientDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
785: {
786:   const PetscInt   debug = ((DM_Plex*)dm->data)->printL2;
787:   PetscSection     section;
788:   PetscQuadrature  quad;
789:   Vec              localX;
790:   PetscScalar     *funcVal, *interpolant;
791:   const PetscReal *quadPoints, *quadWeights;
792:   PetscReal       *coords, *realSpaceDer, *J, *invJ, *detJ;
793:   PetscReal        localDiff = 0.0;
794:   PetscInt         dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, cEndInterior, c, field, fieldOffset;
795:   PetscErrorCode   ierr;

798:   DMGetDimension(dm, &dim);
799:   DMGetCoordinateDim(dm, &coordDim);
800:   DMGetSection(dm, &section);
801:   PetscSectionGetNumFields(section, &numFields);
802:   DMGetLocalVector(dm, &localX);
803:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
804:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
805:   for (field = 0; field < numFields; ++field) {
806:     PetscFE  fe;
807:     PetscInt Nc;

809:     DMGetField(dm, field, NULL, (PetscObject *) &fe);
810:     PetscFEGetQuadrature(fe, &quad);
811:     PetscFEGetNumComponents(fe, &Nc);
812:     numComponents += Nc;
813:   }
814:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
815:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
816:   /* DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
817:   PetscMalloc7(numComponents,&funcVal,coordDim*Nq,&coords,coordDim*Nq,&realSpaceDer,coordDim*coordDim*Nq,&J,coordDim*coordDim*Nq,&invJ,numComponents,&interpolant,Nq,&detJ);
818:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
819:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
820:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
821:   for (c = cStart; c < cEnd; ++c) {
822:     PetscScalar *x = NULL;
823:     PetscReal    elemDiff = 0.0;
824:     PetscInt     qc = 0;

826:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, invJ, detJ);
827:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

829:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
830:       PetscFE          fe;
831:       void * const     ctx = ctxs ? ctxs[field] : NULL;
832:       PetscReal       *basisDer;
833:       PetscInt         Nb, Nc, q, fc;

835:       DMGetField(dm, field, NULL, (PetscObject *) &fe);
836:       PetscFEGetDimension(fe, &Nb);
837:       PetscFEGetNumComponents(fe, &Nc);
838:       PetscFEGetDefaultTabulation(fe, NULL, &basisDer, NULL);
839:       if (debug) {
840:         char title[1024];
841:         PetscSNPrintf(title, 1023, "Solution for Field %d", field);
842:         DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
843:       }
844:       for (q = 0; q < Nq; ++q) {
845:         if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", detJ[q], c, q);
846:         (*funcs[field])(coordDim, time, &coords[q*coordDim], n, numFields, funcVal, ctx);
847:         if (ierr) {
848:           PetscErrorCode ierr2;
849:           ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
850:           ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
851:           ierr2 = PetscFree7(funcVal,coords,realSpaceDer,J,invJ,interpolant,detJ);CHKERRQ(ierr2);
852: 
853:         }
854:         PetscFEInterpolateGradient_Static(fe, &x[fieldOffset], coordDim, invJ, n, q, interpolant);
855:         for (fc = 0; fc < Nc; ++fc) {
856:           const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
857:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %d fieldDer %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q]);}
858:           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
859:         }
860:       }
861:       fieldOffset += Nb;
862:       qc          += Nc;
863:     }
864:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
865:     if (debug) {PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);}
866:     localDiff += elemDiff;
867:   }
868:   PetscFree7(funcVal,coords,realSpaceDer,J,invJ,interpolant,detJ);
869:   DMRestoreLocalVector(dm, &localX);
870:   MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
871:   *diff = PetscSqrtReal(*diff);
872:   return(0);
873: }

875: PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
876: {
877:   const PetscInt   debug = ((DM_Plex*)dm->data)->printL2;
878:   PetscSection     section;
879:   PetscQuadrature  quad;
880:   Vec              localX;
881:   PetscScalar     *funcVal, *interpolant;
882:   PetscReal       *coords, *detJ, *J;
883:   PetscReal       *localDiff;
884:   const PetscReal *quadPoints, *quadWeights;
885:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, cEndInterior, c, field, fieldOffset;
886:   PetscErrorCode   ierr;

889:   DMGetDimension(dm, &dim);
890:   DMGetCoordinateDim(dm, &coordDim);
891:   DMGetSection(dm, &section);
892:   PetscSectionGetNumFields(section, &numFields);
893:   DMGetLocalVector(dm, &localX);
894:   DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
895:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
896:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
897:   for (field = 0; field < numFields; ++field) {
898:     PetscObject  obj;
899:     PetscClassId id;
900:     PetscInt     Nc;

902:     DMGetField(dm, field, NULL, &obj);
903:     PetscObjectGetClassId(obj, &id);
904:     if (id == PETSCFE_CLASSID) {
905:       PetscFE fe = (PetscFE) obj;

907:       PetscFEGetQuadrature(fe, &quad);
908:       PetscFEGetNumComponents(fe, &Nc);
909:     } else if (id == PETSCFV_CLASSID) {
910:       PetscFV fv = (PetscFV) obj;

912:       PetscFVGetQuadrature(fv, &quad);
913:       PetscFVGetNumComponents(fv, &Nc);
914:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
915:     numComponents += Nc;
916:   }
917:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
918:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
919:   PetscCalloc6(numFields,&localDiff,numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J);
920:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
921:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
922:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
923:   for (c = cStart; c < cEnd; ++c) {
924:     PetscScalar *x = NULL;
925:     PetscInt     qc = 0;

927:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, NULL, detJ);
928:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

930:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
931:       PetscObject  obj;
932:       PetscClassId id;
933:       void * const ctx = ctxs ? ctxs[field] : NULL;
934:       PetscInt     Nb, Nc, q, fc;

936:       PetscReal       elemDiff = 0.0;

938:       DMGetField(dm, field, NULL, &obj);
939:       PetscObjectGetClassId(obj, &id);
940:       if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
941:       else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
942:       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
943:       if (debug) {
944:         char title[1024];
945:         PetscSNPrintf(title, 1023, "Solution for Field %d", field);
946:         DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);
947:       }
948:       for (q = 0; q < Nq; ++q) {
949:         if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature point %D", detJ, c, q);
950:         (*funcs[field])(coordDim, time, &coords[coordDim*q], numFields, funcVal, ctx);
951:         if (ierr) {
952:           PetscErrorCode ierr2;
953:           ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
954:           ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
955:           ierr2 = PetscFree6(localDiff,funcVal,interpolant,coords,detJ,J);CHKERRQ(ierr2);
956: 
957:         }
958:         if (id == PETSCFE_CLASSID)      {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);}
959:         else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
960:         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
961:         for (fc = 0; fc < Nc; ++fc) {
962:           const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
963:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d point %g %g %g diff %g\n", c, field, coordDim > 0 ? coords[0] : 0., coordDim > 1 ? coords[1] : 0., coordDim > 2 ? coords[2] : 0., PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q]);}
964:           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
965:         }
966:       }
967:       fieldOffset += Nb;
968:       qc          += Nc;
969:       localDiff[field] += elemDiff;
970:     }
971:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
972:   }
973:   DMRestoreLocalVector(dm, &localX);
974:   MPIU_Allreduce(localDiff, diff, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
975:   for (field = 0; field < numFields; ++field) diff[field] = PetscSqrtReal(diff[field]);
976:   PetscFree6(localDiff,funcVal,interpolant,coords,detJ,J);
977:   return(0);
978: }

980: /*@C
981:   DMPlexComputeL2DiffVec - This function computes the cellwise L_2 difference between a function u and an FEM interpolant solution u_h, and stores it in a Vec.

983:   Input Parameters:
984: + dm    - The DM
985: . time  - The time
986: . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation
987: . ctxs  - Optional array of contexts to pass to each function, or NULL.
988: - X     - The coefficient vector u_h

990:   Output Parameter:
991: . D - A Vec which holds the difference ||u - u_h||_2 for each cell

993:   Level: developer

995: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
996: @*/
997: PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
998: {
999:   PetscSection     section;
1000:   PetscQuadrature  quad;
1001:   Vec              localX;
1002:   PetscScalar     *funcVal, *interpolant;
1003:   PetscReal       *coords, *detJ, *J;
1004:   const PetscReal *quadPoints, *quadWeights;
1005:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, cEndInterior, c, field, fieldOffset;
1006:   PetscErrorCode   ierr;

1009:   VecSet(D, 0.0);
1010:   DMGetDimension(dm, &dim);
1011:   DMGetCoordinateDim(dm, &coordDim);
1012:   DMGetSection(dm, &section);
1013:   PetscSectionGetNumFields(section, &numFields);
1014:   DMGetLocalVector(dm, &localX);
1015:   DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1016:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1017:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1018:   for (field = 0; field < numFields; ++field) {
1019:     PetscObject  obj;
1020:     PetscClassId id;
1021:     PetscInt     Nc;

1023:     DMGetField(dm, field, NULL, &obj);
1024:     PetscObjectGetClassId(obj, &id);
1025:     if (id == PETSCFE_CLASSID) {
1026:       PetscFE fe = (PetscFE) obj;

1028:       PetscFEGetQuadrature(fe, &quad);
1029:       PetscFEGetNumComponents(fe, &Nc);
1030:     } else if (id == PETSCFV_CLASSID) {
1031:       PetscFV fv = (PetscFV) obj;

1033:       PetscFVGetQuadrature(fv, &quad);
1034:       PetscFVGetNumComponents(fv, &Nc);
1035:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1036:     numComponents += Nc;
1037:   }
1038:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1039:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1040:   PetscMalloc5(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J);
1041:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1042:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
1043:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1044:   for (c = cStart; c < cEnd; ++c) {
1045:     PetscScalar *x = NULL;
1046:     PetscScalar  elemDiff = 0.0;
1047:     PetscInt     qc = 0;

1049:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, J, NULL, detJ);
1050:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

1052:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1053:       PetscObject  obj;
1054:       PetscClassId id;
1055:       void * const ctx = ctxs ? ctxs[field] : NULL;
1056:       PetscInt     Nb, Nc, q, fc;

1058:       DMGetField(dm, field, NULL, &obj);
1059:       PetscObjectGetClassId(obj, &id);
1060:       if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1061:       else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1062:       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1063:       if (funcs[field]) {
1064:         for (q = 0; q < Nq; ++q) {
1065:           if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)detJ[q], c, q);
1066:           (*funcs[field])(coordDim, time, &coords[q*coordDim], Nc, funcVal, ctx);
1067:           if (ierr) {
1068:             PetscErrorCode ierr2;
1069:             ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1070:             ierr2 = PetscFree5(funcVal,interpolant,coords,detJ,J);CHKERRQ(ierr2);
1071:             ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1072: 
1073:           }
1074:           if (id == PETSCFE_CLASSID)      {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);}
1075:           else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
1076:           else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1077:           for (fc = 0; fc < Nc; ++fc) {
1078:             const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1079:             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*detJ[q];
1080:           }
1081:         }
1082:       }
1083:       fieldOffset += Nb;
1084:       qc          += Nc;
1085:     }
1086:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1087:     VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES);
1088:   }
1089:   PetscFree5(funcVal,interpolant,coords,detJ,J);
1090:   DMRestoreLocalVector(dm, &localX);
1091:   VecSqrtAbs(D);
1092:   return(0);
1093: }

1095: /*@C
1096:   DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec.

1098:   Input Parameters:
1099: + dm - The DM
1100: - LocX  - The coefficient vector u_h

1102:   Output Parameter:
1103: . locC - A Vec which holds the Clement interpolant of the gradient

1105:   Notes:
1106:     Add citation to (Clement, 1975) and definition of the interpolant
1107:   \nabla u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| \nabla u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| where |T_i| is the cell volume

1109:   Level: developer

1111: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
1112: @*/
1113: PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
1114: {
1115:   DM_Plex         *mesh  = (DM_Plex *) dm->data;
1116:   PetscInt         debug = mesh->printFEM;
1117:   DM               dmC;
1118:   PetscSection     section;
1119:   PetscQuadrature  quad;
1120:   PetscScalar     *interpolant, *gradsum;
1121:   PetscReal       *coords, *detJ, *J, *invJ;
1122:   const PetscReal *quadPoints, *quadWeights;
1123:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, cEndInterior, vStart, vEnd, v, field, fieldOffset;
1124:   PetscErrorCode   ierr;

1127:   VecGetDM(locC, &dmC);
1128:   VecSet(locC, 0.0);
1129:   DMGetDimension(dm, &dim);
1130:   DMGetCoordinateDim(dm, &coordDim);
1131:   DMGetSection(dm, &section);
1132:   PetscSectionGetNumFields(section, &numFields);
1133:   for (field = 0; field < numFields; ++field) {
1134:     PetscObject  obj;
1135:     PetscClassId id;
1136:     PetscInt     Nc;

1138:     DMGetField(dm, field, NULL, &obj);
1139:     PetscObjectGetClassId(obj, &id);
1140:     if (id == PETSCFE_CLASSID) {
1141:       PetscFE fe = (PetscFE) obj;

1143:       PetscFEGetQuadrature(fe, &quad);
1144:       PetscFEGetNumComponents(fe, &Nc);
1145:     } else if (id == PETSCFV_CLASSID) {
1146:       PetscFV fv = (PetscFV) obj;

1148:       PetscFVGetQuadrature(fv, &quad);
1149:       PetscFVGetNumComponents(fv, &Nc);
1150:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1151:     numComponents += Nc;
1152:   }
1153:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1154:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1155:   PetscMalloc6(coordDim*numComponents*2,&gradsum,coordDim*numComponents,&interpolant,coordDim*Nq,&coords,Nq,&detJ,coordDim*coordDim*Nq,&J,coordDim*coordDim*Nq,&invJ);
1156:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1157:   DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);
1158:   DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);
1159:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1160:   for (v = vStart; v < vEnd; ++v) {
1161:     PetscScalar volsum = 0.0;
1162:     PetscInt   *star = NULL;
1163:     PetscInt    starSize, st, d, fc;

1165:     PetscMemzero(gradsum, coordDim*numComponents * sizeof(PetscScalar));
1166:     DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1167:     for (st = 0; st < starSize*2; st += 2) {
1168:       const PetscInt cell = star[st];
1169:       PetscScalar   *grad = &gradsum[coordDim*numComponents];
1170:       PetscScalar   *x    = NULL;
1171:       PetscReal      vol  = 0.0;

1173:       if ((cell < cStart) || (cell >= cEnd)) continue;
1174:       DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, J, invJ, detJ);
1175:       DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);
1176:       for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1177:         PetscObject  obj;
1178:         PetscClassId id;
1179:         PetscInt     Nb, Nc, q, qc = 0;

1181:         PetscMemzero(grad, coordDim*numComponents * sizeof(PetscScalar));
1182:         DMGetField(dm, field, NULL, &obj);
1183:         PetscObjectGetClassId(obj, &id);
1184:         if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1185:         else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1186:         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1187:         for (q = 0; q < Nq; ++q) {
1188:           if (detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)detJ[q], cell, q);
1189:           if (ierr) {
1190:             PetscErrorCode ierr2;
1191:             ierr2 = DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr2);
1192:             ierr2 = DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr2);
1193:             ierr2 = PetscFree4(interpolant,coords,detJ,J);CHKERRQ(ierr2);
1194: 
1195:           }
1196:           if (id == PETSCFE_CLASSID)      {PetscFEInterpolateGradient_Static((PetscFE) obj, &x[fieldOffset], coordDim, invJ, NULL, q, interpolant);}
1197:           else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field);
1198:           for (fc = 0; fc < Nc; ++fc) {
1199:             const PetscReal wt = quadWeights[q*qNc+qc+fc];

1201:             for (d = 0; d < coordDim; ++d) grad[fc*coordDim+d] += interpolant[fc*dim+d]*wt*detJ[q];
1202:           }
1203:           vol += quadWeights[q*qNc]*detJ[q];
1204:         }
1205:         fieldOffset += Nb;
1206:         qc          += Nc;
1207:       }
1208:       DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);
1209:       for (fc = 0; fc < numComponents; ++fc) {
1210:         for (d = 0; d < coordDim; ++d) {
1211:           gradsum[fc*coordDim+d] += grad[fc*coordDim+d];
1212:         }
1213:       }
1214:       volsum += vol;
1215:       if (debug) {
1216:         PetscPrintf(PETSC_COMM_SELF, "Cell %D gradient: [", cell);
1217:         for (fc = 0; fc < numComponents; ++fc) {
1218:           for (d = 0; d < coordDim; ++d) {
1219:             if (fc || d > 0) {PetscPrintf(PETSC_COMM_SELF, ", ");}
1220:             PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc*coordDim+d]));
1221:           }
1222:         }
1223:         PetscPrintf(PETSC_COMM_SELF, "]\n");
1224:       }
1225:     }
1226:     for (fc = 0; fc < numComponents; ++fc) {
1227:       for (d = 0; d < coordDim; ++d) gradsum[fc*coordDim+d] /= volsum;
1228:     }
1229:     DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1230:     DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES);
1231:   }
1232:   PetscFree6(gradsum,interpolant,coords,detJ,J,invJ);
1233:   return(0);
1234: }

1236: static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
1237: {
1238:   DM                 dmAux = NULL;
1239:   PetscDS            prob,    probAux = NULL;
1240:   PetscSection       section, sectionAux;
1241:   Vec                locX,    locA;
1242:   PetscInt           dim, numCells = cEnd - cStart, c, f;
1243:   PetscBool          useFVM = PETSC_FALSE;
1244:   /* DS */
1245:   PetscInt           Nf,    totDim,    *uOff, *uOff_x, numConstants;
1246:   PetscInt           NfAux, totDimAux, *aOff;
1247:   PetscScalar       *u, *a;
1248:   const PetscScalar *constants;
1249:   /* Geometry */
1250:   PetscFEGeom       *cgeomFEM;
1251:   DM                 dmGrad;
1252:   PetscQuadrature    affineQuad = NULL;
1253:   Vec                cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
1254:   PetscFVCellGeom   *cgeomFVM;
1255:   const PetscScalar *lgrad;
1256:   PetscInt           maxDegree;
1257:   DMField            coordField;
1258:   IS                 cellIS;
1259:   PetscErrorCode     ierr;

1262:   DMGetDS(dm, &prob);
1263:   DMGetDimension(dm, &dim);
1264:   DMGetSection(dm, &section);
1265:   PetscSectionGetNumFields(section, &Nf);
1266:   /* Determine which discretizations we have */
1267:   for (f = 0; f < Nf; ++f) {
1268:     PetscObject  obj;
1269:     PetscClassId id;

1271:     PetscDSGetDiscretization(prob, f, &obj);
1272:     PetscObjectGetClassId(obj, &id);
1273:     if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
1274:   }
1275:   /* Get local solution with boundary values */
1276:   DMGetLocalVector(dm, &locX);
1277:   DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
1278:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
1279:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
1280:   /* Read DS information */
1281:   PetscDSGetTotalDimension(prob, &totDim);
1282:   PetscDSGetComponentOffsets(prob, &uOff);
1283:   PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
1284:   ISCreateStride(PETSC_COMM_SELF,numCells,cStart,1,&cellIS);
1285:   PetscDSGetConstants(prob, &numConstants, &constants);
1286:   /* Read Auxiliary DS information */
1287:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
1288:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
1289:   if (dmAux) {
1290:     DMGetDS(dmAux, &probAux);
1291:     PetscDSGetNumFields(probAux, &NfAux);
1292:     DMGetSection(dmAux, &sectionAux);
1293:     PetscDSGetTotalDimension(probAux, &totDimAux);
1294:     PetscDSGetComponentOffsets(probAux, &aOff);
1295:   }
1296:   /* Allocate data  arrays */
1297:   PetscCalloc1(numCells*totDim, &u);
1298:   if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
1299:   /* Read out geometry */
1300:   DMGetCoordinateField(dm,&coordField);
1301:   DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
1302:   if (maxDegree <= 1) {
1303:     DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
1304:     if (affineQuad) {
1305:       DMFieldCreateFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&cgeomFEM);
1306:     }
1307:   }
1308:   if (useFVM) {
1309:     PetscFV   fv = NULL;
1310:     Vec       grad;
1311:     PetscInt  fStart, fEnd;
1312:     PetscBool compGrad;

1314:     for (f = 0; f < Nf; ++f) {
1315:       PetscObject  obj;
1316:       PetscClassId id;

1318:       PetscDSGetDiscretization(prob, f, &obj);
1319:       PetscObjectGetClassId(obj, &id);
1320:       if (id == PETSCFV_CLASSID) {fv = (PetscFV) obj; break;}
1321:     }
1322:     PetscFVGetComputeGradients(fv, &compGrad);
1323:     PetscFVSetComputeGradients(fv, PETSC_TRUE);
1324:     DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM);
1325:     DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad);
1326:     PetscFVSetComputeGradients(fv, compGrad);
1327:     VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
1328:     /* Reconstruct and limit cell gradients */
1329:     DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1330:     DMGetGlobalVector(dmGrad, &grad);
1331:     DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
1332:     /* Communicate gradient values */
1333:     DMGetLocalVector(dmGrad, &locGrad);
1334:     DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
1335:     DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
1336:     DMRestoreGlobalVector(dmGrad, &grad);
1337:     /* Handle non-essential (e.g. outflow) boundary values */
1338:     DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad);
1339:     VecGetArrayRead(locGrad, &lgrad);
1340:   }
1341:   /* Read out data from inputs */
1342:   for (c = cStart; c < cEnd; ++c) {
1343:     PetscScalar *x = NULL;
1344:     PetscInt     i;

1346:     DMPlexVecGetClosure(dm, section, locX, c, NULL, &x);
1347:     for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
1348:     DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x);
1349:     if (dmAux) {
1350:       DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x);
1351:       for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
1352:       DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x);
1353:     }
1354:   }
1355:   /* Do integration for each field */
1356:   for (f = 0; f < Nf; ++f) {
1357:     PetscObject  obj;
1358:     PetscClassId id;
1359:     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

1361:     PetscDSGetDiscretization(prob, f, &obj);
1362:     PetscObjectGetClassId(obj, &id);
1363:     if (id == PETSCFE_CLASSID) {
1364:       PetscFE         fe = (PetscFE) obj;
1365:       PetscQuadrature q;
1366:       PetscFEGeom     *chunkGeom = NULL;
1367:       PetscInt        Nq, Nb;

1369:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
1370:       PetscFEGetQuadrature(fe, &q);
1371:       PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
1372:       PetscFEGetDimension(fe, &Nb);
1373:       blockSize = Nb*Nq;
1374:       batchSize = numBlocks * blockSize;
1375:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
1376:       numChunks = numCells / (numBatches*batchSize);
1377:       Ne        = numChunks*numBatches*batchSize;
1378:       Nr        = numCells % (numBatches*batchSize);
1379:       offset    = numCells - Nr;
1380:       if (!affineQuad) {
1381:         DMFieldCreateFEGeom(coordField,cellIS,q,PETSC_FALSE,&cgeomFEM);
1382:       }
1383:       PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
1384:       PetscFEIntegrate(fe, prob, f, Ne, chunkGeom, u, probAux, a, cintegral);
1385:       PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&chunkGeom);
1386:       PetscFEIntegrate(fe, prob, f, Nr, chunkGeom, &u[offset*totDim], probAux, &a[offset*totDimAux], &cintegral[offset*Nf]);
1387:       PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&chunkGeom);
1388:       if (!affineQuad) {
1389:         PetscFEGeomDestroy(&cgeomFEM);
1390:       }
1391:     } else if (id == PETSCFV_CLASSID) {
1392:       PetscInt       foff;
1393:       PetscPointFunc obj_func;
1394:       PetscScalar    lint;

1396:       PetscDSGetObjective(prob, f, &obj_func);
1397:       PetscDSGetFieldOffset(prob, f, &foff);
1398:       if (obj_func) {
1399:         for (c = 0; c < numCells; ++c) {
1400:           PetscScalar *u_x;

1402:           DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x);
1403:           obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim*c+foff], NULL, u_x, aOff, NULL, &a[totDimAux*c], NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint);
1404:           cintegral[c*Nf+f] += PetscRealPart(lint)*cgeomFVM[c].volume;
1405:         }
1406:       }
1407:     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
1408:   }
1409:   /* Cleanup data arrays */
1410:   if (useFVM) {
1411:     VecRestoreArrayRead(locGrad, &lgrad);
1412:     VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
1413:     DMRestoreLocalVector(dmGrad, &locGrad);
1414:     VecDestroy(&faceGeometryFVM);
1415:     VecDestroy(&cellGeometryFVM);
1416:     DMDestroy(&dmGrad);
1417:   }
1418:   if (dmAux) {PetscFree(a);}
1419:   PetscFree(u);
1420:   /* Cleanup */
1421:   if (affineQuad) {
1422:     PetscFEGeomDestroy(&cgeomFEM);
1423:   }
1424:   PetscQuadratureDestroy(&affineQuad);
1425:   ISDestroy(&cellIS);
1426:   DMRestoreLocalVector(dm, &locX);
1427:   return(0);
1428: }

1430: /*@
1431:   DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user

1433:   Input Parameters:
1434: + dm - The mesh
1435: . X  - Global input vector
1436: - user - The user context

1438:   Output Parameter:
1439: . integral - Integral for each field

1441:   Level: developer

1443: .seealso: DMPlexComputeResidualFEM()
1444: @*/
1445: PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
1446: {
1447:   DM_Plex       *mesh = (DM_Plex *) dm->data;
1448:   PetscScalar   *cintegral, *lintegral;
1449:   PetscInt       Nf, f, cellHeight, cStart, cEnd, cEndInterior[4], cell;

1456:   PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
1457:   DMGetNumFields(dm, &Nf);
1458:   DMPlexGetVTKCellHeight(dm, &cellHeight);
1459:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
1460:   DMPlexGetHybridBounds(dm, &cEndInterior[0], &cEndInterior[1], &cEndInterior[2], &cEndInterior[3]);
1461:   cEnd = cEndInterior[cellHeight] < 0 ? cEnd : cEndInterior[cellHeight];
1462:   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
1463:   PetscCalloc2(Nf, &lintegral, (cEnd-cStart)*Nf, &cintegral);
1464:   DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
1465:   /* Sum up values */
1466:   for (cell = cStart; cell < cEnd; ++cell) {
1467:     const PetscInt c = cell - cStart;

1469:     if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
1470:     for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c*Nf+f];
1471:   }
1472:   MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject) dm));
1473:   if (mesh->printFEM) {
1474:     PetscPrintf(PetscObjectComm((PetscObject) dm), "Integral:");
1475:     for (f = 0; f < Nf; ++f) {PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", (double) PetscRealPart(integral[f]));}
1476:     PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");
1477:   }
1478:   PetscFree2(lintegral, cintegral);
1479:   PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
1480:   return(0);
1481: }

1483: /*@
1484:   DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user

1486:   Input Parameters:
1487: + dm - The mesh
1488: . X  - Global input vector
1489: - user - The user context

1491:   Output Parameter:
1492: . integral - Cellwise integrals for each field

1494:   Level: developer

1496: .seealso: DMPlexComputeResidualFEM()
1497: @*/
1498: PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
1499: {
1500:   DM_Plex       *mesh = (DM_Plex *) dm->data;
1501:   DM             dmF;
1502:   PetscSection   sectionF;
1503:   PetscScalar   *cintegral, *af;
1504:   PetscInt       Nf, f, cellHeight, cStart, cEnd, cEndInterior[4], cell;

1511:   PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
1512:   DMGetNumFields(dm, &Nf);
1513:   DMPlexGetVTKCellHeight(dm, &cellHeight);
1514:   DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);
1515:   DMPlexGetHybridBounds(dm, &cEndInterior[0], &cEndInterior[1], &cEndInterior[2], &cEndInterior[3]);
1516:   cEnd = cEndInterior[cellHeight] < 0 ? cEnd : cEndInterior[cellHeight];
1517:   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
1518:   PetscCalloc1((cEnd-cStart)*Nf, &cintegral);
1519:   DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
1520:   /* Put values in F*/
1521:   VecGetDM(F, &dmF);
1522:   DMGetSection(dmF, &sectionF);
1523:   VecGetArray(F, &af);
1524:   for (cell = cStart; cell < cEnd; ++cell) {
1525:     const PetscInt c = cell - cStart;
1526:     PetscInt       dof, off;

1528:     if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
1529:     PetscSectionGetDof(sectionF, cell, &dof);
1530:     PetscSectionGetOffset(sectionF, cell, &off);
1531:     if (dof != Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %D != %D", dof, Nf);
1532:     for (f = 0; f < Nf; ++f) af[off+f] = cintegral[c*Nf+f];
1533:   }
1534:   VecRestoreArray(F, &af);
1535:   PetscFree(cintegral);
1536:   PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
1537:   return(0);
1538: }

1540: static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS,
1541:                                                        void (*func)(PetscInt, PetscInt, PetscInt,
1542:                                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1543:                                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1544:                                                                     PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
1545:                                                        PetscScalar *fintegral, void *user)
1546: {
1547:   DM                 plex = NULL, plexA = NULL;
1548:   PetscDS            prob, probAux = NULL;
1549:   PetscSection       section, sectionAux = NULL;
1550:   Vec                locA = NULL;
1551:   DMField            coordField;
1552:   PetscInt           Nf,        totDim,        *uOff, *uOff_x;
1553:   PetscInt           NfAux = 0, totDimAux = 0, *aOff = NULL;
1554:   PetscScalar       *u, *a = NULL;
1555:   const PetscScalar *constants;
1556:   PetscInt           numConstants, f;
1557:   PetscErrorCode     ierr;

1560:   DMGetCoordinateField(dm, &coordField);
1561:   DMConvert(dm, DMPLEX, &plex);
1562:   DMGetDS(dm, &prob);
1563:   DMGetDefaultSection(dm, &section);
1564:   PetscSectionGetNumFields(section, &Nf);
1565:   /* Determine which discretizations we have */
1566:   for (f = 0; f < Nf; ++f) {
1567:     PetscObject  obj;
1568:     PetscClassId id;

1570:     PetscDSGetDiscretization(prob, f, &obj);
1571:     PetscObjectGetClassId(obj, &id);
1572:     if (id == PETSCFV_CLASSID) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not supported for FVM (field %D)", f);
1573:   }
1574:   /* Read DS information */
1575:   PetscDSGetTotalDimension(prob, &totDim);
1576:   PetscDSGetComponentOffsets(prob, &uOff);
1577:   PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
1578:   PetscDSGetConstants(prob, &numConstants, &constants);
1579:   /* Read Auxiliary DS information */
1580:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
1581:   if (locA) {
1582:     DM dmAux;

1584:     VecGetDM(locA, &dmAux);
1585:     DMConvert(dmAux, DMPLEX, &plexA);
1586:     DMGetDS(dmAux, &probAux);
1587:     PetscDSGetNumFields(probAux, &NfAux);
1588:     DMGetDefaultSection(dmAux, &sectionAux);
1589:     PetscDSGetTotalDimension(probAux, &totDimAux);
1590:     PetscDSGetComponentOffsets(probAux, &aOff);
1591:   }
1592:   /* Integrate over points */
1593:   {
1594:     PetscFEGeom    *fgeom, *chunkGeom = NULL;
1595:     PetscInt        maxDegree;
1596:     PetscQuadrature qGeom = NULL;
1597:     const PetscInt *points;
1598:     PetscInt        numFaces, face, Nq, field;
1599:     PetscInt        numChunks, chunkSize, chunk, Nr, offset;

1601:     ISGetLocalSize(pointIS, &numFaces);
1602:     ISGetIndices(pointIS, &points);
1603:     PetscCalloc2(numFaces*totDim, &u, locA ? numFaces*totDimAux : 0, &a);
1604:     DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
1605:     for (field = 0; field < Nf; ++field) {
1606:       PetscFE fe;

1608:       PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
1609:       if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);}
1610:       if (!qGeom) {
1611:         PetscFEGetFaceQuadrature(fe, &qGeom);
1612:         PetscObjectReference((PetscObject) qGeom);
1613:       }
1614:       PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
1615:       DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
1616:       for (face = 0; face < numFaces; ++face) {
1617:         const PetscInt point = points[face], *support, *cone;
1618:         PetscScalar    *x    = NULL;
1619:         PetscInt       i, coneSize, faceLoc;

1621:         DMPlexGetSupport(dm, point, &support);
1622:         DMPlexGetConeSize(dm, support[0], &coneSize);
1623:         DMPlexGetCone(dm, support[0], &cone);
1624:         for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
1625:         if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", face, support[0]);
1626:         fgeom->face[face][0] = faceLoc;
1627:         DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
1628:         for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
1629:         DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
1630:         if (locA) {
1631:           PetscInt subp;
1632:           DMPlexGetSubpoint(plexA, support[0], &subp);
1633:           DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
1634:           for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i];
1635:           DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
1636:         }
1637:       }
1638:       /* Get blocking */
1639:       {
1640:         PetscQuadrature q;
1641:         PetscInt        numBatches, batchSize, numBlocks, blockSize;
1642:         PetscInt        Nq, Nb;

1644:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
1645:         PetscFEGetQuadrature(fe, &q);
1646:         PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
1647:         PetscFEGetDimension(fe, &Nb);
1648:         blockSize = Nb*Nq;
1649:         batchSize = numBlocks * blockSize;
1650:         chunkSize = numBatches*batchSize;
1651:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
1652:         numChunks = numFaces / chunkSize;
1653:         Nr        = numFaces % chunkSize;
1654:         offset    = numFaces - Nr;
1655:       }
1656:       /* Do integration for each field */
1657:       for (chunk = 0; chunk < numChunks; ++chunk) {
1658:         PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);
1659:         PetscFEIntegrateBd(fe, prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);
1660:         PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
1661:       }
1662:       PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
1663:       PetscFEIntegrateBd(fe, prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);
1664:       PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
1665:       /* Cleanup data arrays */
1666:       DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
1667:       PetscQuadratureDestroy(&qGeom);
1668:       PetscFree2(u, a);
1669:       ISRestoreIndices(pointIS, &points);
1670:     }
1671:   }
1672:   if (plex)  {DMDestroy(&plex);}
1673:   if (plexA) {DMDestroy(&plexA);}
1674:   return(0);
1675: }

1677: /*@
1678:   DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user

1680:   Input Parameters:
1681: + dm      - The mesh
1682: . X       - Global input vector
1683: . label   - The boundary DMLabel
1684: . numVals - The number of label values to use, or PETSC_DETERMINE for all values
1685: . vals    - The label values to use, or PETSC_NULL for all values
1686: . func    = The function to integrate along the boundary
1687: - user    - The user context

1689:   Output Parameter:
1690: . integral - Integral for each field

1692:   Level: developer

1694: .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM()
1695: @*/
1696: PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[],
1697:                                        void (*func)(PetscInt, PetscInt, PetscInt,
1698:                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1699:                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1700:                                                     PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
1701:                                        PetscScalar *integral, void *user)
1702: {
1703:   Vec            locX;
1704:   PetscSection   section;
1705:   DMLabel        depthLabel;
1706:   IS             facetIS;
1707:   PetscInt       dim, Nf, f, v;

1716:   PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
1717:   DMPlexGetDepthLabel(dm, &depthLabel);
1718:   DMGetDimension(dm, &dim);
1719:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
1720:   DMGetDefaultSection(dm, &section);
1721:   PetscSectionGetNumFields(section, &Nf);
1722:   /* Get local solution with boundary values */
1723:   DMGetLocalVector(dm, &locX);
1724:   DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
1725:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
1726:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
1727:   /* Loop over label values */
1728:   PetscMemzero(integral, Nf * sizeof(PetscScalar));
1729:   for (v = 0; v < numVals; ++v) {
1730:     IS           pointIS;
1731:     PetscInt     numFaces, face;
1732:     PetscScalar *fintegral;

1734:     DMLabelGetStratumIS(label, vals[v], &pointIS);
1735:     if (!pointIS) continue; /* No points with that id on this process */
1736:     {
1737:       IS isectIS;

1739:       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
1740:       ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
1741:       ISDestroy(&pointIS);
1742:       pointIS = isectIS;
1743:     }
1744:     ISGetLocalSize(pointIS, &numFaces);
1745:     PetscCalloc1(numFaces*Nf, &fintegral);
1746:     DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);
1747:     /* Sum point contributions into integral */
1748:     for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f];
1749:     PetscFree(fintegral);
1750:     ISDestroy(&pointIS);
1751:   }
1752:   DMRestoreLocalVector(dm, &locX);
1753:   ISDestroy(&facetIS);
1754:   PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
1755:   return(0);
1756: }

1758: /*@
1759:   DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to the uniformly refined DM.

1761:   Input Parameters:
1762: + dmf  - The fine mesh
1763: . dmc  - The coarse mesh
1764: - user - The user context

1766:   Output Parameter:
1767: . In  - The interpolation matrix

1769:   Level: developer

1771: .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
1772: @*/
1773: PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, Mat In, void *user)
1774: {
1775:   DM_Plex          *mesh  = (DM_Plex *) dmc->data;
1776:   const char       *name  = "Interpolator";
1777:   PetscDS           prob;
1778:   PetscFE          *feRef;
1779:   PetscFV          *fvRef;
1780:   PetscSection      fsection, fglobalSection;
1781:   PetscSection      csection, cglobalSection;
1782:   PetscScalar      *elemMat;
1783:   PetscInt          dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, cEndInterior, c;
1784:   PetscInt          cTotDim, rTotDim = 0;
1785:   PetscErrorCode    ierr;

1788:   PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
1789:   DMGetDimension(dmf, &dim);
1790:   DMGetSection(dmf, &fsection);
1791:   DMGetGlobalSection(dmf, &fglobalSection);
1792:   DMGetSection(dmc, &csection);
1793:   DMGetGlobalSection(dmc, &cglobalSection);
1794:   PetscSectionGetNumFields(fsection, &Nf);
1795:   DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);
1796:   DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);
1797:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
1798:   DMGetDS(dmf, &prob);
1799:   PetscCalloc2(Nf,&feRef,Nf,&fvRef);
1800:   for (f = 0; f < Nf; ++f) {
1801:     PetscObject  obj;
1802:     PetscClassId id;
1803:     PetscInt     rNb = 0, Nc = 0;

1805:     PetscDSGetDiscretization(prob, f, &obj);
1806:     PetscObjectGetClassId(obj, &id);
1807:     if (id == PETSCFE_CLASSID) {
1808:       PetscFE fe = (PetscFE) obj;

1810:       PetscFERefine(fe, &feRef[f]);
1811:       PetscFEGetDimension(feRef[f], &rNb);
1812:       PetscFEGetNumComponents(fe, &Nc);
1813:     } else if (id == PETSCFV_CLASSID) {
1814:       PetscFV        fv = (PetscFV) obj;
1815:       PetscDualSpace Q;

1817:       PetscFVRefine(fv, &fvRef[f]);
1818:       PetscFVGetDualSpace(fvRef[f], &Q);
1819:       PetscDualSpaceGetDimension(Q, &rNb);
1820:       PetscFVGetNumComponents(fv, &Nc);
1821:     }
1822:     rTotDim += rNb;
1823:   }
1824:   PetscDSGetTotalDimension(prob, &cTotDim);
1825:   PetscMalloc1(rTotDim*cTotDim,&elemMat);
1826:   PetscMemzero(elemMat, rTotDim*cTotDim * sizeof(PetscScalar));
1827:   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
1828:     PetscDualSpace   Qref;
1829:     PetscQuadrature  f;
1830:     const PetscReal *qpoints, *qweights;
1831:     PetscReal       *points;
1832:     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;

1834:     /* Compose points from all dual basis functionals */
1835:     if (feRef[fieldI]) {
1836:       PetscFEGetDualSpace(feRef[fieldI], &Qref);
1837:       PetscFEGetNumComponents(feRef[fieldI], &Nc);
1838:     } else {
1839:       PetscFVGetDualSpace(fvRef[fieldI], &Qref);
1840:       PetscFVGetNumComponents(fvRef[fieldI], &Nc);
1841:     }
1842:     PetscDualSpaceGetDimension(Qref, &fpdim);
1843:     for (i = 0; i < fpdim; ++i) {
1844:       PetscDualSpaceGetFunctional(Qref, i, &f);
1845:       PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);
1846:       npoints += Np;
1847:     }
1848:     PetscMalloc1(npoints*dim,&points);
1849:     for (i = 0, k = 0; i < fpdim; ++i) {
1850:       PetscDualSpaceGetFunctional(Qref, i, &f);
1851:       PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
1852:       for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
1853:     }

1855:     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
1856:       PetscObject  obj;
1857:       PetscClassId id;
1858:       PetscReal   *B;
1859:       PetscInt     NcJ = 0, cpdim = 0, j, qNc;

1861:       PetscDSGetDiscretization(prob, fieldJ, &obj);
1862:       PetscObjectGetClassId(obj, &id);
1863:       if (id == PETSCFE_CLASSID) {
1864:         PetscFE fe = (PetscFE) obj;

1866:         /* Evaluate basis at points */
1867:         PetscFEGetNumComponents(fe, &NcJ);
1868:         PetscFEGetDimension(fe, &cpdim);
1869:         /* For now, fields only interpolate themselves */
1870:         if (fieldI == fieldJ) {
1871:           if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", Nc, NcJ);
1872:           PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);
1873:           for (i = 0, k = 0; i < fpdim; ++i) {
1874:             PetscDualSpaceGetFunctional(Qref, i, &f);
1875:             PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
1876:             if (qNc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ);
1877:             for (p = 0; p < Np; ++p, ++k) {
1878:               for (j = 0; j < cpdim; ++j) {
1879:                 /*
1880:                    cTotDim:            Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
1881:                    offsetI, offsetJ:   Offsets into the larger element interpolation matrix for different fields
1882:                    fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
1883:                    qNC, Nc, Ncj, c:    Number of components in this field
1884:                    Np, p:              Number of quad points in the fine grid functional i
1885:                    k:                  i*Np + p, overall point number for the interpolation
1886:                 */
1887:                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += B[k*cpdim*NcJ+j*Nc+c]*qweights[p*qNc+c];
1888:               }
1889:             }
1890:           }
1891:           PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);
1892:         }
1893:       } else if (id == PETSCFV_CLASSID) {
1894:         PetscFV        fv = (PetscFV) obj;

1896:         /* Evaluate constant function at points */
1897:         PetscFVGetNumComponents(fv, &NcJ);
1898:         cpdim = 1;
1899:         /* For now, fields only interpolate themselves */
1900:         if (fieldI == fieldJ) {
1901:           if (Nc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", Nc, NcJ);
1902:           for (i = 0, k = 0; i < fpdim; ++i) {
1903:             PetscDualSpaceGetFunctional(Qref, i, &f);
1904:             PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
1905:             if (qNc != NcJ) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ);
1906:             for (p = 0; p < Np; ++p, ++k) {
1907:               for (j = 0; j < cpdim; ++j) {
1908:                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c];
1909:               }
1910:             }
1911:           }
1912:         }
1913:       }
1914:       offsetJ += cpdim;
1915:     }
1916:     offsetI += fpdim;
1917:     PetscFree(points);
1918:   }
1919:   if (mesh->printFEM > 1) {DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);}
1920:   /* Preallocate matrix */
1921:   {
1922:     Mat          preallocator;
1923:     PetscScalar *vals;
1924:     PetscInt    *cellCIndices, *cellFIndices;
1925:     PetscInt     locRows, locCols, cell;

1927:     MatGetLocalSize(In, &locRows, &locCols);
1928:     MatCreate(PetscObjectComm((PetscObject) In), &preallocator);
1929:     MatSetType(preallocator, MATPREALLOCATOR);
1930:     MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
1931:     MatSetUp(preallocator);
1932:     PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);
1933:     for (cell = cStart; cell < cEnd; ++cell) {
1934:       DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);
1935:       MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);
1936:     }
1937:     PetscFree3(vals,cellCIndices,cellFIndices);
1938:     MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);
1939:     MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);
1940:     MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);
1941:     MatDestroy(&preallocator);
1942:   }
1943:   /* Fill matrix */
1944:   MatZeroEntries(In);
1945:   for (c = cStart; c < cEnd; ++c) {
1946:     DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
1947:   }
1948:   for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);}
1949:   PetscFree2(feRef,fvRef);
1950:   PetscFree(elemMat);
1951:   MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
1952:   MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
1953:   if (mesh->printFEM) {
1954:     PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);
1955:     MatChop(In, 1.0e-10);
1956:     MatView(In, NULL);
1957:   }
1958:   PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
1959:   return(0);
1960: }

1962: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
1963: {
1964:   SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness");
1965: }

1967: /*@
1968:   DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM.

1970:   Input Parameters:
1971: + dmf  - The fine mesh
1972: . dmc  - The coarse mesh
1973: - user - The user context

1975:   Output Parameter:
1976: . In  - The interpolation matrix

1978:   Level: developer

1980: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
1981: @*/
1982: PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
1983: {
1984:   DM_Plex       *mesh = (DM_Plex *) dmf->data;
1985:   const char    *name = "Interpolator";
1986:   PetscDS        prob;
1987:   PetscSection   fsection, csection, globalFSection, globalCSection;
1988:   PetscHSetIJ    ht;
1989:   PetscLayout    rLayout;
1990:   PetscInt      *dnz, *onz;
1991:   PetscInt       locRows, rStart, rEnd;
1992:   PetscReal     *x, *v0, *J, *invJ, detJ;
1993:   PetscReal     *v0c, *Jc, *invJc, detJc;
1994:   PetscScalar   *elemMat;
1995:   PetscInt       dim, Nf, field, totDim, cStart, cEnd, cell, ccell;

1999:   PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2000:   DMGetCoordinateDim(dmc, &dim);
2001:   DMGetDS(dmc, &prob);
2002:   PetscDSGetRefCoordArrays(prob, &x, NULL);
2003:   PetscDSGetNumFields(prob, &Nf);
2004:   PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2005:   PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2006:   DMGetSection(dmf, &fsection);
2007:   DMGetGlobalSection(dmf, &globalFSection);
2008:   DMGetSection(dmc, &csection);
2009:   DMGetGlobalSection(dmc, &globalCSection);
2010:   DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2011:   PetscDSGetTotalDimension(prob, &totDim);
2012:   PetscMalloc1(totDim, &elemMat);

2014:   MatGetLocalSize(In, &locRows, NULL);
2015:   PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);
2016:   PetscLayoutSetLocalSize(rLayout, locRows);
2017:   PetscLayoutSetBlockSize(rLayout, 1);
2018:   PetscLayoutSetUp(rLayout);
2019:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2020:   PetscLayoutDestroy(&rLayout);
2021:   PetscCalloc2(locRows,&dnz,locRows,&onz);
2022:   PetscHSetIJCreate(&ht);
2023:   for (field = 0; field < Nf; ++field) {
2024:     PetscObject      obj;
2025:     PetscClassId     id;
2026:     PetscDualSpace   Q = NULL;
2027:     PetscQuadrature  f;
2028:     const PetscReal *qpoints;
2029:     PetscInt         Nc, Np, fpdim, i, d;

2031:     PetscDSGetDiscretization(prob, field, &obj);
2032:     PetscObjectGetClassId(obj, &id);
2033:     if (id == PETSCFE_CLASSID) {
2034:       PetscFE fe = (PetscFE) obj;

2036:       PetscFEGetDualSpace(fe, &Q);
2037:       PetscFEGetNumComponents(fe, &Nc);
2038:     } else if (id == PETSCFV_CLASSID) {
2039:       PetscFV fv = (PetscFV) obj;

2041:       PetscFVGetDualSpace(fv, &Q);
2042:       Nc   = 1;
2043:     }
2044:     PetscDualSpaceGetDimension(Q, &fpdim);
2045:     /* For each fine grid cell */
2046:     for (cell = cStart; cell < cEnd; ++cell) {
2047:       PetscInt *findices,   *cindices;
2048:       PetscInt  numFIndices, numCIndices;

2050:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2051:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2052:       if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %d != %d dual basis vecs", numFIndices, fpdim);
2053:       for (i = 0; i < fpdim; ++i) {
2054:         Vec             pointVec;
2055:         PetscScalar    *pV;
2056:         PetscSF         coarseCellSF = NULL;
2057:         const PetscSFNode *coarseCells;
2058:         PetscInt        numCoarseCells, q, c;

2060:         /* Get points from the dual basis functional quadrature */
2061:         PetscDualSpaceGetFunctional(Q, i, &f);
2062:         PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2063:         VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2064:         VecSetBlockSize(pointVec, dim);
2065:         VecGetArray(pointVec, &pV);
2066:         for (q = 0; q < Np; ++q) {
2067:           const PetscReal xi0[3] = {-1., -1., -1.};

2069:           /* Transform point to real space */
2070:           CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2071:           for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2072:         }
2073:         VecRestoreArray(pointVec, &pV);
2074:         /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2075:         /* OPT: Pack all quad points from fine cell */
2076:         DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2077:         PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2078:         /* Update preallocation info */
2079:         PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2080:         if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2081:         {
2082:           PetscHashIJKey key;
2083:           PetscBool      missing;

2085:           key.i = findices[i];
2086:           if (key.i >= 0) {
2087:             /* Get indices for coarse elements */
2088:             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2089:               DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2090:               for (c = 0; c < numCIndices; ++c) {
2091:                 key.j = cindices[c];
2092:                 if (key.j < 0) continue;
2093:                 PetscHSetIJQueryAdd(ht, key, &missing);
2094:                 if (missing) {
2095:                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2096:                   else                                     ++onz[key.i-rStart];
2097:                 }
2098:               }
2099:               DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2100:             }
2101:           }
2102:         }
2103:         PetscSFDestroy(&coarseCellSF);
2104:         VecDestroy(&pointVec);
2105:       }
2106:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2107:     }
2108:   }
2109:   PetscHSetIJDestroy(&ht);
2110:   MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);
2111:   MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2112:   PetscFree2(dnz,onz);
2113:   for (field = 0; field < Nf; ++field) {
2114:     PetscObject      obj;
2115:     PetscClassId     id;
2116:     PetscDualSpace   Q = NULL;
2117:     PetscQuadrature  f;
2118:     const PetscReal *qpoints, *qweights;
2119:     PetscInt         Nc, qNc, Np, fpdim, i, d;

2121:     PetscDSGetDiscretization(prob, field, &obj);
2122:     PetscObjectGetClassId(obj, &id);
2123:     if (id == PETSCFE_CLASSID) {
2124:       PetscFE fe = (PetscFE) obj;

2126:       PetscFEGetDualSpace(fe, &Q);
2127:       PetscFEGetNumComponents(fe, &Nc);
2128:     } else if (id == PETSCFV_CLASSID) {
2129:       PetscFV fv = (PetscFV) obj;

2131:       PetscFVGetDualSpace(fv, &Q);
2132:       Nc   = 1;
2133:     } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %d",field);
2134:     PetscDualSpaceGetDimension(Q, &fpdim);
2135:     /* For each fine grid cell */
2136:     for (cell = cStart; cell < cEnd; ++cell) {
2137:       PetscInt *findices,   *cindices;
2138:       PetscInt  numFIndices, numCIndices;

2140:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2141:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2142:       if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %d != %d dual basis vecs", numFIndices, fpdim);
2143:       for (i = 0; i < fpdim; ++i) {
2144:         Vec             pointVec;
2145:         PetscScalar    *pV;
2146:         PetscSF         coarseCellSF = NULL;
2147:         const PetscSFNode *coarseCells;
2148:         PetscInt        numCoarseCells, cpdim, q, c, j;

2150:         /* Get points from the dual basis functional quadrature */
2151:         PetscDualSpaceGetFunctional(Q, i, &f);
2152:         PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);
2153:         if (qNc != Nc) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, Nc);
2154:         VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2155:         VecSetBlockSize(pointVec, dim);
2156:         VecGetArray(pointVec, &pV);
2157:         for (q = 0; q < Np; ++q) {
2158:           const PetscReal xi0[3] = {-1., -1., -1.};

2160:           /* Transform point to real space */
2161:           CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2162:           for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2163:         }
2164:         VecRestoreArray(pointVec, &pV);
2165:         /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2166:         /* OPT: Read this out from preallocation information */
2167:         DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2168:         /* Update preallocation info */
2169:         PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2170:         if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2171:         VecGetArray(pointVec, &pV);
2172:         for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2173:           PetscReal pVReal[3];
2174:           const PetscReal xi0[3] = {-1., -1., -1.};

2176:           DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2177:           /* Transform points from real space to coarse reference space */
2178:           DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2179:           for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
2180:           CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);

2182:           if (id == PETSCFE_CLASSID) {
2183:             PetscFE    fe = (PetscFE) obj;
2184:             PetscReal *B;

2186:             /* Evaluate coarse basis on contained point */
2187:             PetscFEGetDimension(fe, &cpdim);
2188:             PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);
2189:             PetscMemzero(elemMat, cpdim * sizeof(PetscScalar));
2190:             /* Get elemMat entries by multiplying by weight */
2191:             for (j = 0; j < cpdim; ++j) {
2192:               for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*qweights[ccell*qNc + c];
2193:             }
2194:             PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);
2195:           } else {
2196:             cpdim = 1;
2197:             for (j = 0; j < cpdim; ++j) {
2198:               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c];
2199:             }
2200:           }
2201:           /* Update interpolator */
2202:           if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2203:           if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2204:           MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);
2205:           DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2206:         }
2207:         VecRestoreArray(pointVec, &pV);
2208:         PetscSFDestroy(&coarseCellSF);
2209:         VecDestroy(&pointVec);
2210:       }
2211:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2212:     }
2213:   }
2214:   PetscFree3(v0,J,invJ);
2215:   PetscFree3(v0c,Jc,invJc);
2216:   PetscFree(elemMat);
2217:   MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2218:   MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2219:   PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2220:   return(0);
2221: }

2223: /*@
2224:   DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM.

2226:   Input Parameters:
2227: + dmf  - The fine mesh
2228: . dmc  - The coarse mesh
2229: - user - The user context

2231:   Output Parameter:
2232: . mass  - The mass matrix

2234:   Level: developer

2236: .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2237: @*/
2238: PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2239: {
2240:   DM_Plex       *mesh = (DM_Plex *) dmf->data;
2241:   const char    *name = "Mass Matrix";
2242:   PetscDS        prob;
2243:   PetscSection   fsection, csection, globalFSection, globalCSection;
2244:   PetscHSetIJ    ht;
2245:   PetscLayout    rLayout;
2246:   PetscInt      *dnz, *onz;
2247:   PetscInt       locRows, rStart, rEnd;
2248:   PetscReal     *x, *v0, *J, *invJ, detJ;
2249:   PetscReal     *v0c, *Jc, *invJc, detJc;
2250:   PetscScalar   *elemMat;
2251:   PetscInt       dim, Nf, field, totDim, cStart, cEnd, cell, ccell;

2255:   DMGetCoordinateDim(dmc, &dim);
2256:   DMGetDS(dmc, &prob);
2257:   PetscDSGetRefCoordArrays(prob, &x, NULL);
2258:   PetscDSGetNumFields(prob, &Nf);
2259:   PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2260:   PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2261:   DMGetSection(dmf, &fsection);
2262:   DMGetGlobalSection(dmf, &globalFSection);
2263:   DMGetSection(dmc, &csection);
2264:   DMGetGlobalSection(dmc, &globalCSection);
2265:   DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2266:   PetscDSGetTotalDimension(prob, &totDim);
2267:   PetscMalloc1(totDim, &elemMat);

2269:   MatGetLocalSize(mass, &locRows, NULL);
2270:   PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);
2271:   PetscLayoutSetLocalSize(rLayout, locRows);
2272:   PetscLayoutSetBlockSize(rLayout, 1);
2273:   PetscLayoutSetUp(rLayout);
2274:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2275:   PetscLayoutDestroy(&rLayout);
2276:   PetscCalloc2(locRows,&dnz,locRows,&onz);
2277:   PetscHSetIJCreate(&ht);
2278:   for (field = 0; field < Nf; ++field) {
2279:     PetscObject      obj;
2280:     PetscClassId     id;
2281:     PetscQuadrature  quad;
2282:     const PetscReal *qpoints;
2283:     PetscInt         Nq, Nc, i, d;

2285:     PetscDSGetDiscretization(prob, field, &obj);
2286:     PetscObjectGetClassId(obj, &id);
2287:     if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);}
2288:     else                       {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2289:     PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);
2290:     /* For each fine grid cell */
2291:     for (cell = cStart; cell < cEnd; ++cell) {
2292:       Vec                pointVec;
2293:       PetscScalar       *pV;
2294:       PetscSF            coarseCellSF = NULL;
2295:       const PetscSFNode *coarseCells;
2296:       PetscInt           numCoarseCells, q, c;
2297:       PetscInt          *findices,   *cindices;
2298:       PetscInt           numFIndices, numCIndices;

2300:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2301:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2302:       /* Get points from the quadrature */
2303:       VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2304:       VecSetBlockSize(pointVec, dim);
2305:       VecGetArray(pointVec, &pV);
2306:       for (q = 0; q < Nq; ++q) {
2307:         const PetscReal xi0[3] = {-1., -1., -1.};

2309:         /* Transform point to real space */
2310:         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2311:         for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2312:       }
2313:       VecRestoreArray(pointVec, &pV);
2314:       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2315:       DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2316:       PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2317:       /* Update preallocation info */
2318:       PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2319:       if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2320:       {
2321:         PetscHashIJKey key;
2322:         PetscBool      missing;

2324:         for (i = 0; i < numFIndices; ++i) {
2325:           key.i = findices[i];
2326:           if (key.i >= 0) {
2327:             /* Get indices for coarse elements */
2328:             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2329:               DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2330:               for (c = 0; c < numCIndices; ++c) {
2331:                 key.j = cindices[c];
2332:                 if (key.j < 0) continue;
2333:                 PetscHSetIJQueryAdd(ht, key, &missing);
2334:                 if (missing) {
2335:                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2336:                   else                                     ++onz[key.i-rStart];
2337:                 }
2338:               }
2339:               DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2340:             }
2341:           }
2342:         }
2343:       }
2344:       PetscSFDestroy(&coarseCellSF);
2345:       VecDestroy(&pointVec);
2346:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2347:     }
2348:   }
2349:   PetscHSetIJDestroy(&ht);
2350:   MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);
2351:   MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2352:   PetscFree2(dnz,onz);
2353:   for (field = 0; field < Nf; ++field) {
2354:     PetscObject      obj;
2355:     PetscClassId     id;
2356:     PetscQuadrature  quad;
2357:     PetscReal       *Bfine;
2358:     const PetscReal *qpoints, *qweights;
2359:     PetscInt         Nq, Nc, i, d;

2361:     PetscDSGetDiscretization(prob, field, &obj);
2362:     PetscObjectGetClassId(obj, &id);
2363:     if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);PetscFEGetDefaultTabulation((PetscFE) obj, &Bfine, NULL, NULL);}
2364:     else                       {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2365:     PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);
2366:     /* For each fine grid cell */
2367:     for (cell = cStart; cell < cEnd; ++cell) {
2368:       Vec                pointVec;
2369:       PetscScalar       *pV;
2370:       PetscSF            coarseCellSF = NULL;
2371:       const PetscSFNode *coarseCells;
2372:       PetscInt           numCoarseCells, cpdim, q, c, j;
2373:       PetscInt          *findices,   *cindices;
2374:       PetscInt           numFIndices, numCIndices;

2376:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2377:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2378:       /* Get points from the quadrature */
2379:       VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2380:       VecSetBlockSize(pointVec, dim);
2381:       VecGetArray(pointVec, &pV);
2382:       for (q = 0; q < Nq; ++q) {
2383:         const PetscReal xi0[3] = {-1., -1., -1.};

2385:         /* Transform point to real space */
2386:         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2387:         for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2388:       }
2389:       VecRestoreArray(pointVec, &pV);
2390:       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2391:       DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2392:       /* Update matrix */
2393:       PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2394:       if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2395:       VecGetArray(pointVec, &pV);
2396:       for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2397:         PetscReal pVReal[3];
2398:         const PetscReal xi0[3] = {-1., -1., -1.};


2401:         DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2402:         /* Transform points from real space to coarse reference space */
2403:         DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);
2404:         for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]);
2405:         CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);

2407:         if (id == PETSCFE_CLASSID) {
2408:           PetscFE    fe = (PetscFE) obj;
2409:           PetscReal *B;

2411:           /* Evaluate coarse basis on contained point */
2412:           PetscFEGetDimension(fe, &cpdim);
2413:           PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);
2414:           /* Get elemMat entries by multiplying by weight */
2415:           for (i = 0; i < numFIndices; ++i) {
2416:             PetscMemzero(elemMat, cpdim * sizeof(PetscScalar));
2417:             for (j = 0; j < cpdim; ++j) {
2418:               for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*Bfine[(ccell*numFIndices + i)*Nc + c]*qweights[ccell*Nc + c]*detJ;
2419:             }
2420:             /* Update interpolator */
2421:             if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2422:             if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2423:             MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
2424:           }
2425:           PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);
2426:         } else {
2427:           cpdim = 1;
2428:           for (i = 0; i < numFIndices; ++i) {
2429:             PetscMemzero(elemMat, cpdim * sizeof(PetscScalar));
2430:             for (j = 0; j < cpdim; ++j) {
2431:               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ;
2432:             }
2433:             /* Update interpolator */
2434:             if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2435:             PetscPrintf(PETSC_COMM_SELF, "Nq: %d %d Nf: %d %d Nc: %d %d\n", ccell, Nq, i, numFIndices, j, numCIndices);
2436:             if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2437:             MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
2438:           }
2439:         }
2440:         DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);
2441:       }
2442:       VecRestoreArray(pointVec, &pV);
2443:       PetscSFDestroy(&coarseCellSF);
2444:       VecDestroy(&pointVec);
2445:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);
2446:     }
2447:   }
2448:   PetscFree3(v0,J,invJ);
2449:   PetscFree3(v0c,Jc,invJc);
2450:   PetscFree(elemMat);
2451:   MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);
2452:   MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);
2453:   return(0);
2454: }

2456: /*@
2457:   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns

2459:   Input Parameters:
2460: + dmc  - The coarse mesh
2461: - dmf  - The fine mesh
2462: - user - The user context

2464:   Output Parameter:
2465: . sc   - The mapping

2467:   Level: developer

2469: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
2470: @*/
2471: PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
2472: {
2473:   PetscDS        prob;
2474:   PetscFE       *feRef;
2475:   PetscFV       *fvRef;
2476:   Vec            fv, cv;
2477:   IS             fis, cis;
2478:   PetscSection   fsection, fglobalSection, csection, cglobalSection;
2479:   PetscInt      *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
2480:   PetscInt       cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, cEndInterior, c, dim, d, startC, endC, offsetC, offsetF, m;
2481:   PetscBool     *needAvg;

2485:   PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);
2486:   DMGetDimension(dmf, &dim);
2487:   DMGetSection(dmf, &fsection);
2488:   DMGetGlobalSection(dmf, &fglobalSection);
2489:   DMGetSection(dmc, &csection);
2490:   DMGetGlobalSection(dmc, &cglobalSection);
2491:   PetscSectionGetNumFields(fsection, &Nf);
2492:   DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);
2493:   DMPlexGetHybridBounds(dmc, &cEndInterior, NULL, NULL, NULL);
2494:   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
2495:   DMGetDS(dmc, &prob);
2496:   PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);
2497:   for (f = 0; f < Nf; ++f) {
2498:     PetscObject  obj;
2499:     PetscClassId id;
2500:     PetscInt     fNb = 0, Nc = 0;

2502:     PetscDSGetDiscretization(prob, f, &obj);
2503:     PetscObjectGetClassId(obj, &id);
2504:     if (id == PETSCFE_CLASSID) {
2505:       PetscFE    fe = (PetscFE) obj;
2506:       PetscSpace sp;
2507:       PetscInt   maxDegree;

2509:       PetscFERefine(fe, &feRef[f]);
2510:       PetscFEGetDimension(feRef[f], &fNb);
2511:       PetscFEGetNumComponents(fe, &Nc);
2512:       PetscFEGetBasisSpace(fe, &sp);
2513:       PetscSpaceGetDegree(sp, NULL, &maxDegree);
2514:       if (!maxDegree) needAvg[f] = PETSC_TRUE;
2515:     } else if (id == PETSCFV_CLASSID) {
2516:       PetscFV        fv = (PetscFV) obj;
2517:       PetscDualSpace Q;

2519:       PetscFVRefine(fv, &fvRef[f]);
2520:       PetscFVGetDualSpace(fvRef[f], &Q);
2521:       PetscDualSpaceGetDimension(Q, &fNb);
2522:       PetscFVGetNumComponents(fv, &Nc);
2523:       needAvg[f] = PETSC_TRUE;
2524:     }
2525:     fTotDim += fNb;
2526:   }
2527:   PetscDSGetTotalDimension(prob, &cTotDim);
2528:   PetscMalloc1(cTotDim,&cmap);
2529:   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
2530:     PetscFE        feC;
2531:     PetscFV        fvC;
2532:     PetscDualSpace QF, QC;
2533:     PetscInt       order = -1, NcF, NcC, fpdim, cpdim;

2535:     if (feRef[field]) {
2536:       PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);
2537:       PetscFEGetNumComponents(feC, &NcC);
2538:       PetscFEGetNumComponents(feRef[field], &NcF);
2539:       PetscFEGetDualSpace(feRef[field], &QF);
2540:       PetscDualSpaceGetOrder(QF, &order);
2541:       PetscDualSpaceGetDimension(QF, &fpdim);
2542:       PetscFEGetDualSpace(feC, &QC);
2543:       PetscDualSpaceGetDimension(QC, &cpdim);
2544:     } else {
2545:       PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);
2546:       PetscFVGetNumComponents(fvC, &NcC);
2547:       PetscFVGetNumComponents(fvRef[field], &NcF);
2548:       PetscFVGetDualSpace(fvRef[field], &QF);
2549:       PetscDualSpaceGetDimension(QF, &fpdim);
2550:       PetscFVGetDualSpace(fvC, &QC);
2551:       PetscDualSpaceGetDimension(QC, &cpdim);
2552:     }
2553:     if (NcF != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %d does not match coarse field %d", NcF, NcC);
2554:     for (c = 0; c < cpdim; ++c) {
2555:       PetscQuadrature  cfunc;
2556:       const PetscReal *cqpoints, *cqweights;
2557:       PetscInt         NqcC, NpC;
2558:       PetscBool        found = PETSC_FALSE;

2560:       PetscDualSpaceGetFunctional(QC, c, &cfunc);
2561:       PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
2562:       if (NqcC != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components", NqcC, NcC);
2563:       if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
2564:       for (f = 0; f < fpdim; ++f) {
2565:         PetscQuadrature  ffunc;
2566:         const PetscReal *fqpoints, *fqweights;
2567:         PetscReal        sum = 0.0;
2568:         PetscInt         NqcF, NpF;

2570:         PetscDualSpaceGetFunctional(QF, f, &ffunc);
2571:         PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
2572:         if (NqcF != NcF) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components", NqcF, NcF);
2573:         if (NpC != NpF) continue;
2574:         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
2575:         if (sum > 1.0e-9) continue;
2576:         for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]);
2577:         if (sum < 1.0e-9) continue;
2578:         cmap[offsetC+c] = offsetF+f;
2579:         found = PETSC_TRUE;
2580:         break;
2581:       }
2582:       if (!found) {
2583:         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
2584:         if (fvRef[field] || (feRef[field] && order == 0)) {
2585:           cmap[offsetC+c] = offsetF+0;
2586:         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
2587:       }
2588:     }
2589:     offsetC += cpdim;
2590:     offsetF += fpdim;
2591:   }
2592:   for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);PetscFVDestroy(&fvRef[f]);}
2593:   PetscFree3(feRef,fvRef,needAvg);

2595:   DMGetGlobalVector(dmf, &fv);
2596:   DMGetGlobalVector(dmc, &cv);
2597:   VecGetOwnershipRange(cv, &startC, &endC);
2598:   PetscSectionGetConstrainedStorageSize(cglobalSection, &m);
2599:   PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);
2600:   PetscMalloc1(m,&cindices);
2601:   PetscMalloc1(m,&findices);
2602:   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
2603:   for (c = cStart; c < cEnd; ++c) {
2604:     DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);
2605:     for (d = 0; d < cTotDim; ++d) {
2606:       if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
2607:       if ((findices[cellCIndices[d]-startC] >= 0) && (findices[cellCIndices[d]-startC] != cellFIndices[cmap[d]])) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %d maps to both %d and %d", cindices[cellCIndices[d]-startC], findices[cellCIndices[d]-startC], cellFIndices[cmap[d]]);
2608:       cindices[cellCIndices[d]-startC] = cellCIndices[d];
2609:       findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
2610:     }
2611:   }
2612:   PetscFree(cmap);
2613:   PetscFree2(cellCIndices,cellFIndices);

2615:   ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
2616:   ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
2617:   VecScatterCreate(cv, cis, fv, fis, sc);
2618:   ISDestroy(&cis);
2619:   ISDestroy(&fis);
2620:   DMRestoreGlobalVector(dmf, &fv);
2621:   DMRestoreGlobalVector(dmc, &cv);
2622:   PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);
2623:   return(0);
2624: }

2626: /*@C
2627:   DMPlexGetCellFields - Retrieve the field values values for a chunk of cells

2629:   Input Parameters:
2630: + dm     - The DM
2631: . cellIS - The cells to include
2632: . locX   - A local vector with the solution fields
2633: . locX_t - A local vector with solution field time derivatives, or NULL
2634: - locA   - A local vector with auxiliary fields, or NULL

2636:   Output Parameters:
2637: + u   - The field coefficients
2638: . u_t - The fields derivative coefficients
2639: - a   - The auxiliary field coefficients

2641:   Level: developer

2643: .seealso: DMPlexGetFaceFields()
2644: @*/
2645: PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
2646: {
2647:   DM              plex, plexA = NULL;
2648:   PetscSection    section, sectionAux;
2649:   PetscDS         prob;
2650:   const PetscInt *cells;
2651:   PetscInt        cStart, cEnd, numCells, totDim, totDimAux, c;
2652:   PetscErrorCode  ierr;

2662:   DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
2663:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
2664:   DMGetSection(dm, &section);
2665:   DMGetCellDS(dm, cStart, &prob);
2666:   PetscDSGetTotalDimension(prob, &totDim);
2667:   if (locA) {
2668:     DM      dmAux;
2669:     PetscDS probAux;

2671:     VecGetDM(locA, &dmAux);
2672:     DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
2673:     DMGetSection(dmAux, &sectionAux);
2674:     DMGetDS(dmAux, &probAux);
2675:     PetscDSGetTotalDimension(probAux, &totDimAux);
2676:   }
2677:   numCells = cEnd - cStart;
2678:   DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);
2679:   if (locX_t) {DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);} else {*u_t = NULL;}
2680:   if (locA)   {DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);} else {*a = NULL;}
2681:   for (c = cStart; c < cEnd; ++c) {
2682:     const PetscInt cell = cells ? cells[c] : c;
2683:     const PetscInt cind = c - cStart;
2684:     PetscScalar   *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
2685:     PetscInt       i;

2687:     DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);
2688:     for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i];
2689:     DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);
2690:     if (locX_t) {
2691:       DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);
2692:       for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i];
2693:       DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);
2694:     }
2695:     if (locA) {
2696:       PetscInt subcell;
2697:       DMPlexGetAuxiliaryPoint(plex, plexA, cell, &subcell);
2698:       DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);
2699:       for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i];
2700:       DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);
2701:     }
2702:   }
2703:   DMDestroy(&plex);
2704:   if (locA) {DMDestroy(&plexA);}
2705:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
2706:   return(0);
2707: }

2709: /*@C
2710:   DMPlexRestoreCellFields - Restore the field values values for a chunk of cells

2712:   Input Parameters:
2713: + dm     - The DM
2714: . cellIS - The cells to include
2715: . locX   - A local vector with the solution fields
2716: . locX_t - A local vector with solution field time derivatives, or NULL
2717: - locA   - A local vector with auxiliary fields, or NULL

2719:   Output Parameters:
2720: + u   - The field coefficients
2721: . u_t - The fields derivative coefficients
2722: - a   - The auxiliary field coefficients

2724:   Level: developer

2726: .seealso: DMPlexGetFaceFields()
2727: @*/
2728: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
2729: {

2733:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
2734:   if (locX_t) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);}
2735:   if (locA)   {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);}
2736:   return(0);
2737: }

2739: /*@C
2740:   DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces

2742:   Input Parameters:
2743: + dm     - The DM
2744: . fStart - The first face to include
2745: . fEnd   - The first face to exclude
2746: . locX   - A local vector with the solution fields
2747: . locX_t - A local vector with solution field time derivatives, or NULL
2748: . faceGeometry - A local vector with face geometry
2749: . cellGeometry - A local vector with cell geometry
2750: - locaGrad - A local vector with field gradients, or NULL

2752:   Output Parameters:
2753: + Nface - The number of faces with field values
2754: . uL - The field values at the left side of the face
2755: - uR - The field values at the right side of the face

2757:   Level: developer

2759: .seealso: DMPlexGetCellFields()
2760: @*/
2761: PetscErrorCode DMPlexGetFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR)
2762: {
2763:   DM                 dmFace, dmCell, dmGrad = NULL;
2764:   PetscSection       section;
2765:   PetscDS            prob;
2766:   DMLabel            ghostLabel;
2767:   const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
2768:   PetscBool         *isFE;
2769:   PetscInt           dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
2770:   PetscErrorCode     ierr;

2781:   DMGetDimension(dm, &dim);
2782:   DMGetDS(dm, &prob);
2783:   DMGetSection(dm, &section);
2784:   PetscDSGetNumFields(prob, &Nf);
2785:   PetscDSGetTotalComponents(prob, &Nc);
2786:   PetscMalloc1(Nf, &isFE);
2787:   for (f = 0; f < Nf; ++f) {
2788:     PetscObject  obj;
2789:     PetscClassId id;

2791:     PetscDSGetDiscretization(prob, f, &obj);
2792:     PetscObjectGetClassId(obj, &id);
2793:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
2794:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
2795:     else                            {isFE[f] = PETSC_FALSE;}
2796:   }
2797:   DMGetLabel(dm, "ghost", &ghostLabel);
2798:   VecGetArrayRead(locX, &x);
2799:   VecGetDM(faceGeometry, &dmFace);
2800:   VecGetArrayRead(faceGeometry, &facegeom);
2801:   VecGetDM(cellGeometry, &dmCell);
2802:   VecGetArrayRead(cellGeometry, &cellgeom);
2803:   if (locGrad) {
2804:     VecGetDM(locGrad, &dmGrad);
2805:     VecGetArrayRead(locGrad, &lgrad);
2806:   }
2807:   DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);
2808:   DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);
2809:   /* Right now just eat the extra work for FE (could make a cell loop) */
2810:   for (face = fStart, iface = 0; face < fEnd; ++face) {
2811:     const PetscInt        *cells;
2812:     PetscFVFaceGeom       *fg;
2813:     PetscFVCellGeom       *cgL, *cgR;
2814:     PetscScalar           *xL, *xR, *gL, *gR;
2815:     PetscScalar           *uLl = *uL, *uRl = *uR;
2816:     PetscInt               ghost, nsupp, nchild;

2818:     DMLabelGetValue(ghostLabel, face, &ghost);
2819:     DMPlexGetSupportSize(dm, face, &nsupp);
2820:     DMPlexGetTreeChildren(dm, face, &nchild, NULL);
2821:     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
2822:     DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
2823:     DMPlexGetSupport(dm, face, &cells);
2824:     DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
2825:     DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
2826:     for (f = 0; f < Nf; ++f) {
2827:       PetscInt off;

2829:       PetscDSGetComponentOffset(prob, f, &off);
2830:       if (isFE[f]) {
2831:         const PetscInt *cone;
2832:         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;

2834:         xL = xR = NULL;
2835:         PetscSectionGetFieldComponents(section, f, &comp);
2836:         DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
2837:         DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
2838:         DMPlexGetCone(dm, cells[0], &cone);
2839:         DMPlexGetConeSize(dm, cells[0], &coneSizeL);
2840:         for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break;
2841:         DMPlexGetCone(dm, cells[1], &cone);
2842:         DMPlexGetConeSize(dm, cells[1], &coneSizeR);
2843:         for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break;
2844:         if (faceLocL == coneSizeL && faceLocR == coneSizeR) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d or cell %d", face, cells[0], cells[1]);
2845:         /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
2846:         /* TODO: this is a hack that might not be right for nonconforming */
2847:         if (faceLocL < coneSizeL) {
2848:           EvaluateFaceFields(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);
2849:           if (rdof == ldof && faceLocR < coneSizeR) {EvaluateFaceFields(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);}
2850:           else              {for(d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];}
2851:         }
2852:         else {
2853:           EvaluateFaceFields(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);
2854:           PetscSectionGetFieldComponents(section, f, &comp);
2855:           for(d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d];
2856:         }
2857:         DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
2858:         DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
2859:       } else {
2860:         PetscFV  fv;
2861:         PetscInt numComp, c;

2863:         PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
2864:         PetscFVGetNumComponents(fv, &numComp);
2865:         DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
2866:         DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
2867:         if (dmGrad) {
2868:           PetscReal dxL[3], dxR[3];

2870:           DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
2871:           DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
2872:           DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
2873:           DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
2874:           for (c = 0; c < numComp; ++c) {
2875:             uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL);
2876:             uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR);
2877:           }
2878:         } else {
2879:           for (c = 0; c < numComp; ++c) {
2880:             uLl[iface*Nc+off+c] = xL[c];
2881:             uRl[iface*Nc+off+c] = xR[c];
2882:           }
2883:         }
2884:       }
2885:     }
2886:     ++iface;
2887:   }
2888:   *Nface = iface;
2889:   VecRestoreArrayRead(locX, &x);
2890:   VecRestoreArrayRead(faceGeometry, &facegeom);
2891:   VecRestoreArrayRead(cellGeometry, &cellgeom);
2892:   if (locGrad) {
2893:     VecRestoreArrayRead(locGrad, &lgrad);
2894:   }
2895:   PetscFree(isFE);
2896:   return(0);
2897: }

2899: /*@C
2900:   DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces

2902:   Input Parameters:
2903: + dm     - The DM
2904: . fStart - The first face to include
2905: . fEnd   - The first face to exclude
2906: . locX   - A local vector with the solution fields
2907: . locX_t - A local vector with solution field time derivatives, or NULL
2908: . faceGeometry - A local vector with face geometry
2909: . cellGeometry - A local vector with cell geometry
2910: - locaGrad - A local vector with field gradients, or NULL

2912:   Output Parameters:
2913: + Nface - The number of faces with field values
2914: . uL - The field values at the left side of the face
2915: - uR - The field values at the right side of the face

2917:   Level: developer

2919: .seealso: DMPlexGetFaceFields()
2920: @*/
2921: PetscErrorCode DMPlexRestoreFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR)
2922: {

2926:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
2927:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
2928:   return(0);
2929: }

2931: /*@C
2932:   DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces

2934:   Input Parameters:
2935: + dm     - The DM
2936: . fStart - The first face to include
2937: . fEnd   - The first face to exclude
2938: . faceGeometry - A local vector with face geometry
2939: - cellGeometry - A local vector with cell geometry

2941:   Output Parameters:
2942: + Nface - The number of faces with field values
2943: . fgeom - The extract the face centroid and normal
2944: - vol   - The cell volume

2946:   Level: developer

2948: .seealso: DMPlexGetCellFields()
2949: @*/
2950: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
2951: {
2952:   DM                 dmFace, dmCell;
2953:   DMLabel            ghostLabel;
2954:   const PetscScalar *facegeom, *cellgeom;
2955:   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
2956:   PetscErrorCode     ierr;

2964:   DMGetDimension(dm, &dim);
2965:   DMGetLabel(dm, "ghost", &ghostLabel);
2966:   VecGetDM(faceGeometry, &dmFace);
2967:   VecGetArrayRead(faceGeometry, &facegeom);
2968:   VecGetDM(cellGeometry, &dmCell);
2969:   VecGetArrayRead(cellGeometry, &cellgeom);
2970:   PetscMalloc1(numFaces, fgeom);
2971:   DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);
2972:   for (face = fStart, iface = 0; face < fEnd; ++face) {
2973:     const PetscInt        *cells;
2974:     PetscFVFaceGeom       *fg;
2975:     PetscFVCellGeom       *cgL, *cgR;
2976:     PetscFVFaceGeom       *fgeoml = *fgeom;
2977:     PetscReal             *voll   = *vol;
2978:     PetscInt               ghost, d, nchild, nsupp;

2980:     DMLabelGetValue(ghostLabel, face, &ghost);
2981:     DMPlexGetSupportSize(dm, face, &nsupp);
2982:     DMPlexGetTreeChildren(dm, face, &nchild, NULL);
2983:     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
2984:     DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
2985:     DMPlexGetSupport(dm, face, &cells);
2986:     DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
2987:     DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
2988:     for (d = 0; d < dim; ++d) {
2989:       fgeoml[iface].centroid[d] = fg->centroid[d];
2990:       fgeoml[iface].normal[d]   = fg->normal[d];
2991:     }
2992:     voll[iface*2+0] = cgL->volume;
2993:     voll[iface*2+1] = cgR->volume;
2994:     ++iface;
2995:   }
2996:   *Nface = iface;
2997:   VecRestoreArrayRead(faceGeometry, &facegeom);
2998:   VecRestoreArrayRead(cellGeometry, &cellgeom);
2999:   return(0);
3000: }

3002: /*@C
3003:   DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces

3005:   Input Parameters:
3006: + dm     - The DM
3007: . fStart - The first face to include
3008: . fEnd   - The first face to exclude
3009: . faceGeometry - A local vector with face geometry
3010: - cellGeometry - A local vector with cell geometry

3012:   Output Parameters:
3013: + Nface - The number of faces with field values
3014: . fgeom - The extract the face centroid and normal
3015: - vol   - The cell volume

3017:   Level: developer

3019: .seealso: DMPlexGetFaceFields()
3020: @*/
3021: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3022: {

3026:   PetscFree(*fgeom);
3027:   DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3028:   return(0);
3029: }

3031: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3032: {
3033:   char            composeStr[33] = {0};
3034:   PetscObjectId   id;
3035:   PetscContainer  container;
3036:   PetscErrorCode  ierr;

3039:   PetscObjectGetId((PetscObject)quad,&id);
3040:   PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);
3041:   PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
3042:   if (container) {
3043:     PetscContainerGetPointer(container, (void **) geom);
3044:   } else {
3045:     DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3046:     PetscContainerCreate(PETSC_COMM_SELF,&container);
3047:     PetscContainerSetPointer(container, (void *) *geom);
3048:     PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3049:     PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
3050:     PetscContainerDestroy(&container);
3051:   }
3052:   return(0);
3053: }

3055: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3056: {
3058:   *geom = NULL;
3059:   return(0);
3060: }

3062: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3063: {
3064:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
3065:   const char      *name       = "Residual";
3066:   DM               dmAux      = NULL;
3067:   DMLabel          ghostLabel = NULL;
3068:   PetscDS          prob       = NULL;
3069:   PetscDS          probAux    = NULL;
3070:   PetscBool        useFEM     = PETSC_FALSE;
3071:   PetscBool        isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3072:   DMField          coordField = NULL;
3073:   Vec              locA;
3074:   PetscScalar     *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3075:   IS               chunkIS;
3076:   const PetscInt  *cells;
3077:   PetscInt         cStart, cEnd, numCells;
3078:   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3079:   PetscInt         maxDegree = PETSC_MAX_INT;
3080:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
3081:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
3082:   PetscErrorCode   ierr;

3085:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
3086:   /* FEM+FVM */
3087:   /* 1: Get sizes from dm and dmAux */
3088:   DMGetLabel(dm, "ghost", &ghostLabel);
3089:   DMGetDS(dm, &prob);
3090:   PetscDSGetNumFields(prob, &Nf);
3091:   PetscDSGetTotalDimension(prob, &totDim);
3092:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
3093:   if (locA) {
3094:     VecGetDM(locA, &dmAux);
3095:     DMGetDS(dmAux, &probAux);
3096:     PetscDSGetTotalDimension(probAux, &totDimAux);
3097:   }
3098:   /* 2: Get geometric data */
3099:   for (f = 0; f < Nf; ++f) {
3100:     PetscObject  obj;
3101:     PetscClassId id;
3102:     PetscBool    fimp;

3104:     PetscDSGetImplicit(prob, f, &fimp);
3105:     if (isImplicit != fimp) continue;
3106:     PetscDSGetDiscretization(prob, f, &obj);
3107:     PetscObjectGetClassId(obj, &id);
3108:     if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
3109:     if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented");
3110:   }
3111:   if (useFEM) {
3112:     DMGetCoordinateField(dm, &coordField);
3113:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
3114:     if (maxDegree <= 1) {
3115:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
3116:       if (affineQuad) {
3117:         DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3118:       }
3119:     } else {
3120:       PetscCalloc2(Nf,&quads,Nf,&geoms);
3121:       for (f = 0; f < Nf; ++f) {
3122:         PetscObject  obj;
3123:         PetscClassId id;
3124:         PetscBool    fimp;

3126:         PetscDSGetImplicit(prob, f, &fimp);
3127:         if (isImplicit != fimp) continue;
3128:         PetscDSGetDiscretization(prob, f, &obj);
3129:         PetscObjectGetClassId(obj, &id);
3130:         if (id == PETSCFE_CLASSID) {
3131:           PetscFE fe = (PetscFE) obj;

3133:           PetscFEGetQuadrature(fe, &quads[f]);
3134:           PetscObjectReference((PetscObject)quads[f]);
3135:           DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3136:         }
3137:       }
3138:     }
3139:   }
3140:   /* Loop over chunks */
3141:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3142:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3143:   if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
3144:   numCells      = cEnd - cStart;
3145:   numChunks     = 1;
3146:   cellChunkSize = numCells/numChunks;
3147:   numChunks     = PetscMin(1,numCells);
3148:   for (chunk = 0; chunk < numChunks; ++chunk) {
3149:     PetscScalar     *elemVec, *fluxL = NULL, *fluxR = NULL;
3150:     PetscReal       *vol = NULL;
3151:     PetscFVFaceGeom *fgeom = NULL;
3152:     PetscInt         cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
3153:     PetscInt         numFaces = 0;

3155:     /* Extract field coefficients */
3156:     if (useFEM) {
3157:       ISGetPointSubrange(chunkIS, cS, cE, cells);
3158:       DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3159:       DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3160:       PetscMemzero(elemVec, numCells*totDim * sizeof(PetscScalar));
3161:     }
3162:     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3163:     /* Loop over fields */
3164:     for (f = 0; f < Nf; ++f) {
3165:       PetscObject  obj;
3166:       PetscClassId id;
3167:       PetscBool    fimp;
3168:       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

3170:       PetscDSGetImplicit(prob, f, &fimp);
3171:       if (isImplicit != fimp) continue;
3172:       PetscDSGetDiscretization(prob, f, &obj);
3173:       PetscObjectGetClassId(obj, &id);
3174:       if (id == PETSCFE_CLASSID) {
3175:         PetscFE         fe = (PetscFE) obj;
3176:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
3177:         PetscFEGeom    *chunkGeom = NULL;
3178:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3179:         PetscInt        Nq, Nb;

3181:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3182:         PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3183:         PetscFEGetDimension(fe, &Nb);
3184:         blockSize = Nb;
3185:         batchSize = numBlocks * blockSize;
3186:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3187:         numChunks = numCells / (numBatches*batchSize);
3188:         Ne        = numChunks*numBatches*batchSize;
3189:         Nr        = numCells % (numBatches*batchSize);
3190:         offset    = numCells - Nr;
3191:         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3192:         /*   For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */
3193:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
3194:         PetscFEIntegrateResidual(fe, prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3195:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
3196:         PetscFEIntegrateResidual(fe, prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
3197:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
3198:       } else if (id == PETSCFV_CLASSID) {
3199:         PetscFV fv = (PetscFV) obj;

3201:         Ne = numFaces;
3202:         /* Riemann solve over faces (need fields at face centroids) */
3203:         /*   We need to evaluate FE fields at those coordinates */
3204:         PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3205:       } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
3206:     }
3207:     /* Loop over domain */
3208:     if (useFEM) {
3209:       /* Add elemVec to locX */
3210:       for (c = cS; c < cE; ++c) {
3211:         const PetscInt cell = cells ? cells[c] : c;
3212:         const PetscInt cind = c - cStart;

3214:         if (mesh->printFEM > 1) {DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);}
3215:         if (ghostLabel) {
3216:           PetscInt ghostVal;

3218:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
3219:           if (ghostVal > 0) continue;
3220:         }
3221:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3222:       }
3223:     }
3224:     /* Handle time derivative */
3225:     if (locX_t) {
3226:       PetscScalar *x_t, *fa;

3228:       VecGetArray(locF, &fa);
3229:       VecGetArray(locX_t, &x_t);
3230:       for (f = 0; f < Nf; ++f) {
3231:         PetscFV      fv;
3232:         PetscObject  obj;
3233:         PetscClassId id;
3234:         PetscInt     pdim, d;

3236:         PetscDSGetDiscretization(prob, f, &obj);
3237:         PetscObjectGetClassId(obj, &id);
3238:         if (id != PETSCFV_CLASSID) continue;
3239:         fv   = (PetscFV) obj;
3240:         PetscFVGetNumComponents(fv, &pdim);
3241:         for (c = cS; c < cE; ++c) {
3242:           const PetscInt cell = cells ? cells[c] : c;
3243:           PetscScalar   *u_t, *r;

3245:           if (ghostLabel) {
3246:             PetscInt ghostVal;

3248:             DMLabelGetValue(ghostLabel, cell, &ghostVal);
3249:             if (ghostVal > 0) continue;
3250:           }
3251:           DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3252:           DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3253:           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3254:         }
3255:       }
3256:       VecRestoreArray(locX_t, &x_t);
3257:       VecRestoreArray(locF, &fa);
3258:     }
3259:     if (useFEM) {
3260:       DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3261:       DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3262:     }
3263:   }
3264:   if (useFEM) {ISDestroy(&chunkIS);}
3265:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3266:   /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3267:   if (useFEM) {
3268:     if (maxDegree <= 1) {
3269:       DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3270:       PetscQuadratureDestroy(&affineQuad);
3271:     } else {
3272:       for (f = 0; f < Nf; ++f) {
3273:         DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3274:         PetscQuadratureDestroy(&quads[f]);
3275:       }
3276:       PetscFree2(quads,geoms);
3277:     }
3278:   }
3279:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
3280:   return(0);
3281: }

3283: /*
3284:   We always assemble JacP, and if the matrix is different from Jac and two different sets of point functions are provided, we also assemble Jac

3286:   X   - The local solution vector
3287:   X_t - The local solution time derviative vector, or NULL
3288: */
3289: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS,
3290:                                                     PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
3291: {
3292:   DM_Plex         *mesh  = (DM_Plex *) dm->data;
3293:   const char      *name = "Jacobian", *nameP = "JacobianPre";
3294:   DM               dmAux = NULL;
3295:   PetscDS          prob,   probAux = NULL;
3296:   PetscSection     sectionAux = NULL;
3297:   Vec              A;
3298:   DMField          coordField;
3299:   PetscFEGeom     *cgeomFEM;
3300:   PetscQuadrature  qGeom = NULL;
3301:   Mat              J = Jac, JP = JacP;
3302:   PetscScalar     *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
3303:   PetscBool        hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE;
3304:   const PetscInt  *cells;
3305:   PetscInt         Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
3306:   PetscErrorCode   ierr;

3309:   CHKMEMQ;
3310:   ISGetLocalSize(cellIS, &numCells);
3311:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3312:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
3313:   DMGetDS(dm, &prob);
3314:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3315:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3316:   if (dmAux) {
3317:     DMGetDefaultSection(dmAux, &sectionAux);
3318:     DMGetDS(dmAux, &probAux);
3319:   }
3320:   /* Get flags */
3321:   PetscDSGetNumFields(prob, &Nf);
3322:   DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
3323:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
3324:     PetscObject  disc;
3325:     PetscClassId id;
3326:     PetscDSGetDiscretization(prob, fieldI, &disc);
3327:     PetscObjectGetClassId(disc, &id);
3328:     if (id == PETSCFE_CLASSID)      {isFE[fieldI] = PETSC_TRUE;}
3329:     else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;}
3330:   }
3331:   PetscDSHasJacobian(prob, &hasJac);
3332:   PetscDSHasJacobianPreconditioner(prob, &hasPrec);
3333:   PetscDSHasDynamicJacobian(prob, &hasDyn);
3334:   assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
3335:   hasDyn      = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
3336:   PetscObjectTypeCompare((PetscObject) Jac,  MATIS, &isMatIS);
3337:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
3338:   /* Setup input data and temp arrays (should be DMGetWorkArray) */
3339:   if (isMatISP || isMatISP) {DMPlexGetSubdomainSection(dm, &globalSection);}
3340:   if (isMatIS)  {MatISGetLocalMat(Jac,  &J);}
3341:   if (isMatISP) {MatISGetLocalMat(JacP, &JP);}
3342:   if (hasFV)    {MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);} /* No allocated space for FV stuff, so ignore the zero entries */
3343:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3344:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3345:   PetscDSGetTotalDimension(prob, &totDim);
3346:   if (probAux) {PetscDSGetTotalDimension(probAux, &totDimAux);}
3347:   CHKMEMQ;
3348:   /* Compute batch sizes */
3349:   if (isFE[0]) {
3350:     PetscFE         fe;
3351:     PetscQuadrature q;
3352:     PetscInt        numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;

3354:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
3355:     PetscFEGetQuadrature(fe, &q);
3356:     PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
3357:     PetscFEGetDimension(fe, &Nb);
3358:     PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3359:     blockSize = Nb*numQuadPoints;
3360:     batchSize = numBlocks  * blockSize;
3361:     chunkSize = numBatches * batchSize;
3362:     numChunks = numCells / chunkSize + numCells % chunkSize;
3363:     PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3364:   } else {
3365:     chunkSize = numCells;
3366:     numChunks = 1;
3367:   }
3368:   /* Get work space */
3369:   wsz  = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize;
3370:   DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
3371:   PetscMemzero(work, wsz * sizeof(PetscScalar));
3372:   off      = 0;
3373:   u        = X       ? (sz = chunkSize*totDim,        off += sz, work+off-sz) : NULL;
3374:   u_t      = X_t     ? (sz = chunkSize*totDim,        off += sz, work+off-sz) : NULL;
3375:   a        = dmAux   ? (sz = chunkSize*totDimAux,     off += sz, work+off-sz) : NULL;
3376:   elemMat  = hasJac  ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
3377:   elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
3378:   elemMatD = hasDyn  ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
3379:   if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz);
3380:   /* Setup geometry */
3381:   DMGetCoordinateField(dm, &coordField);
3382:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
3383:   if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);}
3384:   if (!qGeom) {
3385:     PetscFE fe;

3387:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
3388:     PetscFEGetQuadrature(fe, &qGeom);
3389:     PetscObjectReference((PetscObject) qGeom);
3390:   }
3391:   DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
3392:   /* Compute volume integrals */
3393:   if (assembleJac) {MatZeroEntries(J);}
3394:   MatZeroEntries(JP);
3395:   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
3396:     const PetscInt   Ncell = PetscMin(chunkSize, numCells - offCell);
3397:     PetscInt         c;

3399:     /* Extract values */
3400:     for (c = 0; c < Ncell; ++c) {
3401:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
3402:       PetscScalar   *x = NULL,  *x_t = NULL;
3403:       PetscInt       i;

3405:       if (X) {
3406:         DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
3407:         for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
3408:         DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
3409:       }
3410:       if (X_t) {
3411:         DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
3412:         for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i];
3413:         DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
3414:       }
3415:       if (dmAux) {
3416:         DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
3417:         for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
3418:         DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
3419:       }
3420:     }
3421:     CHKMEMQ;
3422:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
3423:       PetscFE fe;
3424:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
3425:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
3426:         if (hasJac)  {PetscFEIntegrateJacobian(fe, prob, PETSCFE_JACOBIAN,     fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);}
3427:         if (hasPrec) {PetscFEIntegrateJacobian(fe, prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);}
3428:         if (hasDyn)  {PetscFEIntegrateJacobian(fe, prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);}
3429:       }
3430:       /* For finite volume, add the identity */
3431:       if (!isFE[fieldI]) {
3432:         PetscFV  fv;
3433:         PetscInt eOffset = 0, Nc, fc, foff;

3435:         PetscDSGetFieldOffset(prob, fieldI, &foff);
3436:         PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
3437:         PetscFVGetNumComponents(fv, &Nc);
3438:         for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) {
3439:           for (fc = 0; fc < Nc; ++fc) {
3440:             const PetscInt i = foff + fc;
3441:             if (hasJac)  {elemMat [eOffset+i*totDim+i] = 1.0;}
3442:             if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;}
3443:           }
3444:         }
3445:       }
3446:     }
3447:     CHKMEMQ;
3448:     /*   Add contribution from X_t */
3449:     if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
3450:     /* Insert values into matrix */
3451:     for (c = 0; c < Ncell; ++c) {
3452:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
3453:       if (mesh->printFEM > 1) {
3454:         if (hasJac)  {DMPrintCellMatrix(cell, name,  totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);}
3455:         if (hasPrec) {DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);}
3456:       }
3457:       if (assembleJac) {DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);}
3458:       DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);
3459:     }
3460:     CHKMEMQ;
3461:   }
3462:   /* Cleanup */
3463:   DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
3464:   PetscQuadratureDestroy(&qGeom);
3465:   if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
3466:   DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
3467:   DMRestoreWorkArray(dm, ((1 + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize, MPIU_SCALAR, &work);
3468:   /* Compute boundary integrals */
3469:   /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
3470:   /* Assemble matrix */
3471:   if (assembleJac) {MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);}
3472:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
3473:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
3474:   CHKMEMQ;
3475:   return(0);
3476: }