Actual source code: plexfem.c

petsc-master 2020-09-24
Report Typos and Errors
  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petscsf.h>

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

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

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

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

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

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

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

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

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

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

 91:   Not collective

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

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

100:   Level: advanced

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

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

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

118:   Not collective

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

125:   Level: advanced

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

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

139: static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx)
140: {
141:   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}}};
142:   PetscInt *ctxInt  = (PetscInt *) ctx;
143:   PetscInt  dim2    = ctxInt[0];
144:   PetscInt  d       = ctxInt[1];
145:   PetscInt  i, j, k = dim > 2 ? d - dim : d;

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

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

165:   Collective on dm

167:   Input Arguments:
168: + dm - the DM
169: - field - The field number for the rigid body space, or 0 for the default

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, PetscInt field, MatNullSpace *sp)
181: {
182:   PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
183:   MPI_Comm          comm;
184:   Vec               mode[6];
185:   PetscSection      section, globalSection;
186:   PetscInt          dim, dimEmbed, Nf, n, m, mmin, d, i, j;
187:   PetscErrorCode    ierr;

190:   PetscObjectGetComm((PetscObject) dm, &comm);
191:   DMGetDimension(dm, &dim);
192:   DMGetCoordinateDim(dm, &dimEmbed);
193:   DMGetNumFields(dm, &Nf);
194:   if (Nf && (field < 0 || field >= Nf)) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, Nf)", field, Nf);
195:   if (dim == 1 && Nf < 2) {
196:     MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);
197:     return(0);
198:   }
199:   DMGetLocalSection(dm, &section);
200:   DMGetGlobalSection(dm, &globalSection);
201:   PetscSectionGetConstrainedStorageSize(globalSection, &n);
202:   PetscCalloc1(Nf, &func);
203:   m    = (dim*(dim+1))/2;
204:   VecCreate(comm, &mode[0]);
205:   VecSetSizes(mode[0], n, PETSC_DETERMINE);
206:   VecSetUp(mode[0]);
207:   VecGetSize(mode[0], &n);
208:   mmin = PetscMin(m, n);
209:   func[field] = DMPlexProjectRigidBody_Private;
210:   for (i = 1; i < m; ++i) {VecDuplicate(mode[0], &mode[i]);}
211:   for (d = 0; d < m; d++) {
212:     PetscInt ctx[2];
213:     void    *voidctx = (void *) (&ctx[0]);

215:     ctx[0] = dimEmbed;
216:     ctx[1] = d;
217:     DMProjectFunction(dm, 0.0, func, &voidctx, INSERT_VALUES, mode[d]);
218:   }
219:   /* Orthonormalize system */
220:   for (i = 0; i < mmin; ++i) {
221:     PetscScalar dots[6];

223:     VecNormalize(mode[i], NULL);
224:     VecMDot(mode[i], mmin-i-1, mode+i+1, dots+i+1);
225:     for (j = i+1; j < mmin; ++j) {
226:       dots[j] *= -1.0;
227:       VecAXPY(mode[j], dots[j], mode[i]);
228:     }
229:   }
230:   MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp);
231:   for (i = 0; i < m; ++i) {VecDestroy(&mode[i]);}
232:   PetscFree(func);
233:   return(0);
234: }

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

239:   Collective on dm

241:   Input Arguments:
242: + dm    - the DM
243: . nb    - The number of bodies
244: . label - The DMLabel marking each domain
245: . nids  - The number of ids per body
246: - ids   - An array of the label ids in sequence for each domain

248:   Output Argument:
249: . sp - the null space

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

253:   Level: advanced

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

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

285:       ctx[0] = dimEmbed;
286:       ctx[1] = d;
287:       DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);
288:       off   += nids[b];
289:     }
290:   }
291:   /* Orthonormalize system */
292:   for (i = 0; i < m; ++i) {
293:     PetscScalar dots[6];

295:     VecNormalize(mode[i], NULL);
296:     VecMDot(mode[i], m-i-1, mode+i+1, dots+i+1);
297:     for (j = i+1; j < m; ++j) {
298:       dots[j] *= -1.0;
299:       VecAXPY(mode[j], dots[j], mode[i]);
300:     }
301:   }
302:   MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
303:   for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
304:   PetscFree2(mode, dots);
305:   return(0);
306: }

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

317:   Input Parameters:
318: + dm - the DMPlex object
319: - height - the maximum projection height >= 0

321:   Level: advanced

323: .seealso: DMPlexGetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
324: @*/
325: PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
326: {
327:   DM_Plex *plex = (DM_Plex *) dm->data;

331:   plex->maxProjectionHeight = height;
332:   return(0);
333: }

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

339:   Input Parameters:
340: . dm - the DMPlex object

342:   Output Parameters:
343: . height - the maximum projection height

345:   Level: intermediate

347: .seealso: DMPlexSetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal()
348: @*/
349: PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
350: {
351:   DM_Plex *plex = (DM_Plex *) dm->data;

355:   *height = plex->maxProjectionHeight;
356:   return(0);
357: }

359: typedef struct {
360:   PetscReal    alpha; /* The first Euler angle, and in 2D the only one */
361:   PetscReal    beta;  /* The second Euler angle */
362:   PetscReal    gamma; /* The third Euler angle */
363:   PetscInt     dim;   /* The dimension of R */
364:   PetscScalar *R;     /* The rotation matrix, transforming a vector in the local basis to the global basis */
365:   PetscScalar *RT;    /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
366: } RotCtx;

368: /*
369:   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
370:   we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows:
371:   $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
372:   $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis.
373:   $ The XYZ system rotates a third time about the z axis by gamma.
374: */
375: static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx)
376: {
377:   RotCtx        *rc  = (RotCtx *) ctx;
378:   PetscInt       dim = rc->dim;
379:   PetscReal      c1, s1, c2, s2, c3, s3;

383:   PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT);
384:   switch (dim) {
385:   case 2:
386:     c1 = PetscCosReal(rc->alpha);s1 = PetscSinReal(rc->alpha);
387:     rc->R[0] =  c1;rc->R[1] = s1;
388:     rc->R[2] = -s1;rc->R[3] = c1;
389:     PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));
390:     DMPlex_Transpose2D_Internal(rc->RT);break;
391:     break;
392:   case 3:
393:     c1 = PetscCosReal(rc->alpha);s1 = PetscSinReal(rc->alpha);
394:     c2 = PetscCosReal(rc->beta); s2 = PetscSinReal(rc->beta);
395:     c3 = PetscCosReal(rc->gamma);s3 = PetscSinReal(rc->gamma);
396:     rc->R[0] =  c1*c3 - c2*s1*s3;rc->R[1] =  c3*s1    + c1*c2*s3;rc->R[2] = s2*s3;
397:     rc->R[3] = -c1*s3 - c2*c3*s1;rc->R[4] =  c1*c2*c3 - s1*s3;   rc->R[5] = c3*s2;
398:     rc->R[6] =  s1*s2;           rc->R[7] = -c1*s2;              rc->R[8] = c2;
399:     PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));
400:     DMPlex_Transpose3D_Internal(rc->RT);break;
401:     break;
402:   default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
403:   }
404:   return(0);
405: }

407: static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx)
408: {
409:   RotCtx        *rc = (RotCtx *) ctx;

413:   PetscFree2(rc->R, rc->RT);
414:   PetscFree(rc);
415:   return(0);
416: }

418: static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx)
419: {
420:   RotCtx *rc = (RotCtx *) ctx;

424:   if (l2g) {*A = rc->R;}
425:   else     {*A = rc->RT;}
426:   return(0);
427: }

429: PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx)
430: {

434:   #if defined(PETSC_USE_COMPLEX)
435:   switch (dim) {
436:     case 2:
437:     {
438:       PetscScalar yt[2], zt[2];

440:       yt[0] = y[0]; yt[1] = y[1];
441:       DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
442:       z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]);
443:     }
444:     break;
445:     case 3:
446:     {
447:       PetscScalar yt[3], zt[3];

449:       yt[0] = y[0]; yt[1] = y[1]; yt[2] = y[2];
450:       DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
451:       z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]); z[2] = PetscRealPart(zt[2]);
452:     }
453:     break;
454:   }
455:   #else
456:   DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx);
457:   #endif
458:   return(0);
459: }

461: PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx)
462: {
463:   const PetscScalar *A;
464:   PetscErrorCode     ierr;

467:   (*dm->transformGetMatrix)(dm, x, l2g, &A, ctx);
468:   switch (dim) {
469:   case 2: DMPlex_Mult2D_Internal(A, 1, y, z);break;
470:   case 3: DMPlex_Mult3D_Internal(A, 1, y, z);break;
471:   }
472:   return(0);
473: }

475: static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
476: {
477:   PetscSection       ts;
478:   const PetscScalar *ta, *tva;
479:   PetscInt           dof;
480:   PetscErrorCode     ierr;

483:   DMGetLocalSection(tdm, &ts);
484:   PetscSectionGetFieldDof(ts, p, f, &dof);
485:   VecGetArrayRead(tv, &ta);
486:   DMPlexPointLocalFieldRead(tdm, p, f, ta, (void *) &tva);
487:   if (l2g) {
488:     switch (dof) {
489:     case 4: DMPlex_Mult2D_Internal(tva, 1, a, a);break;
490:     case 9: DMPlex_Mult3D_Internal(tva, 1, a, a);break;
491:     }
492:   } else {
493:     switch (dof) {
494:     case 4: DMPlex_MultTranspose2D_Internal(tva, 1, a, a);break;
495:     case 9: DMPlex_MultTranspose3D_Internal(tva, 1, a, a);break;
496:     }
497:   }
498:   VecRestoreArrayRead(tv, &ta);
499:   return(0);
500: }

502: static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a)
503: {
504:   PetscSection       s, ts;
505:   const PetscScalar *ta, *tvaf, *tvag;
506:   PetscInt           fdof, gdof, fpdof, gpdof;
507:   PetscErrorCode     ierr;

510:   DMGetLocalSection(dm, &s);
511:   DMGetLocalSection(tdm, &ts);
512:   PetscSectionGetFieldDof(s, pf, f, &fpdof);
513:   PetscSectionGetFieldDof(s, pg, g, &gpdof);
514:   PetscSectionGetFieldDof(ts, pf, f, &fdof);
515:   PetscSectionGetFieldDof(ts, pg, g, &gdof);
516:   VecGetArrayRead(tv, &ta);
517:   DMPlexPointLocalFieldRead(tdm, pf, f, ta, (void *) &tvaf);
518:   DMPlexPointLocalFieldRead(tdm, pg, g, ta, (void *) &tvag);
519:   if (l2g) {
520:     switch (fdof) {
521:     case 4: DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);break;
522:     case 9: DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);break;
523:     }
524:     switch (gdof) {
525:     case 4: DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);break;
526:     case 9: DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);break;
527:     }
528:   } else {
529:     switch (fdof) {
530:     case 4: DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);break;
531:     case 9: DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);break;
532:     }
533:     switch (gdof) {
534:     case 4: DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);break;
535:     case 9: DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);break;
536:     }
537:   }
538:   VecRestoreArrayRead(tv, &ta);
539:   return(0);
540: }

542: PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
543: {
544:   PetscSection    s;
545:   PetscSection    clSection;
546:   IS              clPoints;
547:   const PetscInt *clp;
548:   PetscInt       *points = NULL;
549:   PetscInt        Nf, f, Np, cp, dof, d = 0;
550:   PetscErrorCode  ierr;

553:   DMGetLocalSection(dm, &s);
554:   PetscSectionGetNumFields(s, &Nf);
555:   DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
556:   for (f = 0; f < Nf; ++f) {
557:     for (cp = 0; cp < Np*2; cp += 2) {
558:       PetscSectionGetFieldDof(s, points[cp], f, &dof);
559:       if (!dof) continue;
560:       if (fieldActive[f]) {DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]);}
561:       d += dof;
562:     }
563:   }
564:   DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
565:   return(0);
566: }

568: PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
569: {
570:   PetscSection    s;
571:   PetscSection    clSection;
572:   IS              clPoints;
573:   const PetscInt *clp;
574:   PetscInt       *points = NULL;
575:   PetscInt        Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
576:   PetscErrorCode  ierr;

579:   DMGetLocalSection(dm, &s);
580:   PetscSectionGetNumFields(s, &Nf);
581:   DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
582:   for (f = 0, r = 0; f < Nf; ++f) {
583:     for (cpf = 0; cpf < Np*2; cpf += 2) {
584:       PetscSectionGetFieldDof(s, points[cpf], f, &fdof);
585:       for (g = 0, c = 0; g < Nf; ++g) {
586:         for (cpg = 0; cpg < Np*2; cpg += 2) {
587:           PetscSectionGetFieldDof(s, points[cpg], g, &gdof);
588:           DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r*lda+c]);
589:           c += gdof;
590:         }
591:       }
592:       if (c != lda) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %D should be %D", c, lda);
593:       r += fdof;
594:     }
595:   }
596:   if (r != lda) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %D should be %D", c, lda);
597:   DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
598:   return(0);
599: }

601: static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
602: {
603:   DM                 tdm;
604:   Vec                tv;
605:   PetscSection       ts, s;
606:   const PetscScalar *ta;
607:   PetscScalar       *a, *va;
608:   PetscInt           pStart, pEnd, p, Nf, f;
609:   PetscErrorCode     ierr;

612:   DMGetBasisTransformDM_Internal(dm, &tdm);
613:   DMGetBasisTransformVec_Internal(dm, &tv);
614:   DMGetLocalSection(tdm, &ts);
615:   DMGetLocalSection(dm, &s);
616:   PetscSectionGetChart(s, &pStart, &pEnd);
617:   PetscSectionGetNumFields(s, &Nf);
618:   VecGetArray(lv, &a);
619:   VecGetArrayRead(tv, &ta);
620:   for (p = pStart; p < pEnd; ++p) {
621:     for (f = 0; f < Nf; ++f) {
622:       DMPlexPointLocalFieldRef(dm, p, f, a, (void *) &va);
623:       DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va);
624:     }
625:   }
626:   VecRestoreArray(lv, &a);
627:   VecRestoreArrayRead(tv, &ta);
628:   return(0);
629: }

631: /*@
632:   DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis

634:   Input Parameters:
635: + dm - The DM
636: - lv - A local vector with values in the global basis

638:   Output Parameters:
639: . lv - A local vector with values in the local basis

641:   Note: This method is only intended to be called inside DMGlobalToLocal(). It is unlikely that a user will have a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal.

643:   Level: developer

645: .seealso: DMPlexLocalToGlobalBasis(), DMGetLocalSection(), DMPlexCreateBasisRotation()
646: @*/
647: PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
648: {

654:   DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE);
655:   return(0);
656: }

658: /*@
659:   DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis

661:   Input Parameters:
662: + dm - The DM
663: - lv - A local vector with values in the local basis

665:   Output Parameters:
666: . lv - A local vector with values in the global basis

668:   Note: This method is only intended to be called inside DMGlobalToLocal(). It is unlikely that a user would want a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal.

670:   Level: developer

672: .seealso: DMPlexGlobalToLocalBasis(), DMGetLocalSection(), DMPlexCreateBasisRotation()
673: @*/
674: PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
675: {

681:   DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE);
682:   return(0);
683: }

685: /*@
686:   DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions
687:     and global solutions, to a local basis, appropriate for discretization integrals and assembly.

689:   Input Parameters:
690: + dm    - The DM
691: . alpha - The first Euler angle, and in 2D the only one
692: . beta  - The second Euler angle
693: - gamma - The third Euler angle

695:   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
696:   we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows:
697:   $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
698:   $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis.
699:   $ The XYZ system rotates a third time about the z axis by gamma.

701:   Level: developer

703: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis()
704: @*/
705: PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
706: {
707:   RotCtx        *rc;
708:   PetscInt       cdim;

711:   DMGetCoordinateDim(dm, &cdim);
712:   PetscMalloc1(1, &rc);
713:   dm->transformCtx       = rc;
714:   dm->transformSetUp     = DMPlexBasisTransformSetUp_Rotation_Internal;
715:   dm->transformDestroy   = DMPlexBasisTransformDestroy_Rotation_Internal;
716:   dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
717:   rc->dim   = cdim;
718:   rc->alpha = alpha;
719:   rc->beta  = beta;
720:   rc->gamma = gamma;
721:   (*dm->transformSetUp)(dm, dm->transformCtx);
722:   DMConstructBasisTransform_Internal(dm);
723:   return(0);
724: }

726: /*@C
727:   DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates

729:   Input Parameters:
730: + dm     - The DM, with a PetscDS that matches the problem being constrained
731: . time   - The time
732: . field  - The field to constrain
733: . Nc     - The number of constrained field components, or 0 for all components
734: . comps  - An array of constrained component numbers, or NULL for all components
735: . label  - The DMLabel defining constrained points
736: . numids - The number of DMLabel ids for constrained points
737: . ids    - An array of ids for constrained points
738: . func   - A pointwise function giving boundary values
739: - ctx    - An optional user context for bcFunc

741:   Output Parameter:
742: . locX   - A local vector to receives the boundary values

744:   Level: developer

746: .seealso: DMPlexInsertBoundaryValuesEssentialField(), DMPlexInsertBoundaryValuesEssentialBdField(), DMAddBoundary()
747: @*/
748: 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)
749: {
750:   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
751:   void            **ctxs;
752:   PetscInt          numFields;
753:   PetscErrorCode    ierr;

756:   DMGetNumFields(dm, &numFields);
757:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
758:   funcs[field] = func;
759:   ctxs[field]  = ctx;
760:   DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);
761:   PetscFree2(funcs,ctxs);
762:   return(0);
763: }

765: /*@C
766:   DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data

768:   Input Parameters:
769: + dm     - The DM, with a PetscDS that matches the problem being constrained
770: . time   - The time
771: . locU   - A local vector with the input solution values
772: . field  - The field to constrain
773: . Nc     - The number of constrained field components, or 0 for all components
774: . comps  - An array of constrained component numbers, or NULL for all components
775: . label  - The DMLabel defining constrained points
776: . numids - The number of DMLabel ids for constrained points
777: . ids    - An array of ids for constrained points
778: . func   - A pointwise function giving boundary values
779: - ctx    - An optional user context for bcFunc

781:   Output Parameter:
782: . locX   - A local vector to receives the boundary values

784:   Level: developer

786: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialBdField(), DMAddBoundary()
787: @*/
788: PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
789:                                                         void (*func)(PetscInt, PetscInt, PetscInt,
790:                                                                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
791:                                                                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
792:                                                                      PetscReal, const PetscReal[], PetscInt, const PetscScalar[],
793:                                                                      PetscScalar[]),
794:                                                         void *ctx, Vec locX)
795: {
796:   void (**funcs)(PetscInt, PetscInt, PetscInt,
797:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
798:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
799:                  PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
800:   void            **ctxs;
801:   PetscInt          numFields;
802:   PetscErrorCode    ierr;

805:   DMGetNumFields(dm, &numFields);
806:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
807:   funcs[field] = func;
808:   ctxs[field]  = ctx;
809:   DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
810:   PetscFree2(funcs,ctxs);
811:   return(0);
812: }

814: /*@C
815:   DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coodinates and boundary field data

817:   Collective on dm

819:   Input Parameters:
820: + dm     - The DM, with a PetscDS that matches the problem being constrained
821: . time   - The time
822: . locU   - A local vector with the input solution values
823: . field  - The field to constrain
824: . Nc     - The number of constrained field components, or 0 for all components
825: . comps  - An array of constrained component numbers, or NULL for all components
826: . label  - The DMLabel defining constrained points
827: . numids - The number of DMLabel ids for constrained points
828: . ids    - An array of ids for constrained points
829: . func   - A pointwise function giving boundary values, the calling sequence is given in DMProjectBdFieldLabelLocal()
830: - ctx    - An optional user context for bcFunc

832:   Output Parameter:
833: . locX   - A local vector to receive the boundary values

835:   Level: developer

837: .seealso: DMProjectBdFieldLabelLocal(), DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
838: @*/
839: PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
840:                                                           void (*func)(PetscInt, PetscInt, PetscInt,
841:                                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
842:                                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
843:                                                                        PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[],
844:                                                                        PetscScalar[]),
845:                                                           void *ctx, Vec locX)
846: {
847:   void (**funcs)(PetscInt, PetscInt, PetscInt,
848:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
849:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
850:                  PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
851:   void            **ctxs;
852:   PetscInt          numFields;
853:   PetscErrorCode    ierr;

856:   DMGetNumFields(dm, &numFields);
857:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
858:   funcs[field] = func;
859:   ctxs[field]  = ctx;
860:   DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
861:   PetscFree2(funcs,ctxs);
862:   return(0);
863: }

865: /*@C
866:   DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector

868:   Input Parameters:
869: + dm     - The DM, with a PetscDS that matches the problem being constrained
870: . time   - The time
871: . faceGeometry - A vector with the FVM face geometry information
872: . cellGeometry - A vector with the FVM cell geometry information
873: . Grad         - A vector with the FVM cell gradient information
874: . field  - The field to constrain
875: . Nc     - The number of constrained field components, or 0 for all components
876: . comps  - An array of constrained component numbers, or NULL for all components
877: . label  - The DMLabel defining constrained points
878: . numids - The number of DMLabel ids for constrained points
879: . ids    - An array of ids for constrained points
880: . func   - A pointwise function giving boundary values
881: - ctx    - An optional user context for bcFunc

883:   Output Parameter:
884: . locX   - A local vector to receives the boundary values

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

888:   Level: developer

890: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
891: @*/
892: 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[],
893:                                                  PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX)
894: {
895:   PetscDS            prob;
896:   PetscSF            sf;
897:   DM                 dmFace, dmCell, dmGrad;
898:   const PetscScalar *facegeom, *cellgeom = NULL, *grad;
899:   const PetscInt    *leaves;
900:   PetscScalar       *x, *fx;
901:   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
902:   PetscErrorCode     ierr, ierru = 0;

905:   DMGetPointSF(dm, &sf);
906:   PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
907:   nleaves = PetscMax(0, nleaves);
908:   DMGetDimension(dm, &dim);
909:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
910:   DMGetDS(dm, &prob);
911:   VecGetDM(faceGeometry, &dmFace);
912:   VecGetArrayRead(faceGeometry, &facegeom);
913:   if (cellGeometry) {
914:     VecGetDM(cellGeometry, &dmCell);
915:     VecGetArrayRead(cellGeometry, &cellgeom);
916:   }
917:   if (Grad) {
918:     PetscFV fv;

920:     PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);
921:     VecGetDM(Grad, &dmGrad);
922:     VecGetArrayRead(Grad, &grad);
923:     PetscFVGetNumComponents(fv, &pdim);
924:     DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);
925:   }
926:   VecGetArray(locX, &x);
927:   for (i = 0; i < numids; ++i) {
928:     IS              faceIS;
929:     const PetscInt *faces;
930:     PetscInt        numFaces, f;

932:     DMLabelGetStratumIS(label, ids[i], &faceIS);
933:     if (!faceIS) continue; /* No points with that id on this process */
934:     ISGetLocalSize(faceIS, &numFaces);
935:     ISGetIndices(faceIS, &faces);
936:     for (f = 0; f < numFaces; ++f) {
937:       const PetscInt         face = faces[f], *cells;
938:       PetscFVFaceGeom        *fg;

940:       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
941:       PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);
942:       if (loc >= 0) continue;
943:       DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
944:       DMPlexGetSupport(dm, face, &cells);
945:       if (Grad) {
946:         PetscFVCellGeom       *cg;
947:         PetscScalar           *cx, *cgrad;
948:         PetscScalar           *xG;
949:         PetscReal              dx[3];
950:         PetscInt               d;

952:         DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);
953:         DMPlexPointLocalRead(dm, cells[0], x, &cx);
954:         DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);
955:         DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
956:         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
957:         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx);
958:         ierru = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);
959:         if (ierru) {
960:           ISRestoreIndices(faceIS, &faces);
961:           ISDestroy(&faceIS);
962:           goto cleanup;
963:         }
964:       } else {
965:         PetscScalar       *xI;
966:         PetscScalar       *xG;

968:         DMPlexPointLocalRead(dm, cells[0], x, &xI);
969:         DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);
970:         ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
971:         if (ierru) {
972:           ISRestoreIndices(faceIS, &faces);
973:           ISDestroy(&faceIS);
974:           goto cleanup;
975:         }
976:       }
977:     }
978:     ISRestoreIndices(faceIS, &faces);
979:     ISDestroy(&faceIS);
980:   }
981:   cleanup:
982:   VecRestoreArray(locX, &x);
983:   if (Grad) {
984:     DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx);
985:     VecRestoreArrayRead(Grad, &grad);
986:   }
987:   if (cellGeometry) {VecRestoreArrayRead(cellGeometry, &cellgeom);}
988:   VecRestoreArrayRead(faceGeometry, &facegeom);
989:   CHKERRQ(ierru);
990:   return(0);
991: }

993: static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
994: {
995:   PetscInt c;
996:   for (c = 0; c < Nc; ++c) u[c] = 0.0;
997:   return 0;
998: }

1000: PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1001: {
1002:   PetscObject    isZero;
1003:   PetscDS        prob;
1004:   PetscInt       numBd, b;

1008:   DMGetDS(dm, &prob);
1009:   PetscDSGetNumBoundary(prob, &numBd);
1010:   PetscObjectQuery((PetscObject) locX, "__Vec_bc_zero__", &isZero);
1011:   for (b = 0; b < numBd; ++b) {
1012:     DMBoundaryConditionType type;
1013:     const char             *name, *labelname;
1014:     DMLabel                 label;
1015:     PetscInt                field, Nc;
1016:     const PetscInt         *comps;
1017:     PetscObject             obj;
1018:     PetscClassId            id;
1019:     void                    (*func)(void);
1020:     PetscInt                numids;
1021:     const PetscInt         *ids;
1022:     void                   *ctx;

1024:     DMGetBoundary(dm, b, &type, &name, &labelname, &field, &Nc, &comps, &func, NULL, &numids, &ids, &ctx);
1025:     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1026:     DMGetLabel(dm, labelname, &label);
1027:     if (!label) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "Label %s for boundary condition %s does not exist in the DM", labelname, name);
1028:     DMGetField(dm, field, NULL, &obj);
1029:     PetscObjectGetClassId(obj, &id);
1030:     if (id == PETSCFE_CLASSID) {
1031:       switch (type) {
1032:         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1033:       case DM_BC_ESSENTIAL:
1034:         if (isZero) func = (void (*)(void)) zero;
1035:         DMPlexLabelAddCells(dm,label);
1036:         DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);
1037:         DMPlexLabelClearCells(dm,label);
1038:         break;
1039:       case DM_BC_ESSENTIAL_FIELD:
1040:         DMPlexLabelAddCells(dm,label);
1041:         DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids,
1042:                                                         (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1043:                                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1044:                                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func, ctx, locX);
1045:         DMPlexLabelClearCells(dm,label);
1046:         break;
1047:       default: break;
1048:       }
1049:     } else if (id == PETSCFV_CLASSID) {
1050:       if (!faceGeomFVM) continue;
1051:       DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids,
1052:                                                (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);
1053:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1054:   }
1055:   return(0);
1056: }

1058: PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1059: {
1060:   PetscObject    isZero;
1061:   PetscDS        prob;
1062:   PetscInt       numBd, b;

1066:   if (!locX) return(0);
1067:   DMGetDS(dm, &prob);
1068:   PetscDSGetNumBoundary(prob, &numBd);
1069:   PetscObjectQuery((PetscObject) locX, "__Vec_bc_zero__", &isZero);
1070:   for (b = 0; b < numBd; ++b) {
1071:     DMBoundaryConditionType type;
1072:     const char             *name, *labelname;
1073:     DMLabel                 label;
1074:     PetscInt                field, Nc;
1075:     const PetscInt         *comps;
1076:     PetscObject             obj;
1077:     PetscClassId            id;
1078:     void                    (*func_t)(void);
1079:     PetscInt                numids;
1080:     const PetscInt         *ids;
1081:     void                   *ctx;

1083:     DMGetBoundary(dm, b, &type, &name, &labelname, &field, &Nc, &comps, NULL, &func_t, &numids, &ids, &ctx);
1084:     if (!func_t) continue;
1085:     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1086:     DMGetLabel(dm, labelname, &label);
1087:     if (!label) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "Label %s for boundary condition %s does not exist in the DM", labelname, name);
1088:     DMGetField(dm, field, NULL, &obj);
1089:     PetscObjectGetClassId(obj, &id);
1090:     if (id == PETSCFE_CLASSID) {
1091:       switch (type) {
1092:         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1093:       case DM_BC_ESSENTIAL:
1094:         if (isZero) func_t = (void (*)(void)) zero;
1095:         DMPlexLabelAddCells(dm,label);
1096:         DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func_t, ctx, locX);
1097:         DMPlexLabelClearCells(dm,label);
1098:         break;
1099:       case DM_BC_ESSENTIAL_FIELD:
1100:         DMPlexLabelAddCells(dm,label);
1101:         DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids,
1102:                                                         (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1103:                                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
1104:                                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func_t, ctx, locX);
1105:         DMPlexLabelClearCells(dm,label);
1106:         break;
1107:       default: break;
1108:       }
1109:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1110:   }
1111:   return(0);
1112: }

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

1117:   Input Parameters:
1118: + dm - The DM
1119: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1120: . time - The time
1121: . faceGeomFVM - Face geometry data for FV discretizations
1122: . cellGeomFVM - Cell geometry data for FV discretizations
1123: - gradFVM - Gradient reconstruction data for FV discretizations

1125:   Output Parameters:
1126: . locX - Solution updated with boundary values

1128:   Level: developer

1130: .seealso: DMProjectFunctionLabelLocal()
1131: @*/
1132: PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1133: {

1142:   PetscTryMethod(dm,"DMPlexInsertBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX,time,faceGeomFVM,cellGeomFVM,gradFVM));
1143:   return(0);
1144: }

1146: /*@
1147:   DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derviative into the local solution vector

1149:   Input Parameters:
1150: + dm - The DM
1151: . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1152: . time - The time
1153: . faceGeomFVM - Face geometry data for FV discretizations
1154: . cellGeomFVM - Cell geometry data for FV discretizations
1155: - gradFVM - Gradient reconstruction data for FV discretizations

1157:   Output Parameters:
1158: . locX_t - Solution updated with boundary values

1160:   Level: developer

1162: .seealso: DMProjectFunctionLabelLocal()
1163: @*/
1164: PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1165: {

1174:   PetscTryMethod(dm,"DMPlexInsertTimeDerviativeBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX_t,time,faceGeomFVM,cellGeomFVM,gradFVM));
1175:   return(0);
1176: }

1178: PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1179: {
1180:   Vec              localX;
1181:   PetscErrorCode   ierr;

1184:   DMGetLocalVector(dm, &localX);
1185:   DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL);
1186:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1187:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1188:   DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff);
1189:   DMRestoreLocalVector(dm, &localX);
1190:   return(0);
1191: }

1193: /*@C
1194:   DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.

1196:   Collective on dm

1198:   Input Parameters:
1199: + dm     - The DM
1200: . time   - The time
1201: . funcs  - The functions to evaluate for each field component
1202: . ctxs   - Optional array of contexts to pass to each function, or NULL.
1203: - localX - The coefficient vector u_h, a local vector

1205:   Output Parameter:
1206: . diff - The diff ||u - u_h||_2

1208:   Level: developer

1210: .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
1211: @*/
1212: PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
1213: {
1214:   const PetscInt   debug = ((DM_Plex*)dm->data)->printL2;
1215:   DM               tdm;
1216:   Vec              tv;
1217:   PetscSection     section;
1218:   PetscQuadrature  quad;
1219:   PetscFEGeom      fegeom;
1220:   PetscScalar     *funcVal, *interpolant;
1221:   PetscReal       *coords, *gcoords;
1222:   PetscReal        localDiff = 0.0;
1223:   const PetscReal *quadWeights;
1224:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset;
1225:   PetscBool        transform;
1226:   PetscErrorCode   ierr;

1229:   DMGetDimension(dm, &dim);
1230:   DMGetCoordinateDim(dm, &coordDim);
1231:   fegeom.dimEmbed = coordDim;
1232:   DMGetLocalSection(dm, &section);
1233:   PetscSectionGetNumFields(section, &numFields);
1234:   DMGetBasisTransformDM_Internal(dm, &tdm);
1235:   DMGetBasisTransformVec_Internal(dm, &tv);
1236:   DMHasBasisTransform(dm, &transform);
1237:   for (field = 0; field < numFields; ++field) {
1238:     PetscObject  obj;
1239:     PetscClassId id;
1240:     PetscInt     Nc;

1242:     DMGetField(dm, field, NULL, &obj);
1243:     PetscObjectGetClassId(obj, &id);
1244:     if (id == PETSCFE_CLASSID) {
1245:       PetscFE fe = (PetscFE) obj;

1247:       PetscFEGetQuadrature(fe, &quad);
1248:       PetscFEGetNumComponents(fe, &Nc);
1249:     } else if (id == PETSCFV_CLASSID) {
1250:       PetscFV fv = (PetscFV) obj;

1252:       PetscFVGetQuadrature(fv, &quad);
1253:       PetscFVGetNumComponents(fv, &Nc);
1254:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1255:     numComponents += Nc;
1256:   }
1257:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
1258:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1259:   PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);
1260:   DMPlexGetVTKCellHeight(dm, &cellHeight);
1261:   DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
1262:   for (c = cStart; c < cEnd; ++c) {
1263:     PetscScalar *x = NULL;
1264:     PetscReal    elemDiff = 0.0;
1265:     PetscInt     qc = 0;

1267:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1268:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

1270:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1271:       PetscObject  obj;
1272:       PetscClassId id;
1273:       void * const ctx = ctxs ? ctxs[field] : NULL;
1274:       PetscInt     Nb, Nc, q, fc;

1276:       DMGetField(dm, field, NULL, &obj);
1277:       PetscObjectGetClassId(obj, &id);
1278:       if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1279:       else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1280:       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1281:       if (debug) {
1282:         char title[1024];
1283:         PetscSNPrintf(title, 1023, "Solution for Field %D", field);
1284:         DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
1285:       }
1286:       for (q = 0; q < Nq; ++q) {
1287:         PetscFEGeom qgeom;

1289:         qgeom.dimEmbed = fegeom.dimEmbed;
1290:         qgeom.J        = &fegeom.J[q*coordDim*coordDim];
1291:         qgeom.invJ     = &fegeom.invJ[q*coordDim*coordDim];
1292:         qgeom.detJ     = &fegeom.detJ[q];
1293:         if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, point %D", (double)fegeom.detJ[q], c, q);
1294:         if (transform) {
1295:           gcoords = &coords[coordDim*Nq];
1296:           DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);
1297:         } else {
1298:           gcoords = &coords[coordDim*q];
1299:         }
1300:         (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx);
1301:         if (ierr) {
1302:           PetscErrorCode ierr2;
1303:           ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1304:           ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1305:           ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1306:           
1307:         }
1308:         if (transform) {DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);}
1309:         if (id == PETSCFE_CLASSID)      {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);}
1310:         else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
1311:         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1312:         for (fc = 0; fc < Nc; ++fc) {
1313:           const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1314:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %D field %D,%D point %g %g %g diff %g\n", c, field, fc, (double)(coordDim > 0 ? coords[coordDim*q] : 0.), (double)(coordDim > 1 ? coords[coordDim*q+1] : 0.),(double)(coordDim > 2 ? coords[coordDim*q+2] : 0.), (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));}
1315:           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1316:         }
1317:       }
1318:       fieldOffset += Nb;
1319:       qc += Nc;
1320:     }
1321:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1322:     if (debug) {PetscPrintf(PETSC_COMM_SELF, "  elem %D diff %g\n", c, (double)elemDiff);}
1323:     localDiff += elemDiff;
1324:   }
1325:   PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
1326:   MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1327:   *diff = PetscSqrtReal(*diff);
1328:   return(0);
1329: }

1331: 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)
1332: {
1333:   const PetscInt   debug = ((DM_Plex*)dm->data)->printL2;
1334:   DM               tdm;
1335:   PetscSection     section;
1336:   PetscQuadrature  quad;
1337:   Vec              localX, tv;
1338:   PetscScalar     *funcVal, *interpolant;
1339:   const PetscReal *quadWeights;
1340:   PetscFEGeom      fegeom;
1341:   PetscReal       *coords, *gcoords;
1342:   PetscReal        localDiff = 0.0;
1343:   PetscInt         dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset;
1344:   PetscBool        transform;
1345:   PetscErrorCode   ierr;

1348:   DMGetDimension(dm, &dim);
1349:   DMGetCoordinateDim(dm, &coordDim);
1350:   fegeom.dimEmbed = coordDim;
1351:   DMGetLocalSection(dm, &section);
1352:   PetscSectionGetNumFields(section, &numFields);
1353:   DMGetLocalVector(dm, &localX);
1354:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1355:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1356:   DMGetBasisTransformDM_Internal(dm, &tdm);
1357:   DMGetBasisTransformVec_Internal(dm, &tv);
1358:   DMHasBasisTransform(dm, &transform);
1359:   for (field = 0; field < numFields; ++field) {
1360:     PetscFE  fe;
1361:     PetscInt Nc;

1363:     DMGetField(dm, field, NULL, (PetscObject *) &fe);
1364:     PetscFEGetQuadrature(fe, &quad);
1365:     PetscFEGetNumComponents(fe, &Nc);
1366:     numComponents += Nc;
1367:   }
1368:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);
1369:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1370:   /* DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX); */
1371:   PetscMalloc6(numComponents,&funcVal,coordDim*Nq,&coords,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ,numComponents*coordDim,&interpolant,Nq,&fegeom.detJ);
1372:   DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1373:   for (c = cStart; c < cEnd; ++c) {
1374:     PetscScalar *x = NULL;
1375:     PetscReal    elemDiff = 0.0;
1376:     PetscInt     qc = 0;

1378:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1379:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

1381:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1382:       PetscFE          fe;
1383:       void * const     ctx = ctxs ? ctxs[field] : NULL;
1384:       PetscInt         Nb, Nc, q, fc;

1386:       DMGetField(dm, field, NULL, (PetscObject *) &fe);
1387:       PetscFEGetDimension(fe, &Nb);
1388:       PetscFEGetNumComponents(fe, &Nc);
1389:       if (debug) {
1390:         char title[1024];
1391:         PetscSNPrintf(title, 1023, "Solution for Field %D", field);
1392:         DMPrintCellVector(c, title, Nb, &x[fieldOffset]);
1393:       }
1394:       for (q = 0; q < Nq; ++q) {
1395:         PetscFEGeom qgeom;

1397:         qgeom.dimEmbed = fegeom.dimEmbed;
1398:         qgeom.J        = &fegeom.J[q*coordDim*coordDim];
1399:         qgeom.invJ     = &fegeom.invJ[q*coordDim*coordDim];
1400:         qgeom.detJ     = &fegeom.detJ[q];
1401:         if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], c, q);
1402:         if (transform) {
1403:           gcoords = &coords[coordDim*Nq];
1404:           DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);
1405:         } else {
1406:           gcoords = &coords[coordDim*q];
1407:         }
1408:         (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx);
1409:         if (ierr) {
1410:           PetscErrorCode ierr2;
1411:           ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1412:           ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1413:           ierr2 = PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ);CHKERRQ(ierr2);
1414:           
1415:         }
1416:         if (transform) {DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);}
1417:         PetscFEInterpolateGradient_Static(fe, &x[fieldOffset], &qgeom, q, interpolant);
1418:         /* Overwrite with the dot product if the normal is given */
1419:         if (n) {
1420:           for (fc = 0; fc < Nc; ++fc) {
1421:             PetscScalar sum = 0.0;
1422:             PetscInt    d;
1423:             for (d = 0; d < dim; ++d) sum += interpolant[fc*dim+d]*n[d];
1424:             interpolant[fc] = sum;
1425:           }
1426:         }
1427:         for (fc = 0; fc < Nc; ++fc) {
1428:           const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1429:           if (debug) {PetscPrintf(PETSC_COMM_SELF, "    elem %D fieldDer %D,%D diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));}
1430:           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1431:         }
1432:       }
1433:       fieldOffset += Nb;
1434:       qc          += Nc;
1435:     }
1436:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1437:     if (debug) {PetscPrintf(PETSC_COMM_SELF, "  elem %D diff %g\n", c, (double)elemDiff);}
1438:     localDiff += elemDiff;
1439:   }
1440:   PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ);
1441:   DMRestoreLocalVector(dm, &localX);
1442:   MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1443:   *diff = PetscSqrtReal(*diff);
1444:   return(0);
1445: }

1447: PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1448: {
1449:   const PetscInt   debug = ((DM_Plex*)dm->data)->printL2;
1450:   DM               tdm;
1451:   DMLabel          depthLabel;
1452:   PetscSection     section;
1453:   Vec              localX, tv;
1454:   PetscReal       *localDiff;
1455:   PetscInt         dim, depth, dE, Nf, f, Nds, s;
1456:   PetscBool        transform;
1457:   PetscErrorCode   ierr;

1460:   DMGetDimension(dm, &dim);
1461:   DMGetCoordinateDim(dm, &dE);
1462:   DMGetLocalSection(dm, &section);
1463:   DMGetLocalVector(dm, &localX);
1464:   DMGetBasisTransformDM_Internal(dm, &tdm);
1465:   DMGetBasisTransformVec_Internal(dm, &tv);
1466:   DMHasBasisTransform(dm, &transform);
1467:   DMGetNumFields(dm, &Nf);
1468:   DMPlexGetDepthLabel(dm, &depthLabel);
1469:   DMLabelGetNumValues(depthLabel, &depth);

1471:   VecSet(localX, 0.0);
1472:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1473:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1474:   DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1475:   DMGetNumDS(dm, &Nds);
1476:   PetscCalloc1(Nf, &localDiff);
1477:   for (s = 0; s < Nds; ++s) {
1478:     PetscDS          ds;
1479:     DMLabel          label;
1480:     IS               fieldIS, pointIS;
1481:     const PetscInt  *fields, *points = NULL;
1482:     PetscQuadrature  quad;
1483:     const PetscReal *quadPoints, *quadWeights;
1484:     PetscFEGeom      fegeom;
1485:     PetscReal       *coords, *gcoords;
1486:     PetscScalar     *funcVal, *interpolant;
1487:     PetscBool        isHybrid;
1488:     PetscInt         qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf;

1490:     DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);
1491:     ISGetIndices(fieldIS, &fields);
1492:     PetscDSGetHybrid(ds, &isHybrid);
1493:     PetscDSGetNumFields(ds, &dsNf);
1494:     PetscDSGetTotalComponents(ds, &totNc);
1495:     PetscDSGetQuadrature(ds, &quad);
1496:     PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1497:     if ((qNc != 1) && (qNc != totNc)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, totNc);
1498:     PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE*(Nq+1), &coords,Nq, &fegeom.detJ, dE*dE*Nq, &fegeom.J, dE*dE*Nq, &fegeom.invJ);
1499:     if (!label) {
1500:       DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1501:     } else {
1502:       DMLabelGetStratumIS(label, 1, &pointIS);
1503:       ISGetLocalSize(pointIS, &cEnd);
1504:       ISGetIndices(pointIS, &points);
1505:     }
1506:     for (c = cStart; c < cEnd; ++c) {
1507:       const PetscInt cell = points ? points[c] : c;
1508:       PetscScalar   *x    = NULL;
1509:       PetscInt       qc   = 0, fOff = 0, dep, fStart = isHybrid ? dsNf-1 : 0;

1511:       DMLabelGetValue(depthLabel, cell, &dep);
1512:       if (dep != depth-1) continue;
1513:       if (isHybrid) {
1514:         const PetscInt *cone;

1516:         DMPlexGetCone(dm, cell, &cone);
1517:         DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1518:       } else {
1519:         DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1520:       }
1521:       DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x);
1522:       for (f = fStart; f < dsNf; ++f) {
1523:         PetscObject  obj;
1524:         PetscClassId id;
1525:         void * const ctx = ctxs ? ctxs[fields[f]] : NULL;
1526:         PetscInt     Nb, Nc, q, fc;
1527:         PetscReal    elemDiff = 0.0;

1529:         PetscDSGetDiscretization(ds, f, &obj);
1530:         PetscObjectGetClassId(obj, &id);
1531:         if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1532:         else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1533:         else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", fields[f]);
1534:         if (debug) {
1535:           char title[1024];
1536:           PetscSNPrintf(title, 1023, "Solution for Field %D", fields[f]);
1537:           DMPrintCellVector(cell, title, Nb, &x[fOff]);
1538:         }
1539:         for (q = 0; q < Nq; ++q) {
1540:           PetscFEGeom qgeom;

1542:           qgeom.dimEmbed = fegeom.dimEmbed;
1543:           qgeom.J        = &fegeom.J[q*dE*dE];
1544:           qgeom.invJ     = &fegeom.invJ[q*dE*dE];
1545:           qgeom.detJ     = &fegeom.detJ[q];
1546:           if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for cell %D, quadrature point %D", (double)fegeom.detJ[q], cell, q);
1547:           if (transform) {
1548:             gcoords = &coords[dE*Nq];
1549:             DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE*q], PETSC_TRUE, dE, &coords[dE*q], gcoords, dm->transformCtx);
1550:           } else {
1551:             gcoords = &coords[dE*q];
1552:           }
1553:           (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx);
1554:           if (ierr) {
1555:             PetscErrorCode ierr2;
1556:             ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x);CHKERRQ(ierr2);
1557:             ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1558:             ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1559:             
1560:           }
1561:           if (transform) {DMPlexBasisTransformApply_Internal(dm, &coords[dE*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);}
1562:           /* Call once for each face, except for lagrange field */
1563:           if (id == PETSCFE_CLASSID)      {PetscFEInterpolate_Static((PetscFE) obj, &x[fOff], &qgeom, q, interpolant);}
1564:           else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fOff], q, interpolant);}
1565:           else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", fields[f]);
1566:           for (fc = 0; fc < Nc; ++fc) {
1567:             const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1568:             if (debug) {PetscPrintf(PETSC_COMM_SELF, "    cell %D field %D,%D point %g %g %g diff %g\n", cell, fields[f], fc, (double)(dE > 0 ? coords[dE*q] : 0.), (double)(dE > 1 ? coords[dE*q+1] : 0.),(double)(dE > 2 ? coords[dE*q+2] : 0.), (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));}
1569:             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1570:           }
1571:         }
1572:         fOff += Nb;
1573:         qc   += Nc;
1574:         localDiff[fields[f]] += elemDiff;
1575:         if (debug) {PetscPrintf(PETSC_COMM_SELF, "  cell %D field %D cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]]);}
1576:       }
1577:       DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x);
1578:     }
1579:     if (label) {
1580:       ISRestoreIndices(pointIS, &points);
1581:       ISDestroy(&pointIS);
1582:     }
1583:     ISRestoreIndices(fieldIS, &fields);
1584:     PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ);
1585:   }
1586:   DMRestoreLocalVector(dm, &localX);
1587:   MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));
1588:   PetscFree(localDiff);
1589:   for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]);
1590:   return(0);
1591: }

1593: /*@C
1594:   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.

1596:   Collective on dm

1598:   Input Parameters:
1599: + dm    - The DM
1600: . time  - The time
1601: . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation
1602: . ctxs  - Optional array of contexts to pass to each function, or NULL.
1603: - X     - The coefficient vector u_h

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

1608:   Level: developer

1610: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
1611: @*/
1612: PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1613: {
1614:   PetscSection     section;
1615:   PetscQuadrature  quad;
1616:   Vec              localX;
1617:   PetscFEGeom      fegeom;
1618:   PetscScalar     *funcVal, *interpolant;
1619:   PetscReal       *coords;
1620:   const PetscReal *quadPoints, *quadWeights;
1621:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset;
1622:   PetscErrorCode   ierr;

1625:   VecSet(D, 0.0);
1626:   DMGetDimension(dm, &dim);
1627:   DMGetCoordinateDim(dm, &coordDim);
1628:   DMGetLocalSection(dm, &section);
1629:   PetscSectionGetNumFields(section, &numFields);
1630:   DMGetLocalVector(dm, &localX);
1631:   DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);
1632:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);
1633:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);
1634:   for (field = 0; field < numFields; ++field) {
1635:     PetscObject  obj;
1636:     PetscClassId id;
1637:     PetscInt     Nc;

1639:     DMGetField(dm, field, NULL, &obj);
1640:     PetscObjectGetClassId(obj, &id);
1641:     if (id == PETSCFE_CLASSID) {
1642:       PetscFE fe = (PetscFE) obj;

1644:       PetscFEGetQuadrature(fe, &quad);
1645:       PetscFEGetNumComponents(fe, &Nc);
1646:     } else if (id == PETSCFV_CLASSID) {
1647:       PetscFV fv = (PetscFV) obj;

1649:       PetscFVGetQuadrature(fv, &quad);
1650:       PetscFVGetNumComponents(fv, &Nc);
1651:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1652:     numComponents += Nc;
1653:   }
1654:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1655:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1656:   PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);
1657:   DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1658:   for (c = cStart; c < cEnd; ++c) {
1659:     PetscScalar *x = NULL;
1660:     PetscScalar  elemDiff = 0.0;
1661:     PetscInt     qc = 0;

1663:     DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1664:     DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);

1666:     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1667:       PetscObject  obj;
1668:       PetscClassId id;
1669:       void * const ctx = ctxs ? ctxs[field] : NULL;
1670:       PetscInt     Nb, Nc, q, fc;

1672:       DMGetField(dm, field, NULL, &obj);
1673:       PetscObjectGetClassId(obj, &id);
1674:       if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1675:       else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1676:       else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1677:       if (funcs[field]) {
1678:         for (q = 0; q < Nq; ++q) {
1679:           PetscFEGeom qgeom;

1681:           qgeom.dimEmbed = fegeom.dimEmbed;
1682:           qgeom.J        = &fegeom.J[q*coordDim*coordDim];
1683:           qgeom.invJ     = &fegeom.invJ[q*coordDim*coordDim];
1684:           qgeom.detJ     = &fegeom.detJ[q];
1685:           if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], c, q);
1686:           (*funcs[field])(coordDim, time, &coords[q*coordDim], Nc, funcVal, ctx);
1687:           if (ierr) {
1688:             PetscErrorCode ierr2;
1689:             ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2);
1690:             ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1691:             ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2);
1692:             
1693:           }
1694:           if (id == PETSCFE_CLASSID)      {PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);}
1695:           else if (id == PETSCFV_CLASSID) {PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);}
1696:           else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1697:           for (fc = 0; fc < Nc; ++fc) {
1698:             const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)];
1699:             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q];
1700:           }
1701:         }
1702:       }
1703:       fieldOffset += Nb;
1704:       qc          += Nc;
1705:     }
1706:     DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);
1707:     VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES);
1708:   }
1709:   PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
1710:   DMRestoreLocalVector(dm, &localX);
1711:   VecSqrtAbs(D);
1712:   return(0);
1713: }

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

1718:   Collective on dm

1720:   Input Parameters:
1721: + dm - The DM
1722: - LocX  - The coefficient vector u_h

1724:   Output Parameter:
1725: . locC - A Vec which holds the Clement interpolant of the gradient

1727:   Notes:
1728:     Add citation to (Clement, 1975) and definition of the interpolant
1729:   \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

1731:   Level: developer

1733: .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff()
1734: @*/
1735: PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
1736: {
1737:   DM_Plex         *mesh  = (DM_Plex *) dm->data;
1738:   PetscInt         debug = mesh->printFEM;
1739:   DM               dmC;
1740:   PetscSection     section;
1741:   PetscQuadrature  quad;
1742:   PetscScalar     *interpolant, *gradsum;
1743:   PetscFEGeom      fegeom;
1744:   PetscReal       *coords;
1745:   const PetscReal *quadPoints, *quadWeights;
1746:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
1747:   PetscErrorCode   ierr;

1750:   VecGetDM(locC, &dmC);
1751:   VecSet(locC, 0.0);
1752:   DMGetDimension(dm, &dim);
1753:   DMGetCoordinateDim(dm, &coordDim);
1754:   fegeom.dimEmbed = coordDim;
1755:   DMGetLocalSection(dm, &section);
1756:   PetscSectionGetNumFields(section, &numFields);
1757:   for (field = 0; field < numFields; ++field) {
1758:     PetscObject  obj;
1759:     PetscClassId id;
1760:     PetscInt     Nc;

1762:     DMGetField(dm, field, NULL, &obj);
1763:     PetscObjectGetClassId(obj, &id);
1764:     if (id == PETSCFE_CLASSID) {
1765:       PetscFE fe = (PetscFE) obj;

1767:       PetscFEGetQuadrature(fe, &quad);
1768:       PetscFEGetNumComponents(fe, &Nc);
1769:     } else if (id == PETSCFV_CLASSID) {
1770:       PetscFV fv = (PetscFV) obj;

1772:       PetscFVGetQuadrature(fv, &quad);
1773:       PetscFVGetNumComponents(fv, &Nc);
1774:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1775:     numComponents += Nc;
1776:   }
1777:   PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);
1778:   if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents);
1779:   PetscMalloc6(coordDim*numComponents*2,&gradsum,coordDim*numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);
1780:   DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);
1781:   DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd);
1782:   for (v = vStart; v < vEnd; ++v) {
1783:     PetscScalar volsum = 0.0;
1784:     PetscInt   *star = NULL;
1785:     PetscInt    starSize, st, d, fc;

1787:     PetscArrayzero(gradsum, coordDim*numComponents);
1788:     DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1789:     for (st = 0; st < starSize*2; st += 2) {
1790:       const PetscInt cell = star[st];
1791:       PetscScalar   *grad = &gradsum[coordDim*numComponents];
1792:       PetscScalar   *x    = NULL;
1793:       PetscReal      vol  = 0.0;

1795:       if ((cell < cStart) || (cell >= cEnd)) continue;
1796:       DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);
1797:       DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);
1798:       for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1799:         PetscObject  obj;
1800:         PetscClassId id;
1801:         PetscInt     Nb, Nc, q, qc = 0;

1803:         PetscArrayzero(grad, coordDim*numComponents);
1804:         DMGetField(dm, field, NULL, &obj);
1805:         PetscObjectGetClassId(obj, &id);
1806:         if (id == PETSCFE_CLASSID)      {PetscFEGetNumComponents((PetscFE) obj, &Nc);PetscFEGetDimension((PetscFE) obj, &Nb);}
1807:         else if (id == PETSCFV_CLASSID) {PetscFVGetNumComponents((PetscFV) obj, &Nc);Nb = 1;}
1808:         else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1809:         for (q = 0; q < Nq; ++q) {
1810:           PetscFEGeom qgeom;

1812:           qgeom.dimEmbed = fegeom.dimEmbed;
1813:           qgeom.J        = &fegeom.J[q*coordDim*coordDim];
1814:           qgeom.invJ     = &fegeom.invJ[q*coordDim*coordDim];
1815:           qgeom.detJ     = &fegeom.detJ[q];
1816:           if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], cell, q);
1817:           if (ierr) {
1818:             PetscErrorCode ierr2;
1819:             ierr2 = DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr2);
1820:             ierr2 = DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr2);
1821:             ierr2 = PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2);
1822:             
1823:           }
1824:           if (id == PETSCFE_CLASSID)      {PetscFEInterpolateGradient_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);}
1825:           else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1826:           for (fc = 0; fc < Nc; ++fc) {
1827:             const PetscReal wt = quadWeights[q*qNc+qc+fc];

1829:             for (d = 0; d < coordDim; ++d) grad[fc*coordDim+d] += interpolant[fc*dim+d]*wt*fegeom.detJ[q];
1830:           }
1831:           vol += quadWeights[q*qNc]*fegeom.detJ[q];
1832:         }
1833:         fieldOffset += Nb;
1834:         qc          += Nc;
1835:       }
1836:       DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);
1837:       for (fc = 0; fc < numComponents; ++fc) {
1838:         for (d = 0; d < coordDim; ++d) {
1839:           gradsum[fc*coordDim+d] += grad[fc*coordDim+d];
1840:         }
1841:       }
1842:       volsum += vol;
1843:       if (debug) {
1844:         PetscPrintf(PETSC_COMM_SELF, "Cell %D gradient: [", cell);
1845:         for (fc = 0; fc < numComponents; ++fc) {
1846:           for (d = 0; d < coordDim; ++d) {
1847:             if (fc || d > 0) {PetscPrintf(PETSC_COMM_SELF, ", ");}
1848:             PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc*coordDim+d]));
1849:           }
1850:         }
1851:         PetscPrintf(PETSC_COMM_SELF, "]\n");
1852:       }
1853:     }
1854:     for (fc = 0; fc < numComponents; ++fc) {
1855:       for (d = 0; d < coordDim; ++d) gradsum[fc*coordDim+d] /= volsum;
1856:     }
1857:     DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);
1858:     DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES);
1859:   }
1860:   PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);
1861:   return(0);
1862: }

1864: static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
1865: {
1866:   DM                 dmAux = NULL;
1867:   PetscDS            prob,    probAux = NULL;
1868:   PetscSection       section, sectionAux;
1869:   Vec                locX,    locA;
1870:   PetscInt           dim, numCells = cEnd - cStart, c, f;
1871:   PetscBool          useFVM = PETSC_FALSE;
1872:   /* DS */
1873:   PetscInt           Nf,    totDim,    *uOff, *uOff_x, numConstants;
1874:   PetscInt           NfAux, totDimAux, *aOff;
1875:   PetscScalar       *u, *a;
1876:   const PetscScalar *constants;
1877:   /* Geometry */
1878:   PetscFEGeom       *cgeomFEM;
1879:   DM                 dmGrad;
1880:   PetscQuadrature    affineQuad = NULL;
1881:   Vec                cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
1882:   PetscFVCellGeom   *cgeomFVM;
1883:   const PetscScalar *lgrad;
1884:   PetscInt           maxDegree;
1885:   DMField            coordField;
1886:   IS                 cellIS;
1887:   PetscErrorCode     ierr;

1890:   DMGetDS(dm, &prob);
1891:   DMGetDimension(dm, &dim);
1892:   DMGetLocalSection(dm, &section);
1893:   PetscSectionGetNumFields(section, &Nf);
1894:   /* Determine which discretizations we have */
1895:   for (f = 0; f < Nf; ++f) {
1896:     PetscObject  obj;
1897:     PetscClassId id;

1899:     PetscDSGetDiscretization(prob, f, &obj);
1900:     PetscObjectGetClassId(obj, &id);
1901:     if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
1902:   }
1903:   /* Get local solution with boundary values */
1904:   DMGetLocalVector(dm, &locX);
1905:   DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
1906:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
1907:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
1908:   /* Read DS information */
1909:   PetscDSGetTotalDimension(prob, &totDim);
1910:   PetscDSGetComponentOffsets(prob, &uOff);
1911:   PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
1912:   ISCreateStride(PETSC_COMM_SELF,numCells,cStart,1,&cellIS);
1913:   PetscDSGetConstants(prob, &numConstants, &constants);
1914:   /* Read Auxiliary DS information */
1915:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
1916:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
1917:   if (dmAux) {
1918:     DMGetDS(dmAux, &probAux);
1919:     PetscDSGetNumFields(probAux, &NfAux);
1920:     DMGetLocalSection(dmAux, &sectionAux);
1921:     PetscDSGetTotalDimension(probAux, &totDimAux);
1922:     PetscDSGetComponentOffsets(probAux, &aOff);
1923:   }
1924:   /* Allocate data  arrays */
1925:   PetscCalloc1(numCells*totDim, &u);
1926:   if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
1927:   /* Read out geometry */
1928:   DMGetCoordinateField(dm,&coordField);
1929:   DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
1930:   if (maxDegree <= 1) {
1931:     DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
1932:     if (affineQuad) {
1933:       DMFieldCreateFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&cgeomFEM);
1934:     }
1935:   }
1936:   if (useFVM) {
1937:     PetscFV   fv = NULL;
1938:     Vec       grad;
1939:     PetscInt  fStart, fEnd;
1940:     PetscBool compGrad;

1942:     for (f = 0; f < Nf; ++f) {
1943:       PetscObject  obj;
1944:       PetscClassId id;

1946:       PetscDSGetDiscretization(prob, f, &obj);
1947:       PetscObjectGetClassId(obj, &id);
1948:       if (id == PETSCFV_CLASSID) {fv = (PetscFV) obj; break;}
1949:     }
1950:     PetscFVGetComputeGradients(fv, &compGrad);
1951:     PetscFVSetComputeGradients(fv, PETSC_TRUE);
1952:     DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM);
1953:     DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad);
1954:     PetscFVSetComputeGradients(fv, compGrad);
1955:     VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
1956:     /* Reconstruct and limit cell gradients */
1957:     DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
1958:     DMGetGlobalVector(dmGrad, &grad);
1959:     DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
1960:     /* Communicate gradient values */
1961:     DMGetLocalVector(dmGrad, &locGrad);
1962:     DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
1963:     DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
1964:     DMRestoreGlobalVector(dmGrad, &grad);
1965:     /* Handle non-essential (e.g. outflow) boundary values */
1966:     DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad);
1967:     VecGetArrayRead(locGrad, &lgrad);
1968:   }
1969:   /* Read out data from inputs */
1970:   for (c = cStart; c < cEnd; ++c) {
1971:     PetscScalar *x = NULL;
1972:     PetscInt     i;

1974:     DMPlexVecGetClosure(dm, section, locX, c, NULL, &x);
1975:     for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
1976:     DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x);
1977:     if (dmAux) {
1978:       DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x);
1979:       for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
1980:       DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x);
1981:     }
1982:   }
1983:   /* Do integration for each field */
1984:   for (f = 0; f < Nf; ++f) {
1985:     PetscObject  obj;
1986:     PetscClassId id;
1987:     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

1989:     PetscDSGetDiscretization(prob, f, &obj);
1990:     PetscObjectGetClassId(obj, &id);
1991:     if (id == PETSCFE_CLASSID) {
1992:       PetscFE         fe = (PetscFE) obj;
1993:       PetscQuadrature q;
1994:       PetscFEGeom     *chunkGeom = NULL;
1995:       PetscInt        Nq, Nb;

1997:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
1998:       PetscFEGetQuadrature(fe, &q);
1999:       PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2000:       PetscFEGetDimension(fe, &Nb);
2001:       blockSize = Nb*Nq;
2002:       batchSize = numBlocks * blockSize;
2003:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2004:       numChunks = numCells / (numBatches*batchSize);
2005:       Ne        = numChunks*numBatches*batchSize;
2006:       Nr        = numCells % (numBatches*batchSize);
2007:       offset    = numCells - Nr;
2008:       if (!affineQuad) {
2009:         DMFieldCreateFEGeom(coordField,cellIS,q,PETSC_FALSE,&cgeomFEM);
2010:       }
2011:       PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
2012:       PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral);
2013:       PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&chunkGeom);
2014:       PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset*totDim], probAux, &a[offset*totDimAux], &cintegral[offset*Nf]);
2015:       PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&chunkGeom);
2016:       if (!affineQuad) {
2017:         PetscFEGeomDestroy(&cgeomFEM);
2018:       }
2019:     } else if (id == PETSCFV_CLASSID) {
2020:       PetscInt       foff;
2021:       PetscPointFunc obj_func;
2022:       PetscScalar    lint;

2024:       PetscDSGetObjective(prob, f, &obj_func);
2025:       PetscDSGetFieldOffset(prob, f, &foff);
2026:       if (obj_func) {
2027:         for (c = 0; c < numCells; ++c) {
2028:           PetscScalar *u_x;

2030:           DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x);
2031:           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);
2032:           cintegral[c*Nf+f] += PetscRealPart(lint)*cgeomFVM[c].volume;
2033:         }
2034:       }
2035:     } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
2036:   }
2037:   /* Cleanup data arrays */
2038:   if (useFVM) {
2039:     VecRestoreArrayRead(locGrad, &lgrad);
2040:     VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
2041:     DMRestoreLocalVector(dmGrad, &locGrad);
2042:     VecDestroy(&faceGeometryFVM);
2043:     VecDestroy(&cellGeometryFVM);
2044:     DMDestroy(&dmGrad);
2045:   }
2046:   if (dmAux) {PetscFree(a);}
2047:   PetscFree(u);
2048:   /* Cleanup */
2049:   if (affineQuad) {
2050:     PetscFEGeomDestroy(&cgeomFEM);
2051:   }
2052:   PetscQuadratureDestroy(&affineQuad);
2053:   ISDestroy(&cellIS);
2054:   DMRestoreLocalVector(dm, &locX);
2055:   return(0);
2056: }

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

2061:   Input Parameters:
2062: + dm - The mesh
2063: . X  - Global input vector
2064: - user - The user context

2066:   Output Parameter:
2067: . integral - Integral for each field

2069:   Level: developer

2071: .seealso: DMPlexComputeResidualFEM()
2072: @*/
2073: PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
2074: {
2075:   DM_Plex       *mesh = (DM_Plex *) dm->data;
2076:   PetscScalar   *cintegral, *lintegral;
2077:   PetscInt       Nf, f, cellHeight, cStart, cEnd, cell;

2084:   PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2085:   DMGetNumFields(dm, &Nf);
2086:   DMPlexGetVTKCellHeight(dm, &cellHeight);
2087:   DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
2088:   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
2089:   PetscCalloc2(Nf, &lintegral, (cEnd-cStart)*Nf, &cintegral);
2090:   DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
2091:   /* Sum up values */
2092:   for (cell = cStart; cell < cEnd; ++cell) {
2093:     const PetscInt c = cell - cStart;

2095:     if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
2096:     for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c*Nf+f];
2097:   }
2098:   MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject) dm));
2099:   if (mesh->printFEM) {
2100:     PetscPrintf(PetscObjectComm((PetscObject) dm), "Integral:");
2101:     for (f = 0; f < Nf; ++f) {PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", (double) PetscRealPart(integral[f]));}
2102:     PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");
2103:   }
2104:   PetscFree2(lintegral, cintegral);
2105:   PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2106:   return(0);
2107: }

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

2112:   Input Parameters:
2113: + dm - The mesh
2114: . X  - Global input vector
2115: - user - The user context

2117:   Output Parameter:
2118: . integral - Cellwise integrals for each field

2120:   Level: developer

2122: .seealso: DMPlexComputeResidualFEM()
2123: @*/
2124: PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
2125: {
2126:   DM_Plex       *mesh = (DM_Plex *) dm->data;
2127:   DM             dmF;
2128:   PetscSection   sectionF;
2129:   PetscScalar   *cintegral, *af;
2130:   PetscInt       Nf, f, cellHeight, cStart, cEnd, cell;

2137:   PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2138:   DMGetNumFields(dm, &Nf);
2139:   DMPlexGetVTKCellHeight(dm, &cellHeight);
2140:   DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd);
2141:   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
2142:   PetscCalloc1((cEnd-cStart)*Nf, &cintegral);
2143:   DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);
2144:   /* Put values in F*/
2145:   VecGetDM(F, &dmF);
2146:   DMGetLocalSection(dmF, &sectionF);
2147:   VecGetArray(F, &af);
2148:   for (cell = cStart; cell < cEnd; ++cell) {
2149:     const PetscInt c = cell - cStart;
2150:     PetscInt       dof, off;

2152:     if (mesh->printFEM > 1) {DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);}
2153:     PetscSectionGetDof(sectionF, cell, &dof);
2154:     PetscSectionGetOffset(sectionF, cell, &off);
2155:     if (dof != Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %D != %D", dof, Nf);
2156:     for (f = 0; f < Nf; ++f) af[off+f] = cintegral[c*Nf+f];
2157:   }
2158:   VecRestoreArray(F, &af);
2159:   PetscFree(cintegral);
2160:   PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2161:   return(0);
2162: }

2164: static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS,
2165:                                                        void (*func)(PetscInt, PetscInt, PetscInt,
2166:                                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2167:                                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2168:                                                                     PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
2169:                                                        PetscScalar *fintegral, void *user)
2170: {
2171:   DM                 plex = NULL, plexA = NULL;
2172:   DMEnclosureType    encAux;
2173:   PetscDS            prob, probAux = NULL;
2174:   PetscSection       section, sectionAux = NULL;
2175:   Vec                locA = NULL;
2176:   DMField            coordField;
2177:   PetscInt           Nf,        totDim,        *uOff, *uOff_x;
2178:   PetscInt           NfAux = 0, totDimAux = 0, *aOff = NULL;
2179:   PetscScalar       *u, *a = NULL;
2180:   const PetscScalar *constants;
2181:   PetscInt           numConstants, f;
2182:   PetscErrorCode     ierr;

2185:   DMGetCoordinateField(dm, &coordField);
2186:   DMConvert(dm, DMPLEX, &plex);
2187:   DMGetDS(dm, &prob);
2188:   DMGetLocalSection(dm, &section);
2189:   PetscSectionGetNumFields(section, &Nf);
2190:   /* Determine which discretizations we have */
2191:   for (f = 0; f < Nf; ++f) {
2192:     PetscObject  obj;
2193:     PetscClassId id;

2195:     PetscDSGetDiscretization(prob, f, &obj);
2196:     PetscObjectGetClassId(obj, &id);
2197:     if (id == PETSCFV_CLASSID) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not supported for FVM (field %D)", f);
2198:   }
2199:   /* Read DS information */
2200:   PetscDSGetTotalDimension(prob, &totDim);
2201:   PetscDSGetComponentOffsets(prob, &uOff);
2202:   PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);
2203:   PetscDSGetConstants(prob, &numConstants, &constants);
2204:   /* Read Auxiliary DS information */
2205:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
2206:   if (locA) {
2207:     DM dmAux;

2209:     VecGetDM(locA, &dmAux);
2210:     DMGetEnclosureRelation(dmAux, dm, &encAux);
2211:     DMConvert(dmAux, DMPLEX, &plexA);
2212:     DMGetDS(dmAux, &probAux);
2213:     PetscDSGetNumFields(probAux, &NfAux);
2214:     DMGetLocalSection(dmAux, &sectionAux);
2215:     PetscDSGetTotalDimension(probAux, &totDimAux);
2216:     PetscDSGetComponentOffsets(probAux, &aOff);
2217:   }
2218:   /* Integrate over points */
2219:   {
2220:     PetscFEGeom    *fgeom, *chunkGeom = NULL;
2221:     PetscInt        maxDegree;
2222:     PetscQuadrature qGeom = NULL;
2223:     const PetscInt *points;
2224:     PetscInt        numFaces, face, Nq, field;
2225:     PetscInt        numChunks, chunkSize, chunk, Nr, offset;

2227:     ISGetLocalSize(pointIS, &numFaces);
2228:     ISGetIndices(pointIS, &points);
2229:     PetscCalloc2(numFaces*totDim, &u, locA ? numFaces*totDimAux : 0, &a);
2230:     DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);
2231:     for (field = 0; field < Nf; ++field) {
2232:       PetscFE fe;

2234:       PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
2235:       if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);}
2236:       if (!qGeom) {
2237:         PetscFEGetFaceQuadrature(fe, &qGeom);
2238:         PetscObjectReference((PetscObject) qGeom);
2239:       }
2240:       PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
2241:       DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2242:       for (face = 0; face < numFaces; ++face) {
2243:         const PetscInt point = points[face], *support, *cone;
2244:         PetscScalar    *x    = NULL;
2245:         PetscInt       i, coneSize, faceLoc;

2247:         DMPlexGetSupport(dm, point, &support);
2248:         DMPlexGetConeSize(dm, support[0], &coneSize);
2249:         DMPlexGetCone(dm, support[0], &cone);
2250:         for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
2251:         if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", face, support[0]);
2252:         fgeom->face[face][0] = faceLoc;
2253:         DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
2254:         for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
2255:         DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
2256:         if (locA) {
2257:           PetscInt subp;
2258:           DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
2259:           DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
2260:           for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i];
2261:           DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
2262:         }
2263:       }
2264:       /* Get blocking */
2265:       {
2266:         PetscQuadrature q;
2267:         PetscInt        numBatches, batchSize, numBlocks, blockSize;
2268:         PetscInt        Nq, Nb;

2270:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
2271:         PetscFEGetQuadrature(fe, &q);
2272:         PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);
2273:         PetscFEGetDimension(fe, &Nb);
2274:         blockSize = Nb*Nq;
2275:         batchSize = numBlocks * blockSize;
2276:         chunkSize = numBatches*batchSize;
2277:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
2278:         numChunks = numFaces / chunkSize;
2279:         Nr        = numFaces % chunkSize;
2280:         offset    = numFaces - Nr;
2281:       }
2282:       /* Do integration for each field */
2283:       for (chunk = 0; chunk < numChunks; ++chunk) {
2284:         PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);
2285:         PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);
2286:         PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
2287:       }
2288:       PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);
2289:       PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);
2290:       PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);
2291:       /* Cleanup data arrays */
2292:       DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);
2293:       PetscQuadratureDestroy(&qGeom);
2294:       PetscFree2(u, a);
2295:       ISRestoreIndices(pointIS, &points);
2296:     }
2297:   }
2298:   if (plex)  {DMDestroy(&plex);}
2299:   if (plexA) {DMDestroy(&plexA);}
2300:   return(0);
2301: }

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

2306:   Input Parameters:
2307: + dm      - The mesh
2308: . X       - Global input vector
2309: . label   - The boundary DMLabel
2310: . numVals - The number of label values to use, or PETSC_DETERMINE for all values
2311: . vals    - The label values to use, or PETSC_NULL for all values
2312: . func    = The function to integrate along the boundary
2313: - user    - The user context

2315:   Output Parameter:
2316: . integral - Integral for each field

2318:   Level: developer

2320: .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM()
2321: @*/
2322: PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[],
2323:                                        void (*func)(PetscInt, PetscInt, PetscInt,
2324:                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2325:                                                     const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
2326:                                                     PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
2327:                                        PetscScalar *integral, void *user)
2328: {
2329:   Vec            locX;
2330:   PetscSection   section;
2331:   DMLabel        depthLabel;
2332:   IS             facetIS;
2333:   PetscInt       dim, Nf, f, v;

2342:   PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);
2343:   DMPlexGetDepthLabel(dm, &depthLabel);
2344:   DMGetDimension(dm, &dim);
2345:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
2346:   DMGetLocalSection(dm, &section);
2347:   PetscSectionGetNumFields(section, &Nf);
2348:   /* Get local solution with boundary values */
2349:   DMGetLocalVector(dm, &locX);
2350:   DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);
2351:   DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);
2352:   DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);
2353:   /* Loop over label values */
2354:   PetscArrayzero(integral, Nf);
2355:   for (v = 0; v < numVals; ++v) {
2356:     IS           pointIS;
2357:     PetscInt     numFaces, face;
2358:     PetscScalar *fintegral;

2360:     DMLabelGetStratumIS(label, vals[v], &pointIS);
2361:     if (!pointIS) continue; /* No points with that id on this process */
2362:     {
2363:       IS isectIS;

2365:       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
2366:       ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);
2367:       ISDestroy(&pointIS);
2368:       pointIS = isectIS;
2369:     }
2370:     ISGetLocalSize(pointIS, &numFaces);
2371:     PetscCalloc1(numFaces*Nf, &fintegral);
2372:     DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);
2373:     /* Sum point contributions into integral */
2374:     for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f];
2375:     PetscFree(fintegral);
2376:     ISDestroy(&pointIS);
2377:   }
2378:   DMRestoreLocalVector(dm, &locX);
2379:   ISDestroy(&facetIS);
2380:   PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);
2381:   return(0);
2382: }

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

2387:   Input Parameters:
2388: + dmc  - The coarse mesh
2389: . dmf  - The fine mesh
2390: . isRefined - Flag indicating regular refinement, rather than the same topology
2391: - user - The user context

2393:   Output Parameter:
2394: . In  - The interpolation matrix

2396:   Level: developer

2398: .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2399: @*/
2400: PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user)
2401: {
2402:   DM_Plex          *mesh  = (DM_Plex *) dmc->data;
2403:   const char       *name  = "Interpolator";
2404:   PetscDS           cds, rds;
2405:   PetscFE          *feRef;
2406:   PetscFV          *fvRef;
2407:   PetscSection      fsection, fglobalSection;
2408:   PetscSection      csection, cglobalSection;
2409:   PetscScalar      *elemMat;
2410:   PetscInt          dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
2411:   PetscInt          cTotDim, rTotDim = 0;
2412:   PetscErrorCode    ierr;

2415:   PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2416:   DMGetDimension(dmf, &dim);
2417:   DMGetLocalSection(dmf, &fsection);
2418:   DMGetGlobalSection(dmf, &fglobalSection);
2419:   DMGetLocalSection(dmc, &csection);
2420:   DMGetGlobalSection(dmc, &cglobalSection);
2421:   PetscSectionGetNumFields(fsection, &Nf);
2422:   DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
2423:   DMGetDS(dmc, &cds);
2424:   DMGetDS(dmf, &rds);
2425:   PetscCalloc2(Nf, &feRef, Nf, &fvRef);
2426:   for (f = 0; f < Nf; ++f) {
2427:     PetscObject  obj;
2428:     PetscClassId id;
2429:     PetscInt     rNb = 0, Nc = 0;

2431:     PetscDSGetDiscretization(rds, f, &obj);
2432:     PetscObjectGetClassId(obj, &id);
2433:     if (id == PETSCFE_CLASSID) {
2434:       PetscFE fe = (PetscFE) obj;

2436:       if (isRefined) {
2437:         PetscFERefine(fe, &feRef[f]);
2438:       } else {
2439:         PetscObjectReference((PetscObject) fe);
2440:         feRef[f] = fe;
2441:       }
2442:       PetscFEGetDimension(feRef[f], &rNb);
2443:       PetscFEGetNumComponents(fe, &Nc);
2444:     } else if (id == PETSCFV_CLASSID) {
2445:       PetscFV        fv = (PetscFV) obj;
2446:       PetscDualSpace Q;

2448:       if (isRefined) {
2449:         PetscFVRefine(fv, &fvRef[f]);
2450:       } else {
2451:         PetscObjectReference((PetscObject) fv);
2452:         fvRef[f] = fv;
2453:       }
2454:       PetscFVGetDualSpace(fvRef[f], &Q);
2455:       PetscDualSpaceGetDimension(Q, &rNb);
2456:       PetscFVGetNumComponents(fv, &Nc);
2457:     }
2458:     rTotDim += rNb;
2459:   }
2460:   PetscDSGetTotalDimension(cds, &cTotDim);
2461:   PetscMalloc1(rTotDim*cTotDim,&elemMat);
2462:   PetscArrayzero(elemMat, rTotDim*cTotDim);
2463:   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2464:     PetscDualSpace   Qref;
2465:     PetscQuadrature  f;
2466:     const PetscReal *qpoints, *qweights;
2467:     PetscReal       *points;
2468:     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;

2470:     /* Compose points from all dual basis functionals */
2471:     if (feRef[fieldI]) {
2472:       PetscFEGetDualSpace(feRef[fieldI], &Qref);
2473:       PetscFEGetNumComponents(feRef[fieldI], &Nc);
2474:     } else {
2475:       PetscFVGetDualSpace(fvRef[fieldI], &Qref);
2476:       PetscFVGetNumComponents(fvRef[fieldI], &Nc);
2477:     }
2478:     PetscDualSpaceGetDimension(Qref, &fpdim);
2479:     for (i = 0; i < fpdim; ++i) {
2480:       PetscDualSpaceGetFunctional(Qref, i, &f);
2481:       PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);
2482:       npoints += Np;
2483:     }
2484:     PetscMalloc1(npoints*dim,&points);
2485:     for (i = 0, k = 0; i < fpdim; ++i) {
2486:       PetscDualSpaceGetFunctional(Qref, i, &f);
2487:       PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2488:       for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d];
2489:     }

2491:     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
2492:       PetscObject  obj;
2493:       PetscClassId id;
2494:       PetscInt     NcJ = 0, cpdim = 0, j, qNc;

2496:       PetscDSGetDiscretization(cds, fieldJ, &obj);
2497:       PetscObjectGetClassId(obj, &id);
2498:       if (id == PETSCFE_CLASSID) {
2499:         PetscFE           fe = (PetscFE) obj;
2500:         PetscTabulation T  = NULL;

2502:         /* Evaluate basis at points */
2503:         PetscFEGetNumComponents(fe, &NcJ);
2504:         PetscFEGetDimension(fe, &cpdim);
2505:         /* For now, fields only interpolate themselves */
2506:         if (fieldI == fieldJ) {
2507:           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);
2508:           PetscFECreateTabulation(fe, 1, npoints, points, 0, &T);
2509:           for (i = 0, k = 0; i < fpdim; ++i) {
2510:             PetscDualSpaceGetFunctional(Qref, i, &f);
2511:             PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2512:             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);
2513:             for (p = 0; p < Np; ++p, ++k) {
2514:               for (j = 0; j < cpdim; ++j) {
2515:                 /*
2516:                    cTotDim:            Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
2517:                    offsetI, offsetJ:   Offsets into the larger element interpolation matrix for different fields
2518:                    fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
2519:                    qNC, Nc, Ncj, c:    Number of components in this field
2520:                    Np, p:              Number of quad points in the fine grid functional i
2521:                    k:                  i*Np + p, overall point number for the interpolation
2522:                 */
2523:                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += T->T[0][k*cpdim*NcJ+j*Nc+c]*qweights[p*qNc+c];
2524:               }
2525:             }
2526:           }
2527:           PetscTabulationDestroy(&T);
2528:         }
2529:       } else if (id == PETSCFV_CLASSID) {
2530:         PetscFV        fv = (PetscFV) obj;

2532:         /* Evaluate constant function at points */
2533:         PetscFVGetNumComponents(fv, &NcJ);
2534:         cpdim = 1;
2535:         /* For now, fields only interpolate themselves */
2536:         if (fieldI == fieldJ) {
2537:           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);
2538:           for (i = 0, k = 0; i < fpdim; ++i) {
2539:             PetscDualSpaceGetFunctional(Qref, i, &f);
2540:             PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);
2541:             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);
2542:             for (p = 0; p < Np; ++p, ++k) {
2543:               for (j = 0; j < cpdim; ++j) {
2544:                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c];
2545:               }
2546:             }
2547:           }
2548:         }
2549:       }
2550:       offsetJ += cpdim;
2551:     }
2552:     offsetI += fpdim;
2553:     PetscFree(points);
2554:   }
2555:   if (mesh->printFEM > 1) {DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);}
2556:   /* Preallocate matrix */
2557:   {
2558:     Mat          preallocator;
2559:     PetscScalar *vals;
2560:     PetscInt    *cellCIndices, *cellFIndices;
2561:     PetscInt     locRows, locCols, cell;

2563:     MatGetLocalSize(In, &locRows, &locCols);
2564:     MatCreate(PetscObjectComm((PetscObject) In), &preallocator);
2565:     MatSetType(preallocator, MATPREALLOCATOR);
2566:     MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);
2567:     MatSetUp(preallocator);
2568:     PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);
2569:     for (cell = cStart; cell < cEnd; ++cell) {
2570:       if (isRefined) {
2571:         DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);
2572:         MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);
2573:       } else {
2574:         DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES);
2575:       }
2576:     }
2577:     PetscFree3(vals,cellCIndices,cellFIndices);
2578:     MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);
2579:     MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);
2580:     MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);
2581:     MatDestroy(&preallocator);
2582:   }
2583:   /* Fill matrix */
2584:   MatZeroEntries(In);
2585:   for (c = cStart; c < cEnd; ++c) {
2586:     if (isRefined) {
2587:       DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2588:     } else {
2589:       DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);
2590:     }
2591:   }
2592:   for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);}
2593:   PetscFree2(feRef,fvRef);
2594:   PetscFree(elemMat);
2595:   MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2596:   MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2597:   if (mesh->printFEM) {
2598:     PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);
2599:     MatChop(In, 1.0e-10);
2600:     MatView(In, NULL);
2601:   }
2602:   PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2603:   return(0);
2604: }

2606: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2607: {
2608:   SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness");
2609: }

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

2614:   Input Parameters:
2615: + dmf  - The fine mesh
2616: . dmc  - The coarse mesh
2617: - user - The user context

2619:   Output Parameter:
2620: . In  - The interpolation matrix

2622:   Level: developer

2624: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
2625: @*/
2626: PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
2627: {
2628:   DM_Plex       *mesh = (DM_Plex *) dmf->data;
2629:   const char    *name = "Interpolator";
2630:   PetscDS        prob;
2631:   PetscSection   fsection, csection, globalFSection, globalCSection;
2632:   PetscHSetIJ    ht;
2633:   PetscLayout    rLayout;
2634:   PetscInt      *dnz, *onz;
2635:   PetscInt       locRows, rStart, rEnd;
2636:   PetscReal     *x, *v0, *J, *invJ, detJ;
2637:   PetscReal     *v0c, *Jc, *invJc, detJc;
2638:   PetscScalar   *elemMat;
2639:   PetscInt       dim, Nf, field, totDim, cStart, cEnd, cell, ccell;

2643:   PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2644:   DMGetCoordinateDim(dmc, &dim);
2645:   DMGetDS(dmc, &prob);
2646:   PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2647:   PetscDSGetNumFields(prob, &Nf);
2648:   PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2649:   PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2650:   DMGetLocalSection(dmf, &fsection);
2651:   DMGetGlobalSection(dmf, &globalFSection);
2652:   DMGetLocalSection(dmc, &csection);
2653:   DMGetGlobalSection(dmc, &globalCSection);
2654:   DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2655:   PetscDSGetTotalDimension(prob, &totDim);
2656:   PetscMalloc1(totDim, &elemMat);

2658:   MatGetLocalSize(In, &locRows, NULL);
2659:   PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);
2660:   PetscLayoutSetLocalSize(rLayout, locRows);
2661:   PetscLayoutSetBlockSize(rLayout, 1);
2662:   PetscLayoutSetUp(rLayout);
2663:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2664:   PetscLayoutDestroy(&rLayout);
2665:   PetscCalloc2(locRows,&dnz,locRows,&onz);
2666:   PetscHSetIJCreate(&ht);
2667:   for (field = 0; field < Nf; ++field) {
2668:     PetscObject      obj;
2669:     PetscClassId     id;
2670:     PetscDualSpace   Q = NULL;
2671:     PetscQuadrature  f;
2672:     const PetscReal *qpoints;
2673:     PetscInt         Nc, Np, fpdim, i, d;

2675:     PetscDSGetDiscretization(prob, field, &obj);
2676:     PetscObjectGetClassId(obj, &id);
2677:     if (id == PETSCFE_CLASSID) {
2678:       PetscFE fe = (PetscFE) obj;

2680:       PetscFEGetDualSpace(fe, &Q);
2681:       PetscFEGetNumComponents(fe, &Nc);
2682:     } else if (id == PETSCFV_CLASSID) {
2683:       PetscFV fv = (PetscFV) obj;

2685:       PetscFVGetDualSpace(fv, &Q);
2686:       Nc   = 1;
2687:     }
2688:     PetscDualSpaceGetDimension(Q, &fpdim);
2689:     /* For each fine grid cell */
2690:     for (cell = cStart; cell < cEnd; ++cell) {
2691:       PetscInt *findices,   *cindices;
2692:       PetscInt  numFIndices, numCIndices;

2694:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2695:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2696:       if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim);
2697:       for (i = 0; i < fpdim; ++i) {
2698:         Vec             pointVec;
2699:         PetscScalar    *pV;
2700:         PetscSF         coarseCellSF = NULL;
2701:         const PetscSFNode *coarseCells;
2702:         PetscInt        numCoarseCells, q, c;

2704:         /* Get points from the dual basis functional quadrature */
2705:         PetscDualSpaceGetFunctional(Q, i, &f);
2706:         PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2707:         VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2708:         VecSetBlockSize(pointVec, dim);
2709:         VecGetArray(pointVec, &pV);
2710:         for (q = 0; q < Np; ++q) {
2711:           const PetscReal xi0[3] = {-1., -1., -1.};

2713:           /* Transform point to real space */
2714:           CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2715:           for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2716:         }
2717:         VecRestoreArray(pointVec, &pV);
2718:         /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2719:         /* OPT: Pack all quad points from fine cell */
2720:         DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2721:         PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2722:         /* Update preallocation info */
2723:         PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2724:         if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2725:         {
2726:           PetscHashIJKey key;
2727:           PetscBool      missing;

2729:           key.i = findices[i];
2730:           if (key.i >= 0) {
2731:             /* Get indices for coarse elements */
2732:             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2733:               DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2734:               for (c = 0; c < numCIndices; ++c) {
2735:                 key.j = cindices[c];
2736:                 if (key.j < 0) continue;
2737:                 PetscHSetIJQueryAdd(ht, key, &missing);
2738:                 if (missing) {
2739:                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2740:                   else                                     ++onz[key.i-rStart];
2741:                 }
2742:               }
2743:               DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2744:             }
2745:           }
2746:         }
2747:         PetscSFDestroy(&coarseCellSF);
2748:         VecDestroy(&pointVec);
2749:       }
2750:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2751:     }
2752:   }
2753:   PetscHSetIJDestroy(&ht);
2754:   MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);
2755:   MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2756:   PetscFree2(dnz,onz);
2757:   for (field = 0; field < Nf; ++field) {
2758:     PetscObject       obj;
2759:     PetscClassId      id;
2760:     PetscDualSpace    Q = NULL;
2761:     PetscTabulation T = NULL;
2762:     PetscQuadrature   f;
2763:     const PetscReal  *qpoints, *qweights;
2764:     PetscInt          Nc, qNc, Np, fpdim, i, d;

2766:     PetscDSGetDiscretization(prob, field, &obj);
2767:     PetscObjectGetClassId(obj, &id);
2768:     if (id == PETSCFE_CLASSID) {
2769:       PetscFE fe = (PetscFE) obj;

2771:       PetscFEGetDualSpace(fe, &Q);
2772:       PetscFEGetNumComponents(fe, &Nc);
2773:       PetscFECreateTabulation(fe, 1, 1, x, 0, &T);
2774:     } else if (id == PETSCFV_CLASSID) {
2775:       PetscFV fv = (PetscFV) obj;

2777:       PetscFVGetDualSpace(fv, &Q);
2778:       Nc   = 1;
2779:     } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field);
2780:     PetscDualSpaceGetDimension(Q, &fpdim);
2781:     /* For each fine grid cell */
2782:     for (cell = cStart; cell < cEnd; ++cell) {
2783:       PetscInt *findices,   *cindices;
2784:       PetscInt  numFIndices, numCIndices;

2786:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2787:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2788:       if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim);
2789:       for (i = 0; i < fpdim; ++i) {
2790:         Vec             pointVec;
2791:         PetscScalar    *pV;
2792:         PetscSF         coarseCellSF = NULL;
2793:         const PetscSFNode *coarseCells;
2794:         PetscInt        numCoarseCells, cpdim, q, c, j;

2796:         /* Get points from the dual basis functional quadrature */
2797:         PetscDualSpaceGetFunctional(Q, i, &f);
2798:         PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);
2799:         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);
2800:         VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2801:         VecSetBlockSize(pointVec, dim);
2802:         VecGetArray(pointVec, &pV);
2803:         for (q = 0; q < Np; ++q) {
2804:           const PetscReal xi0[3] = {-1., -1., -1.};

2806:           /* Transform point to real space */
2807:           CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2808:           for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2809:         }
2810:         VecRestoreArray(pointVec, &pV);
2811:         /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2812:         /* OPT: Read this out from preallocation information */
2813:         DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2814:         /* Update preallocation info */
2815:         PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2816:         if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2817:         VecGetArray(pointVec, &pV);
2818:         for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2819:           PetscReal pVReal[3];
2820:           const PetscReal xi0[3] = {-1., -1., -1.};

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

2828:           if (id == PETSCFE_CLASSID) {
2829:             PetscFE fe = (PetscFE) obj;

2831:             /* Evaluate coarse basis on contained point */
2832:             PetscFEGetDimension(fe, &cpdim);
2833:             PetscFEComputeTabulation(fe, 1, x, 0, T);
2834:             PetscArrayzero(elemMat, cpdim);
2835:             /* Get elemMat entries by multiplying by weight */
2836:             for (j = 0; j < cpdim; ++j) {
2837:               for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j*Nc + c]*qweights[ccell*qNc + c];
2838:             }
2839:           } else {
2840:             cpdim = 1;
2841:             for (j = 0; j < cpdim; ++j) {
2842:               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c];
2843:             }
2844:           }
2845:           /* Update interpolator */
2846:           if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
2847:           if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
2848:           MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);
2849:           DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2850:         }
2851:         VecRestoreArray(pointVec, &pV);
2852:         PetscSFDestroy(&coarseCellSF);
2853:         VecDestroy(&pointVec);
2854:       }
2855:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2856:     }
2857:     if (id == PETSCFE_CLASSID) {PetscTabulationDestroy(&T);}
2858:   }
2859:   PetscFree3(v0,J,invJ);
2860:   PetscFree3(v0c,Jc,invJc);
2861:   PetscFree(elemMat);
2862:   MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);
2863:   MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);
2864:   PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2865:   return(0);
2866: }

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

2871:   Input Parameters:
2872: + dmf  - The fine mesh
2873: . dmc  - The coarse mesh
2874: - user - The user context

2876:   Output Parameter:
2877: . mass  - The mass matrix

2879:   Level: developer

2881: .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM()
2882: @*/
2883: PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2884: {
2885:   DM_Plex       *mesh = (DM_Plex *) dmf->data;
2886:   const char    *name = "Mass Matrix";
2887:   PetscDS        prob;
2888:   PetscSection   fsection, csection, globalFSection, globalCSection;
2889:   PetscHSetIJ    ht;
2890:   PetscLayout    rLayout;
2891:   PetscInt      *dnz, *onz;
2892:   PetscInt       locRows, rStart, rEnd;
2893:   PetscReal     *x, *v0, *J, *invJ, detJ;
2894:   PetscReal     *v0c, *Jc, *invJc, detJc;
2895:   PetscScalar   *elemMat;
2896:   PetscInt       dim, Nf, field, totDim, cStart, cEnd, cell, ccell;

2900:   DMGetCoordinateDim(dmc, &dim);
2901:   DMGetDS(dmc, &prob);
2902:   PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2903:   PetscDSGetNumFields(prob, &Nf);
2904:   PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2905:   PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2906:   DMGetLocalSection(dmf, &fsection);
2907:   DMGetGlobalSection(dmf, &globalFSection);
2908:   DMGetLocalSection(dmc, &csection);
2909:   DMGetGlobalSection(dmc, &globalCSection);
2910:   DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2911:   PetscDSGetTotalDimension(prob, &totDim);
2912:   PetscMalloc1(totDim, &elemMat);

2914:   MatGetLocalSize(mass, &locRows, NULL);
2915:   PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);
2916:   PetscLayoutSetLocalSize(rLayout, locRows);
2917:   PetscLayoutSetBlockSize(rLayout, 1);
2918:   PetscLayoutSetUp(rLayout);
2919:   PetscLayoutGetRange(rLayout, &rStart, &rEnd);
2920:   PetscLayoutDestroy(&rLayout);
2921:   PetscCalloc2(locRows,&dnz,locRows,&onz);
2922:   PetscHSetIJCreate(&ht);
2923:   for (field = 0; field < Nf; ++field) {
2924:     PetscObject      obj;
2925:     PetscClassId     id;
2926:     PetscQuadrature  quad;
2927:     const PetscReal *qpoints;
2928:     PetscInt         Nq, Nc, i, d;

2930:     PetscDSGetDiscretization(prob, field, &obj);
2931:     PetscObjectGetClassId(obj, &id);
2932:     if (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, &quad);}
2933:     else                       {PetscFVGetQuadrature((PetscFV) obj, &quad);}
2934:     PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);
2935:     /* For each fine grid cell */
2936:     for (cell = cStart; cell < cEnd; ++cell) {
2937:       Vec                pointVec;
2938:       PetscScalar       *pV;
2939:       PetscSF            coarseCellSF = NULL;
2940:       const PetscSFNode *coarseCells;
2941:       PetscInt           numCoarseCells, q, c;
2942:       PetscInt          *findices,   *cindices;
2943:       PetscInt           numFIndices, numCIndices;

2945:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2946:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2947:       /* Get points from the quadrature */
2948:       VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2949:       VecSetBlockSize(pointVec, dim);
2950:       VecGetArray(pointVec, &pV);
2951:       for (q = 0; q < Nq; ++q) {
2952:         const PetscReal xi0[3] = {-1., -1., -1.};

2954:         /* Transform point to real space */
2955:         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
2956:         for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
2957:       }
2958:       VecRestoreArray(pointVec, &pV);
2959:       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
2960:       DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
2961:       PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");
2962:       /* Update preallocation info */
2963:       PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
2964:       if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
2965:       {
2966:         PetscHashIJKey key;
2967:         PetscBool      missing;

2969:         for (i = 0; i < numFIndices; ++i) {
2970:           key.i = findices[i];
2971:           if (key.i >= 0) {
2972:             /* Get indices for coarse elements */
2973:             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2974:               DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2975:               for (c = 0; c < numCIndices; ++c) {
2976:                 key.j = cindices[c];
2977:                 if (key.j < 0) continue;
2978:                 PetscHSetIJQueryAdd(ht, key, &missing);
2979:                 if (missing) {
2980:                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart];
2981:                   else                                     ++onz[key.i-rStart];
2982:                 }
2983:               }
2984:               DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
2985:             }
2986:           }
2987:         }
2988:       }
2989:       PetscSFDestroy(&coarseCellSF);
2990:       VecDestroy(&pointVec);
2991:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2992:     }
2993:   }
2994:   PetscHSetIJDestroy(&ht);
2995:   MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);
2996:   MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);
2997:   PetscFree2(dnz,onz);
2998:   for (field = 0; field < Nf; ++field) {
2999:     PetscObject       obj;
3000:     PetscClassId      id;
3001:     PetscTabulation T, Tfine;
3002:     PetscQuadrature   quad;
3003:     const PetscReal  *qpoints, *qweights;
3004:     PetscInt          Nq, Nc, i, d;

3006:     PetscDSGetDiscretization(prob, field, &obj);
3007:     PetscObjectGetClassId(obj, &id);
3008:     if (id == PETSCFE_CLASSID) {
3009:       PetscFEGetQuadrature((PetscFE) obj, &quad);
3010:       PetscFEGetCellTabulation((PetscFE) obj, &Tfine);
3011:       PetscFECreateTabulation((PetscFE) obj, 1, 1, x, 0, &T);
3012:     } else {
3013:       PetscFVGetQuadrature((PetscFV) obj, &quad);
3014:     }
3015:     PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);
3016:     /* For each fine grid cell */
3017:     for (cell = cStart; cell < cEnd; ++cell) {
3018:       Vec                pointVec;
3019:       PetscScalar       *pV;
3020:       PetscSF            coarseCellSF = NULL;
3021:       const PetscSFNode *coarseCells;
3022:       PetscInt           numCoarseCells, cpdim, q, c, j;
3023:       PetscInt          *findices,   *cindices;
3024:       PetscInt           numFIndices, numCIndices;

3026:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3027:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
3028:       /* Get points from the quadrature */
3029:       VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
3030:       VecSetBlockSize(pointVec, dim);
3031:       VecGetArray(pointVec, &pV);
3032:       for (q = 0; q < Nq; ++q) {
3033:         const PetscReal xi0[3] = {-1., -1., -1.};

3035:         /* Transform point to real space */
3036:         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x);
3037:         for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d];
3038:       }
3039:       VecRestoreArray(pointVec, &pV);
3040:       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
3041:       DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);
3042:       /* Update matrix */
3043:       PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);
3044:       if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located");
3045:       VecGetArray(pointVec, &pV);
3046:       for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3047:         PetscReal pVReal[3];
3048:         const PetscReal xi0[3] = {-1., -1., -1.};


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

3057:         if (id == PETSCFE_CLASSID) {
3058:           PetscFE fe = (PetscFE) obj;

3060:           /* Evaluate coarse basis on contained point */
3061:           PetscFEGetDimension(fe, &cpdim);
3062:           PetscFEComputeTabulation(fe, 1, x, 0, T);
3063:           /* Get elemMat entries by multiplying by weight */
3064:           for (i = 0; i < numFIndices; ++i) {
3065:             PetscArrayzero(elemMat, cpdim);
3066:             for (j = 0; j < cpdim; ++j) {
3067:               for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j*Nc + c]*Tfine->T[0][(ccell*numFIndices + i)*Nc + c]*qweights[ccell*Nc + c]*detJ;
3068:             }
3069:             /* Update interpolator */
3070:             if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
3071:             if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
3072:             MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3073:           }
3074:         } else {
3075:           cpdim = 1;
3076:           for (i = 0; i < numFIndices; ++i) {
3077:             PetscArrayzero(elemMat, cpdim);
3078:             for (j = 0; j < cpdim; ++j) {
3079:               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ;
3080:             }
3081:             /* Update interpolator */
3082:             if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);}
3083:             PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices);
3084:             if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim);
3085:             MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);
3086:           }
3087:         }
3088:         DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);
3089:       }
3090:       VecRestoreArray(pointVec, &pV);
3091:       PetscSFDestroy(&coarseCellSF);
3092:       VecDestroy(&pointVec);
3093:       DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3094:     }
3095:     if (id == PETSCFE_CLASSID) {PetscTabulationDestroy(&T);}
3096:   }
3097:   PetscFree3(v0,J,invJ);
3098:   PetscFree3(v0c,Jc,invJc);
3099:   PetscFree(elemMat);
3100:   MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);
3101:   MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);
3102:   return(0);
3103: }

3105: /*@
3106:   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns

3108:   Input Parameters:
3109: + dmc  - The coarse mesh
3110: - dmf  - The fine mesh
3111: - user - The user context

3113:   Output Parameter:
3114: . sc   - The mapping

3116:   Level: developer

3118: .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM()
3119: @*/
3120: PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
3121: {
3122:   PetscDS        prob;
3123:   PetscFE       *feRef;
3124:   PetscFV       *fvRef;
3125:   Vec            fv, cv;
3126:   IS             fis, cis;
3127:   PetscSection   fsection, fglobalSection, csection, cglobalSection;
3128:   PetscInt      *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3129:   PetscInt       cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
3130:   PetscBool     *needAvg;

3134:   PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3135:   DMGetDimension(dmf, &dim);
3136:   DMGetLocalSection(dmf, &fsection);
3137:   DMGetGlobalSection(dmf, &fglobalSection);
3138:   DMGetLocalSection(dmc, &csection);
3139:   DMGetGlobalSection(dmc, &cglobalSection);
3140:   PetscSectionGetNumFields(fsection, &Nf);
3141:   DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
3142:   DMGetDS(dmc, &prob);
3143:   PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);
3144:   for (f = 0; f < Nf; ++f) {
3145:     PetscObject  obj;
3146:     PetscClassId id;
3147:     PetscInt     fNb = 0, Nc = 0;

3149:     PetscDSGetDiscretization(prob, f, &obj);
3150:     PetscObjectGetClassId(obj, &id);
3151:     if (id == PETSCFE_CLASSID) {
3152:       PetscFE    fe = (PetscFE) obj;
3153:       PetscSpace sp;
3154:       PetscInt   maxDegree;

3156:       PetscFERefine(fe, &feRef[f]);
3157:       PetscFEGetDimension(feRef[f], &fNb);
3158:       PetscFEGetNumComponents(fe, &Nc);
3159:       PetscFEGetBasisSpace(fe, &sp);
3160:       PetscSpaceGetDegree(sp, NULL, &maxDegree);
3161:       if (!maxDegree) needAvg[f] = PETSC_TRUE;
3162:     } else if (id == PETSCFV_CLASSID) {
3163:       PetscFV        fv = (PetscFV) obj;
3164:       PetscDualSpace Q;

3166:       PetscFVRefine(fv, &fvRef[f]);
3167:       PetscFVGetDualSpace(fvRef[f], &Q);
3168:       PetscDualSpaceGetDimension(Q, &fNb);
3169:       PetscFVGetNumComponents(fv, &Nc);
3170:       needAvg[f] = PETSC_TRUE;
3171:     }
3172:     fTotDim += fNb;
3173:   }
3174:   PetscDSGetTotalDimension(prob, &cTotDim);
3175:   PetscMalloc1(cTotDim,&cmap);
3176:   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
3177:     PetscFE        feC;
3178:     PetscFV        fvC;
3179:     PetscDualSpace QF, QC;
3180:     PetscInt       order = -1, NcF, NcC, fpdim, cpdim;

3182:     if (feRef[field]) {
3183:       PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);
3184:       PetscFEGetNumComponents(feC, &NcC);
3185:       PetscFEGetNumComponents(feRef[field], &NcF);
3186:       PetscFEGetDualSpace(feRef[field], &QF);
3187:       PetscDualSpaceGetOrder(QF, &order);
3188:       PetscDualSpaceGetDimension(QF, &fpdim);
3189:       PetscFEGetDualSpace(feC, &QC);
3190:       PetscDualSpaceGetDimension(QC, &cpdim);
3191:     } else {
3192:       PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);
3193:       PetscFVGetNumComponents(fvC, &NcC);
3194:       PetscFVGetNumComponents(fvRef[field], &NcF);
3195:       PetscFVGetDualSpace(fvRef[field], &QF);
3196:       PetscDualSpaceGetDimension(QF, &fpdim);
3197:       PetscFVGetDualSpace(fvC, &QC);
3198:       PetscDualSpaceGetDimension(QC, &cpdim);
3199:     }
3200:     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);
3201:     for (c = 0; c < cpdim; ++c) {
3202:       PetscQuadrature  cfunc;
3203:       const PetscReal *cqpoints, *cqweights;
3204:       PetscInt         NqcC, NpC;
3205:       PetscBool        found = PETSC_FALSE;

3207:       PetscDualSpaceGetFunctional(QC, c, &cfunc);
3208:       PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
3209:       if (NqcC != NcC) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components %D", NqcC, NcC);
3210:       if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
3211:       for (f = 0; f < fpdim; ++f) {
3212:         PetscQuadrature  ffunc;
3213:         const PetscReal *fqpoints, *fqweights;
3214:         PetscReal        sum = 0.0;
3215:         PetscInt         NqcF, NpF;

3217:         PetscDualSpaceGetFunctional(QF, f, &ffunc);
3218:         PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
3219:         if (NqcF != NcF) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components %D", NqcF, NcF);
3220:         if (NpC != NpF) continue;
3221:         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
3222:         if (sum > 1.0e-9) continue;
3223:         for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]);
3224:         if (sum < 1.0e-9) continue;
3225:         cmap[offsetC+c] = offsetF+f;
3226:         found = PETSC_TRUE;
3227:         break;
3228:       }
3229:       if (!found) {
3230:         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3231:         if (fvRef[field] || (feRef[field] && order == 0)) {
3232:           cmap[offsetC+c] = offsetF+0;
3233:         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
3234:       }
3235:     }
3236:     offsetC += cpdim;
3237:     offsetF += fpdim;
3238:   }
3239:   for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);PetscFVDestroy(&fvRef[f]);}
3240:   PetscFree3(feRef,fvRef,needAvg);

3242:   DMGetGlobalVector(dmf, &fv);
3243:   DMGetGlobalVector(dmc, &cv);
3244:   VecGetOwnershipRange(cv, &startC, &endC);
3245:   PetscSectionGetConstrainedStorageSize(cglobalSection, &m);
3246:   PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);
3247:   PetscMalloc1(m,&cindices);
3248:   PetscMalloc1(m,&findices);
3249:   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
3250:   for (c = cStart; c < cEnd; ++c) {
3251:     DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);
3252:     for (d = 0; d < cTotDim; ++d) {
3253:       if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
3254:       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]]);
3255:       cindices[cellCIndices[d]-startC] = cellCIndices[d];
3256:       findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]];
3257:     }
3258:   }
3259:   PetscFree(cmap);
3260:   PetscFree2(cellCIndices,cellFIndices);

3262:   ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
3263:   ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
3264:   VecScatterCreate(cv, cis, fv, fis, sc);
3265:   ISDestroy(&cis);
3266:   ISDestroy(&fis);
3267:   DMRestoreGlobalVector(dmf, &fv);
3268:   DMRestoreGlobalVector(dmc, &cv);
3269:   PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3270:   return(0);
3271: }

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

3276:   Input Parameters:
3277: + dm     - The DM
3278: . cellIS - The cells to include
3279: . locX   - A local vector with the solution fields
3280: . locX_t - A local vector with solution field time derivatives, or NULL
3281: - locA   - A local vector with auxiliary fields, or NULL

3283:   Output Parameters:
3284: + u   - The field coefficients
3285: . u_t - The fields derivative coefficients
3286: - a   - The auxiliary field coefficients

3288:   Level: developer

3290: .seealso: DMPlexGetFaceFields()
3291: @*/
3292: PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3293: {
3294:   DM              plex, plexA = NULL;
3295:   DMEnclosureType encAux;
3296:   PetscSection    section, sectionAux;
3297:   PetscDS         prob;
3298:   const PetscInt *cells;
3299:   PetscInt        cStart, cEnd, numCells, totDim, totDimAux, c;
3300:   PetscErrorCode  ierr;

3310:   DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
3311:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3312:   DMGetLocalSection(dm, &section);
3313:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
3314:   PetscDSGetTotalDimension(prob, &totDim);
3315:   if (locA) {
3316:     DM      dmAux;
3317:     PetscDS probAux;

3319:     VecGetDM(locA, &dmAux);
3320:     DMGetEnclosureRelation(dmAux, dm, &encAux);
3321:     DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
3322:     DMGetLocalSection(dmAux, &sectionAux);
3323:     DMGetDS(dmAux, &probAux);
3324:     PetscDSGetTotalDimension(probAux, &totDimAux);
3325:   }
3326:   numCells = cEnd - cStart;
3327:   DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);
3328:   if (locX_t) {DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);} else {*u_t = NULL;}
3329:   if (locA)   {DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);} else {*a = NULL;}
3330:   for (c = cStart; c < cEnd; ++c) {
3331:     const PetscInt cell = cells ? cells[c] : c;
3332:     const PetscInt cind = c - cStart;
3333:     PetscScalar   *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
3334:     PetscInt       i;

3336:     DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);
3337:     for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i];
3338:     DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);
3339:     if (locX_t) {
3340:       DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);
3341:       for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i];
3342:       DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);
3343:     }
3344:     if (locA) {
3345:       PetscInt subcell;
3346:       DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell);
3347:       DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3348:       for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i];
3349:       DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);
3350:     }
3351:   }
3352:   DMDestroy(&plex);
3353:   if (locA) {DMDestroy(&plexA);}
3354:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3355:   return(0);
3356: }

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

3361:   Input Parameters:
3362: + dm     - The DM
3363: . cellIS - The cells to include
3364: . locX   - A local vector with the solution fields
3365: . locX_t - A local vector with solution field time derivatives, or NULL
3366: - locA   - A local vector with auxiliary fields, or NULL

3368:   Output Parameters:
3369: + u   - The field coefficients
3370: . u_t - The fields derivative coefficients
3371: - a   - The auxiliary field coefficients

3373:   Level: developer

3375: .seealso: DMPlexGetFaceFields()
3376: @*/
3377: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3378: {

3382:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
3383:   if (locX_t) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);}
3384:   if (locA)   {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);}
3385:   return(0);
3386: }

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

3391:   Input Parameters:
3392: + dm     - The DM
3393: . fStart - The first face to include
3394: . fEnd   - The first face to exclude
3395: . locX   - A local vector with the solution fields
3396: . locX_t - A local vector with solution field time derivatives, or NULL
3397: . faceGeometry - A local vector with face geometry
3398: . cellGeometry - A local vector with cell geometry
3399: - locaGrad - A local vector with field gradients, or NULL

3401:   Output Parameters:
3402: + Nface - The number of faces with field values
3403: . uL - The field values at the left side of the face
3404: - uR - The field values at the right side of the face

3406:   Level: developer

3408: .seealso: DMPlexGetCellFields()
3409: @*/
3410: 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)
3411: {
3412:   DM                 dmFace, dmCell, dmGrad = NULL;
3413:   PetscSection       section;
3414:   PetscDS            prob;
3415:   DMLabel            ghostLabel;
3416:   const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
3417:   PetscBool         *isFE;
3418:   PetscInt           dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
3419:   PetscErrorCode     ierr;

3430:   DMGetDimension(dm, &dim);
3431:   DMGetDS(dm, &prob);
3432:   DMGetLocalSection(dm, &section);
3433:   PetscDSGetNumFields(prob, &Nf);
3434:   PetscDSGetTotalComponents(prob, &Nc);
3435:   PetscMalloc1(Nf, &isFE);
3436:   for (f = 0; f < Nf; ++f) {
3437:     PetscObject  obj;
3438:     PetscClassId id;

3440:     PetscDSGetDiscretization(prob, f, &obj);
3441:     PetscObjectGetClassId(obj, &id);
3442:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3443:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3444:     else                            {isFE[f] = PETSC_FALSE;}
3445:   }
3446:   DMGetLabel(dm, "ghost", &ghostLabel);
3447:   VecGetArrayRead(locX, &x);
3448:   VecGetDM(faceGeometry, &dmFace);
3449:   VecGetArrayRead(faceGeometry, &facegeom);
3450:   VecGetDM(cellGeometry, &dmCell);
3451:   VecGetArrayRead(cellGeometry, &cellgeom);
3452:   if (locGrad) {
3453:     VecGetDM(locGrad, &dmGrad);
3454:     VecGetArrayRead(locGrad, &lgrad);
3455:   }
3456:   DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);
3457:   DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);
3458:   /* Right now just eat the extra work for FE (could make a cell loop) */
3459:   for (face = fStart, iface = 0; face < fEnd; ++face) {
3460:     const PetscInt        *cells;
3461:     PetscFVFaceGeom       *fg;
3462:     PetscFVCellGeom       *cgL, *cgR;
3463:     PetscScalar           *xL, *xR, *gL, *gR;
3464:     PetscScalar           *uLl = *uL, *uRl = *uR;
3465:     PetscInt               ghost, nsupp, nchild;

3467:     DMLabelGetValue(ghostLabel, face, &ghost);
3468:     DMPlexGetSupportSize(dm, face, &nsupp);
3469:     DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3470:     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3471:     DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3472:     DMPlexGetSupport(dm, face, &cells);
3473:     DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3474:     DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3475:     for (f = 0; f < Nf; ++f) {
3476:       PetscInt off;

3478:       PetscDSGetComponentOffset(prob, f, &off);
3479:       if (isFE[f]) {
3480:         const PetscInt *cone;
3481:         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;

3483:         xL = xR = NULL;
3484:         PetscSectionGetFieldComponents(section, f, &comp);
3485:         DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3486:         DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3487:         DMPlexGetCone(dm, cells[0], &cone);
3488:         DMPlexGetConeSize(dm, cells[0], &coneSizeL);
3489:         for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break;
3490:         DMPlexGetCone(dm, cells[1], &cone);
3491:         DMPlexGetConeSize(dm, cells[1], &coneSizeR);
3492:         for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break;
3493:         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]);
3494:         /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
3495:         /* TODO: this is a hack that might not be right for nonconforming */
3496:         if (faceLocL < coneSizeL) {
3497:           PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);
3498:           if (rdof == ldof && faceLocR < coneSizeR) {PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);}
3499:           else              {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];}
3500:         }
3501:         else {
3502:           PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);
3503:           PetscSectionGetFieldComponents(section, f, &comp);
3504:           for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d];
3505:         }
3506:         DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3507:         DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3508:       } else {
3509:         PetscFV  fv;
3510:         PetscInt numComp, c;

3512:         PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
3513:         PetscFVGetNumComponents(fv, &numComp);
3514:         DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
3515:         DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
3516:         if (dmGrad) {
3517:           PetscReal dxL[3], dxR[3];

3519:           DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
3520:           DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
3521:           DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
3522:           DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
3523:           for (c = 0; c < numComp; ++c) {
3524:             uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL);
3525:             uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR);
3526:           }
3527:         } else {
3528:           for (c = 0; c < numComp; ++c) {
3529:             uLl[iface*Nc+off+c] = xL[c];
3530:             uRl[iface*Nc+off+c] = xR[c];
3531:           }
3532:         }
3533:       }
3534:     }
3535:     ++iface;
3536:   }
3537:   *Nface = iface;
3538:   VecRestoreArrayRead(locX, &x);
3539:   VecRestoreArrayRead(faceGeometry, &facegeom);
3540:   VecRestoreArrayRead(cellGeometry, &cellgeom);
3541:   if (locGrad) {
3542:     VecRestoreArrayRead(locGrad, &lgrad);
3543:   }
3544:   PetscFree(isFE);
3545:   return(0);
3546: }

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

3551:   Input Parameters:
3552: + dm     - The DM
3553: . fStart - The first face to include
3554: . fEnd   - The first face to exclude
3555: . locX   - A local vector with the solution fields
3556: . locX_t - A local vector with solution field time derivatives, or NULL
3557: . faceGeometry - A local vector with face geometry
3558: . cellGeometry - A local vector with cell geometry
3559: - locaGrad - A local vector with field gradients, or NULL

3561:   Output Parameters:
3562: + Nface - The number of faces with field values
3563: . uL - The field values at the left side of the face
3564: - uR - The field values at the right side of the face

3566:   Level: developer

3568: .seealso: DMPlexGetFaceFields()
3569: @*/
3570: 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)
3571: {

3575:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
3576:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
3577:   return(0);
3578: }

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

3583:   Input Parameters:
3584: + dm     - The DM
3585: . fStart - The first face to include
3586: . fEnd   - The first face to exclude
3587: . faceGeometry - A local vector with face geometry
3588: - cellGeometry - A local vector with cell geometry

3590:   Output Parameters:
3591: + Nface - The number of faces with field values
3592: . fgeom - The extract the face centroid and normal
3593: - vol   - The cell volume

3595:   Level: developer

3597: .seealso: DMPlexGetCellFields()
3598: @*/
3599: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3600: {
3601:   DM                 dmFace, dmCell;
3602:   DMLabel            ghostLabel;
3603:   const PetscScalar *facegeom, *cellgeom;
3604:   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
3605:   PetscErrorCode     ierr;

3613:   DMGetDimension(dm, &dim);
3614:   DMGetLabel(dm, "ghost", &ghostLabel);
3615:   VecGetDM(faceGeometry, &dmFace);
3616:   VecGetArrayRead(faceGeometry, &facegeom);
3617:   VecGetDM(cellGeometry, &dmCell);
3618:   VecGetArrayRead(cellGeometry, &cellgeom);
3619:   PetscMalloc1(numFaces, fgeom);
3620:   DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);
3621:   for (face = fStart, iface = 0; face < fEnd; ++face) {
3622:     const PetscInt        *cells;
3623:     PetscFVFaceGeom       *fg;
3624:     PetscFVCellGeom       *cgL, *cgR;
3625:     PetscFVFaceGeom       *fgeoml = *fgeom;
3626:     PetscReal             *voll   = *vol;
3627:     PetscInt               ghost, d, nchild, nsupp;

3629:     DMLabelGetValue(ghostLabel, face, &ghost);
3630:     DMPlexGetSupportSize(dm, face, &nsupp);
3631:     DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3632:     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3633:     DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3634:     DMPlexGetSupport(dm, face, &cells);
3635:     DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3636:     DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3637:     for (d = 0; d < dim; ++d) {
3638:       fgeoml[iface].centroid[d] = fg->centroid[d];
3639:       fgeoml[iface].normal[d]   = fg->normal[d];
3640:     }
3641:     voll[iface*2+0] = cgL->volume;
3642:     voll[iface*2+1] = cgR->volume;
3643:     ++iface;
3644:   }
3645:   *Nface = iface;
3646:   VecRestoreArrayRead(faceGeometry, &facegeom);
3647:   VecRestoreArrayRead(cellGeometry, &cellgeom);
3648:   return(0);
3649: }

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

3654:   Input Parameters:
3655: + dm     - The DM
3656: . fStart - The first face to include
3657: . fEnd   - The first face to exclude
3658: . faceGeometry - A local vector with face geometry
3659: - cellGeometry - A local vector with cell geometry

3661:   Output Parameters:
3662: + Nface - The number of faces with field values
3663: . fgeom - The extract the face centroid and normal
3664: - vol   - The cell volume

3666:   Level: developer

3668: .seealso: DMPlexGetFaceFields()
3669: @*/
3670: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3671: {

3675:   PetscFree(*fgeom);
3676:   DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3677:   return(0);
3678: }

3680: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3681: {
3682:   char            composeStr[33] = {0};
3683:   PetscObjectId   id;
3684:   PetscContainer  container;
3685:   PetscErrorCode  ierr;

3688:   PetscObjectGetId((PetscObject)quad,&id);
3689:   PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);
3690:   PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
3691:   if (container) {
3692:     PetscContainerGetPointer(container, (void **) geom);
3693:   } else {
3694:     DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3695:     PetscContainerCreate(PETSC_COMM_SELF,&container);
3696:     PetscContainerSetPointer(container, (void *) *geom);
3697:     PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3698:     PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
3699:     PetscContainerDestroy(&container);
3700:   }
3701:   return(0);
3702: }

3704: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3705: {
3707:   *geom = NULL;
3708:   return(0);
3709: }

3711: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3712: {
3713:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
3714:   const char      *name       = "Residual";
3715:   DM               dmAux      = NULL;
3716:   DMLabel          ghostLabel = NULL;
3717:   PetscDS          prob       = NULL;
3718:   PetscDS          probAux    = NULL;
3719:   PetscBool        useFEM     = PETSC_FALSE;
3720:   PetscBool        isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3721:   DMField          coordField = NULL;
3722:   Vec              locA;
3723:   PetscScalar     *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3724:   IS               chunkIS;
3725:   const PetscInt  *cells;
3726:   PetscInt         cStart, cEnd, numCells;
3727:   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3728:   PetscInt         maxDegree = PETSC_MAX_INT;
3729:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
3730:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
3731:   PetscErrorCode   ierr;

3734:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
3735:   /* FEM+FVM */
3736:   /* 1: Get sizes from dm and dmAux */
3737:   DMGetLabel(dm, "ghost", &ghostLabel);
3738:   DMGetDS(dm, &prob);
3739:   PetscDSGetNumFields(prob, &Nf);
3740:   PetscDSGetTotalDimension(prob, &totDim);
3741:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
3742:   if (locA) {
3743:     VecGetDM(locA, &dmAux);
3744:     DMGetDS(dmAux, &probAux);
3745:     PetscDSGetTotalDimension(probAux, &totDimAux);
3746:   }
3747:   /* 2: Get geometric data */
3748:   for (f = 0; f < Nf; ++f) {
3749:     PetscObject  obj;
3750:     PetscClassId id;
3751:     PetscBool    fimp;

3753:     PetscDSGetImplicit(prob, f, &fimp);
3754:     if (isImplicit != fimp) continue;
3755:     PetscDSGetDiscretization(prob, f, &obj);
3756:     PetscObjectGetClassId(obj, &id);
3757:     if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
3758:     if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented");
3759:   }
3760:   if (useFEM) {
3761:     DMGetCoordinateField(dm, &coordField);
3762:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
3763:     if (maxDegree <= 1) {
3764:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
3765:       if (affineQuad) {
3766:         DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3767:       }
3768:     } else {
3769:       PetscCalloc2(Nf,&quads,Nf,&geoms);
3770:       for (f = 0; f < Nf; ++f) {
3771:         PetscObject  obj;
3772:         PetscClassId id;
3773:         PetscBool    fimp;

3775:         PetscDSGetImplicit(prob, f, &fimp);
3776:         if (isImplicit != fimp) continue;
3777:         PetscDSGetDiscretization(prob, f, &obj);
3778:         PetscObjectGetClassId(obj, &id);
3779:         if (id == PETSCFE_CLASSID) {
3780:           PetscFE fe = (PetscFE) obj;

3782:           PetscFEGetQuadrature(fe, &quads[f]);
3783:           PetscObjectReference((PetscObject)quads[f]);
3784:           DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3785:         }
3786:       }
3787:     }
3788:   }
3789:   /* Loop over chunks */
3790:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3791:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3792:   if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
3793:   numCells      = cEnd - cStart;
3794:   numChunks     = 1;
3795:   cellChunkSize = numCells/numChunks;
3796:   numChunks     = PetscMin(1,numCells);
3797:   for (chunk = 0; chunk < numChunks; ++chunk) {
3798:     PetscScalar     *elemVec, *fluxL = NULL, *fluxR = NULL;
3799:     PetscReal       *vol = NULL;
3800:     PetscFVFaceGeom *fgeom = NULL;
3801:     PetscInt         cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
3802:     PetscInt         numFaces = 0;

3804:     /* Extract field coefficients */
3805:     if (useFEM) {
3806:       ISGetPointSubrange(chunkIS, cS, cE, cells);
3807:       DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3808:       DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3809:       PetscArrayzero(elemVec, numCells*totDim);
3810:     }
3811:     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3812:     /* Loop over fields */
3813:     for (f = 0; f < Nf; ++f) {
3814:       PetscObject  obj;
3815:       PetscClassId id;
3816:       PetscBool    fimp;
3817:       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

3819:       PetscDSGetImplicit(prob, f, &fimp);
3820:       if (isImplicit != fimp) continue;
3821:       PetscDSGetDiscretization(prob, f, &obj);
3822:       PetscObjectGetClassId(obj, &id);
3823:       if (id == PETSCFE_CLASSID) {
3824:         PetscFE         fe = (PetscFE) obj;
3825:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
3826:         PetscFEGeom    *chunkGeom = NULL;
3827:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3828:         PetscInt        Nq, Nb;

3830:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3831:         PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3832:         PetscFEGetDimension(fe, &Nb);
3833:         blockSize = Nb;
3834:         batchSize = numBlocks * blockSize;
3835:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3836:         numChunks = numCells / (numBatches*batchSize);
3837:         Ne        = numChunks*numBatches*batchSize;
3838:         Nr        = numCells % (numBatches*batchSize);
3839:         offset    = numCells - Nr;
3840:         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3841:         /*   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) */
3842:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
3843:         PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3844:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
3845:         PetscFEIntegrateResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
3846:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
3847:       } else if (id == PETSCFV_CLASSID) {
3848:         PetscFV fv = (PetscFV) obj;

3850:         Ne = numFaces;
3851:         /* Riemann solve over faces (need fields at face centroids) */
3852:         /*   We need to evaluate FE fields at those coordinates */
3853:         PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3854:       } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
3855:     }
3856:     /* Loop over domain */
3857:     if (useFEM) {
3858:       /* Add elemVec to locX */
3859:       for (c = cS; c < cE; ++c) {
3860:         const PetscInt cell = cells ? cells[c] : c;
3861:         const PetscInt cind = c - cStart;

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

3867:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
3868:           if (ghostVal > 0) continue;
3869:         }
3870:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3871:       }
3872:     }
3873:     /* Handle time derivative */
3874:     if (locX_t) {
3875:       PetscScalar *x_t, *fa;

3877:       VecGetArray(locF, &fa);
3878:       VecGetArray(locX_t, &x_t);
3879:       for (f = 0; f < Nf; ++f) {
3880:         PetscFV      fv;
3881:         PetscObject  obj;
3882:         PetscClassId id;
3883:         PetscInt     pdim, d;

3885:         PetscDSGetDiscretization(prob, f, &obj);
3886:         PetscObjectGetClassId(obj, &id);
3887:         if (id != PETSCFV_CLASSID) continue;
3888:         fv   = (PetscFV) obj;
3889:         PetscFVGetNumComponents(fv, &pdim);
3890:         for (c = cS; c < cE; ++c) {
3891:           const PetscInt cell = cells ? cells[c] : c;
3892:           PetscScalar   *u_t, *r;

3894:           if (ghostLabel) {
3895:             PetscInt ghostVal;

3897:             DMLabelGetValue(ghostLabel, cell, &ghostVal);
3898:             if (ghostVal > 0) continue;
3899:           }
3900:           DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3901:           DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3902:           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3903:         }
3904:       }
3905:       VecRestoreArray(locX_t, &x_t);
3906:       VecRestoreArray(locF, &fa);
3907:     }
3908:     if (useFEM) {
3909:       DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3910:       DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3911:     }
3912:   }
3913:   if (useFEM) {ISDestroy(&chunkIS);}
3914:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3915:   /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3916:   if (useFEM) {
3917:     if (maxDegree <= 1) {
3918:       DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3919:       PetscQuadratureDestroy(&affineQuad);
3920:     } else {
3921:       for (f = 0; f < Nf; ++f) {
3922:         DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3923:         PetscQuadratureDestroy(&quads[f]);
3924:       }
3925:       PetscFree2(quads,geoms);
3926:     }
3927:   }
3928:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
3929:   return(0);
3930: }

3932: /*
3933:   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

3935:   X   - The local solution vector
3936:   X_t - The local solution time derviative vector, or NULL
3937: */
3938: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS,
3939:                                                     PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
3940: {
3941:   DM_Plex         *mesh  = (DM_Plex *) dm->data;
3942:   const char      *name = "Jacobian", *nameP = "JacobianPre";
3943:   DM               dmAux = NULL;
3944:   PetscDS          prob,   probAux = NULL;
3945:   PetscSection     sectionAux = NULL;
3946:   Vec              A;
3947:   DMField          coordField;
3948:   PetscFEGeom     *cgeomFEM;
3949:   PetscQuadrature  qGeom = NULL;
3950:   Mat              J = Jac, JP = JacP;
3951:   PetscScalar     *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
3952:   PetscBool        hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE;
3953:   const PetscInt  *cells;
3954:   PetscInt         Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
3955:   PetscErrorCode   ierr;

3958:   CHKMEMQ;
3959:   ISGetLocalSize(cellIS, &numCells);
3960:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3961:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
3962:   DMGetDS(dm, &prob);
3963:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3964:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3965:   if (dmAux) {
3966:     DMGetLocalSection(dmAux, &sectionAux);
3967:     DMGetDS(dmAux, &probAux);
3968:   }
3969:   /* Get flags */
3970:   PetscDSGetNumFields(prob, &Nf);
3971:   DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
3972:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
3973:     PetscObject  disc;
3974:     PetscClassId id;
3975:     PetscDSGetDiscretization(prob, fieldI, &disc);
3976:     PetscObjectGetClassId(disc, &id);
3977:     if (id == PETSCFE_CLASSID)      {isFE[fieldI] = PETSC_TRUE;}
3978:     else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;}
3979:   }
3980:   PetscDSHasJacobian(prob, &hasJac);
3981:   PetscDSHasJacobianPreconditioner(prob, &hasPrec);
3982:   PetscDSHasDynamicJacobian(prob, &hasDyn);
3983:   assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
3984:   hasDyn      = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
3985:   PetscObjectTypeCompare((PetscObject) Jac,  MATIS, &isMatIS);
3986:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
3987:   /* Setup input data and temp arrays (should be DMGetWorkArray) */
3988:   if (isMatISP || isMatISP) {DMPlexGetSubdomainSection(dm, &globalSection);}
3989:   if (isMatIS)  {MatISGetLocalMat(Jac,  &J);}
3990:   if (isMatISP) {MatISGetLocalMat(JacP, &JP);}
3991:   if (hasFV)    {MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);} /* No allocated space for FV stuff, so ignore the zero entries */
3992:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
3993:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
3994:   PetscDSGetTotalDimension(prob, &totDim);
3995:   if (probAux) {PetscDSGetTotalDimension(probAux, &totDimAux);}
3996:   CHKMEMQ;
3997:   /* Compute batch sizes */
3998:   if (isFE[0]) {
3999:     PetscFE         fe;
4000:     PetscQuadrature q;
4001:     PetscInt        numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;

4003:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4004:     PetscFEGetQuadrature(fe, &q);
4005:     PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
4006:     PetscFEGetDimension(fe, &Nb);
4007:     PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4008:     blockSize = Nb*numQuadPoints;
4009:     batchSize = numBlocks  * blockSize;
4010:     chunkSize = numBatches * batchSize;
4011:     numChunks = numCells / chunkSize + numCells % chunkSize;
4012:     PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4013:   } else {
4014:     chunkSize = numCells;
4015:     numChunks = 1;
4016:   }
4017:   /* Get work space */
4018:   wsz  = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize;
4019:   DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
4020:   PetscArrayzero(work, wsz);
4021:   off      = 0;
4022:   u        = X       ? (sz = chunkSize*totDim,        off += sz, work+off-sz) : NULL;
4023:   u_t      = X_t     ? (sz = chunkSize*totDim,        off += sz, work+off-sz) : NULL;
4024:   a        = dmAux   ? (sz = chunkSize*totDimAux,     off += sz, work+off-sz) : NULL;
4025:   elemMat  = hasJac  ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4026:   elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4027:   elemMatD = hasDyn  ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4028:   if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz);
4029:   /* Setup geometry */
4030:   DMGetCoordinateField(dm, &coordField);
4031:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4032:   if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);}
4033:   if (!qGeom) {
4034:     PetscFE fe;

4036:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4037:     PetscFEGetQuadrature(fe, &qGeom);
4038:     PetscObjectReference((PetscObject) qGeom);
4039:   }
4040:   DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4041:   /* Compute volume integrals */
4042:   if (assembleJac) {MatZeroEntries(J);}
4043:   MatZeroEntries(JP);
4044:   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4045:     const PetscInt   Ncell = PetscMin(chunkSize, numCells - offCell);
4046:     PetscInt         c;

4048:     /* Extract values */
4049:     for (c = 0; c < Ncell; ++c) {
4050:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4051:       PetscScalar   *x = NULL,  *x_t = NULL;
4052:       PetscInt       i;

4054:       if (X) {
4055:         DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
4056:         for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
4057:         DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
4058:       }
4059:       if (X_t) {
4060:         DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
4061:         for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i];
4062:         DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
4063:       }
4064:       if (dmAux) {
4065:         DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
4066:         for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
4067:         DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
4068:       }
4069:     }
4070:     CHKMEMQ;
4071:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
4072:       PetscFE fe;
4073:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
4074:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
4075:         if (hasJac)  {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN,     fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);}
4076:         if (hasPrec) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);}
4077:         if (hasDyn)  {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);}
4078:       }
4079:       /* For finite volume, add the identity */
4080:       if (!isFE[fieldI]) {
4081:         PetscFV  fv;
4082:         PetscInt eOffset = 0, Nc, fc, foff;

4084:         PetscDSGetFieldOffset(prob, fieldI, &foff);
4085:         PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
4086:         PetscFVGetNumComponents(fv, &Nc);
4087:         for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) {
4088:           for (fc = 0; fc < Nc; ++fc) {
4089:             const PetscInt i = foff + fc;
4090:             if (hasJac)  {elemMat [eOffset+i*totDim+i] = 1.0;}
4091:             if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;}
4092:           }
4093:         }
4094:       }
4095:     }
4096:     CHKMEMQ;
4097:     /*   Add contribution from X_t */
4098:     if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
4099:     /* Insert values into matrix */
4100:     for (c = 0; c < Ncell; ++c) {
4101:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4102:       if (mesh->printFEM > 1) {
4103:         if (hasJac)  {DMPrintCellMatrix(cell, name,  totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);}
4104:         if (hasPrec) {DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);}
4105:       }
4106:       if (assembleJac) {DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);}
4107:       DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);
4108:     }
4109:     CHKMEMQ;
4110:   }
4111:   /* Cleanup */
4112:   DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4113:   PetscQuadratureDestroy(&qGeom);
4114:   if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
4115:   DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4116:   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);
4117:   /* Compute boundary integrals */
4118:   /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
4119:   /* Assemble matrix */
4120:   if (assembleJac) {MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);}
4121:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
4122:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
4123:   CHKMEMQ;
4124:   return(0);
4125: }

4127: /******** FEM Assembly Function ********/

4129: static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4130: {
4131:   PetscBool      isPlex;

4135:   PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
4136:   if (isPlex) {
4137:     *plex = dm;
4138:     PetscObjectReference((PetscObject) dm);
4139:   } else {
4140:     PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
4141:     if (!*plex) {
4142:       DMConvert(dm,DMPLEX,plex);
4143:       PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
4144:       if (copy) {
4145:         const char *comps[] = {"A", "dmAux"};
4146:         PetscObject obj;
4147:         PetscInt    i;

4149:         for (i = 0; i < 2; ++i) {
4150:           PetscObjectQuery((PetscObject) dm, comps[i], &obj);
4151:           PetscObjectCompose((PetscObject) *plex, comps[i], obj);
4152:         }
4153:       }
4154:     } else {
4155:       PetscObjectReference((PetscObject) *plex);
4156:     }
4157:   }
4158:   return(0);
4159: }

4161: /*@
4162:   DMPlexGetGeometryFVM - Return precomputed geometric data

4164:   Collective on DM

4166:   Input Parameter:
4167: . dm - The DM

4169:   Output Parameters:
4170: + facegeom - The values precomputed from face geometry
4171: . cellgeom - The values precomputed from cell geometry
4172: - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell

4174:   Level: developer

4176: .seealso: DMPlexTSSetRHSFunctionLocal()
4177: @*/
4178: PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4179: {
4180:   DM             plex;

4185:   DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4186:   DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);
4187:   if (minRadius) {DMPlexGetMinRadius(plex, minRadius);}
4188:   DMDestroy(&plex);
4189:   return(0);
4190: }

4192: /*@
4193:   DMPlexGetGradientDM - Return gradient data layout

4195:   Collective on DM

4197:   Input Parameters:
4198: + dm - The DM
4199: - fv - The PetscFV

4201:   Output Parameter:
4202: . dmGrad - The layout for gradient values

4204:   Level: developer

4206: .seealso: DMPlexSNESGetGeometryFVM()
4207: @*/
4208: PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4209: {
4210:   DM             plex;
4211:   PetscBool      computeGradients;

4218:   PetscFVGetComputeGradients(fv, &computeGradients);
4219:   if (!computeGradients) {*dmGrad = NULL; return(0);}
4220:   DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4221:   DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);
4222:   DMDestroy(&plex);
4223:   return(0);
4224: }

4226: static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS)
4227: {
4228:   DM_Plex         *mesh = (DM_Plex *) dm->data;
4229:   DM               plex = NULL, plexA = NULL;
4230:   DMEnclosureType  encAux;
4231:   PetscDS          prob, probAux = NULL;
4232:   PetscSection     section, sectionAux = NULL;
4233:   Vec              locA = NULL;
4234:   PetscScalar     *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
4235:   PetscInt         v;
4236:   PetscInt         totDim, totDimAux = 0;
4237:   PetscErrorCode   ierr;

4240:   DMConvert(dm, DMPLEX, &plex);
4241:   DMGetLocalSection(dm, &section);
4242:   DMGetDS(dm, &prob);
4243:   PetscDSGetTotalDimension(prob, &totDim);
4244:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4245:   if (locA) {
4246:     DM dmAux;

4248:     VecGetDM(locA, &dmAux);
4249:     DMGetEnclosureRelation(dmAux, dm, &encAux);
4250:     DMConvert(dmAux, DMPLEX, &plexA);
4251:     DMGetDS(plexA, &probAux);
4252:     PetscDSGetTotalDimension(probAux, &totDimAux);
4253:     DMGetLocalSection(plexA, &sectionAux);
4254:   }
4255:   for (v = 0; v < numValues; ++v) {
4256:     PetscFEGeom    *fgeom;
4257:     PetscInt        maxDegree;
4258:     PetscQuadrature qGeom = NULL;
4259:     IS              pointIS;
4260:     const PetscInt *points;
4261:     PetscInt        numFaces, face, Nq;

4263:     DMLabelGetStratumIS(label, values[v], &pointIS);
4264:     if (!pointIS) continue; /* No points with that id on this process */
4265:     {
4266:       IS isectIS;

4268:       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
4269:       ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
4270:       ISDestroy(&pointIS);
4271:       pointIS = isectIS;
4272:     }
4273:     ISGetLocalSize(pointIS,&numFaces);
4274:     ISGetIndices(pointIS,&points);
4275:     PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a);
4276:     DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
4277:     if (maxDegree <= 1) {
4278:       DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
4279:     }
4280:     if (!qGeom) {
4281:       PetscFE fe;

4283:       PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
4284:       PetscFEGetFaceQuadrature(fe, &qGeom);
4285:       PetscObjectReference((PetscObject)qGeom);
4286:     }
4287:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
4288:     DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4289:     for (face = 0; face < numFaces; ++face) {
4290:       const PetscInt point = points[face], *support, *cone;
4291:       PetscScalar   *x     = NULL;
4292:       PetscInt       i, coneSize, faceLoc;

4294:       DMPlexGetSupport(dm, point, &support);
4295:       DMPlexGetConeSize(dm, support[0], &coneSize);
4296:       DMPlexGetCone(dm, support[0], &cone);
4297:       for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
4298:       if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", point, support[0]);
4299:       fgeom->face[face][0] = faceLoc;
4300:       DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
4301:       for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
4302:       DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
4303:       if (locX_t) {
4304:         DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
4305:         for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
4306:         DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
4307:       }
4308:       if (locA) {
4309:         PetscInt subp;

4311:         DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
4312:         DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
4313:         for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
4314:         DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
4315:       }
4316:     }
4317:     PetscArrayzero(elemVec, numFaces*totDim);
4318:     {
4319:       PetscFE         fe;
4320:       PetscInt        Nb;
4321:       PetscFEGeom     *chunkGeom = NULL;
4322:       /* Conforming batches */
4323:       PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
4324:       /* Remainder */
4325:       PetscInt        Nr, offset;

4327:       PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);
4328:       PetscFEGetDimension(fe, &Nb);
4329:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4330:       /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
4331:       blockSize = Nb;
4332:       batchSize = numBlocks * blockSize;
4333:        PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4334:       numChunks = numFaces / (numBatches*batchSize);
4335:       Ne        = numChunks*numBatches*batchSize;
4336:       Nr        = numFaces % (numBatches*batchSize);
4337:       offset    = numFaces - Nr;
4338:       PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
4339:       PetscFEIntegrateBdResidual(prob, field, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4340:       PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
4341:       PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
4342:       PetscFEIntegrateBdResidual(prob, field, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, a ? &a[offset*totDimAux] : NULL, t, &elemVec[offset*totDim]);
4343:       PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
4344:     }
4345:     for (face = 0; face < numFaces; ++face) {
4346:       const PetscInt point = points[face], *support;

4348:       if (mesh->printFEM > 1) {DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim]);}
4349:       DMPlexGetSupport(plex, point, &support);
4350:       DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES);
4351:     }
4352:     DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4353:     PetscQuadratureDestroy(&qGeom);
4354:     ISRestoreIndices(pointIS, &points);
4355:     ISDestroy(&pointIS);
4356:     PetscFree4(u, u_t, elemVec, a);
4357:   }
4358:   DMDestroy(&plex);
4359:   DMDestroy(&plexA);
4360:   return(0);
4361: }

4363: PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF)
4364: {
4365:   DMField        coordField;
4366:   DMLabel        depthLabel;
4367:   IS             facetIS;
4368:   PetscInt       dim;

4372:   DMGetDimension(dm, &dim);
4373:   DMPlexGetDepthLabel(dm, &depthLabel);
4374:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
4375:   DMGetCoordinateField(dm, &coordField);
4376:   DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4377:   ISDestroy(&facetIS);
4378:   return(0);
4379: }

4381: PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4382: {
4383:   PetscDS        prob;
4384:   PetscInt       numBd, bd;
4385:   DMField        coordField = NULL;
4386:   IS             facetIS    = NULL;
4387:   DMLabel        depthLabel;
4388:   PetscInt       dim;

4392:   DMGetDS(dm, &prob);
4393:   DMPlexGetDepthLabel(dm, &depthLabel);
4394:   DMGetDimension(dm, &dim);
4395:   DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS);
4396:   PetscDSGetNumBoundary(prob, &numBd);
4397:   for (bd = 0; bd < numBd; ++bd) {
4398:     DMBoundaryConditionType type;
4399:     const char             *bdLabel;
4400:     DMLabel                 label;
4401:     const PetscInt         *values;
4402:     PetscInt                field, numValues;
4403:     PetscObject             obj;
4404:     PetscClassId            id;

4406:     PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &field, NULL, NULL, NULL, NULL, &numValues, &values, NULL);
4407:     PetscDSGetDiscretization(prob, field, &obj);
4408:     PetscObjectGetClassId(obj, &id);
4409:     if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
4410:     if (!facetIS) {
4411:       DMLabel  depthLabel;
4412:       PetscInt dim;

4414:       DMPlexGetDepthLabel(dm, &depthLabel);
4415:       DMGetDimension(dm, &dim);
4416:       DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4417:     }
4418:     DMGetCoordinateField(dm, &coordField);
4419:     DMGetLabel(dm, bdLabel, &label);
4420:     DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4421:   }
4422:   ISDestroy(&facetIS);
4423:   return(0);
4424: }

4426: PetscErrorCode DMPlexComputeResidual_Internal(DM dm, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4427: {
4428:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
4429:   const char      *name       = "Residual";
4430:   DM               dmAux      = NULL;
4431:   DM               dmGrad     = NULL;
4432:   DMLabel          ghostLabel = NULL;
4433:   PetscDS          prob       = NULL;
4434:   PetscDS          probAux    = NULL;
4435:   PetscSection     section    = NULL;
4436:   PetscBool        useFEM     = PETSC_FALSE;
4437:   PetscBool        useFVM     = PETSC_FALSE;
4438:   PetscBool        isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
4439:   PetscFV          fvm        = NULL;
4440:   PetscFVCellGeom *cgeomFVM   = NULL;
4441:   PetscFVFaceGeom *fgeomFVM   = NULL;
4442:   DMField          coordField = NULL;
4443:   Vec              locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
4444:   PetscScalar     *u = NULL, *u_t, *a, *uL, *uR;
4445:   IS               chunkIS;
4446:   const PetscInt  *cells;
4447:   PetscInt         cStart, cEnd, numCells;
4448:   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
4449:   PetscInt         maxDegree = PETSC_MAX_INT;
4450:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
4451:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
4452:   PetscErrorCode   ierr;

4455:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4456:   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4457:   /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
4458:   /* FEM+FVM */
4459:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4460:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4461:   /* 1: Get sizes from dm and dmAux */
4462:   DMGetLocalSection(dm, &section);
4463:   DMGetLabel(dm, "ghost", &ghostLabel);
4464:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
4465:   PetscDSGetNumFields(prob, &Nf);
4466:   PetscDSGetTotalDimension(prob, &totDim);
4467:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4468:   if (locA) {
4469:     PetscInt subcell;
4470:     VecGetDM(locA, &dmAux);
4471:     DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cStart, &subcell);
4472:     DMGetCellDS(dmAux, subcell, &probAux);
4473:     PetscDSGetTotalDimension(probAux, &totDimAux);
4474:   }
4475:   /* 2: Get geometric data */
4476:   for (f = 0; f < Nf; ++f) {
4477:     PetscObject  obj;
4478:     PetscClassId id;
4479:     PetscBool    fimp;

4481:     PetscDSGetImplicit(prob, f, &fimp);
4482:     if (isImplicit != fimp) continue;
4483:     PetscDSGetDiscretization(prob, f, &obj);
4484:     PetscObjectGetClassId(obj, &id);
4485:     if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
4486:     if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;}
4487:   }
4488:   if (useFEM) {
4489:     DMGetCoordinateField(dm, &coordField);
4490:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
4491:     if (maxDegree <= 1) {
4492:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
4493:       if (affineQuad) {
4494:         DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4495:       }
4496:     } else {
4497:       PetscCalloc2(Nf,&quads,Nf,&geoms);
4498:       for (f = 0; f < Nf; ++f) {
4499:         PetscObject  obj;
4500:         PetscClassId id;
4501:         PetscBool    fimp;

4503:         PetscDSGetImplicit(prob, f, &fimp);
4504:         if (isImplicit != fimp) continue;
4505:         PetscDSGetDiscretization(prob, f, &obj);
4506:         PetscObjectGetClassId(obj, &id);
4507:         if (id == PETSCFE_CLASSID) {
4508:           PetscFE fe = (PetscFE) obj;

4510:           PetscFEGetQuadrature(fe, &quads[f]);
4511:           PetscObjectReference((PetscObject)quads[f]);
4512:           DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4513:         }
4514:       }
4515:     }
4516:   }
4517:   if (useFVM) {
4518:     DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL);
4519:     VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM);
4520:     VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
4521:     /* Reconstruct and limit cell gradients */
4522:     DMPlexGetGradientDM(dm, fvm, &dmGrad);
4523:     if (dmGrad) {
4524:       DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4525:       DMGetGlobalVector(dmGrad, &grad);
4526:       DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
4527:       /* Communicate gradient values */
4528:       DMGetLocalVector(dmGrad, &locGrad);
4529:       DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
4530:       DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
4531:       DMRestoreGlobalVector(dmGrad, &grad);
4532:     }
4533:     /* Handle non-essential (e.g. outflow) boundary values */
4534:     DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad);
4535:   }
4536:   /* Loop over chunks */
4537:   if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
4538:   numCells      = cEnd - cStart;
4539:   numChunks     = 1;
4540:   cellChunkSize = numCells/numChunks;
4541:   faceChunkSize = (fEnd - fStart)/numChunks;
4542:   numChunks     = PetscMin(1,numCells);
4543:   for (chunk = 0; chunk < numChunks; ++chunk) {
4544:     PetscScalar     *elemVec, *fluxL, *fluxR;
4545:     PetscReal       *vol;
4546:     PetscFVFaceGeom *fgeom;
4547:     PetscInt         cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
4548:     PetscInt         fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face;

4550:     /* Extract field coefficients */
4551:     if (useFEM) {
4552:       ISGetPointSubrange(chunkIS, cS, cE, cells);
4553:       DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4554:       DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4555:       PetscArrayzero(elemVec, numCells*totDim);
4556:     }
4557:     if (useFVM) {
4558:       DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4559:       DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4560:       DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4561:       DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4562:       PetscArrayzero(fluxL, numFaces*totDim);
4563:       PetscArrayzero(fluxR, numFaces*totDim);
4564:     }
4565:     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
4566:     /* Loop over fields */
4567:     for (f = 0; f < Nf; ++f) {
4568:       PetscObject  obj;
4569:       PetscClassId id;
4570:       PetscBool    fimp;
4571:       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

4573:       PetscDSGetImplicit(prob, f, &fimp);
4574:       if (isImplicit != fimp) continue;
4575:       PetscDSGetDiscretization(prob, f, &obj);
4576:       PetscObjectGetClassId(obj, &id);
4577:       if (id == PETSCFE_CLASSID) {
4578:         PetscFE         fe = (PetscFE) obj;
4579:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
4580:         PetscFEGeom    *chunkGeom = NULL;
4581:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4582:         PetscInt        Nq, Nb;

4584:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4585:         PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4586:         PetscFEGetDimension(fe, &Nb);
4587:         blockSize = Nb;
4588:         batchSize = numBlocks * blockSize;
4589:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4590:         numChunks = numCells / (numBatches*batchSize);
4591:         Ne        = numChunks*numBatches*batchSize;
4592:         Nr        = numCells % (numBatches*batchSize);
4593:         offset    = numCells - Nr;
4594:         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
4595:         /*   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) */
4596:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4597:         PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4598:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4599:         PetscFEIntegrateResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4600:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4601:       } else if (id == PETSCFV_CLASSID) {
4602:         PetscFV fv = (PetscFV) obj;

4604:         Ne = numFaces;
4605:         /* Riemann solve over faces (need fields at face centroids) */
4606:         /*   We need to evaluate FE fields at those coordinates */
4607:         PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
4608:       } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
4609:     }
4610:     /* Loop over domain */
4611:     if (useFEM) {
4612:       /* Add elemVec to locX */
4613:       for (c = cS; c < cE; ++c) {
4614:         const PetscInt cell = cells ? cells[c] : c;
4615:         const PetscInt cind = c - cStart;

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

4621:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
4622:           if (ghostVal > 0) continue;
4623:         }
4624:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4625:       }
4626:     }
4627:     if (useFVM) {
4628:       PetscScalar *fa;
4629:       PetscInt     iface;

4631:       VecGetArray(locF, &fa);
4632:       for (f = 0; f < Nf; ++f) {
4633:         PetscFV      fv;
4634:         PetscObject  obj;
4635:         PetscClassId id;
4636:         PetscInt     foff, pdim;

4638:         PetscDSGetDiscretization(prob, f, &obj);
4639:         PetscDSGetFieldOffset(prob, f, &foff);
4640:         PetscObjectGetClassId(obj, &id);
4641:         if (id != PETSCFV_CLASSID) continue;
4642:         fv   = (PetscFV) obj;
4643:         PetscFVGetNumComponents(fv, &pdim);
4644:         /* Accumulate fluxes to cells */
4645:         for (face = fS, iface = 0; face < fE; ++face) {
4646:           const PetscInt *scells;
4647:           PetscScalar    *fL = NULL, *fR = NULL;
4648:           PetscInt        ghost, d, nsupp, nchild;

4650:           DMLabelGetValue(ghostLabel, face, &ghost);
4651:           DMPlexGetSupportSize(dm, face, &nsupp);
4652:           DMPlexGetTreeChildren(dm, face, &nchild, NULL);
4653:           if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
4654:           DMPlexGetSupport(dm, face, &scells);
4655:           DMLabelGetValue(ghostLabel,scells[0],&ghost);
4656:           if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);}
4657:           DMLabelGetValue(ghostLabel,scells[1],&ghost);
4658:           if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);}
4659:           for (d = 0; d < pdim; ++d) {
4660:             if (fL) fL[d] -= fluxL[iface*totDim+foff+d];
4661:             if (fR) fR[d] += fluxR[iface*totDim+foff+d];
4662:           }
4663:           ++iface;
4664:         }
4665:       }
4666:       VecRestoreArray(locF, &fa);
4667:     }
4668:     /* Handle time derivative */
4669:     if (locX_t) {
4670:       PetscScalar *x_t, *fa;

4672:       VecGetArray(locF, &fa);
4673:       VecGetArray(locX_t, &x_t);
4674:       for (f = 0; f < Nf; ++f) {
4675:         PetscFV      fv;
4676:         PetscObject  obj;
4677:         PetscClassId id;
4678:         PetscInt     pdim, d;

4680:         PetscDSGetDiscretization(prob, f, &obj);
4681:         PetscObjectGetClassId(obj, &id);
4682:         if (id != PETSCFV_CLASSID) continue;
4683:         fv   = (PetscFV) obj;
4684:         PetscFVGetNumComponents(fv, &pdim);
4685:         for (c = cS; c < cE; ++c) {
4686:           const PetscInt cell = cells ? cells[c] : c;
4687:           PetscScalar   *u_t, *r;

4689:           if (ghostLabel) {
4690:             PetscInt ghostVal;

4692:             DMLabelGetValue(ghostLabel, cell, &ghostVal);
4693:             if (ghostVal > 0) continue;
4694:           }
4695:           DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
4696:           DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
4697:           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
4698:         }
4699:       }
4700:       VecRestoreArray(locX_t, &x_t);
4701:       VecRestoreArray(locF, &fa);
4702:     }
4703:     if (useFEM) {
4704:       DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4705:       DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4706:     }
4707:     if (useFVM) {
4708:       DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4709:       DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4710:       DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4711:       DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4712:       if (dmGrad) {DMRestoreLocalVector(dmGrad, &locGrad);}
4713:     }
4714:   }
4715:   if (useFEM) {ISDestroy(&chunkIS);}
4716:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);

4718:   if (useFEM) {
4719:     DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);

4721:     if (maxDegree <= 1) {
4722:       DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4723:       PetscQuadratureDestroy(&affineQuad);
4724:     } else {
4725:       for (f = 0; f < Nf; ++f) {
4726:         DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4727:         PetscQuadratureDestroy(&quads[f]);
4728:       }
4729:       PetscFree2(quads,geoms);
4730:     }
4731:   }

4733:   /* FEM */
4734:   /* 1: Get sizes from dm and dmAux */
4735:   /* 2: Get geometric data */
4736:   /* 3: Handle boundary values */
4737:   /* 4: Loop over domain */
4738:   /*   Extract coefficients */
4739:   /* Loop over fields */
4740:   /*   Set tiling for FE*/
4741:   /*   Integrate FE residual to get elemVec */
4742:   /*     Loop over subdomain */
4743:   /*       Loop over quad points */
4744:   /*         Transform coords to real space */
4745:   /*         Evaluate field and aux fields at point */
4746:   /*         Evaluate residual at point */
4747:   /*         Transform residual to real space */
4748:   /*       Add residual to elemVec */
4749:   /* Loop over domain */
4750:   /*   Add elemVec to locX */

4752:   /* FVM */
4753:   /* Get geometric data */
4754:   /* If using gradients */
4755:   /*   Compute gradient data */
4756:   /*   Loop over domain faces */
4757:   /*     Count computational faces */
4758:   /*     Reconstruct cell gradient */
4759:   /*   Loop over domain cells */
4760:   /*     Limit cell gradients */
4761:   /* Handle boundary values */
4762:   /* Loop over domain faces */
4763:   /*   Read out field, centroid, normal, volume for each side of face */
4764:   /* Riemann solve over faces */
4765:   /* Loop over domain faces */
4766:   /*   Accumulate fluxes to cells */
4767:   /* TODO Change printFEM to printDisc here */
4768:   if (mesh->printFEM) {
4769:     Vec         locFbc;
4770:     PetscInt    pStart, pEnd, p, maxDof;
4771:     PetscScalar *zeroes;

4773:     VecDuplicate(locF,&locFbc);
4774:     VecCopy(locF,locFbc);
4775:     PetscSectionGetChart(section,&pStart,&pEnd);
4776:     PetscSectionGetMaxDof(section,&maxDof);
4777:     PetscCalloc1(maxDof,&zeroes);
4778:     for (p = pStart; p < pEnd; p++) {
4779:       VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES);
4780:     }
4781:     PetscFree(zeroes);
4782:     DMPrintLocalVec(dm, name, mesh->printTol, locFbc);
4783:     VecDestroy(&locFbc);
4784:   }
4785:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4786:   return(0);
4787: }

4789: PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4790: {
4791:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
4792:   const char      *name       = "Hybrid Residual";
4793:   DM               dmAux      = NULL;
4794:   DMLabel          ghostLabel = NULL;
4795:   PetscDS          prob       = NULL;
4796:   PetscDS          probAux    = NULL;
4797:   PetscSection     section    = NULL;
4798:   DMField          coordField = NULL;
4799:   Vec              locA;
4800:   PetscScalar     *u = NULL, *u_t, *a;
4801:   PetscScalar     *elemVec;
4802:   IS               chunkIS;
4803:   const PetscInt  *cells;
4804:   PetscInt        *faces;
4805:   PetscInt         cStart, cEnd, numCells;
4806:   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk;
4807:   PetscInt         maxDegree = PETSC_MAX_INT;
4808:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
4809:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
4810:   PetscErrorCode   ierr;

4813:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4814:   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4815:   /* FEM */
4816:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4817:   /* 1: Get sizes from dm and dmAux */
4818:   DMGetSection(dm, &section);
4819:   DMGetLabel(dm, "ghost", &ghostLabel);
4820:   DMGetCellDS(dm, cStart, &prob);
4821:   PetscDSGetNumFields(prob, &Nf);
4822:   PetscDSGetTotalDimension(prob, &totDim);
4823:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4824:   if (locA) {
4825:     VecGetDM(locA, &dmAux);
4826:     DMGetCellDS(dmAux, cStart, &probAux);
4827:     PetscDSGetTotalDimension(probAux, &totDimAux);
4828:   }
4829:   /* 2: Setup geometric data */
4830:   DMGetCoordinateField(dm, &coordField);
4831:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4832:   if (maxDegree > 1) {
4833:     PetscCalloc2(Nf,&quads,Nf,&geoms);
4834:     for (f = 0; f < Nf; ++f) {
4835:       PetscFE fe;

4837:       PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
4838:       if (fe) {
4839:         PetscFEGetQuadrature(fe, &quads[f]);
4840:         PetscObjectReference((PetscObject) quads[f]);
4841:       }
4842:     }
4843:   }
4844:   /* Loop over chunks */
4845:   numCells      = cEnd - cStart;
4846:   cellChunkSize = numCells;
4847:   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
4848:   PetscCalloc1(2*cellChunkSize, &faces);
4849:   ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
4850:   /* Extract field coefficients */
4851:   /* NOTE This needs the end cap faces to have identical orientations */
4852:   DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
4853:   DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec);
4854:   for (chunk = 0; chunk < numChunks; ++chunk) {
4855:     PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;

4857:     PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar));
4858:     /* Get faces */
4859:     for (c = cS; c < cE; ++c) {
4860:       const PetscInt  cell = cells ? cells[c] : c;
4861:       const PetscInt *cone;
4862:       DMPlexGetCone(dm, cell, &cone);
4863:       faces[(c-cS)*2+0] = cone[0];
4864:       faces[(c-cS)*2+1] = cone[1];
4865:     }
4866:     ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
4867:     /* Get geometric data */
4868:     if (maxDegree <= 1) {
4869:       if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
4870:       if (affineQuad)  {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
4871:     } else {
4872:       for (f = 0; f < Nf; ++f) {
4873:         if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
4874:       }
4875:     }
4876:     /* Loop over fields */
4877:     for (f = 0; f < Nf; ++f) {
4878:       PetscFE         fe;
4879:       PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
4880:       PetscFEGeom    *chunkGeom = NULL;
4881:       PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4882:       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;

4884:       PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
4885:       if (!fe) continue;
4886:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4887:       PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4888:       PetscFEGetDimension(fe, &Nb);
4889:       blockSize = Nb;
4890:       batchSize = numBlocks * blockSize;
4891:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4892:       numChunks = numCells / (numBatches*batchSize);
4893:       Ne        = numChunks*numBatches*batchSize;
4894:       Nr        = numCells % (numBatches*batchSize);
4895:       offset    = numCells - Nr;
4896:       PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4897:       PetscFEIntegrateHybridResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4898:       PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4899:       PetscFEIntegrateHybridResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4900:       PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4901:     }
4902:     /* Add elemVec to locX */
4903:     for (c = cS; c < cE; ++c) {
4904:       const PetscInt cell = cells ? cells[c] : c;
4905:       const PetscInt cind = c - cStart;

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

4911:         DMLabelGetValue(ghostLabel,cell,&ghostVal);
4912:         if (ghostVal > 0) continue;
4913:       }
4914:       DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4915:     }
4916:   }
4917:   DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
4918:   DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4919:   PetscFree(faces);
4920:   ISDestroy(&chunkIS);
4921:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
4922:   if (maxDegree <= 1) {
4923:     DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4924:     PetscQuadratureDestroy(&affineQuad);
4925:   } else {
4926:     for (f = 0; f < Nf; ++f) {
4927:       if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);}
4928:       if (quads) {PetscQuadratureDestroy(&quads[f]);}
4929:     }
4930:     PetscFree2(quads,geoms);
4931:   }
4932:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4933:   return(0);
4934: }

4936: PetscErrorCode DMPlexComputeBdJacobian_Single_Internal(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt fieldI, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP, DMField coordField, IS facetIS)
4937: {
4938:   DM_Plex        *mesh = (DM_Plex *) dm->data;
4939:   DM              plex = NULL, plexA = NULL, tdm;
4940:   DMEnclosureType encAux;
4941:   PetscDS         prob, probAux = NULL;
4942:   PetscSection    section, sectionAux = NULL;
4943:   PetscSection    globalSection, subSection = NULL;
4944:   Vec             locA = NULL, tv;
4945:   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
4946:   PetscInt        v;
4947:   PetscInt        Nf, totDim, totDimAux = 0;
4948:   PetscBool       isMatISP, transform;
4949:   PetscErrorCode  ierr;

4952:   DMConvert(dm, DMPLEX, &plex);
4953:   DMHasBasisTransform(dm, &transform);
4954:   DMGetBasisTransformDM_Internal(dm, &tdm);
4955:   DMGetBasisTransformVec_Internal(dm, &tv);
4956:   DMGetLocalSection(dm, &section);
4957:   DMGetDS(dm, &prob);
4958:   PetscDSGetNumFields(prob, &Nf);
4959:   PetscDSGetTotalDimension(prob, &totDim);
4960:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
4961:   if (locA) {
4962:     DM dmAux;

4964:     VecGetDM(locA, &dmAux);
4965:     DMGetEnclosureRelation(dmAux, dm, &encAux);
4966:     DMConvert(dmAux, DMPLEX, &plexA);
4967:     DMGetDS(plexA, &probAux);
4968:     PetscDSGetTotalDimension(probAux, &totDimAux);
4969:     DMGetLocalSection(plexA, &sectionAux);
4970:   }

4972:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
4973:   DMGetGlobalSection(dm, &globalSection);
4974:   if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
4975:   for (v = 0; v < numValues; ++v) {
4976:     PetscFEGeom    *fgeom;
4977:     PetscInt        maxDegree;
4978:     PetscQuadrature qGeom = NULL;
4979:     IS              pointIS;
4980:     const PetscInt *points;
4981:     PetscInt        numFaces, face, Nq;

4983:     DMLabelGetStratumIS(label, values[v], &pointIS);
4984:     if (!pointIS) continue; /* No points with that id on this process */
4985:     {
4986:       IS isectIS;

4988:       /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
4989:       ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
4990:       ISDestroy(&pointIS);
4991:       pointIS = isectIS;
4992:     }
4993:     ISGetLocalSize(pointIS, &numFaces);
4994:     ISGetIndices(pointIS, &points);
4995:     PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a);
4996:     DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
4997:     if (maxDegree <= 1) {
4998:       DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
4999:     }
5000:     if (!qGeom) {
5001:       PetscFE fe;

5003:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5004:       PetscFEGetFaceQuadrature(fe, &qGeom);
5005:       PetscObjectReference((PetscObject)qGeom);
5006:     }
5007:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5008:     DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5009:     for (face = 0; face < numFaces; ++face) {
5010:       const PetscInt point = points[face], *support, *cone;
5011:       PetscScalar   *x     = NULL;
5012:       PetscInt       i, coneSize, faceLoc;

5014:       DMPlexGetSupport(dm, point, &support);
5015:       DMPlexGetConeSize(dm, support[0], &coneSize);
5016:       DMPlexGetCone(dm, support[0], &cone);
5017:       for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break;
5018:       if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", point, support[0]);
5019:       fgeom->face[face][0] = faceLoc;
5020:       DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
5021:       for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
5022:       DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
5023:       if (locX_t) {
5024:         DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
5025:         for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
5026:         DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
5027:       }
5028:       if (locA) {
5029:         PetscInt subp;
5030:         DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
5031:         DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
5032:         for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
5033:         DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
5034:       }
5035:     }
5036:     PetscArrayzero(elemMat, numFaces*totDim*totDim);
5037:     {
5038:       PetscFE         fe;
5039:       PetscInt        Nb;
5040:       /* Conforming batches */
5041:       PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5042:       /* Remainder */
5043:       PetscFEGeom    *chunkGeom = NULL;
5044:       PetscInt        fieldJ, Nr, offset;

5046:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5047:       PetscFEGetDimension(fe, &Nb);
5048:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5049:       blockSize = Nb;
5050:       batchSize = numBlocks * blockSize;
5051:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5052:       numChunks = numFaces / (numBatches*batchSize);
5053:       Ne        = numChunks*numBatches*batchSize;
5054:       Nr        = numFaces % (numBatches*batchSize);
5055:       offset    = numFaces - Nr;
5056:       PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
5057:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5058:         PetscFEIntegrateBdJacobian(prob, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5059:       }
5060:       PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
5061:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5062:         PetscFEIntegrateBdJacobian(prob, fieldI, fieldJ, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, a ? &a[offset*totDimAux] : NULL, t, X_tShift, &elemMat[offset*totDim*totDim]);
5063:       }
5064:       PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
5065:     }
5066:     for (face = 0; face < numFaces; ++face) {
5067:       const PetscInt point = points[face], *support;

5069:       /* Transform to global basis before insertion in Jacobian */
5070:       DMPlexGetSupport(plex, point, &support);
5071:       if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim]);}
5072:       if (mesh->printFEM > 1) {DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim]);}
5073:       if (!isMatISP) {
5074:         DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5075:       } else {
5076:         Mat lJ;

5078:         MatISGetLocalMat(JacP, &lJ);
5079:         DMPlexMatSetClosure(plex, section, subSection, lJ, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5080:       }
5081:     }
5082:     DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5083:     PetscQuadratureDestroy(&qGeom);
5084:     ISRestoreIndices(pointIS, &points);
5085:     ISDestroy(&pointIS);
5086:     PetscFree4(u, u_t, elemMat, a);
5087:   }
5088:   if (plex)  {DMDestroy(&plex);}
5089:   if (plexA) {DMDestroy(&plexA);}
5090:   return(0);
5091: }

5093: PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP)
5094: {
5095:   DMField        coordField;
5096:   DMLabel        depthLabel;
5097:   IS             facetIS;
5098:   PetscInt       dim;

5102:   DMGetDimension(dm, &dim);
5103:   DMPlexGetDepthLabel(dm, &depthLabel);
5104:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5105:   DMGetCoordinateField(dm, &coordField);
5106:   DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5107:   ISDestroy(&facetIS);
5108:   return(0);
5109: }

5111: PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5112: {
5113:   PetscDS          prob;
5114:   PetscInt         dim, numBd, bd;
5115:   DMLabel          depthLabel;
5116:   DMField          coordField = NULL;
5117:   IS               facetIS;
5118:   PetscErrorCode   ierr;

5121:   DMGetDS(dm, &prob);
5122:   DMPlexGetDepthLabel(dm, &depthLabel);
5123:   DMGetDimension(dm, &dim);
5124:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5125:   PetscDSGetNumBoundary(prob, &numBd);
5126:   DMGetCoordinateField(dm, &coordField);
5127:   for (bd = 0; bd < numBd; ++bd) {
5128:     DMBoundaryConditionType type;
5129:     const char             *bdLabel;
5130:     DMLabel                 label;
5131:     const PetscInt         *values;
5132:     PetscInt                fieldI, numValues;
5133:     PetscObject             obj;
5134:     PetscClassId            id;

5136:     PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &fieldI, NULL, NULL, NULL, NULL, &numValues, &values, NULL);
5137:     PetscDSGetDiscretization(prob, fieldI, &obj);
5138:     PetscObjectGetClassId(obj, &id);
5139:     if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
5140:     DMGetLabel(dm, bdLabel, &label);
5141:     DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5142:   }
5143:   ISDestroy(&facetIS);
5144:   return(0);
5145: }

5147: PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP,void *user)
5148: {
5149:   DM_Plex        *mesh  = (DM_Plex *) dm->data;
5150:   const char     *name  = "Jacobian";
5151:   DM              dmAux, plex, tdm;
5152:   DMEnclosureType encAux;
5153:   Vec             A, tv;
5154:   DMField         coordField;
5155:   PetscDS         prob, probAux = NULL;
5156:   PetscSection    section, globalSection, subSection, sectionAux;
5157:   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
5158:   const PetscInt *cells;
5159:   PetscInt        Nf, fieldI, fieldJ;
5160:   PetscInt        totDim, totDimAux, cStart, cEnd, numCells, c;
5161:   PetscBool       isMatIS, isMatISP, hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform;
5162:   PetscErrorCode  ierr;

5165:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5166:   ISGetLocalSize(cellIS, &numCells);
5167:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5168:   DMHasBasisTransform(dm, &transform);
5169:   DMGetBasisTransformDM_Internal(dm, &tdm);
5170:   DMGetBasisTransformVec_Internal(dm, &tv);
5171:   DMGetLocalSection(dm, &section);
5172:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5173:   DMGetGlobalSection(dm, &globalSection);
5174:   if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5175:   ISGetLocalSize(cellIS, &numCells);
5176:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5177:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5178:   PetscDSGetNumFields(prob, &Nf);
5179:   PetscDSGetTotalDimension(prob, &totDim);
5180:   PetscDSHasJacobian(prob, &hasJac);
5181:   PetscDSHasJacobianPreconditioner(prob, &hasPrec);
5182:   /* user passed in the same matrix, avoid double contributions and
5183:      only assemble the Jacobian */
5184:   if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
5185:   PetscDSHasDynamicJacobian(prob, &hasDyn);
5186:   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5187:   PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);
5188:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);
5189:   if (dmAux) {
5190:     DMGetEnclosureRelation(dmAux, dm, &encAux);
5191:     DMConvert(dmAux, DMPLEX, &plex);
5192:     DMGetLocalSection(plex, &sectionAux);
5193:     DMGetDS(dmAux, &probAux);
5194:     PetscDSGetTotalDimension(probAux, &totDimAux);
5195:   }
5196:   PetscMalloc5(numCells*totDim,&u,X_t ? numCells*totDim : 0,&u_t,hasJac ? numCells*totDim*totDim : 0,&elemMat,hasPrec ? numCells*totDim*totDim : 0, &elemMatP,hasDyn ? numCells*totDim*totDim : 0, &elemMatD);
5197:   if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
5198:   DMGetCoordinateField(dm, &coordField);
5199:   for (c = cStart; c < cEnd; ++c) {
5200:     const PetscInt cell = cells ? cells[c] : c;
5201:     const PetscInt cind = c - cStart;
5202:     PetscScalar   *x = NULL,  *x_t = NULL;
5203:     PetscInt       i;

5205:     DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
5206:     for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
5207:     DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
5208:     if (X_t) {
5209:       DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
5210:       for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
5211:       DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
5212:     }
5213:     if (dmAux) {
5214:       PetscInt subcell;
5215:       DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5216:       DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);
5217:       for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
5218:       DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);
5219:     }
5220:   }
5221:   if (hasJac)  {PetscArrayzero(elemMat,  numCells*totDim*totDim);}
5222:   if (hasPrec) {PetscArrayzero(elemMatP, numCells*totDim*totDim);}
5223:   if (hasDyn)  {PetscArrayzero(elemMatD, numCells*totDim*totDim);}
5224:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
5225:     PetscClassId    id;
5226:     PetscFE         fe;
5227:     PetscQuadrature qGeom = NULL;
5228:     PetscInt        Nb;
5229:     /* Conforming batches */
5230:     PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5231:     /* Remainder */
5232:     PetscInt        Nr, offset, Nq;
5233:     PetscInt        maxDegree;
5234:     PetscFEGeom     *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;

5236:     PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5237:     PetscObjectGetClassId((PetscObject) fe, &id);
5238:     if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;}
5239:     PetscFEGetDimension(fe, &Nb);
5240:     PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5241:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
5242:     if (maxDegree <= 1) {
5243:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);
5244:     }
5245:     if (!qGeom) {
5246:       PetscFEGetQuadrature(fe,&qGeom);
5247:       PetscObjectReference((PetscObject)qGeom);
5248:     }
5249:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5250:     DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5251:     blockSize = Nb;
5252:     batchSize = numBlocks * blockSize;
5253:     PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5254:     numChunks = numCells / (numBatches*batchSize);
5255:     Ne        = numChunks*numBatches*batchSize;
5256:     Nr        = numCells % (numBatches*batchSize);
5257:     offset    = numCells - Nr;
5258:     PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
5259:     PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);
5260:     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5261:       if (hasJac) {
5262:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5263:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5264:       }
5265:       if (hasPrec) {
5266:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5267:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5268:       }
5269:       if (hasDyn) {
5270:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5271:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatD[offset*totDim*totDim]);
5272:       }
5273:     }
5274:     PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);
5275:     PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);
5276:     DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5277:     PetscQuadratureDestroy(&qGeom);
5278:   }
5279:   /*   Add contribution from X_t */
5280:   if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
5281:   if (hasFV) {
5282:     PetscClassId id;
5283:     PetscFV      fv;
5284:     PetscInt     offsetI, NcI, NbI = 1, fc, f;

5286:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
5287:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
5288:       PetscDSGetFieldOffset(prob, fieldI, &offsetI);
5289:       PetscObjectGetClassId((PetscObject) fv, &id);
5290:       if (id != PETSCFV_CLASSID) continue;
5291:       /* Put in the identity */
5292:       PetscFVGetNumComponents(fv, &NcI);
5293:       for (c = cStart; c < cEnd; ++c) {
5294:         const PetscInt cind    = c - cStart;
5295:         const PetscInt eOffset = cind*totDim*totDim;
5296:         for (fc = 0; fc < NcI; ++fc) {
5297:           for (f = 0; f < NbI; ++f) {
5298:             const PetscInt i = offsetI + f*NcI+fc;
5299:             if (hasPrec) {
5300:               if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;}
5301:               elemMatP[eOffset+i*totDim+i] = 1.0;
5302:             } else {elemMat[eOffset+i*totDim+i] = 1.0;}
5303:           }
5304:         }
5305:       }
5306:     }
5307:     /* No allocated space for FV stuff, so ignore the zero entries */
5308:     MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);
5309:   }
5310:   /* Insert values into matrix */
5311:   isMatIS = PETSC_FALSE;
5312:   if (hasPrec && hasJac) {
5313:     PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);
5314:   }
5315:   if (isMatIS && !subSection) {
5316:     DMPlexGetSubdomainSection(dm, &subSection);
5317:   }
5318:   for (c = cStart; c < cEnd; ++c) {
5319:     const PetscInt cell = cells ? cells[c] : c;
5320:     const PetscInt cind = c - cStart;

5322:     /* Transform to global basis before insertion in Jacobian */
5323:     if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim]);}
5324:     if (hasPrec) {
5325:       if (hasJac) {
5326:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5327:         if (!isMatIS) {
5328:           DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5329:         } else {
5330:           Mat lJ;

5332:           MatISGetLocalMat(Jac,&lJ);
5333:           DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5334:         }
5335:       }
5336:       if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5337:       if (!isMatISP) {
5338:         DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5339:       } else {
5340:         Mat lJ;

5342:         MatISGetLocalMat(JacP,&lJ);
5343:         DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5344:       }
5345:     } else {
5346:       if (hasJac) {
5347:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5348:         if (!isMatISP) {
5349:           DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5350:         } else {
5351:           Mat lJ;

5353:           MatISGetLocalMat(JacP,&lJ);
5354:           DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5355:         }
5356:       }
5357:     }
5358:   }
5359:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5360:   if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
5361:   PetscFree5(u,u_t,elemMat,elemMatP,elemMatD);
5362:   if (dmAux) {
5363:     PetscFree(a);
5364:     DMDestroy(&plex);
5365:   }
5366:   /* Compute boundary integrals */
5367:   DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);
5368:   /* Assemble matrix */
5369:   if (hasJac && hasPrec) {
5370:     MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5371:     MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5372:   }
5373:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5374:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5375:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5376:   return(0);
5377: }

5379: PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5380: {
5381:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
5382:   const char      *name       = "Hybrid Jacobian";
5383:   DM               dmAux      = NULL;
5384:   DM               plex       = NULL;
5385:   DM               plexA      = NULL;
5386:   DMLabel          ghostLabel = NULL;
5387:   PetscDS          prob       = NULL;
5388:   PetscDS          probAux    = NULL;
5389:   PetscSection     section    = NULL;
5390:   DMField          coordField = NULL;
5391:   Vec              locA;
5392:   PetscScalar     *u = NULL, *u_t, *a = NULL;
5393:   PetscScalar     *elemMat, *elemMatP;
5394:   PetscSection     globalSection, subSection, sectionAux;
5395:   IS               chunkIS;
5396:   const PetscInt  *cells;
5397:   PetscInt        *faces;
5398:   PetscInt         cStart, cEnd, numCells;
5399:   PetscInt         Nf, fieldI, fieldJ, totDim, totDimAux, numChunks, cellChunkSize, chunk;
5400:   PetscInt         maxDegree = PETSC_MAX_INT;
5401:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
5402:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
5403:   PetscBool        isMatIS = PETSC_FALSE, isMatISP = PETSC_FALSE, hasBdJac, hasBdPrec;
5404:   PetscErrorCode   ierr;

5407:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5408:   ISGetLocalSize(cellIS, &numCells);
5409:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5410:   DMConvert(dm, DMPLEX, &plex);
5411:   DMGetSection(dm, &section);
5412:   DMGetGlobalSection(dm, &globalSection);
5413:   DMGetLabel(dm, "ghost", &ghostLabel);
5414:   DMGetCellDS(dm, cStart, &prob);
5415:   PetscDSGetNumFields(prob, &Nf);
5416:   PetscDSGetTotalDimension(prob, &totDim);
5417:   PetscDSHasBdJacobian(prob, &hasBdJac);
5418:   PetscDSHasBdJacobianPreconditioner(prob, &hasBdPrec);
5419:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5420:   if (isMatISP) {DMPlexGetSubdomainSection(plex, &subSection);}
5421:   if (hasBdPrec && hasBdJac) {PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);}
5422:   if (isMatIS && !subSection) {DMPlexGetSubdomainSection(plex, &subSection);}
5423:   PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);
5424:   if (locA) {
5425:     VecGetDM(locA, &dmAux);
5426:     DMConvert(dmAux, DMPLEX, &plexA);
5427:     DMGetSection(dmAux, &sectionAux);
5428:     DMGetCellDS(dmAux, cStart, &probAux);
5429:     PetscDSGetTotalDimension(probAux, &totDimAux);
5430:   }
5431:   DMGetCoordinateField(dm, &coordField);
5432:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5433:   if (maxDegree > 1) {
5434:     PetscInt f;
5435:     PetscCalloc2(Nf,&quads,Nf,&geoms);
5436:     for (f = 0; f < Nf; ++f) {
5437:       PetscFE fe;

5439:       PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
5440:       if (fe) {
5441:         PetscFEGetQuadrature(fe, &quads[f]);
5442:         PetscObjectReference((PetscObject) quads[f]);
5443:       }
5444:     }
5445:   }
5446:   cellChunkSize = numCells;
5447:   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
5448:   PetscCalloc1(2*cellChunkSize, &faces);
5449:   ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
5450:   DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5451:   DMGetWorkArray(dm, hasBdJac  ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5452:   DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5453:   for (chunk = 0; chunk < numChunks; ++chunk) {
5454:     PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;

5456:     if (hasBdJac)  {PetscMemzero(elemMat,  numCells*totDim*totDim * sizeof(PetscScalar));}
5457:     if (hasBdPrec) {PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar));}
5458:     /* Get faces */
5459:     for (c = cS; c < cE; ++c) {
5460:       const PetscInt  cell = cells ? cells[c] : c;
5461:       const PetscInt *cone;
5462:       DMPlexGetCone(plex, cell, &cone);
5463:       faces[(c-cS)*2+0] = cone[0];
5464:       faces[(c-cS)*2+1] = cone[1];
5465:     }
5466:     ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
5467:     if (maxDegree <= 1) {
5468:       if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
5469:       if (affineQuad)  {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
5470:     } else {
5471:       PetscInt f;
5472:       for (f = 0; f < Nf; ++f) {
5473:         if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
5474:       }
5475:     }

5477:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
5478:       PetscFE         feI;
5479:       PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[fieldI];
5480:       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
5481:       PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
5482:       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;

5484:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &feI);
5485:       if (!feI) continue;
5486:       PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);
5487:       PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
5488:       PetscFEGetDimension(feI, &Nb);
5489:       blockSize = Nb;
5490:       batchSize = numBlocks * blockSize;
5491:       PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);
5492:       numChunks = numCells / (numBatches*batchSize);
5493:       Ne        = numChunks*numBatches*batchSize;
5494:       Nr        = numCells % (numBatches*batchSize);
5495:       offset    = numCells - Nr;
5496:       PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
5497:       PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);
5498:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5499:         PetscFE feJ;

5501:         PetscDSGetDiscretization(prob, fieldJ, (PetscObject *) &feJ);
5502:         if (!feJ) continue;
5503:         if (hasBdJac) {
5504:           PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5505:           PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5506:         }
5507:         if (hasBdPrec) {
5508:           PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5509:           PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5510:         }
5511:       }
5512:       PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);
5513:       PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);
5514:     }
5515:     /* Insert values into matrix */
5516:     for (c = cS; c < cE; ++c) {
5517:       const PetscInt cell = cells ? cells[c] : c;
5518:       const PetscInt cind = c - cS;

5520:       if (hasBdPrec) {
5521:         if (hasBdJac) {
5522:           if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5523:           if (!isMatIS) {
5524:             DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5525:           } else {
5526:             Mat lJ;

5528:             MatISGetLocalMat(Jac,&lJ);
5529:             DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5530:           }
5531:         }
5532:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5533:         if (!isMatISP) {
5534:           DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5535:         } else {
5536:           Mat lJ;

5538:           MatISGetLocalMat(JacP,&lJ);
5539:           DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5540:         }
5541:       } else if (hasBdJac) {
5542:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5543:         if (!isMatISP) {
5544:           DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5545:         } else {
5546:           Mat lJ;

5548:           MatISGetLocalMat(JacP,&lJ);
5549:           DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5550:         }
5551:       }
5552:     }
5553:   }
5554:   DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5555:   DMRestoreWorkArray(dm, hasBdJac  ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5556:   DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5557:   PetscFree(faces);
5558:   ISDestroy(&chunkIS);
5559:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5560:   if (maxDegree <= 1) {
5561:     DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5562:     PetscQuadratureDestroy(&affineQuad);
5563:   } else {
5564:     PetscInt f;
5565:     for (f = 0; f < Nf; ++f) {
5566:       if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f]);}
5567:       if (quads) {PetscQuadratureDestroy(&quads[f]);}
5568:     }
5569:     PetscFree2(quads,geoms);
5570:   }
5571:   if (dmAux) {DMDestroy(&plexA);}
5572:   DMDestroy(&plex);
5573:   /* Assemble matrix */
5574:   if (hasBdJac && hasBdPrec) {
5575:     MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5576:     MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5577:   }
5578:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5579:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5580:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5581:   return(0);
5582: }