Actual source code: plexfem.c

  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petscsf.h>

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

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

 15:   PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
 16:   if (isPlex) {
 17:     *plex = dm;
 18:     PetscObjectReference((PetscObject) dm);
 19:   } else {
 20:     PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
 21:     if (!*plex) {
 22:       DMConvert(dm, DMPLEX, plex);
 23:       PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
 24:       if (copy) {
 25:         DMSubDomainHookLink link;

 27:         DMCopyAuxiliaryVec(dm, *plex);
 28:         /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
 29:         for (link = dm->subdomainhook; link; link = link->next) {
 30:           if (link->ddhook) {(*link->ddhook)(dm, *plex, link->ctx);}
 31:         }
 32:       }
 33:     } else {
 34:       PetscObjectReference((PetscObject) *plex);
 35:     }
 36:   }
 37:   return(0);
 38: }

 40: static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom (void *ctx)
 41: {
 42:   PetscFEGeom *geom = (PetscFEGeom *) ctx;

 46:   PetscFEGeomDestroy(&geom);
 47:   return(0);
 48: }

 50: static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
 51: {
 52:   char            composeStr[33] = {0};
 53:   PetscObjectId   id;
 54:   PetscContainer  container;
 55:   PetscErrorCode  ierr;

 58:   PetscObjectGetId((PetscObject)quad,&id);
 59:   PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%x\n", id);
 60:   PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
 61:   if (container) {
 62:     PetscContainerGetPointer(container, (void **) geom);
 63:   } else {
 64:     DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
 65:     PetscContainerCreate(PETSC_COMM_SELF,&container);
 66:     PetscContainerSetPointer(container, (void *) *geom);
 67:     PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
 68:     PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
 69:     PetscContainerDestroy(&container);
 70:   }
 71:   return(0);
 72: }

 74: static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
 75: {
 77:   *geom = NULL;
 78:   return(0);
 79: }

 81: /*@
 82:   DMPlexGetScale - Get the scale for the specified fundamental unit

 84:   Not collective

 86:   Input Parameters:
 87: + dm   - the DM
 88: - unit - The SI unit

 90:   Output Parameter:
 91: . scale - The value used to scale all quantities with this unit

 93:   Level: advanced

 95: .seealso: DMPlexSetScale(), PetscUnit
 96: @*/
 97: PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
 98: {
 99:   DM_Plex *mesh = (DM_Plex*) dm->data;

104:   *scale = mesh->scale[unit];
105:   return(0);
106: }

108: /*@
109:   DMPlexSetScale - Set the scale for the specified fundamental unit

111:   Not collective

113:   Input Parameters:
114: + dm   - the DM
115: . unit - The SI unit
116: - scale - The value used to scale all quantities with this unit

118:   Level: advanced

120: .seealso: DMPlexGetScale(), PetscUnit
121: @*/
122: PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
123: {
124:   DM_Plex *mesh = (DM_Plex*) dm->data;

128:   mesh->scale[unit] = scale;
129:   return(0);
130: }

132: static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx)
133: {
134:   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}}};
135:   PetscInt *ctxInt  = (PetscInt *) ctx;
136:   PetscInt  dim2    = ctxInt[0];
137:   PetscInt  d       = ctxInt[1];
138:   PetscInt  i, j, k = dim > 2 ? d - dim : d;

141:   if (dim != dim2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %D does not match context dimension %D", dim, dim2);
142:   for (i = 0; i < dim; i++) mode[i] = 0.;
143:   if (d < dim) {
144:     mode[d] = 1.; /* Translation along axis d */
145:   } else {
146:     for (i = 0; i < dim; i++) {
147:       for (j = 0; j < dim; j++) {
148:         mode[j] += eps[i][j][k]*X[i]; /* Rotation about axis d */
149:       }
150:     }
151:   }
152:   return(0);
153: }

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

158:   Collective on dm

160:   Input Parameters:
161: + dm - the DM
162: - field - The field number for the rigid body space, or 0 for the default

164:   Output Parameter:
165: . sp - the null space

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

169:   Level: advanced

171: .seealso: MatNullSpaceCreate(), PCGAMG
172: @*/
173: PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp)
174: {
175:   PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
176:   MPI_Comm          comm;
177:   Vec               mode[6];
178:   PetscSection      section, globalSection;
179:   PetscInt          dim, dimEmbed, Nf, n, m, mmin, d, i, j;
180:   PetscErrorCode    ierr;

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

208:     ctx[0] = dimEmbed;
209:     ctx[1] = d;
210:     DMProjectFunction(dm, 0.0, func, &voidctx, INSERT_VALUES, mode[d]);
211:   }
212:   /* Orthonormalize system */
213:   for (i = 0; i < mmin; ++i) {
214:     PetscScalar dots[6];

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

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

232:   Collective on dm

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

241:   Output Parameter:
242: . sp - the null space

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

246:   Level: advanced

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

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

278:       ctx[0] = dimEmbed;
279:       ctx[1] = d;
280:       DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);
281:       off   += nids[b];
282:     }
283:   }
284:   /* Orthonormalize system */
285:   for (i = 0; i < m; ++i) {
286:     PetscScalar dots[6];

288:     VecNormalize(mode[i], NULL);
289:     VecMDot(mode[i], m-i-1, mode+i+1, dots+i+1);
290:     for (j = i+1; j < m; ++j) {
291:       dots[j] *= -1.0;
292:       VecAXPY(mode[j], dots[j], mode[i]);
293:     }
294:   }
295:   MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);
296:   for (i = 0; i< m; ++i) {VecDestroy(&mode[i]);}
297:   PetscFree2(mode, dots);
298:   return(0);
299: }

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

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

314:   Level: advanced

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

324:   plex->maxProjectionHeight = height;
325:   return(0);
326: }

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

332:   Input Parameters:
333: . dm - the DMPlex object

335:   Output Parameters:
336: . height - the maximum projection height

338:   Level: intermediate

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

348:   *height = plex->maxProjectionHeight;
349:   return(0);
350: }

352: typedef struct {
353:   PetscReal    alpha; /* The first Euler angle, and in 2D the only one */
354:   PetscReal    beta;  /* The second Euler angle */
355:   PetscReal    gamma; /* The third Euler angle */
356:   PetscInt     dim;   /* The dimension of R */
357:   PetscScalar *R;     /* The rotation matrix, transforming a vector in the local basis to the global basis */
358:   PetscScalar *RT;    /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
359: } RotCtx;

361: /*
362:   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
363:   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:
364:   $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
365:   $ 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.
366:   $ The XYZ system rotates a third time about the z axis by gamma.
367: */
368: static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx)
369: {
370:   RotCtx        *rc  = (RotCtx *) ctx;
371:   PetscInt       dim = rc->dim;
372:   PetscReal      c1, s1, c2, s2, c3, s3;

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

400: static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx)
401: {
402:   RotCtx        *rc = (RotCtx *) ctx;

406:   PetscFree2(rc->R, rc->RT);
407:   PetscFree(rc);
408:   return(0);
409: }

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

417:   if (l2g) {*A = rc->R;}
418:   else     {*A = rc->RT;}
419:   return(0);
420: }

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

427:   #if defined(PETSC_USE_COMPLEX)
428:   switch (dim) {
429:     case 2:
430:     {
431:       PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0,0.0};

433:       DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
434:       z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]);
435:     }
436:     break;
437:     case 3:
438:     {
439:       PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0,0.0,0.0};

441:       DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);
442:       z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]); z[2] = PetscRealPart(zt[2]);
443:     }
444:     break;
445:   }
446:   #else
447:   DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx);
448:   #endif
449:   return(0);
450: }

452: PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx)
453: {
454:   const PetscScalar *A;
455:   PetscErrorCode     ierr;

458:   (*dm->transformGetMatrix)(dm, x, l2g, &A, ctx);
459:   switch (dim) {
460:   case 2: DMPlex_Mult2D_Internal(A, 1, y, z);break;
461:   case 3: DMPlex_Mult3D_Internal(A, 1, y, z);break;
462:   }
463:   return(0);
464: }

466: static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
467: {
468:   PetscSection       ts;
469:   const PetscScalar *ta, *tva;
470:   PetscInt           dof;
471:   PetscErrorCode     ierr;

474:   DMGetLocalSection(tdm, &ts);
475:   PetscSectionGetFieldDof(ts, p, f, &dof);
476:   VecGetArrayRead(tv, &ta);
477:   DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva);
478:   if (l2g) {
479:     switch (dof) {
480:     case 4: DMPlex_Mult2D_Internal(tva, 1, a, a);break;
481:     case 9: DMPlex_Mult3D_Internal(tva, 1, a, a);break;
482:     }
483:   } else {
484:     switch (dof) {
485:     case 4: DMPlex_MultTranspose2D_Internal(tva, 1, a, a);break;
486:     case 9: DMPlex_MultTranspose3D_Internal(tva, 1, a, a);break;
487:     }
488:   }
489:   VecRestoreArrayRead(tv, &ta);
490:   return(0);
491: }

493: static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a)
494: {
495:   PetscSection       s, ts;
496:   const PetscScalar *ta, *tvaf, *tvag;
497:   PetscInt           fdof, gdof, fpdof, gpdof;
498:   PetscErrorCode     ierr;

501:   DMGetLocalSection(dm, &s);
502:   DMGetLocalSection(tdm, &ts);
503:   PetscSectionGetFieldDof(s, pf, f, &fpdof);
504:   PetscSectionGetFieldDof(s, pg, g, &gpdof);
505:   PetscSectionGetFieldDof(ts, pf, f, &fdof);
506:   PetscSectionGetFieldDof(ts, pg, g, &gdof);
507:   VecGetArrayRead(tv, &ta);
508:   DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf);
509:   DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag);
510:   if (l2g) {
511:     switch (fdof) {
512:     case 4: DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);break;
513:     case 9: DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);break;
514:     }
515:     switch (gdof) {
516:     case 4: DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);break;
517:     case 9: DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);break;
518:     }
519:   } else {
520:     switch (fdof) {
521:     case 4: DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);break;
522:     case 9: DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);break;
523:     }
524:     switch (gdof) {
525:     case 4: DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);break;
526:     case 9: DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);break;
527:     }
528:   }
529:   VecRestoreArrayRead(tv, &ta);
530:   return(0);
531: }

533: PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
534: {
535:   PetscSection    s;
536:   PetscSection    clSection;
537:   IS              clPoints;
538:   const PetscInt *clp;
539:   PetscInt       *points = NULL;
540:   PetscInt        Nf, f, Np, cp, dof, d = 0;
541:   PetscErrorCode  ierr;

544:   DMGetLocalSection(dm, &s);
545:   PetscSectionGetNumFields(s, &Nf);
546:   DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
547:   for (f = 0; f < Nf; ++f) {
548:     for (cp = 0; cp < Np*2; cp += 2) {
549:       PetscSectionGetFieldDof(s, points[cp], f, &dof);
550:       if (!dof) continue;
551:       if (fieldActive[f]) {DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]);}
552:       d += dof;
553:     }
554:   }
555:   DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);
556:   return(0);
557: }

559: PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
560: {
561:   PetscSection    s;
562:   PetscSection    clSection;
563:   IS              clPoints;
564:   const PetscInt *clp;
565:   PetscInt       *points = NULL;
566:   PetscInt        Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
567:   PetscErrorCode  ierr;

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

592: static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
593: {
594:   DM                 tdm;
595:   Vec                tv;
596:   PetscSection       ts, s;
597:   const PetscScalar *ta;
598:   PetscScalar       *a, *va;
599:   PetscInt           pStart, pEnd, p, Nf, f;
600:   PetscErrorCode     ierr;

603:   DMGetBasisTransformDM_Internal(dm, &tdm);
604:   DMGetBasisTransformVec_Internal(dm, &tv);
605:   DMGetLocalSection(tdm, &ts);
606:   DMGetLocalSection(dm, &s);
607:   PetscSectionGetChart(s, &pStart, &pEnd);
608:   PetscSectionGetNumFields(s, &Nf);
609:   VecGetArray(lv, &a);
610:   VecGetArrayRead(tv, &ta);
611:   for (p = pStart; p < pEnd; ++p) {
612:     for (f = 0; f < Nf; ++f) {
613:       DMPlexPointLocalFieldRef(dm, p, f, a, &va);
614:       DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va);
615:     }
616:   }
617:   VecRestoreArray(lv, &a);
618:   VecRestoreArrayRead(tv, &ta);
619:   return(0);
620: }

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

625:   Input Parameters:
626: + dm - The DM
627: - lv - A local vector with values in the global basis

629:   Output Parameters:
630: . lv - A local vector with values in the local basis

632:   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.

634:   Level: developer

636: .seealso: DMPlexLocalToGlobalBasis(), DMGetLocalSection(), DMPlexCreateBasisRotation()
637: @*/
638: PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
639: {

645:   DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE);
646:   return(0);
647: }

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

652:   Input Parameters:
653: + dm - The DM
654: - lv - A local vector with values in the local basis

656:   Output Parameters:
657: . lv - A local vector with values in the global basis

659:   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.

661:   Level: developer

663: .seealso: DMPlexGlobalToLocalBasis(), DMGetLocalSection(), DMPlexCreateBasisRotation()
664: @*/
665: PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
666: {

672:   DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE);
673:   return(0);
674: }

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

680:   Input Parameters:
681: + dm    - The DM
682: . alpha - The first Euler angle, and in 2D the only one
683: . beta  - The second Euler angle
684: - gamma - The third Euler angle

686:   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
687:   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:
688:   $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
689:   $ 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.
690:   $ The XYZ system rotates a third time about the z axis by gamma.

692:   Level: developer

694: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis()
695: @*/
696: PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
697: {
698:   RotCtx        *rc;
699:   PetscInt       cdim;

703:   DMGetCoordinateDim(dm, &cdim);
704:   PetscMalloc1(1, &rc);
705:   dm->transformCtx       = rc;
706:   dm->transformSetUp     = DMPlexBasisTransformSetUp_Rotation_Internal;
707:   dm->transformDestroy   = DMPlexBasisTransformDestroy_Rotation_Internal;
708:   dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
709:   rc->dim   = cdim;
710:   rc->alpha = alpha;
711:   rc->beta  = beta;
712:   rc->gamma = gamma;
713:   (*dm->transformSetUp)(dm, dm->transformCtx);
714:   DMConstructBasisTransform_Internal(dm);
715:   return(0);
716: }

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

721:   Input Parameters:
722: + dm     - The DM, with a PetscDS that matches the problem being constrained
723: . time   - The time
724: . field  - The field to constrain
725: . Nc     - The number of constrained field components, or 0 for all components
726: . comps  - An array of constrained component numbers, or NULL for all components
727: . label  - The DMLabel defining constrained points
728: . numids - The number of DMLabel ids for constrained points
729: . ids    - An array of ids for constrained points
730: . func   - A pointwise function giving boundary values
731: - ctx    - An optional user context for bcFunc

733:   Output Parameter:
734: . locX   - A local vector to receives the boundary values

736:   Level: developer

738: .seealso: DMPlexInsertBoundaryValuesEssentialField(), DMPlexInsertBoundaryValuesEssentialBdField(), DMAddBoundary()
739: @*/
740: 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)
741: {
742:   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
743:   void            **ctxs;
744:   PetscInt          numFields;
745:   PetscErrorCode    ierr;

748:   DMGetNumFields(dm, &numFields);
749:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
750:   funcs[field] = func;
751:   ctxs[field]  = ctx;
752:   DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);
753:   PetscFree2(funcs,ctxs);
754:   return(0);
755: }

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

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

773:   Output Parameter:
774: . locX   - A local vector to receives the boundary values

776:   Level: developer

778: .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialBdField(), DMAddBoundary()
779: @*/
780: PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
781:                                                         void (*func)(PetscInt, PetscInt, PetscInt,
782:                                                                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
783:                                                                      const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
784:                                                                      PetscReal, const PetscReal[], PetscInt, const PetscScalar[],
785:                                                                      PetscScalar[]),
786:                                                         void *ctx, Vec locX)
787: {
788:   void (**funcs)(PetscInt, PetscInt, PetscInt,
789:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
790:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
791:                  PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
792:   void            **ctxs;
793:   PetscInt          numFields;
794:   PetscErrorCode    ierr;

797:   DMGetNumFields(dm, &numFields);
798:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
799:   funcs[field] = func;
800:   ctxs[field]  = ctx;
801:   DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
802:   PetscFree2(funcs,ctxs);
803:   return(0);
804: }

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

809:   Collective on dm

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

824:   Output Parameter:
825: . locX   - A local vector to receive the boundary values

827:   Level: developer

829: .seealso: DMProjectBdFieldLabelLocal(), DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary()
830: @*/
831: PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[],
832:                                                           void (*func)(PetscInt, PetscInt, PetscInt,
833:                                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
834:                                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
835:                                                                        PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[],
836:                                                                        PetscScalar[]),
837:                                                           void *ctx, Vec locX)
838: {
839:   void (**funcs)(PetscInt, PetscInt, PetscInt,
840:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
841:                  const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
842:                  PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
843:   void            **ctxs;
844:   PetscInt          numFields;
845:   PetscErrorCode    ierr;

848:   DMGetNumFields(dm, &numFields);
849:   PetscCalloc2(numFields,&funcs,numFields,&ctxs);
850:   funcs[field] = func;
851:   ctxs[field]  = ctx;
852:   DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);
853:   PetscFree2(funcs,ctxs);
854:   return(0);
855: }

857: /*@C
858:   DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector

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

875:   Output Parameter:
876: . locX   - A local vector to receives the boundary values

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

880:   Level: developer

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

897:   DMGetPointSF(dm, &sf);
898:   PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);
899:   nleaves = PetscMax(0, nleaves);
900:   DMGetDimension(dm, &dim);
901:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
902:   DMGetDS(dm, &prob);
903:   VecGetDM(faceGeometry, &dmFace);
904:   VecGetArrayRead(faceGeometry, &facegeom);
905:   if (cellGeometry) {
906:     VecGetDM(cellGeometry, &dmCell);
907:     VecGetArrayRead(cellGeometry, &cellgeom);
908:   }
909:   if (Grad) {
910:     PetscFV fv;

912:     PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);
913:     VecGetDM(Grad, &dmGrad);
914:     VecGetArrayRead(Grad, &grad);
915:     PetscFVGetNumComponents(fv, &pdim);
916:     DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);
917:   }
918:   VecGetArray(locX, &x);
919:   for (i = 0; i < numids; ++i) {
920:     IS              faceIS;
921:     const PetscInt *faces;
922:     PetscInt        numFaces, f;

924:     DMLabelGetStratumIS(label, ids[i], &faceIS);
925:     if (!faceIS) continue; /* No points with that id on this process */
926:     ISGetLocalSize(faceIS, &numFaces);
927:     ISGetIndices(faceIS, &faces);
928:     for (f = 0; f < numFaces; ++f) {
929:       const PetscInt         face = faces[f], *cells;
930:       PetscFVFaceGeom        *fg;

932:       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
933:       PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);
934:       if (loc >= 0) continue;
935:       DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
936:       DMPlexGetSupport(dm, face, &cells);
937:       if (Grad) {
938:         PetscFVCellGeom       *cg;
939:         PetscScalar           *cx, *cgrad;
940:         PetscScalar           *xG;
941:         PetscReal              dx[3];
942:         PetscInt               d;

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

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

985: static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
986: {
987:   PetscInt c;
988:   for (c = 0; c < Nc; ++c) u[c] = 0.0;
989:   return 0;
990: }

992: PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
993: {
994:   PetscObject    isZero;
995:   PetscDS        prob;
996:   PetscInt       numBd, b;

1000:   DMGetDS(dm, &prob);
1001:   PetscDSGetNumBoundary(prob, &numBd);
1002:   PetscObjectQuery((PetscObject) locX, "__Vec_bc_zero__", &isZero);
1003:   for (b = 0; b < numBd; ++b) {
1004:     PetscWeakForm           wf;
1005:     DMBoundaryConditionType type;
1006:     const char             *name;
1007:     DMLabel                 label;
1008:     PetscInt                field, Nc;
1009:     const PetscInt         *comps;
1010:     PetscObject             obj;
1011:     PetscClassId            id;
1012:     void                  (*bvfunc)(void);
1013:     PetscInt                numids;
1014:     const PetscInt         *ids;
1015:     void                   *ctx;

1017:     PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx);
1018:     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1019:     DMGetField(dm, field, NULL, &obj);
1020:     PetscObjectGetClassId(obj, &id);
1021:     if (id == PETSCFE_CLASSID) {
1022:       switch (type) {
1023:         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1024:       case DM_BC_ESSENTIAL:
1025:         {
1026:           PetscSimplePointFunc func = (PetscSimplePointFunc) bvfunc;

1028:           if (isZero) func = zero;
1029:           DMPlexLabelAddCells(dm,label);
1030:           DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX);
1031:           DMPlexLabelClearCells(dm,label);
1032:         }
1033:         break;
1034:       case DM_BC_ESSENTIAL_FIELD:
1035:         {
1036:           PetscPointFunc func = (PetscPointFunc) bvfunc;

1038:           DMPlexLabelAddCells(dm,label);
1039:           DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX);
1040:           DMPlexLabelClearCells(dm,label);
1041:         }
1042:         break;
1043:       default: break;
1044:       }
1045:     } else if (id == PETSCFV_CLASSID) {
1046:       {
1047:         PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*) = (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) bvfunc;

1049:         if (!faceGeomFVM) continue;
1050:         DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX);
1051:       }
1052:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1053:   }
1054:   return(0);
1055: }

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

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

1083:     PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx);
1084:     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
1085:     DMGetField(dm, field, NULL, &obj);
1086:     PetscObjectGetClassId(obj, &id);
1087:     if (id == PETSCFE_CLASSID) {
1088:       switch (type) {
1089:         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
1090:       case DM_BC_ESSENTIAL:
1091:         {
1092:           PetscSimplePointFunc func_t = (PetscSimplePointFunc) bvfunc;

1094:           if (isZero) func_t = zero;
1095:           DMPlexLabelAddCells(dm,label);
1096:           DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX);
1097:           DMPlexLabelClearCells(dm,label);
1098:         }
1099:         break;
1100:       case DM_BC_ESSENTIAL_FIELD:
1101:         {
1102:           PetscPointFunc func_t = (PetscPointFunc) bvfunc;

1104:           DMPlexLabelAddCells(dm,label);
1105:           DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX);
1106:           DMPlexLabelClearCells(dm,label);
1107:         }
1108:         break;
1109:       default: break;
1110:       }
1111:     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field);
1112:   }
1113:   return(0);
1114: }

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

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

1127:   Output Parameters:
1128: . locX - Solution updated with boundary values

1130:   Level: developer

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

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

1148: /*@
1149:   DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector

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

1159:   Output Parameters:
1160: . locX_t - Solution updated with boundary values

1162:   Level: developer

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

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

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

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

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

1198:   Collective on dm

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

1207:   Output Parameter:
1208: . diff - The diff ||u - u_h||_2

1210:   Level: developer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1595: /*@C
1596:   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.

1598:   Collective on dm

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

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

1610:   Level: developer

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

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

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

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

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

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

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

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

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

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

1720:   Collective on dm

1722:   Input Parameters:
1723: + dm - The DM
1724: - LocX  - The coefficient vector u_h

1726:   Output Parameter:
1727: . locC - A Vec which holds the Clement interpolant of the gradient

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

1733:   Level: developer

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

1751:   VecGetDM(locC, &dmC);
1752:   VecSet(locC, 0.0);
1753:   DMGetDimension(dm, &dim);
1754:   DMGetCoordinateDim(dm, &coordDim);
1755:   fegeom.dimEmbed = coordDim;
1756:   DMGetNumFields(dm, &numFields);
1757:   if (numFields == 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
1758:   for (field = 0; field < numFields; ++field) {
1759:     PetscObject  obj;
1760:     PetscClassId id;
1761:     PetscInt     Nc;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2070:   Level: developer

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

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

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

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

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

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

2121:   Level: developer

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

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

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

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

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

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

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

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

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

2248:         DMPlexGetSupport(dm, point, &support);
2249:         DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
2250:         for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
2251:         DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
2252:         if (locA) {
2253:           PetscInt subp;
2254:           DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
2255:           DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
2256:           for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i];
2257:           DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
2258:         }
2259:       }
2260:       /* Get blocking */
2261:       {
2262:         PetscQuadrature q;
2263:         PetscInt        numBatches, batchSize, numBlocks, blockSize;
2264:         PetscInt        Nq, Nb;

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

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

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

2311:   Output Parameter:
2312: . integral - Integral for each field

2314:   Level: developer

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

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

2356:     DMLabelGetStratumIS(label, vals[v], &pointIS);
2357:     if (!pointIS) continue; /* No points with that id on this process */
2358:     {
2359:       IS isectIS;

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

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

2383:   Input Parameters:
2384: + dmc  - The coarse mesh
2385: . dmf  - The fine mesh
2386: . isRefined - Flag indicating regular refinement, rather than the same topology
2387: - user - The user context

2389:   Output Parameter:
2390: . In  - The interpolation matrix

2392:   Level: developer

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

2410:   PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2411:   DMGetDimension(dmf, &dim);
2412:   DMGetLocalSection(dmf, &fsection);
2413:   DMGetGlobalSection(dmf, &fglobalSection);
2414:   DMGetLocalSection(dmc, &csection);
2415:   DMGetGlobalSection(dmc, &cglobalSection);
2416:   PetscSectionGetNumFields(fsection, &Nf);
2417:   DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);
2418:   PetscCalloc2(Nf, &feRef, Nf, &fvRef);
2419:   for (f = 0; f < Nf; ++f) {
2420:     PetscObject  obj, objc;
2421:     PetscClassId id, idc;
2422:     PetscInt     rNb = 0, Nc = 0, cNb = 0;

2424:     DMGetField(dmf, f, NULL, &obj);
2425:     PetscObjectGetClassId(obj, &id);
2426:     if (id == PETSCFE_CLASSID) {
2427:       PetscFE fe = (PetscFE) obj;

2429:       if (isRefined) {
2430:         PetscFERefine(fe, &feRef[f]);
2431:       } else {
2432:         PetscObjectReference((PetscObject) fe);
2433:         feRef[f] = fe;
2434:       }
2435:       PetscFEGetDimension(feRef[f], &rNb);
2436:       PetscFEGetNumComponents(fe, &Nc);
2437:     } else if (id == PETSCFV_CLASSID) {
2438:       PetscFV        fv = (PetscFV) obj;
2439:       PetscDualSpace Q;

2441:       if (isRefined) {
2442:         PetscFVRefine(fv, &fvRef[f]);
2443:       } else {
2444:         PetscObjectReference((PetscObject) fv);
2445:         fvRef[f] = fv;
2446:       }
2447:       PetscFVGetDualSpace(fvRef[f], &Q);
2448:       PetscDualSpaceGetDimension(Q, &rNb);
2449:       PetscFVGetDualSpace(fv, &Q);
2450:       PetscFVGetNumComponents(fv, &Nc);
2451:     }
2452:     DMGetField(dmc, f, NULL, &objc);
2453:     PetscObjectGetClassId(objc, &idc);
2454:     if (idc == PETSCFE_CLASSID) {
2455:       PetscFE fe = (PetscFE) objc;

2457:       PetscFEGetDimension(fe, &cNb);
2458:     } else if (id == PETSCFV_CLASSID) {
2459:       PetscFV        fv = (PetscFV) obj;
2460:       PetscDualSpace Q;

2462:       PetscFVGetDualSpace(fv, &Q);
2463:       PetscDualSpaceGetDimension(Q, &cNb);
2464:     }
2465:     rTotDim += rNb;
2466:     cTotDim += cNb;
2467:   }
2468:   PetscMalloc1(rTotDim*cTotDim,&elemMat);
2469:   PetscArrayzero(elemMat, rTotDim*cTotDim);
2470:   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2471:     PetscDualSpace   Qref;
2472:     PetscQuadrature  f;
2473:     const PetscReal *qpoints, *qweights;
2474:     PetscReal       *points;
2475:     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;

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

2498:     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
2499:       PetscObject  obj;
2500:       PetscClassId id;
2501:       PetscInt     NcJ = 0, cpdim = 0, j, qNc;

2503:       DMGetField(dmc, fieldJ, NULL, &obj);
2504:       PetscObjectGetClassId(obj, &id);
2505:       if (id == PETSCFE_CLASSID) {
2506:         PetscFE           fe = (PetscFE) obj;
2507:         PetscTabulation T  = NULL;

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

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

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

2613: PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2614: {
2615:   SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness");
2616: }

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

2621:   Input Parameters:
2622: + dmf  - The fine mesh
2623: . dmc  - The coarse mesh
2624: - user - The user context

2626:   Output Parameter:
2627: . In  - The interpolation matrix

2629:   Level: developer

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

2650:   PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);
2651:   DMGetCoordinateDim(dmc, &dim);
2652:   DMGetDS(dmc, &prob);
2653:   PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2654:   PetscDSGetNumFields(prob, &Nf);
2655:   PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2656:   PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2657:   DMGetLocalSection(dmf, &fsection);
2658:   DMGetGlobalSection(dmf, &globalFSection);
2659:   DMGetLocalSection(dmc, &csection);
2660:   DMGetGlobalSection(dmc, &globalCSection);
2661:   DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2662:   PetscDSGetTotalDimension(prob, &totDim);
2663:   PetscMalloc1(totDim, &elemMat);

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

2682:     PetscDSGetDiscretization(prob, field, &obj);
2683:     PetscObjectGetClassId(obj, &id);
2684:     if (id == PETSCFE_CLASSID) {
2685:       PetscFE fe = (PetscFE) obj;

2687:       PetscFEGetDualSpace(fe, &Q);
2688:       PetscFEGetNumComponents(fe, &Nc);
2689:     } else if (id == PETSCFV_CLASSID) {
2690:       PetscFV fv = (PetscFV) obj;

2692:       PetscFVGetDualSpace(fv, &Q);
2693:       Nc   = 1;
2694:     }
2695:     PetscDualSpaceGetDimension(Q, &fpdim);
2696:     /* For each fine grid cell */
2697:     for (cell = cStart; cell < cEnd; ++cell) {
2698:       PetscInt *findices,   *cindices;
2699:       PetscInt  numFIndices, numCIndices;

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

2711:         /* Get points from the dual basis functional quadrature */
2712:         PetscDualSpaceGetFunctional(Q, i, &f);
2713:         PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);
2714:         VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);
2715:         VecSetBlockSize(pointVec, dim);
2716:         VecGetArray(pointVec, &pV);
2717:         for (q = 0; q < Np; ++q) {
2718:           const PetscReal xi0[3] = {-1., -1., -1.};

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

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

2773:     PetscDSGetDiscretization(prob, field, &obj);
2774:     PetscObjectGetClassId(obj, &id);
2775:     if (id == PETSCFE_CLASSID) {
2776:       PetscFE fe = (PetscFE) obj;

2778:       PetscFEGetDualSpace(fe, &Q);
2779:       PetscFEGetNumComponents(fe, &Nc);
2780:       PetscFECreateTabulation(fe, 1, 1, x, 0, &T);
2781:     } else if (id == PETSCFV_CLASSID) {
2782:       PetscFV fv = (PetscFV) obj;

2784:       PetscFVGetDualSpace(fv, &Q);
2785:       Nc   = 1;
2786:     } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field);
2787:     PetscDualSpaceGetDimension(Q, &fpdim);
2788:     /* For each fine grid cell */
2789:     for (cell = cStart; cell < cEnd; ++cell) {
2790:       PetscInt *findices,   *cindices;
2791:       PetscInt  numFIndices, numCIndices;

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

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

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

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

2835:           if (id == PETSCFE_CLASSID) {
2836:             PetscFE fe = (PetscFE) obj;

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

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

2878:   Input Parameters:
2879: + dmf  - The fine mesh
2880: . dmc  - The coarse mesh
2881: - user - The user context

2883:   Output Parameter:
2884: . mass  - The mass matrix

2886:   Level: developer

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

2907:   DMGetCoordinateDim(dmc, &dim);
2908:   DMGetDS(dmc, &prob);
2909:   PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);
2910:   PetscDSGetNumFields(prob, &Nf);
2911:   PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);
2912:   PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);
2913:   DMGetLocalSection(dmf, &fsection);
2914:   DMGetGlobalSection(dmf, &globalFSection);
2915:   DMGetLocalSection(dmc, &csection);
2916:   DMGetGlobalSection(dmc, &globalCSection);
2917:   DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);
2918:   PetscDSGetTotalDimension(prob, &totDim);
2919:   PetscMalloc1(totDim, &elemMat);

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

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

2952:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
2953:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
2954:       /* Get points from the quadrature */
2955:       VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
2956:       VecSetBlockSize(pointVec, dim);
2957:       VecGetArray(pointVec, &pV);
2958:       for (q = 0; q < Nq; ++q) {
2959:         const PetscReal xi0[3] = {-1., -1., -1.};

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

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

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

3033:       DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);
3034:       DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);
3035:       /* Get points from the quadrature */
3036:       VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);
3037:       VecSetBlockSize(pointVec, dim);
3038:       VecGetArray(pointVec, &pV);
3039:       for (q = 0; q < Nq; ++q) {
3040:         const PetscReal xi0[3] = {-1., -1., -1.};

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

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

3063:         if (id == PETSCFE_CLASSID) {
3064:           PetscFE fe = (PetscFE) obj;

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

3111: /*@
3112:   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns

3114:   Input Parameters:
3115: + dmc  - The coarse mesh
3116: - dmf  - The fine mesh
3117: - user - The user context

3119:   Output Parameter:
3120: . sc   - The mapping

3122:   Level: developer

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

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

3155:     PetscDSGetDiscretization(prob, f, &obj);
3156:     PetscObjectGetClassId(obj, &id);
3157:     if (id == PETSCFE_CLASSID) {
3158:       PetscFE    fe = (PetscFE) obj;
3159:       PetscSpace sp;
3160:       PetscInt   maxDegree;

3162:       PetscFERefine(fe, &feRef[f]);
3163:       PetscFEGetDimension(feRef[f], &fNb);
3164:       PetscFEGetNumComponents(fe, &Nc);
3165:       PetscFEGetBasisSpace(fe, &sp);
3166:       PetscSpaceGetDegree(sp, NULL, &maxDegree);
3167:       if (!maxDegree) needAvg[f] = PETSC_TRUE;
3168:     } else if (id == PETSCFV_CLASSID) {
3169:       PetscFV        fv = (PetscFV) obj;
3170:       PetscDualSpace Q;

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

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

3213:       PetscDualSpaceGetFunctional(QC, c, &cfunc);
3214:       PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);
3215:       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);
3216:       if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
3217:       for (f = 0; f < fpdim; ++f) {
3218:         PetscQuadrature  ffunc;
3219:         const PetscReal *fqpoints, *fqweights;
3220:         PetscReal        sum = 0.0;
3221:         PetscInt         NqcF, NpF;

3223:         PetscDualSpaceGetFunctional(QF, f, &ffunc);
3224:         PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);
3225:         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);
3226:         if (NpC != NpF) continue;
3227:         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
3228:         if (sum > 1.0e-9) continue;
3229:         for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]);
3230:         if (sum < 1.0e-9) continue;
3231:         cmap[offsetC+c] = offsetF+f;
3232:         found = PETSC_TRUE;
3233:         break;
3234:       }
3235:       if (!found) {
3236:         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3237:         if (fvRef[field] || (feRef[field] && order == 0)) {
3238:           cmap[offsetC+c] = offsetF+0;
3239:         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
3240:       }
3241:     }
3242:     offsetC += cpdim;
3243:     offsetF += fpdim;
3244:   }
3245:   for (f = 0; f < Nf; ++f) {PetscFEDestroy(&feRef[f]);PetscFVDestroy(&fvRef[f]);}
3246:   PetscFree3(feRef,fvRef,needAvg);

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

3268:   ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);
3269:   ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);
3270:   VecScatterCreate(cv, cis, fv, fis, sc);
3271:   ISDestroy(&cis);
3272:   ISDestroy(&fis);
3273:   DMRestoreGlobalVector(dmf, &fv);
3274:   DMRestoreGlobalVector(dmc, &cv);
3275:   PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);
3276:   return(0);
3277: }

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

3282:   Input Parameters:
3283: + dm     - The DM
3284: . cellIS - The cells to include
3285: . locX   - A local vector with the solution fields
3286: . locX_t - A local vector with solution field time derivatives, or NULL
3287: - locA   - A local vector with auxiliary fields, or NULL

3289:   Output Parameters:
3290: + u   - The field coefficients
3291: . u_t - The fields derivative coefficients
3292: - a   - The auxiliary field coefficients

3294:   Level: developer

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

3316:   DMPlexConvertPlex(dm, &plex, PETSC_FALSE);
3317:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3318:   DMGetLocalSection(dm, &section);
3319:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
3320:   PetscDSGetTotalDimension(prob, &totDim);
3321:   if (locA) {
3322:     DM      dmAux;
3323:     PetscDS probAux;

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

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

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

3367:   Input Parameters:
3368: + dm     - The DM
3369: . cellIS - The cells to include
3370: . locX   - A local vector with the solution fields
3371: . locX_t - A local vector with solution field time derivatives, or NULL
3372: - locA   - A local vector with auxiliary fields, or NULL

3374:   Output Parameters:
3375: + u   - The field coefficients
3376: . u_t - The fields derivative coefficients
3377: - a   - The auxiliary field coefficients

3379:   Level: developer

3381: .seealso: DMPlexGetFaceFields()
3382: @*/
3383: PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3384: {

3388:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);
3389:   if (locX_t) {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);}
3390:   if (locA)   {DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);}
3391:   return(0);
3392: }

3394: /*
3395:   Get the auxiliary field vectors for the negative side (s = 0) and positive side (s = 1) of the interfaace
3396: */
3397: static PetscErrorCode DMPlexGetHybridAuxFields(DM dm, DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[])
3398: {
3399:   DM              plexA[2];
3400:   DMEnclosureType encAux[2];
3401:   PetscSection    sectionAux[2];
3402:   const PetscInt *cells;
3403:   PetscInt        cStart, cEnd, numCells, c, s, totDimAux[2];
3404:   PetscErrorCode  ierr;

3408:   if (!locA[0] || !locA[1]) return(0);
3412:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3413:   numCells = cEnd - cStart;
3414:   for (s = 0; s < 2; ++s) {
3418:     DMPlexConvertPlex(dmAux[s], &plexA[s], PETSC_FALSE);
3419:     DMGetEnclosureRelation(dmAux[s], dm, &encAux[s]);
3420:     DMGetLocalSection(dmAux[s], &sectionAux[s]);
3421:     PetscDSGetTotalDimension(dsAux[s], &totDimAux[s]);
3422:     DMGetWorkArray(dmAux[s], numCells*totDimAux[s], MPIU_SCALAR, &a[s]);
3423:   }
3424:   for (c = cStart; c < cEnd; ++c) {
3425:     const PetscInt  cell = cells ? cells[c] : c;
3426:     const PetscInt  cind = c - cStart;
3427:     const PetscInt *cone, *ornt;

3429:     DMPlexGetCone(dm, cell, &cone);
3430:     DMPlexGetConeOrientation(dm, cell, &ornt);
3431:     if (ornt[0]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %D in hybrid cell %D has orientation %D != 0", cone[0], cell, ornt[0]);
3432:     for (s = 0; s < 2; ++s) {
3433:       PetscScalar   *x = NULL, *al = a[s];
3434:       const PetscInt tdA = totDimAux[s];
3435:       PetscInt       subface, Na, i;

3437:       DMGetEnclosurePoint(plexA[s], dm, encAux[s], cone[s], &subface);
3438:       DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x);
3439:       for (i = 0; i < Na; ++i) al[cind*tdA+i] = x[i];
3440:       DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x);
3441:     }
3442:   }
3443:   for (s = 0; s < 2; ++s) {DMDestroy(&plexA[s]);}
3444:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3445:   return(0);
3446: }

3448: static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[])
3449: {

3453:   if (!locA[0] || !locA[1]) return(0);
3454:   DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0]);
3455:   DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1]);
3456:   return(0);
3457: }

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

3462:   Input Parameters:
3463: + dm     - The DM
3464: . fStart - The first face to include
3465: . fEnd   - The first face to exclude
3466: . locX   - A local vector with the solution fields
3467: . locX_t - A local vector with solution field time derivatives, or NULL
3468: . faceGeometry - A local vector with face geometry
3469: . cellGeometry - A local vector with cell geometry
3470: - locaGrad - A local vector with field gradients, or NULL

3472:   Output Parameters:
3473: + Nface - The number of faces with field values
3474: . uL - The field values at the left side of the face
3475: - uR - The field values at the right side of the face

3477:   Level: developer

3479: .seealso: DMPlexGetCellFields()
3480: @*/
3481: 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)
3482: {
3483:   DM                 dmFace, dmCell, dmGrad = NULL;
3484:   PetscSection       section;
3485:   PetscDS            prob;
3486:   DMLabel            ghostLabel;
3487:   const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
3488:   PetscBool         *isFE;
3489:   PetscInt           dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
3490:   PetscErrorCode     ierr;

3501:   DMGetDimension(dm, &dim);
3502:   DMGetDS(dm, &prob);
3503:   DMGetLocalSection(dm, &section);
3504:   PetscDSGetNumFields(prob, &Nf);
3505:   PetscDSGetTotalComponents(prob, &Nc);
3506:   PetscMalloc1(Nf, &isFE);
3507:   for (f = 0; f < Nf; ++f) {
3508:     PetscObject  obj;
3509:     PetscClassId id;

3511:     PetscDSGetDiscretization(prob, f, &obj);
3512:     PetscObjectGetClassId(obj, &id);
3513:     if (id == PETSCFE_CLASSID)      {isFE[f] = PETSC_TRUE;}
3514:     else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;}
3515:     else                            {isFE[f] = PETSC_FALSE;}
3516:   }
3517:   DMGetLabel(dm, "ghost", &ghostLabel);
3518:   VecGetArrayRead(locX, &x);
3519:   VecGetDM(faceGeometry, &dmFace);
3520:   VecGetArrayRead(faceGeometry, &facegeom);
3521:   VecGetDM(cellGeometry, &dmCell);
3522:   VecGetArrayRead(cellGeometry, &cellgeom);
3523:   if (locGrad) {
3524:     VecGetDM(locGrad, &dmGrad);
3525:     VecGetArrayRead(locGrad, &lgrad);
3526:   }
3527:   DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);
3528:   DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);
3529:   /* Right now just eat the extra work for FE (could make a cell loop) */
3530:   for (face = fStart, iface = 0; face < fEnd; ++face) {
3531:     const PetscInt        *cells;
3532:     PetscFVFaceGeom       *fg;
3533:     PetscFVCellGeom       *cgL, *cgR;
3534:     PetscScalar           *xL, *xR, *gL, *gR;
3535:     PetscScalar           *uLl = *uL, *uRl = *uR;
3536:     PetscInt               ghost, nsupp, nchild;

3538:     DMLabelGetValue(ghostLabel, face, &ghost);
3539:     DMPlexGetSupportSize(dm, face, &nsupp);
3540:     DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3541:     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3542:     DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3543:     DMPlexGetSupport(dm, face, &cells);
3544:     DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3545:     DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3546:     for (f = 0; f < Nf; ++f) {
3547:       PetscInt off;

3549:       PetscDSGetComponentOffset(prob, f, &off);
3550:       if (isFE[f]) {
3551:         const PetscInt *cone;
3552:         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;

3554:         xL = xR = NULL;
3555:         PetscSectionGetFieldComponents(section, f, &comp);
3556:         DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3557:         DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3558:         DMPlexGetCone(dm, cells[0], &cone);
3559:         DMPlexGetConeSize(dm, cells[0], &coneSizeL);
3560:         for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break;
3561:         DMPlexGetCone(dm, cells[1], &cone);
3562:         DMPlexGetConeSize(dm, cells[1], &coneSizeR);
3563:         for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break;
3564:         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]);
3565:         /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
3566:         /* TODO: this is a hack that might not be right for nonconforming */
3567:         if (faceLocL < coneSizeL) {
3568:           PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);
3569:           if (rdof == ldof && faceLocR < coneSizeR) {PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);}
3570:           else              {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];}
3571:         }
3572:         else {
3573:           PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);
3574:           PetscSectionGetFieldComponents(section, f, &comp);
3575:           for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d];
3576:         }
3577:         DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);
3578:         DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);
3579:       } else {
3580:         PetscFV  fv;
3581:         PetscInt numComp, c;

3583:         PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
3584:         PetscFVGetNumComponents(fv, &numComp);
3585:         DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
3586:         DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
3587:         if (dmGrad) {
3588:           PetscReal dxL[3], dxR[3];

3590:           DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);
3591:           DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);
3592:           DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
3593:           DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
3594:           for (c = 0; c < numComp; ++c) {
3595:             uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL);
3596:             uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR);
3597:           }
3598:         } else {
3599:           for (c = 0; c < numComp; ++c) {
3600:             uLl[iface*Nc+off+c] = xL[c];
3601:             uRl[iface*Nc+off+c] = xR[c];
3602:           }
3603:         }
3604:       }
3605:     }
3606:     ++iface;
3607:   }
3608:   *Nface = iface;
3609:   VecRestoreArrayRead(locX, &x);
3610:   VecRestoreArrayRead(faceGeometry, &facegeom);
3611:   VecRestoreArrayRead(cellGeometry, &cellgeom);
3612:   if (locGrad) {
3613:     VecRestoreArrayRead(locGrad, &lgrad);
3614:   }
3615:   PetscFree(isFE);
3616:   return(0);
3617: }

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

3622:   Input Parameters:
3623: + dm     - The DM
3624: . fStart - The first face to include
3625: . fEnd   - The first face to exclude
3626: . locX   - A local vector with the solution fields
3627: . locX_t - A local vector with solution field time derivatives, or NULL
3628: . faceGeometry - A local vector with face geometry
3629: . cellGeometry - A local vector with cell geometry
3630: - locaGrad - A local vector with field gradients, or NULL

3632:   Output Parameters:
3633: + Nface - The number of faces with field values
3634: . uL - The field values at the left side of the face
3635: - uR - The field values at the right side of the face

3637:   Level: developer

3639: .seealso: DMPlexGetFaceFields()
3640: @*/
3641: 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)
3642: {

3646:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
3647:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
3648:   return(0);
3649: }

3651: /*@C
3652:   DMPlexGetFaceGeometry - Retrieve the geometric 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: DMPlexGetCellFields()
3669: @*/
3670: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3671: {
3672:   DM                 dmFace, dmCell;
3673:   DMLabel            ghostLabel;
3674:   const PetscScalar *facegeom, *cellgeom;
3675:   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
3676:   PetscErrorCode     ierr;

3684:   DMGetDimension(dm, &dim);
3685:   DMGetLabel(dm, "ghost", &ghostLabel);
3686:   VecGetDM(faceGeometry, &dmFace);
3687:   VecGetArrayRead(faceGeometry, &facegeom);
3688:   VecGetDM(cellGeometry, &dmCell);
3689:   VecGetArrayRead(cellGeometry, &cellgeom);
3690:   PetscMalloc1(numFaces, fgeom);
3691:   DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);
3692:   for (face = fStart, iface = 0; face < fEnd; ++face) {
3693:     const PetscInt        *cells;
3694:     PetscFVFaceGeom       *fg;
3695:     PetscFVCellGeom       *cgL, *cgR;
3696:     PetscFVFaceGeom       *fgeoml = *fgeom;
3697:     PetscReal             *voll   = *vol;
3698:     PetscInt               ghost, d, nchild, nsupp;

3700:     DMLabelGetValue(ghostLabel, face, &ghost);
3701:     DMPlexGetSupportSize(dm, face, &nsupp);
3702:     DMPlexGetTreeChildren(dm, face, &nchild, NULL);
3703:     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
3704:     DMPlexPointLocalRead(dmFace, face, facegeom, &fg);
3705:     DMPlexGetSupport(dm, face, &cells);
3706:     DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);
3707:     DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);
3708:     for (d = 0; d < dim; ++d) {
3709:       fgeoml[iface].centroid[d] = fg->centroid[d];
3710:       fgeoml[iface].normal[d]   = fg->normal[d];
3711:     }
3712:     voll[iface*2+0] = cgL->volume;
3713:     voll[iface*2+1] = cgR->volume;
3714:     ++iface;
3715:   }
3716:   *Nface = iface;
3717:   VecRestoreArrayRead(faceGeometry, &facegeom);
3718:   VecRestoreArrayRead(cellGeometry, &cellgeom);
3719:   return(0);
3720: }

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

3725:   Input Parameters:
3726: + dm     - The DM
3727: . fStart - The first face to include
3728: . fEnd   - The first face to exclude
3729: . faceGeometry - A local vector with face geometry
3730: - cellGeometry - A local vector with cell geometry

3732:   Output Parameters:
3733: + Nface - The number of faces with field values
3734: . fgeom - The extract the face centroid and normal
3735: - vol   - The cell volume

3737:   Level: developer

3739: .seealso: DMPlexGetFaceFields()
3740: @*/
3741: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3742: {

3746:   PetscFree(*fgeom);
3747:   DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3748:   return(0);
3749: }

3751: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3752: {
3753:   char            composeStr[33] = {0};
3754:   PetscObjectId   id;
3755:   PetscContainer  container;
3756:   PetscErrorCode  ierr;

3759:   PetscObjectGetId((PetscObject)quad,&id);
3760:   PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);
3761:   PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);
3762:   if (container) {
3763:     PetscContainerGetPointer(container, (void **) geom);
3764:   } else {
3765:     DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);
3766:     PetscContainerCreate(PETSC_COMM_SELF,&container);
3767:     PetscContainerSetPointer(container, (void *) *geom);
3768:     PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);
3769:     PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);
3770:     PetscContainerDestroy(&container);
3771:   }
3772:   return(0);
3773: }

3775: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3776: {
3778:   *geom = NULL;
3779:   return(0);
3780: }

3782: PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3783: {
3784:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
3785:   const char      *name       = "Residual";
3786:   DM               dmAux      = NULL;
3787:   DMLabel          ghostLabel = NULL;
3788:   PetscDS          prob       = NULL;
3789:   PetscDS          probAux    = NULL;
3790:   PetscBool        useFEM     = PETSC_FALSE;
3791:   PetscBool        isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
3792:   DMField          coordField = NULL;
3793:   Vec              locA;
3794:   PetscScalar     *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
3795:   IS               chunkIS;
3796:   const PetscInt  *cells;
3797:   PetscInt         cStart, cEnd, numCells;
3798:   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
3799:   PetscInt         maxDegree = PETSC_MAX_INT;
3800:   PetscFormKey key;
3801:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
3802:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
3803:   PetscErrorCode   ierr;

3806:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
3807:   /* FEM+FVM */
3808:   /* 1: Get sizes from dm and dmAux */
3809:   DMGetLabel(dm, "ghost", &ghostLabel);
3810:   DMGetDS(dm, &prob);
3811:   PetscDSGetNumFields(prob, &Nf);
3812:   PetscDSGetTotalDimension(prob, &totDim);
3813:   DMGetAuxiliaryVec(dm, NULL, 0, &locA);
3814:   if (locA) {
3815:     VecGetDM(locA, &dmAux);
3816:     DMGetDS(dmAux, &probAux);
3817:     PetscDSGetTotalDimension(probAux, &totDimAux);
3818:   }
3819:   /* 2: Get geometric data */
3820:   for (f = 0; f < Nf; ++f) {
3821:     PetscObject  obj;
3822:     PetscClassId id;
3823:     PetscBool    fimp;

3825:     PetscDSGetImplicit(prob, f, &fimp);
3826:     if (isImplicit != fimp) continue;
3827:     PetscDSGetDiscretization(prob, f, &obj);
3828:     PetscObjectGetClassId(obj, &id);
3829:     if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
3830:     if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented");
3831:   }
3832:   if (useFEM) {
3833:     DMGetCoordinateField(dm, &coordField);
3834:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
3835:     if (maxDegree <= 1) {
3836:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
3837:       if (affineQuad) {
3838:         DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3839:       }
3840:     } else {
3841:       PetscCalloc2(Nf,&quads,Nf,&geoms);
3842:       for (f = 0; f < Nf; ++f) {
3843:         PetscObject  obj;
3844:         PetscClassId id;
3845:         PetscBool    fimp;

3847:         PetscDSGetImplicit(prob, f, &fimp);
3848:         if (isImplicit != fimp) continue;
3849:         PetscDSGetDiscretization(prob, f, &obj);
3850:         PetscObjectGetClassId(obj, &id);
3851:         if (id == PETSCFE_CLASSID) {
3852:           PetscFE fe = (PetscFE) obj;

3854:           PetscFEGetQuadrature(fe, &quads[f]);
3855:           PetscObjectReference((PetscObject)quads[f]);
3856:           DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3857:         }
3858:       }
3859:     }
3860:   }
3861:   /* Loop over chunks */
3862:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3863:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
3864:   if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
3865:   numCells      = cEnd - cStart;
3866:   numChunks     = 1;
3867:   cellChunkSize = numCells/numChunks;
3868:   numChunks     = PetscMin(1,numCells);
3869:   key.label     = NULL;
3870:   key.value     = 0;
3871:   key.part      = 0;
3872:   for (chunk = 0; chunk < numChunks; ++chunk) {
3873:     PetscScalar     *elemVec, *fluxL = NULL, *fluxR = NULL;
3874:     PetscReal       *vol = NULL;
3875:     PetscFVFaceGeom *fgeom = NULL;
3876:     PetscInt         cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
3877:     PetscInt         numFaces = 0;

3879:     /* Extract field coefficients */
3880:     if (useFEM) {
3881:       ISGetPointSubrange(chunkIS, cS, cE, cells);
3882:       DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3883:       DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3884:       PetscArrayzero(elemVec, numCells*totDim);
3885:     }
3886:     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
3887:     /* Loop over fields */
3888:     for (f = 0; f < Nf; ++f) {
3889:       PetscObject  obj;
3890:       PetscClassId id;
3891:       PetscBool    fimp;
3892:       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

3894:       key.field = f;
3895:       PetscDSGetImplicit(prob, f, &fimp);
3896:       if (isImplicit != fimp) continue;
3897:       PetscDSGetDiscretization(prob, f, &obj);
3898:       PetscObjectGetClassId(obj, &id);
3899:       if (id == PETSCFE_CLASSID) {
3900:         PetscFE         fe = (PetscFE) obj;
3901:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
3902:         PetscFEGeom    *chunkGeom = NULL;
3903:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3904:         PetscInt        Nq, Nb;

3906:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
3907:         PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
3908:         PetscFEGetDimension(fe, &Nb);
3909:         blockSize = Nb;
3910:         batchSize = numBlocks * blockSize;
3911:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
3912:         numChunks = numCells / (numBatches*batchSize);
3913:         Ne        = numChunks*numBatches*batchSize;
3914:         Nr        = numCells % (numBatches*batchSize);
3915:         offset    = numCells - Nr;
3916:         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
3917:         /*   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) */
3918:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
3919:         PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
3920:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
3921:         PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
3922:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
3923:       } else if (id == PETSCFV_CLASSID) {
3924:         PetscFV fv = (PetscFV) obj;

3926:         Ne = numFaces;
3927:         /* Riemann solve over faces (need fields at face centroids) */
3928:         /*   We need to evaluate FE fields at those coordinates */
3929:         PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
3930:       } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
3931:     }
3932:     /* Loop over domain */
3933:     if (useFEM) {
3934:       /* Add elemVec to locX */
3935:       for (c = cS; c < cE; ++c) {
3936:         const PetscInt cell = cells ? cells[c] : c;
3937:         const PetscInt cind = c - cStart;

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

3943:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
3944:           if (ghostVal > 0) continue;
3945:         }
3946:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3947:       }
3948:     }
3949:     /* Handle time derivative */
3950:     if (locX_t) {
3951:       PetscScalar *x_t, *fa;

3953:       VecGetArray(locF, &fa);
3954:       VecGetArray(locX_t, &x_t);
3955:       for (f = 0; f < Nf; ++f) {
3956:         PetscFV      fv;
3957:         PetscObject  obj;
3958:         PetscClassId id;
3959:         PetscInt     pdim, d;

3961:         PetscDSGetDiscretization(prob, f, &obj);
3962:         PetscObjectGetClassId(obj, &id);
3963:         if (id != PETSCFV_CLASSID) continue;
3964:         fv   = (PetscFV) obj;
3965:         PetscFVGetNumComponents(fv, &pdim);
3966:         for (c = cS; c < cE; ++c) {
3967:           const PetscInt cell = cells ? cells[c] : c;
3968:           PetscScalar   *u_t, *r;

3970:           if (ghostLabel) {
3971:             PetscInt ghostVal;

3973:             DMLabelGetValue(ghostLabel, cell, &ghostVal);
3974:             if (ghostVal > 0) continue;
3975:           }
3976:           DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
3977:           DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
3978:           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
3979:         }
3980:       }
3981:       VecRestoreArray(locX_t, &x_t);
3982:       VecRestoreArray(locF, &fa);
3983:     }
3984:     if (useFEM) {
3985:       DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
3986:       DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
3987:     }
3988:   }
3989:   if (useFEM) {ISDestroy(&chunkIS);}
3990:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3991:   /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
3992:   if (useFEM) {
3993:     if (maxDegree <= 1) {
3994:       DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
3995:       PetscQuadratureDestroy(&affineQuad);
3996:     } else {
3997:       for (f = 0; f < Nf; ++f) {
3998:         DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
3999:         PetscQuadratureDestroy(&quads[f]);
4000:       }
4001:       PetscFree2(quads,geoms);
4002:     }
4003:   }
4004:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4005:   return(0);
4006: }

4008: /*
4009:   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

4011:   X   - The local solution vector
4012:   X_t - The local solution time derivative vector, or NULL
4013: */
4014: PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS,
4015:                                                     PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
4016: {
4017:   DM_Plex         *mesh  = (DM_Plex *) dm->data;
4018:   const char      *name = "Jacobian", *nameP = "JacobianPre";
4019:   DM               dmAux = NULL;
4020:   PetscDS          prob,   probAux = NULL;
4021:   PetscSection     sectionAux = NULL;
4022:   Vec              A;
4023:   DMField          coordField;
4024:   PetscFEGeom     *cgeomFEM;
4025:   PetscQuadrature  qGeom = NULL;
4026:   Mat              J = Jac, JP = JacP;
4027:   PetscScalar     *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
4028:   PetscBool        hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE;
4029:   const PetscInt  *cells;
4030:   PetscFormKey key;
4031:   PetscInt         Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
4032:   PetscErrorCode   ierr;

4035:   ISGetLocalSize(cellIS, &numCells);
4036:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4037:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
4038:   DMGetDS(dm, &prob);
4039:   DMGetAuxiliaryVec(dm, NULL, 0, &A);
4040:   if (A) {
4041:     VecGetDM(A, &dmAux);
4042:     DMGetLocalSection(dmAux, &sectionAux);
4043:     DMGetDS(dmAux, &probAux);
4044:   }
4045:   /* Get flags */
4046:   PetscDSGetNumFields(prob, &Nf);
4047:   DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4048:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
4049:     PetscObject  disc;
4050:     PetscClassId id;
4051:     PetscDSGetDiscretization(prob, fieldI, &disc);
4052:     PetscObjectGetClassId(disc, &id);
4053:     if (id == PETSCFE_CLASSID)      {isFE[fieldI] = PETSC_TRUE;}
4054:     else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;}
4055:   }
4056:   PetscDSHasJacobian(prob, &hasJac);
4057:   PetscDSHasJacobianPreconditioner(prob, &hasPrec);
4058:   PetscDSHasDynamicJacobian(prob, &hasDyn);
4059:   assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
4060:   hasDyn      = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
4061:   PetscObjectTypeCompare((PetscObject) Jac,  MATIS, &isMatIS);
4062:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
4063:   /* Setup input data and temp arrays (should be DMGetWorkArray) */
4064:   if (isMatISP || isMatISP) {DMPlexGetSubdomainSection(dm, &globalSection);}
4065:   if (isMatIS)  {MatISGetLocalMat(Jac,  &J);}
4066:   if (isMatISP) {MatISGetLocalMat(JacP, &JP);}
4067:   if (hasFV)    {MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);} /* No allocated space for FV stuff, so ignore the zero entries */
4068:   PetscDSGetTotalDimension(prob, &totDim);
4069:   if (probAux) {PetscDSGetTotalDimension(probAux, &totDimAux);}
4070:   /* Compute batch sizes */
4071:   if (isFE[0]) {
4072:     PetscFE         fe;
4073:     PetscQuadrature q;
4074:     PetscInt        numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;

4076:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4077:     PetscFEGetQuadrature(fe, &q);
4078:     PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);
4079:     PetscFEGetDimension(fe, &Nb);
4080:     PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4081:     blockSize = Nb*numQuadPoints;
4082:     batchSize = numBlocks  * blockSize;
4083:     chunkSize = numBatches * batchSize;
4084:     numChunks = numCells / chunkSize + numCells % chunkSize;
4085:     PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4086:   } else {
4087:     chunkSize = numCells;
4088:     numChunks = 1;
4089:   }
4090:   /* Get work space */
4091:   wsz  = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize;
4092:   DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);
4093:   PetscArrayzero(work, wsz);
4094:   off      = 0;
4095:   u        = X       ? (sz = chunkSize*totDim,        off += sz, work+off-sz) : NULL;
4096:   u_t      = X_t     ? (sz = chunkSize*totDim,        off += sz, work+off-sz) : NULL;
4097:   a        = dmAux   ? (sz = chunkSize*totDimAux,     off += sz, work+off-sz) : NULL;
4098:   elemMat  = hasJac  ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4099:   elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4100:   elemMatD = hasDyn  ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL;
4101:   if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz);
4102:   /* Setup geometry */
4103:   DMGetCoordinateField(dm, &coordField);
4104:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4105:   if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);}
4106:   if (!qGeom) {
4107:     PetscFE fe;

4109:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4110:     PetscFEGetQuadrature(fe, &qGeom);
4111:     PetscObjectReference((PetscObject) qGeom);
4112:   }
4113:   DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4114:   /* Compute volume integrals */
4115:   if (assembleJac) {MatZeroEntries(J);}
4116:   MatZeroEntries(JP);
4117:   key.label = NULL;
4118:   key.value = 0;
4119:   key.part  = 0;
4120:   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4121:     const PetscInt   Ncell = PetscMin(chunkSize, numCells - offCell);
4122:     PetscInt         c;

4124:     /* Extract values */
4125:     for (c = 0; c < Ncell; ++c) {
4126:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4127:       PetscScalar   *x = NULL,  *x_t = NULL;
4128:       PetscInt       i;

4130:       if (X) {
4131:         DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
4132:         for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i];
4133:         DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
4134:       }
4135:       if (X_t) {
4136:         DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
4137:         for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i];
4138:         DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
4139:       }
4140:       if (dmAux) {
4141:         DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);
4142:         for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i];
4143:         DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);
4144:       }
4145:     }
4146:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
4147:       PetscFE fe;
4148:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
4149:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
4150:         key.field = fieldI*Nf + fieldJ;
4151:         if (hasJac)  {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN,     key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);}
4152:         if (hasPrec) {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);}
4153:         if (hasDyn)  {PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);}
4154:       }
4155:       /* For finite volume, add the identity */
4156:       if (!isFE[fieldI]) {
4157:         PetscFV  fv;
4158:         PetscInt eOffset = 0, Nc, fc, foff;

4160:         PetscDSGetFieldOffset(prob, fieldI, &foff);
4161:         PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
4162:         PetscFVGetNumComponents(fv, &Nc);
4163:         for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) {
4164:           for (fc = 0; fc < Nc; ++fc) {
4165:             const PetscInt i = foff + fc;
4166:             if (hasJac)  {elemMat [eOffset+i*totDim+i] = 1.0;}
4167:             if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;}
4168:           }
4169:         }
4170:       }
4171:     }
4172:     /*   Add contribution from X_t */
4173:     if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
4174:     /* Insert values into matrix */
4175:     for (c = 0; c < Ncell; ++c) {
4176:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4177:       if (mesh->printFEM > 1) {
4178:         if (hasJac)  {DMPrintCellMatrix(cell, name,  totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);}
4179:         if (hasPrec) {DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);}
4180:       }
4181:       if (assembleJac) {DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);}
4182:       DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);
4183:     }
4184:   }
4185:   /* Cleanup */
4186:   DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4187:   PetscQuadratureDestroy(&qGeom);
4188:   if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
4189:   DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);
4190:   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);
4191:   /* Compute boundary integrals */
4192:   /* DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx); */
4193:   /* Assemble matrix */
4194:   if (assembleJac) {MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);}
4195:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
4196:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
4197:   return(0);
4198: }

4200: /******** FEM Assembly Function ********/

4202: static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4203: {
4204:   PetscBool      isPlex;

4208:   PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
4209:   if (isPlex) {
4210:     *plex = dm;
4211:     PetscObjectReference((PetscObject) dm);
4212:   } else {
4213:     PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
4214:     if (!*plex) {
4215:       DMConvert(dm,DMPLEX,plex);
4216:       PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
4217:       if (copy) {
4218:         DMCopyAuxiliaryVec(dm, *plex);
4219:       }
4220:     } else {
4221:       PetscObjectReference((PetscObject) *plex);
4222:     }
4223:   }
4224:   return(0);
4225: }

4227: /*@
4228:   DMPlexGetGeometryFVM - Return precomputed geometric data

4230:   Collective on DM

4232:   Input Parameter:
4233: . dm - The DM

4235:   Output Parameters:
4236: + facegeom - The values precomputed from face geometry
4237: . cellgeom - The values precomputed from cell geometry
4238: - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell

4240:   Level: developer

4242: .seealso: DMTSSetRHSFunctionLocal()
4243: @*/
4244: PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4245: {
4246:   DM             plex;

4251:   DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4252:   DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);
4253:   if (minRadius) {DMPlexGetMinRadius(plex, minRadius);}
4254:   DMDestroy(&plex);
4255:   return(0);
4256: }

4258: /*@
4259:   DMPlexGetGradientDM - Return gradient data layout

4261:   Collective on DM

4263:   Input Parameters:
4264: + dm - The DM
4265: - fv - The PetscFV

4267:   Output Parameter:
4268: . dmGrad - The layout for gradient values

4270:   Level: developer

4272: .seealso: DMPlexGetGeometryFVM()
4273: @*/
4274: PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4275: {
4276:   DM             plex;
4277:   PetscBool      computeGradients;

4284:   PetscFVGetComputeGradients(fv, &computeGradients);
4285:   if (!computeGradients) {*dmGrad = NULL; return(0);}
4286:   DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4287:   DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);
4288:   DMDestroy(&plex);
4289:   return(0);
4290: }

4292: static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS)
4293: {
4294:   DM_Plex         *mesh = (DM_Plex *) dm->data;
4295:   DM               plex = NULL, plexA = NULL;
4296:   DMEnclosureType  encAux;
4297:   PetscDS          prob, probAux = NULL;
4298:   PetscSection     section, sectionAux = NULL;
4299:   Vec              locA = NULL;
4300:   PetscScalar     *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
4301:   PetscInt         totDim, totDimAux = 0;
4302:   PetscErrorCode   ierr;

4305:   DMConvert(dm, DMPLEX, &plex);
4306:   DMGetLocalSection(dm, &section);
4307:   DMGetDS(dm, &prob);
4308:   PetscDSGetTotalDimension(prob, &totDim);
4309:   DMGetAuxiliaryVec(dm, key.label, key.value, &locA);
4310:   if (locA) {
4311:     DM dmAux;

4313:     VecGetDM(locA, &dmAux);
4314:     DMGetEnclosureRelation(dmAux, dm, &encAux);
4315:     DMConvert(dmAux, DMPLEX, &plexA);
4316:     DMGetDS(plexA, &probAux);
4317:     PetscDSGetTotalDimension(probAux, &totDimAux);
4318:     DMGetLocalSection(plexA, &sectionAux);
4319:   }
4320:   {
4321:     PetscFEGeom     *fgeom;
4322:     PetscInt         maxDegree;
4323:     PetscQuadrature  qGeom = NULL;
4324:     IS               pointIS;
4325:     const PetscInt  *points;
4326:     PetscInt         numFaces, face, Nq;

4328:     DMLabelGetStratumIS(key.label, key.value, &pointIS);
4329:     if (!pointIS) goto end; /* No points with that id on this process */
4330:     {
4331:       IS isectIS;

4333:       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
4334:       ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
4335:       ISDestroy(&pointIS);
4336:       pointIS = isectIS;
4337:     }
4338:     ISGetLocalSize(pointIS,&numFaces);
4339:     ISGetIndices(pointIS,&points);
4340:     PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a);
4341:     DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
4342:     if (maxDegree <= 1) {
4343:       DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
4344:     }
4345:     if (!qGeom) {
4346:       PetscFE fe;

4348:       PetscDSGetDiscretization(prob, key.field, (PetscObject *) &fe);
4349:       PetscFEGetFaceQuadrature(fe, &qGeom);
4350:       PetscObjectReference((PetscObject)qGeom);
4351:     }
4352:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
4353:     DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4354:     for (face = 0; face < numFaces; ++face) {
4355:       const PetscInt point = points[face], *support;
4356:       PetscScalar   *x     = NULL;
4357:       PetscInt       i;

4359:       DMPlexGetSupport(dm, point, &support);
4360:       DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
4361:       for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
4362:       DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
4363:       if (locX_t) {
4364:         DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
4365:         for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
4366:         DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
4367:       }
4368:       if (locA) {
4369:         PetscInt subp;

4371:         DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
4372:         DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
4373:         for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
4374:         DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
4375:       }
4376:     }
4377:     PetscArrayzero(elemVec, numFaces*totDim);
4378:     {
4379:       PetscFE         fe;
4380:       PetscInt        Nb;
4381:       PetscFEGeom     *chunkGeom = NULL;
4382:       /* Conforming batches */
4383:       PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
4384:       /* Remainder */
4385:       PetscInt        Nr, offset;

4387:       PetscDSGetDiscretization(prob, key.field, (PetscObject *) &fe);
4388:       PetscFEGetDimension(fe, &Nb);
4389:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4390:       /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
4391:       blockSize = Nb;
4392:       batchSize = numBlocks * blockSize;
4393:        PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4394:       numChunks = numFaces / (numBatches*batchSize);
4395:       Ne        = numChunks*numBatches*batchSize;
4396:       Nr        = numFaces % (numBatches*batchSize);
4397:       offset    = numFaces - Nr;
4398:       PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
4399:       PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);
4400:       PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);
4401:       PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
4402:       PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, a ? &a[offset*totDimAux] : NULL, t, &elemVec[offset*totDim]);
4403:       PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
4404:     }
4405:     for (face = 0; face < numFaces; ++face) {
4406:       const PetscInt point = points[face], *support;

4408:       if (mesh->printFEM > 1) {DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim]);}
4409:       DMPlexGetSupport(plex, point, &support);
4410:       DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES);
4411:     }
4412:     DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
4413:     PetscQuadratureDestroy(&qGeom);
4414:     ISRestoreIndices(pointIS, &points);
4415:     ISDestroy(&pointIS);
4416:     PetscFree4(u, u_t, elemVec, a);
4417:   }
4418:   end:
4419:   DMDestroy(&plex);
4420:   DMDestroy(&plexA);
4421:   return(0);
4422: }

4424: PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF)
4425: {
4426:   DMField        coordField;
4427:   DMLabel        depthLabel;
4428:   IS             facetIS;
4429:   PetscInt       dim;

4433:   DMGetDimension(dm, &dim);
4434:   DMPlexGetDepthLabel(dm, &depthLabel);
4435:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
4436:   DMGetCoordinateField(dm, &coordField);
4437:   DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS);
4438:   ISDestroy(&facetIS);
4439:   return(0);
4440: }

4442: PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4443: {
4444:   PetscDS        prob;
4445:   PetscInt       numBd, bd;
4446:   DMField        coordField = NULL;
4447:   IS             facetIS    = NULL;
4448:   DMLabel        depthLabel;
4449:   PetscInt       dim;

4453:   DMGetDS(dm, &prob);
4454:   DMPlexGetDepthLabel(dm, &depthLabel);
4455:   DMGetDimension(dm, &dim);
4456:   DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS);
4457:   PetscDSGetNumBoundary(prob, &numBd);
4458:   for (bd = 0; bd < numBd; ++bd) {
4459:     PetscWeakForm           wf;
4460:     DMBoundaryConditionType type;
4461:     DMLabel                 label;
4462:     const PetscInt         *values;
4463:     PetscInt                field, numValues, v;
4464:     PetscObject             obj;
4465:     PetscClassId            id;
4466:     PetscFormKey            key;

4468:     PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL);
4469:     PetscDSGetDiscretization(prob, field, &obj);
4470:     PetscObjectGetClassId(obj, &id);
4471:     if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
4472:     if (!facetIS) {
4473:       DMLabel  depthLabel;
4474:       PetscInt dim;

4476:       DMPlexGetDepthLabel(dm, &depthLabel);
4477:       DMGetDimension(dm, &dim);
4478:       DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4479:     }
4480:     DMGetCoordinateField(dm, &coordField);
4481:     for (v = 0; v < numValues; ++v) {
4482:       key.label = label;
4483:       key.value = values[v];
4484:       key.field = field;
4485:       key.part  = 0;
4486:       DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS);
4487:     }
4488:   }
4489:   ISDestroy(&facetIS);
4490:   return(0);
4491: }

4493: PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4494: {
4495:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
4496:   const char      *name       = "Residual";
4497:   DM               dmAux      = NULL;
4498:   DM               dmGrad     = NULL;
4499:   DMLabel          ghostLabel = NULL;
4500:   PetscDS          ds         = NULL;
4501:   PetscDS          dsAux      = NULL;
4502:   PetscSection     section    = NULL;
4503:   PetscBool        useFEM     = PETSC_FALSE;
4504:   PetscBool        useFVM     = PETSC_FALSE;
4505:   PetscBool        isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
4506:   PetscFV          fvm        = NULL;
4507:   PetscFVCellGeom *cgeomFVM   = NULL;
4508:   PetscFVFaceGeom *fgeomFVM   = NULL;
4509:   DMField          coordField = NULL;
4510:   Vec              locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
4511:   PetscScalar     *u = NULL, *u_t, *a, *uL, *uR;
4512:   IS               chunkIS;
4513:   const PetscInt  *cells;
4514:   PetscInt         cStart, cEnd, numCells;
4515:   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
4516:   PetscInt         maxDegree = PETSC_MAX_INT;
4517:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
4518:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
4519:   PetscErrorCode   ierr;

4522:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4523:   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4524:   /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
4525:   /* FEM+FVM */
4526:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4527:   DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4528:   /* 1: Get sizes from dm and dmAux */
4529:   DMGetLocalSection(dm, &section);
4530:   DMGetLabel(dm, "ghost", &ghostLabel);
4531:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds);
4532:   PetscDSGetNumFields(ds, &Nf);
4533:   PetscDSGetTotalDimension(ds, &totDim);
4534:   DMGetAuxiliaryVec(dm, key.label, key.value, &locA);
4535:   if (locA) {
4536:     PetscInt subcell;
4537:     VecGetDM(locA, &dmAux);
4538:     DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cStart, &subcell);
4539:     DMGetCellDS(dmAux, subcell, &dsAux);
4540:     PetscDSGetTotalDimension(dsAux, &totDimAux);
4541:   }
4542:   /* 2: Get geometric data */
4543:   for (f = 0; f < Nf; ++f) {
4544:     PetscObject  obj;
4545:     PetscClassId id;
4546:     PetscBool    fimp;

4548:     PetscDSGetImplicit(ds, f, &fimp);
4549:     if (isImplicit != fimp) continue;
4550:     PetscDSGetDiscretization(ds, f, &obj);
4551:     PetscObjectGetClassId(obj, &id);
4552:     if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
4553:     if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;}
4554:   }
4555:   if (useFEM) {
4556:     DMGetCoordinateField(dm, &coordField);
4557:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
4558:     if (maxDegree <= 1) {
4559:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
4560:       if (affineQuad) {
4561:         DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4562:       }
4563:     } else {
4564:       PetscCalloc2(Nf,&quads,Nf,&geoms);
4565:       for (f = 0; f < Nf; ++f) {
4566:         PetscObject  obj;
4567:         PetscClassId id;
4568:         PetscBool    fimp;

4570:         PetscDSGetImplicit(ds, f, &fimp);
4571:         if (isImplicit != fimp) continue;
4572:         PetscDSGetDiscretization(ds, f, &obj);
4573:         PetscObjectGetClassId(obj, &id);
4574:         if (id == PETSCFE_CLASSID) {
4575:           PetscFE fe = (PetscFE) obj;

4577:           PetscFEGetQuadrature(fe, &quads[f]);
4578:           PetscObjectReference((PetscObject)quads[f]);
4579:           DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4580:         }
4581:       }
4582:     }
4583:   }
4584:   if (useFVM) {
4585:     DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL);
4586:     VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM);
4587:     VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);
4588:     /* Reconstruct and limit cell gradients */
4589:     DMPlexGetGradientDM(dm, fvm, &dmGrad);
4590:     if (dmGrad) {
4591:       DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);
4592:       DMGetGlobalVector(dmGrad, &grad);
4593:       DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);
4594:       /* Communicate gradient values */
4595:       DMGetLocalVector(dmGrad, &locGrad);
4596:       DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);
4597:       DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);
4598:       DMRestoreGlobalVector(dmGrad, &grad);
4599:     }
4600:     /* Handle non-essential (e.g. outflow) boundary values */
4601:     DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad);
4602:   }
4603:   /* Loop over chunks */
4604:   if (useFEM) {ISCreate(PETSC_COMM_SELF, &chunkIS);}
4605:   numCells      = cEnd - cStart;
4606:   numChunks     = 1;
4607:   cellChunkSize = numCells/numChunks;
4608:   faceChunkSize = (fEnd - fStart)/numChunks;
4609:   numChunks     = PetscMin(1,numCells);
4610:   for (chunk = 0; chunk < numChunks; ++chunk) {
4611:     PetscScalar     *elemVec, *fluxL, *fluxR;
4612:     PetscReal       *vol;
4613:     PetscFVFaceGeom *fgeom;
4614:     PetscInt         cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;
4615:     PetscInt         fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face;

4617:     /* Extract field coefficients */
4618:     if (useFEM) {
4619:       ISGetPointSubrange(chunkIS, cS, cE, cells);
4620:       DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4621:       DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4622:       PetscArrayzero(elemVec, numCells*totDim);
4623:     }
4624:     if (useFVM) {
4625:       DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4626:       DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4627:       DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4628:       DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4629:       PetscArrayzero(fluxL, numFaces*totDim);
4630:       PetscArrayzero(fluxR, numFaces*totDim);
4631:     }
4632:     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
4633:     /* Loop over fields */
4634:     for (f = 0; f < Nf; ++f) {
4635:       PetscObject  obj;
4636:       PetscClassId id;
4637:       PetscBool    fimp;
4638:       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;

4640:       key.field = f;
4641:       PetscDSGetImplicit(ds, f, &fimp);
4642:       if (isImplicit != fimp) continue;
4643:       PetscDSGetDiscretization(ds, f, &obj);
4644:       PetscObjectGetClassId(obj, &id);
4645:       if (id == PETSCFE_CLASSID) {
4646:         PetscFE         fe = (PetscFE) obj;
4647:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
4648:         PetscFEGeom    *chunkGeom = NULL;
4649:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4650:         PetscInt        Nq, Nb;

4652:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4653:         PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4654:         PetscFEGetDimension(fe, &Nb);
4655:         blockSize = Nb;
4656:         batchSize = numBlocks * blockSize;
4657:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4658:         numChunks = numCells / (numBatches*batchSize);
4659:         Ne        = numChunks*numBatches*batchSize;
4660:         Nr        = numCells % (numBatches*batchSize);
4661:         offset    = numCells - Nr;
4662:         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
4663:         /*   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) */
4664:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4665:         PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec);
4666:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4667:         PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4668:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4669:       } else if (id == PETSCFV_CLASSID) {
4670:         PetscFV fv = (PetscFV) obj;

4672:         Ne = numFaces;
4673:         /* Riemann solve over faces (need fields at face centroids) */
4674:         /*   We need to evaluate FE fields at those coordinates */
4675:         PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
4676:       } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
4677:     }
4678:     /* Loop over domain */
4679:     if (useFEM) {
4680:       /* Add elemVec to locX */
4681:       for (c = cS; c < cE; ++c) {
4682:         const PetscInt cell = cells ? cells[c] : c;
4683:         const PetscInt cind = c - cStart;

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

4689:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
4690:           if (ghostVal > 0) continue;
4691:         }
4692:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4693:       }
4694:     }
4695:     if (useFVM) {
4696:       PetscScalar *fa;
4697:       PetscInt     iface;

4699:       VecGetArray(locF, &fa);
4700:       for (f = 0; f < Nf; ++f) {
4701:         PetscFV      fv;
4702:         PetscObject  obj;
4703:         PetscClassId id;
4704:         PetscInt     foff, pdim;

4706:         PetscDSGetDiscretization(ds, f, &obj);
4707:         PetscDSGetFieldOffset(ds, f, &foff);
4708:         PetscObjectGetClassId(obj, &id);
4709:         if (id != PETSCFV_CLASSID) continue;
4710:         fv   = (PetscFV) obj;
4711:         PetscFVGetNumComponents(fv, &pdim);
4712:         /* Accumulate fluxes to cells */
4713:         for (face = fS, iface = 0; face < fE; ++face) {
4714:           const PetscInt *scells;
4715:           PetscScalar    *fL = NULL, *fR = NULL;
4716:           PetscInt        ghost, d, nsupp, nchild;

4718:           DMLabelGetValue(ghostLabel, face, &ghost);
4719:           DMPlexGetSupportSize(dm, face, &nsupp);
4720:           DMPlexGetTreeChildren(dm, face, &nchild, NULL);
4721:           if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
4722:           DMPlexGetSupport(dm, face, &scells);
4723:           DMLabelGetValue(ghostLabel,scells[0],&ghost);
4724:           if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);}
4725:           DMLabelGetValue(ghostLabel,scells[1],&ghost);
4726:           if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);}
4727:           for (d = 0; d < pdim; ++d) {
4728:             if (fL) fL[d] -= fluxL[iface*totDim+foff+d];
4729:             if (fR) fR[d] += fluxR[iface*totDim+foff+d];
4730:           }
4731:           ++iface;
4732:         }
4733:       }
4734:       VecRestoreArray(locF, &fa);
4735:     }
4736:     /* Handle time derivative */
4737:     if (locX_t) {
4738:       PetscScalar *x_t, *fa;

4740:       VecGetArray(locF, &fa);
4741:       VecGetArray(locX_t, &x_t);
4742:       for (f = 0; f < Nf; ++f) {
4743:         PetscFV      fv;
4744:         PetscObject  obj;
4745:         PetscClassId id;
4746:         PetscInt     pdim, d;

4748:         PetscDSGetDiscretization(ds, f, &obj);
4749:         PetscObjectGetClassId(obj, &id);
4750:         if (id != PETSCFV_CLASSID) continue;
4751:         fv   = (PetscFV) obj;
4752:         PetscFVGetNumComponents(fv, &pdim);
4753:         for (c = cS; c < cE; ++c) {
4754:           const PetscInt cell = cells ? cells[c] : c;
4755:           PetscScalar   *u_t, *r;

4757:           if (ghostLabel) {
4758:             PetscInt ghostVal;

4760:             DMLabelGetValue(ghostLabel, cell, &ghostVal);
4761:             if (ghostVal > 0) continue;
4762:           }
4763:           DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
4764:           DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
4765:           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
4766:         }
4767:       }
4768:       VecRestoreArray(locX_t, &x_t);
4769:       VecRestoreArray(locF, &fa);
4770:     }
4771:     if (useFEM) {
4772:       DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4773:       DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4774:     }
4775:     if (useFVM) {
4776:       DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4777:       DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4778:       DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4779:       DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4780:       if (dmGrad) {DMRestoreLocalVector(dmGrad, &locGrad);}
4781:     }
4782:   }
4783:   if (useFEM) {ISDestroy(&chunkIS);}
4784:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);

4786:   if (useFEM) {
4787:     DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);

4789:     if (maxDegree <= 1) {
4790:       DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4791:       PetscQuadratureDestroy(&affineQuad);
4792:     } else {
4793:       for (f = 0; f < Nf; ++f) {
4794:         DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4795:         PetscQuadratureDestroy(&quads[f]);
4796:       }
4797:       PetscFree2(quads,geoms);
4798:     }
4799:   }

4801:   /* FEM */
4802:   /* 1: Get sizes from dm and dmAux */
4803:   /* 2: Get geometric data */
4804:   /* 3: Handle boundary values */
4805:   /* 4: Loop over domain */
4806:   /*   Extract coefficients */
4807:   /* Loop over fields */
4808:   /*   Set tiling for FE*/
4809:   /*   Integrate FE residual to get elemVec */
4810:   /*     Loop over subdomain */
4811:   /*       Loop over quad points */
4812:   /*         Transform coords to real space */
4813:   /*         Evaluate field and aux fields at point */
4814:   /*         Evaluate residual at point */
4815:   /*         Transform residual to real space */
4816:   /*       Add residual to elemVec */
4817:   /* Loop over domain */
4818:   /*   Add elemVec to locX */

4820:   /* FVM */
4821:   /* Get geometric data */
4822:   /* If using gradients */
4823:   /*   Compute gradient data */
4824:   /*   Loop over domain faces */
4825:   /*     Count computational faces */
4826:   /*     Reconstruct cell gradient */
4827:   /*   Loop over domain cells */
4828:   /*     Limit cell gradients */
4829:   /* Handle boundary values */
4830:   /* Loop over domain faces */
4831:   /*   Read out field, centroid, normal, volume for each side of face */
4832:   /* Riemann solve over faces */
4833:   /* Loop over domain faces */
4834:   /*   Accumulate fluxes to cells */
4835:   /* TODO Change printFEM to printDisc here */
4836:   if (mesh->printFEM) {
4837:     Vec         locFbc;
4838:     PetscInt    pStart, pEnd, p, maxDof;
4839:     PetscScalar *zeroes;

4841:     VecDuplicate(locF,&locFbc);
4842:     VecCopy(locF,locFbc);
4843:     PetscSectionGetChart(section,&pStart,&pEnd);
4844:     PetscSectionGetMaxDof(section,&maxDof);
4845:     PetscCalloc1(maxDof,&zeroes);
4846:     for (p = pStart; p < pEnd; p++) {
4847:       VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES);
4848:     }
4849:     PetscFree(zeroes);
4850:     DMPrintLocalVec(dm, name, mesh->printTol, locFbc);
4851:     VecDestroy(&locFbc);
4852:   }
4853:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4854:   return(0);
4855: }

4857: /*
4858:   1) Allow multiple kernels for BdResidual for hybrid DS

4860:   DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux

4862:   DONE 3) Change DMGetCellFields() to get different aux data a[] for each side
4863:      - I think I just need to replace a[] with the closure from each face

4865:   4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before
4866: */
4867: PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4868: {
4869:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
4870:   const char      *name       = "Hybrid Residual";
4871:   DM               dmAux[3]   = {NULL, NULL, NULL};
4872:   DMLabel          ghostLabel = NULL;
4873:   PetscDS          ds         = NULL;
4874:   PetscDS          dsAux[3]   = {NULL, NULL, NULL};
4875:   Vec              locA[3]    = {NULL, NULL, NULL};
4876:   PetscSection     section    = NULL;
4877:   DMField          coordField = NULL;
4878:   PetscScalar     *u = NULL, *u_t, *a[3];
4879:   PetscScalar     *elemVec;
4880:   IS               chunkIS;
4881:   const PetscInt  *cells;
4882:   PetscInt        *faces;
4883:   PetscInt         cStart, cEnd, numCells;
4884:   PetscInt         Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
4885:   PetscInt         maxDegree = PETSC_MAX_INT;
4886:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
4887:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
4888:   PetscErrorCode   ierr;

4891:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4892:   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4893:   /* FEM */
4894:   ISGetLocalSize(cellIS, &numCells);
4895:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4896:   /* 1: Get sizes from dm and dmAux */
4897:   DMGetSection(dm, &section);
4898:   DMGetLabel(dm, "ghost", &ghostLabel);
4899:   DMGetCellDS(dm, cStart, &ds);
4900:   PetscDSGetNumFields(ds, &Nf);
4901:   PetscDSGetTotalDimension(ds, &totDim);
4902:   DMGetAuxiliaryVec(dm, key[2].label, key[2].value, &locA[2]);
4903:   if (locA[2]) {
4904:     VecGetDM(locA[2], &dmAux[2]);
4905:     DMGetCellDS(dmAux[2], cStart, &dsAux[2]);
4906:     PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]);
4907:     {
4908:       const PetscInt *cone;
4909:       PetscInt        c;

4911:       DMPlexGetCone(dm, cStart, &cone);
4912:       for (c = 0; c < 2; ++c) {
4913:         const PetscInt *support;
4914:         PetscInt ssize, s;

4916:         DMPlexGetSupport(dm, cone[c], &support);
4917:         DMPlexGetSupportSize(dm, cone[c], &ssize);
4918:         if (ssize != 2) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D from cell %D has support size %D != 2", cone[c], cStart, ssize);
4919:         if      (support[0] == cStart) s = 1;
4920:         else if (support[1] == cStart) s = 0;
4921:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[c], cStart);
4922:         DMGetAuxiliaryVec(dm, key[c].label, key[c].value, &locA[c]);
4923:         if (locA[c]) {VecGetDM(locA[c], &dmAux[c]);}
4924:         else         {dmAux[c] = dmAux[2];}
4925:         DMGetCellDS(dmAux[c], support[s], &dsAux[c]);
4926:         PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]);
4927:       }
4928:     }
4929:   }
4930:   /* 2: Setup geometric data */
4931:   DMGetCoordinateField(dm, &coordField);
4932:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4933:   if (maxDegree > 1) {
4934:     PetscCalloc2(Nf, &quads, Nf, &geoms);
4935:     for (f = 0; f < Nf; ++f) {
4936:       PetscFE fe;

4938:       PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
4939:       if (fe) {
4940:         PetscFEGetQuadrature(fe, &quads[f]);
4941:         PetscObjectReference((PetscObject) quads[f]);
4942:       }
4943:     }
4944:   }
4945:   /* Loop over chunks */
4946:   cellChunkSize = numCells;
4947:   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
4948:   PetscCalloc1(2*cellChunkSize, &faces);
4949:   ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
4950:   /* Extract field coefficients */
4951:   /* NOTE This needs the end cap faces to have identical orientations */
4952:   DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
4953:   DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a);
4954:   DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec);
4955:   for (chunk = 0; chunk < numChunks; ++chunk) {
4956:     PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;

4958:     PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar));
4959:     /* Get faces */
4960:     for (c = cS; c < cE; ++c) {
4961:       const PetscInt  cell = cells ? cells[c] : c;
4962:       const PetscInt *cone;
4963:       DMPlexGetCone(dm, cell, &cone);
4964:       faces[(c-cS)*2+0] = cone[0];
4965:       faces[(c-cS)*2+1] = cone[1];
4966:     }
4967:     ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
4968:     /* Get geometric data */
4969:     if (maxDegree <= 1) {
4970:       if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
4971:       if (affineQuad)  {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
4972:     } else {
4973:       for (f = 0; f < Nf; ++f) {
4974:         if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
4975:       }
4976:     }
4977:     /* Loop over fields */
4978:     for (f = 0; f < Nf; ++f) {
4979:       PetscFE         fe;
4980:       PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
4981:       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
4982:       PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4983:       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;

4985:       PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
4986:       if (!fe) continue;
4987:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4988:       PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4989:       PetscFEGetDimension(fe, &Nb);
4990:       blockSize = Nb;
4991:       batchSize = numBlocks * blockSize;
4992:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4993:       numChunks = numCells / (numBatches*batchSize);
4994:       Ne        = numChunks*numBatches*batchSize;
4995:       Nr        = numCells % (numBatches*batchSize);
4996:       offset    = numCells - Nr;
4997:       PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4998:       PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);
4999:       chunkGeom->isHybrid = remGeom->isHybrid = PETSC_TRUE;
5000:       if (f == Nf-1) {
5001:         key[2].field = f;
5002:         PetscFEIntegrateHybridResidual(ds, key[2], Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec);
5003:         PetscFEIntegrateHybridResidual(ds, key[2], Nr, remGeom,  &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[2], &a[2][offset*totDimAux[2]], t, &elemVec[offset*totDim]);
5004:       } else {
5005:         key[0].field = f;
5006:         key[1].field = f;
5007:         PetscFEIntegrateHybridResidual(ds, key[0], Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec);
5008:         PetscFEIntegrateHybridResidual(ds, key[1], Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec);
5009:         PetscFEIntegrateHybridResidual(ds, key[0], Nr, remGeom,  &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[0], &a[0][offset*totDimAux[0]], t, &elemVec[offset*totDim]);
5010:         PetscFEIntegrateHybridResidual(ds, key[1], Nr, remGeom,  &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[1], &a[1][offset*totDimAux[1]], t, &elemVec[offset*totDim]);
5011:       }
5012:       PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);
5013:       PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);
5014:     }
5015:     /* Add elemVec to locX */
5016:     for (c = cS; c < cE; ++c) {
5017:       const PetscInt cell = cells ? cells[c] : c;
5018:       const PetscInt cind = c - cStart;

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

5024:         DMLabelGetValue(ghostLabel,cell,&ghostVal);
5025:         if (ghostVal > 0) continue;
5026:       }
5027:       DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
5028:     }
5029:   }
5030:   DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
5031:   DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a);
5032:   DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
5033:   PetscFree(faces);
5034:   ISDestroy(&chunkIS);
5035:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5036:   if (maxDegree <= 1) {
5037:     DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5038:     PetscQuadratureDestroy(&affineQuad);
5039:   } else {
5040:     for (f = 0; f < Nf; ++f) {
5041:       if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);}
5042:       if (quads) {PetscQuadratureDestroy(&quads[f]);}
5043:     }
5044:     PetscFree2(quads,geoms);
5045:   }
5046:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
5047:   return(0);
5048: }

5050: PetscErrorCode DMPlexComputeBdJacobian_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, 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)
5051: {
5052:   DM_Plex        *mesh = (DM_Plex *) dm->data;
5053:   DM              plex = NULL, plexA = NULL, tdm;
5054:   DMEnclosureType encAux;
5055:   PetscDS         prob, probAux = NULL;
5056:   PetscSection    section, sectionAux = NULL;
5057:   PetscSection    globalSection, subSection = NULL;
5058:   Vec             locA = NULL, tv;
5059:   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
5060:   PetscInt        v;
5061:   PetscInt        Nf, totDim, totDimAux = 0;
5062:   PetscBool       isMatISP, transform;
5063:   PetscErrorCode  ierr;

5066:   DMConvert(dm, DMPLEX, &plex);
5067:   DMHasBasisTransform(dm, &transform);
5068:   DMGetBasisTransformDM_Internal(dm, &tdm);
5069:   DMGetBasisTransformVec_Internal(dm, &tv);
5070:   DMGetLocalSection(dm, &section);
5071:   DMGetDS(dm, &prob);
5072:   PetscDSGetNumFields(prob, &Nf);
5073:   PetscDSGetTotalDimension(prob, &totDim);
5074:   DMGetAuxiliaryVec(dm, label, values[0], &locA);
5075:   if (locA) {
5076:     DM dmAux;

5078:     VecGetDM(locA, &dmAux);
5079:     DMGetEnclosureRelation(dmAux, dm, &encAux);
5080:     DMConvert(dmAux, DMPLEX, &plexA);
5081:     DMGetDS(plexA, &probAux);
5082:     PetscDSGetTotalDimension(probAux, &totDimAux);
5083:     DMGetLocalSection(plexA, &sectionAux);
5084:   }

5086:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5087:   DMGetGlobalSection(dm, &globalSection);
5088:   if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5089:   for (v = 0; v < numValues; ++v) {
5090:     PetscFEGeom     *fgeom;
5091:     PetscInt         maxDegree;
5092:     PetscQuadrature  qGeom = NULL;
5093:     IS               pointIS;
5094:     const PetscInt  *points;
5095:     PetscFormKey key;
5096:     PetscInt         numFaces, face, Nq;

5098:     key.label = label;
5099:     key.value = values[v];
5100:     key.part  = 0;
5101:     DMLabelGetStratumIS(label, values[v], &pointIS);
5102:     if (!pointIS) continue; /* No points with that id on this process */
5103:     {
5104:       IS isectIS;

5106:       /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
5107:       ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
5108:       ISDestroy(&pointIS);
5109:       pointIS = isectIS;
5110:     }
5111:     ISGetLocalSize(pointIS, &numFaces);
5112:     ISGetIndices(pointIS, &points);
5113:     PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a);
5114:     DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
5115:     if (maxDegree <= 1) {
5116:       DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
5117:     }
5118:     if (!qGeom) {
5119:       PetscFE fe;

5121:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5122:       PetscFEGetFaceQuadrature(fe, &qGeom);
5123:       PetscObjectReference((PetscObject)qGeom);
5124:     }
5125:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5126:     DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5127:     for (face = 0; face < numFaces; ++face) {
5128:       const PetscInt point = points[face], *support;
5129:       PetscScalar   *x     = NULL;
5130:       PetscInt       i;

5132:       DMPlexGetSupport(dm, point, &support);
5133:       DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
5134:       for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
5135:       DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
5136:       if (locX_t) {
5137:         DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
5138:         for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
5139:         DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
5140:       }
5141:       if (locA) {
5142:         PetscInt subp;
5143:         DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
5144:         DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
5145:         for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
5146:         DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
5147:       }
5148:     }
5149:     PetscArrayzero(elemMat, numFaces*totDim*totDim);
5150:     {
5151:       PetscFE         fe;
5152:       PetscInt        Nb;
5153:       /* Conforming batches */
5154:       PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5155:       /* Remainder */
5156:       PetscFEGeom    *chunkGeom = NULL;
5157:       PetscInt        fieldJ, Nr, offset;

5159:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5160:       PetscFEGetDimension(fe, &Nb);
5161:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5162:       blockSize = Nb;
5163:       batchSize = numBlocks * blockSize;
5164:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5165:       numChunks = numFaces / (numBatches*batchSize);
5166:       Ne        = numChunks*numBatches*batchSize;
5167:       Nr        = numFaces % (numBatches*batchSize);
5168:       offset    = numFaces - Nr;
5169:       PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
5170:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5171:         key.field = fieldI*Nf+fieldJ;
5172:         PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5173:       }
5174:       PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
5175:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5176:         key.field = fieldI*Nf+fieldJ;
5177:         PetscFEIntegrateBdJacobian(prob, wf, key, 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]);
5178:       }
5179:       PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
5180:     }
5181:     for (face = 0; face < numFaces; ++face) {
5182:       const PetscInt point = points[face], *support;

5184:       /* Transform to global basis before insertion in Jacobian */
5185:       DMPlexGetSupport(plex, point, &support);
5186:       if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim]);}
5187:       if (mesh->printFEM > 1) {DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim]);}
5188:       if (!isMatISP) {
5189:         DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5190:       } else {
5191:         Mat lJ;

5193:         MatISGetLocalMat(JacP, &lJ);
5194:         DMPlexMatSetClosure(plex, section, subSection, lJ, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5195:       }
5196:     }
5197:     DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5198:     PetscQuadratureDestroy(&qGeom);
5199:     ISRestoreIndices(pointIS, &points);
5200:     ISDestroy(&pointIS);
5201:     PetscFree4(u, u_t, elemMat, a);
5202:   }
5203:   if (plex)  {DMDestroy(&plex);}
5204:   if (plexA) {DMDestroy(&plexA);}
5205:   return(0);
5206: }

5208: PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP)
5209: {
5210:   DMField        coordField;
5211:   DMLabel        depthLabel;
5212:   IS             facetIS;
5213:   PetscInt       dim;

5217:   DMGetDimension(dm, &dim);
5218:   DMPlexGetDepthLabel(dm, &depthLabel);
5219:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5220:   DMGetCoordinateField(dm, &coordField);
5221:   DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5222:   ISDestroy(&facetIS);
5223:   return(0);
5224: }

5226: PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5227: {
5228:   PetscDS          prob;
5229:   PetscInt         dim, numBd, bd;
5230:   DMLabel          depthLabel;
5231:   DMField          coordField = NULL;
5232:   IS               facetIS;
5233:   PetscErrorCode   ierr;

5236:   DMGetDS(dm, &prob);
5237:   DMPlexGetDepthLabel(dm, &depthLabel);
5238:   DMGetDimension(dm, &dim);
5239:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5240:   PetscDSGetNumBoundary(prob, &numBd);
5241:   DMGetCoordinateField(dm, &coordField);
5242:   for (bd = 0; bd < numBd; ++bd) {
5243:     PetscWeakForm           wf;
5244:     DMBoundaryConditionType type;
5245:     DMLabel                 label;
5246:     const PetscInt         *values;
5247:     PetscInt                fieldI, numValues;
5248:     PetscObject             obj;
5249:     PetscClassId            id;

5251:     PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL);
5252:     PetscDSGetDiscretization(prob, fieldI, &obj);
5253:     PetscObjectGetClassId(obj, &id);
5254:     if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
5255:     DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5256:   }
5257:   ISDestroy(&facetIS);
5258:   return(0);
5259: }

5261: PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP,void *user)
5262: {
5263:   DM_Plex        *mesh  = (DM_Plex *) dm->data;
5264:   const char     *name  = "Jacobian";
5265:   DM              dmAux = NULL, plex, tdm;
5266:   DMEnclosureType encAux;
5267:   Vec             A, tv;
5268:   DMField         coordField;
5269:   PetscDS         prob, probAux = NULL;
5270:   PetscSection    section, globalSection, subSection, sectionAux;
5271:   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
5272:   const PetscInt *cells;
5273:   PetscInt        Nf, fieldI, fieldJ;
5274:   PetscInt        totDim, totDimAux, cStart, cEnd, numCells, c;
5275:   PetscBool       isMatIS, isMatISP, hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform;
5276:   PetscErrorCode  ierr;

5279:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5280:   ISGetLocalSize(cellIS, &numCells);
5281:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5282:   DMHasBasisTransform(dm, &transform);
5283:   DMGetBasisTransformDM_Internal(dm, &tdm);
5284:   DMGetBasisTransformVec_Internal(dm, &tv);
5285:   DMGetLocalSection(dm, &section);
5286:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5287:   DMGetGlobalSection(dm, &globalSection);
5288:   if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5289:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5290:   PetscDSGetNumFields(prob, &Nf);
5291:   PetscDSGetTotalDimension(prob, &totDim);
5292:   PetscDSHasJacobian(prob, &hasJac);
5293:   PetscDSHasJacobianPreconditioner(prob, &hasPrec);
5294:   /* user passed in the same matrix, avoid double contributions and
5295:      only assemble the Jacobian */
5296:   if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
5297:   PetscDSHasDynamicJacobian(prob, &hasDyn);
5298:   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5299:   DMGetAuxiliaryVec(dm, key.label, key.value, &A);
5300:   if (A) {
5301:     VecGetDM(A, &dmAux);
5302:     DMGetEnclosureRelation(dmAux, dm, &encAux);
5303:     DMConvert(dmAux, DMPLEX, &plex);
5304:     DMGetLocalSection(plex, &sectionAux);
5305:     DMGetDS(dmAux, &probAux);
5306:     PetscDSGetTotalDimension(probAux, &totDimAux);
5307:   }
5308:   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);
5309:   if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
5310:   DMGetCoordinateField(dm, &coordField);
5311:   for (c = cStart; c < cEnd; ++c) {
5312:     const PetscInt cell = cells ? cells[c] : c;
5313:     const PetscInt cind = c - cStart;
5314:     PetscScalar   *x = NULL,  *x_t = NULL;
5315:     PetscInt       i;

5317:     DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
5318:     for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
5319:     DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
5320:     if (X_t) {
5321:       DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
5322:       for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
5323:       DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
5324:     }
5325:     if (dmAux) {
5326:       PetscInt subcell;
5327:       DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5328:       DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);
5329:       for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
5330:       DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);
5331:     }
5332:   }
5333:   if (hasJac)  {PetscArrayzero(elemMat,  numCells*totDim*totDim);}
5334:   if (hasPrec) {PetscArrayzero(elemMatP, numCells*totDim*totDim);}
5335:   if (hasDyn)  {PetscArrayzero(elemMatD, numCells*totDim*totDim);}
5336:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
5337:     PetscClassId    id;
5338:     PetscFE         fe;
5339:     PetscQuadrature qGeom = NULL;
5340:     PetscInt        Nb;
5341:     /* Conforming batches */
5342:     PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5343:     /* Remainder */
5344:     PetscInt        Nr, offset, Nq;
5345:     PetscInt        maxDegree;
5346:     PetscFEGeom     *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;

5348:     PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5349:     PetscObjectGetClassId((PetscObject) fe, &id);
5350:     if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;}
5351:     PetscFEGetDimension(fe, &Nb);
5352:     PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5353:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
5354:     if (maxDegree <= 1) {
5355:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);
5356:     }
5357:     if (!qGeom) {
5358:       PetscFEGetQuadrature(fe,&qGeom);
5359:       PetscObjectReference((PetscObject)qGeom);
5360:     }
5361:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5362:     DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5363:     blockSize = Nb;
5364:     batchSize = numBlocks * blockSize;
5365:     PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5366:     numChunks = numCells / (numBatches*batchSize);
5367:     Ne        = numChunks*numBatches*batchSize;
5368:     Nr        = numCells % (numBatches*batchSize);
5369:     offset    = numCells - Nr;
5370:     PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
5371:     PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);
5372:     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5373:       key.field = fieldI*Nf+fieldJ;
5374:       if (hasJac) {
5375:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5376:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5377:       }
5378:       if (hasPrec) {
5379:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5380:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5381:       }
5382:       if (hasDyn) {
5383:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5384:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatD[offset*totDim*totDim]);
5385:       }
5386:     }
5387:     PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);
5388:     PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);
5389:     DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5390:     PetscQuadratureDestroy(&qGeom);
5391:   }
5392:   /*   Add contribution from X_t */
5393:   if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];}
5394:   if (hasFV) {
5395:     PetscClassId id;
5396:     PetscFV      fv;
5397:     PetscInt     offsetI, NcI, NbI = 1, fc, f;

5399:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
5400:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);
5401:       PetscDSGetFieldOffset(prob, fieldI, &offsetI);
5402:       PetscObjectGetClassId((PetscObject) fv, &id);
5403:       if (id != PETSCFV_CLASSID) continue;
5404:       /* Put in the identity */
5405:       PetscFVGetNumComponents(fv, &NcI);
5406:       for (c = cStart; c < cEnd; ++c) {
5407:         const PetscInt cind    = c - cStart;
5408:         const PetscInt eOffset = cind*totDim*totDim;
5409:         for (fc = 0; fc < NcI; ++fc) {
5410:           for (f = 0; f < NbI; ++f) {
5411:             const PetscInt i = offsetI + f*NcI+fc;
5412:             if (hasPrec) {
5413:               if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;}
5414:               elemMatP[eOffset+i*totDim+i] = 1.0;
5415:             } else {elemMat[eOffset+i*totDim+i] = 1.0;}
5416:           }
5417:         }
5418:       }
5419:     }
5420:     /* No allocated space for FV stuff, so ignore the zero entries */
5421:     MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);
5422:   }
5423:   /* Insert values into matrix */
5424:   isMatIS = PETSC_FALSE;
5425:   if (hasPrec && hasJac) {
5426:     PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);
5427:   }
5428:   if (isMatIS && !subSection) {
5429:     DMPlexGetSubdomainSection(dm, &subSection);
5430:   }
5431:   for (c = cStart; c < cEnd; ++c) {
5432:     const PetscInt cell = cells ? cells[c] : c;
5433:     const PetscInt cind = c - cStart;

5435:     /* Transform to global basis before insertion in Jacobian */
5436:     if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim]);}
5437:     if (hasPrec) {
5438:       if (hasJac) {
5439:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5440:         if (!isMatIS) {
5441:           DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5442:         } else {
5443:           Mat lJ;

5445:           MatISGetLocalMat(Jac,&lJ);
5446:           DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5447:         }
5448:       }
5449:       if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5450:       if (!isMatISP) {
5451:         DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5452:       } else {
5453:         Mat lJ;

5455:         MatISGetLocalMat(JacP,&lJ);
5456:         DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5457:       }
5458:     } else {
5459:       if (hasJac) {
5460:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5461:         if (!isMatISP) {
5462:           DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5463:         } else {
5464:           Mat lJ;

5466:           MatISGetLocalMat(JacP,&lJ);
5467:           DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5468:         }
5469:       }
5470:     }
5471:   }
5472:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5473:   if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
5474:   PetscFree5(u,u_t,elemMat,elemMatP,elemMatD);
5475:   if (dmAux) {
5476:     PetscFree(a);
5477:     DMDestroy(&plex);
5478:   }
5479:   /* Compute boundary integrals */
5480:   DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);
5481:   /* Assemble matrix */
5482:   if (hasJac && hasPrec) {
5483:     MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5484:     MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5485:   }
5486:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5487:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5488:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5489:   return(0);
5490: }

5492: PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5493: {
5494:   DM_Plex         *mesh          = (DM_Plex *) dm->data;
5495:   const char      *name          = "Hybrid Jacobian";
5496:   DM               dmAux[3]      = {NULL, NULL, NULL};
5497:   DMLabel          ghostLabel    = NULL;
5498:   DM               plex          = NULL;
5499:   DM               plexA         = NULL;
5500:   PetscDS          ds            = NULL;
5501:   PetscDS          dsAux[3]      = {NULL, NULL, NULL};
5502:   Vec              locA[3]       = {NULL, NULL, NULL};
5503:   PetscSection     section       = NULL;
5504:   PetscSection     sectionAux[3] = {NULL, NULL, NULL};
5505:   DMField          coordField    = NULL;
5506:   PetscScalar     *u = NULL, *u_t, *a[3];
5507:   PetscScalar     *elemMat, *elemMatP;
5508:   PetscSection     globalSection, subSection;
5509:   IS               chunkIS;
5510:   const PetscInt  *cells;
5511:   PetscInt        *faces;
5512:   PetscInt         cStart, cEnd, numCells;
5513:   PetscInt         Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
5514:   PetscInt         maxDegree = PETSC_MAX_INT;
5515:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
5516:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
5517:   PetscBool        repeatKey = PETSC_FALSE, isMatIS = PETSC_FALSE, isMatISP = PETSC_FALSE, hasBdJac, hasBdPrec;
5518:   PetscErrorCode   ierr;

5521:   /* If keys are the same, both kernel will be run using the first key */
5522:   repeatKey = ((key[0].label == key[1].label) && (key[0].value == key[1].value)) ? PETSC_TRUE : PETSC_FALSE;
5523:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5524:   ISGetLocalSize(cellIS, &numCells);
5525:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5526:   DMConvert(dm, DMPLEX, &plex);
5527:   DMGetSection(dm, &section);
5528:   DMGetGlobalSection(dm, &globalSection);
5529:   DMGetLabel(dm, "ghost", &ghostLabel);
5530:   DMGetCellDS(dm, cStart, &ds);
5531:   PetscDSGetNumFields(ds, &Nf);
5532:   PetscDSGetTotalDimension(ds, &totDim);
5533:   PetscDSHasBdJacobian(ds, &hasBdJac);
5534:   PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec);
5535:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5536:   if (isMatISP)               {DMPlexGetSubdomainSection(plex, &subSection);}
5537:   if (hasBdPrec && hasBdJac)  {PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);}
5538:   if (isMatIS && !subSection) {DMPlexGetSubdomainSection(plex, &subSection);}
5539:   DMGetAuxiliaryVec(dm, key[2].label, key[2].value, &locA[2]);
5540:   if (locA[2]) {
5541:     VecGetDM(locA[2], &dmAux[2]);
5542:     DMConvert(dmAux[2], DMPLEX, &plexA);
5543:     DMGetSection(dmAux[2], &sectionAux[2]);
5544:     DMGetCellDS(dmAux[2], cStart, &dsAux[2]);
5545:     PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]);
5546:     {
5547:       const PetscInt *cone;
5548:       PetscInt        c;

5550:       DMPlexGetCone(dm, cStart, &cone);
5551:       for (c = 0; c < 2; ++c) {
5552:         const PetscInt *support;
5553:         PetscInt ssize, s;

5555:         DMPlexGetSupport(dm, cone[c], &support);
5556:         DMPlexGetSupportSize(dm, cone[c], &ssize);
5557:         if (ssize != 2) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D from cell %D has support size %D != 2", cone[c], cStart, ssize);
5558:         if      (support[0] == cStart) s = 1;
5559:         else if (support[1] == cStart) s = 0;
5560:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[c], cStart);
5561:         DMGetAuxiliaryVec(dm, key[c].label, key[c].value, &locA[c]);
5562:         if (locA[c]) {VecGetDM(locA[c], &dmAux[c]);}
5563:         else         {dmAux[c] = dmAux[2];}
5564:         DMGetCellDS(dmAux[c], support[s], &dsAux[c]);
5565:         PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]);
5566:       }
5567:     }
5568:   }
5569:   DMGetCoordinateField(dm, &coordField);
5570:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5571:   if (maxDegree > 1) {
5572:     PetscInt f;
5573:     PetscCalloc2(Nf, &quads, Nf, &geoms);
5574:     for (f = 0; f < Nf; ++f) {
5575:       PetscFE fe;

5577:       PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
5578:       if (fe) {
5579:         PetscFEGetQuadrature(fe, &quads[f]);
5580:         PetscObjectReference((PetscObject) quads[f]);
5581:       }
5582:     }
5583:   }
5584:   cellChunkSize = numCells;
5585:   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
5586:   PetscCalloc1(2*cellChunkSize, &faces);
5587:   ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
5588:   DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
5589:   DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a);
5590:   DMGetWorkArray(dm, hasBdJac  ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5591:   DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5592:   for (chunk = 0; chunk < numChunks; ++chunk) {
5593:     PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;

5595:     if (hasBdJac)  {PetscMemzero(elemMat,  numCells*totDim*totDim * sizeof(PetscScalar));}
5596:     if (hasBdPrec) {PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar));}
5597:     /* Get faces */
5598:     for (c = cS; c < cE; ++c) {
5599:       const PetscInt  cell = cells ? cells[c] : c;
5600:       const PetscInt *cone;
5601:       DMPlexGetCone(plex, cell, &cone);
5602:       faces[(c-cS)*2+0] = cone[0];
5603:       faces[(c-cS)*2+1] = cone[1];
5604:     }
5605:     ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
5606:     if (maxDegree <= 1) {
5607:       if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
5608:       if (affineQuad)  {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
5609:     } else {
5610:       PetscInt f;
5611:       for (f = 0; f < Nf; ++f) {
5612:         if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
5613:       }
5614:     }

5616:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
5617:       PetscFE         feI;
5618:       PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[fieldI];
5619:       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
5620:       PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
5621:       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;

5623:       PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI);
5624:       if (!feI) continue;
5625:       PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);
5626:       PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
5627:       PetscFEGetDimension(feI, &Nb);
5628:       blockSize = Nb;
5629:       batchSize = numBlocks * blockSize;
5630:       PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);
5631:       numChunks = numCells / (numBatches*batchSize);
5632:       Ne        = numChunks*numBatches*batchSize;
5633:       Nr        = numCells % (numBatches*batchSize);
5634:       offset    = numCells - Nr;
5635:       PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
5636:       PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);
5637:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5638:         PetscFE feJ;

5640:         PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ);
5641:         if (!feJ) continue;
5642:         if (fieldI == Nf-1) {
5643:           key[2].field = fieldI*Nf+fieldJ;
5644:           if (hasBdJac) {
5645:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat);
5646:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[2], &a[2][offset*totDimAux[2]], t, X_tShift, &elemMat[offset*totDim*totDim]);
5647:           }
5648:           if (hasBdPrec) {
5649:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP);
5650:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[2], &a[2][offset*totDimAux[2]], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5651:           }
5652:         } else {
5653:           key[0].field = fieldI*Nf+fieldJ;
5654:           key[1].field = fieldI*Nf+fieldJ;
5655:           if (hasBdJac) {
5656:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat);
5657:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[0], &a[0][offset*totDimAux[0]], t, X_tShift, &elemMat[offset*totDim*totDim]);
5658:             if (!repeatKey) {
5659:               PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat);
5660:               PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[1], &a[1][offset*totDimAux[1]], t, X_tShift, &elemMat[offset*totDim*totDim]);
5661:             }
5662:           }
5663:           if (hasBdPrec) {
5664:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP);
5665:             PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[0], &a[0][offset*totDimAux[0]], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5666:             if (!repeatKey) {
5667:               PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP);
5668:               PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[1], &a[1][offset*totDimAux[1]], t, X_tShift, &elemMatP[offset*totDim*totDim]);
5669:             }
5670:           }
5671:         }
5672:       }
5673:       PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);
5674:       PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);
5675:     }
5676:     /* Insert values into matrix */
5677:     for (c = cS; c < cE; ++c) {
5678:       const PetscInt cell = cells ? cells[c] : c;
5679:       const PetscInt cind = c - cS;

5681:       if (hasBdPrec) {
5682:         if (hasBdJac) {
5683:           if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5684:           if (!isMatIS) {
5685:             DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5686:           } else {
5687:             Mat lJ;

5689:             MatISGetLocalMat(Jac,&lJ);
5690:             DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5691:           }
5692:         }
5693:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5694:         if (!isMatISP) {
5695:           DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5696:         } else {
5697:           Mat lJ;

5699:           MatISGetLocalMat(JacP,&lJ);
5700:           DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5701:         }
5702:       } else if (hasBdJac) {
5703:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5704:         if (!isMatISP) {
5705:           DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5706:         } else {
5707:           Mat lJ;

5709:           MatISGetLocalMat(JacP,&lJ);
5710:           DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5711:         }
5712:       }
5713:     }
5714:   }
5715:   DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]);
5716:   DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a);
5717:   DMRestoreWorkArray(dm, hasBdJac  ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5718:   DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5719:   PetscFree(faces);
5720:   ISDestroy(&chunkIS);
5721:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5722:   if (maxDegree <= 1) {
5723:     DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5724:     PetscQuadratureDestroy(&affineQuad);
5725:   } else {
5726:     PetscInt f;
5727:     for (f = 0; f < Nf; ++f) {
5728:       if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f]);}
5729:       if (quads) {PetscQuadratureDestroy(&quads[f]);}
5730:     }
5731:     PetscFree2(quads,geoms);
5732:   }
5733:   if (dmAux[2]) {DMDestroy(&plexA);}
5734:   DMDestroy(&plex);
5735:   /* Assemble matrix */
5736:   if (hasBdJac && hasBdPrec) {
5737:     MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5738:     MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5739:   }
5740:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5741:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5742:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5743:   return(0);
5744: }

5746: /*
5747:   DMPlexComputeJacobian_Action_Internal - Form the local portion of the Jacobian action Z = J(X) Y at the local solution X using pointwise functions specified by the user.

5749:   Input Parameters:
5750: + dm     - The mesh
5751: . key    - The PetscWeakFormKey indcating where integration should happen
5752: . cellIS - The cells to integrate over
5753: . t      - The time
5754: . X_tShift - The multiplier for the Jacobian with repsect to X_t
5755: . X      - Local solution vector
5756: . X_t    - Time-derivative of the local solution vector
5757: . Y      - Local input vector
5758: - user   - the user context

5760:   Output Parameter:
5761: . Z - Local output vector

5763:   Note:
5764:   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
5765:   like a GPU, or vectorize on a multicore machine.
5766: */
5767: PetscErrorCode DMPlexComputeJacobian_Action_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Vec Y, Vec Z, void *user)
5768: {
5769:   DM_Plex        *mesh  = (DM_Plex *) dm->data;
5770:   const char     *name  = "Jacobian";
5771:   DM              dmAux = NULL, plex, plexAux = NULL;
5772:   DMEnclosureType encAux;
5773:   Vec             A;
5774:   DMField         coordField;
5775:   PetscDS         prob, probAux = NULL;
5776:   PetscQuadrature quad;
5777:   PetscSection    section, globalSection, sectionAux;
5778:   PetscScalar    *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z;
5779:   const PetscInt *cells;
5780:   PetscInt        Nf, fieldI, fieldJ;
5781:   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
5782:   PetscBool       hasDyn;
5783:   PetscErrorCode  ierr;

5786:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5787:   DMConvert(dm, DMPLEX, &plex);
5788:   if (!cellIS) {
5789:     PetscInt depth;

5791:     DMPlexGetDepth(plex, &depth);
5792:     DMGetStratumIS(plex, "dim", depth, &cellIS);
5793:     if (!cellIS) {DMGetStratumIS(plex, "depth", depth, &cellIS);}
5794:   } else {
5795:     PetscObjectReference((PetscObject) cellIS);
5796:   }
5797:   ISGetLocalSize(cellIS, &numCells);
5798:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5799:   DMGetLocalSection(dm, &section);
5800:   DMGetGlobalSection(dm, &globalSection);
5801:   DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);
5802:   PetscDSGetNumFields(prob, &Nf);
5803:   PetscDSGetTotalDimension(prob, &totDim);
5804:   PetscDSHasDynamicJacobian(prob, &hasDyn);
5805:   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
5806:   DMGetAuxiliaryVec(dm, key.label, key.value, &A);
5807:   if (A) {
5808:     VecGetDM(A, &dmAux);
5809:     DMGetEnclosureRelation(dmAux, dm, &encAux);
5810:     DMConvert(dmAux, DMPLEX, &plexAux);
5811:     DMGetLocalSection(plexAux, &sectionAux);
5812:     DMGetDS(dmAux, &probAux);
5813:     PetscDSGetTotalDimension(probAux, &totDimAux);
5814:   }
5815:   VecSet(Z, 0.0);
5816:   PetscMalloc6(numCells*totDim,&u,X_t ? numCells*totDim : 0,&u_t,numCells*totDim*totDim,&elemMat,hasDyn ? numCells*totDim*totDim : 0, &elemMatD,numCells*totDim,&y,totDim,&z);
5817:   if (dmAux) {PetscMalloc1(numCells*totDimAux, &a);}
5818:   DMGetCoordinateField(dm, &coordField);
5819:   for (c = cStart; c < cEnd; ++c) {
5820:     const PetscInt cell = cells ? cells[c] : c;
5821:     const PetscInt cind = c - cStart;
5822:     PetscScalar   *x = NULL,  *x_t = NULL;
5823:     PetscInt       i;

5825:     DMPlexVecGetClosure(plex, section, X, cell, NULL, &x);
5826:     for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
5827:     DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x);
5828:     if (X_t) {
5829:       DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t);
5830:       for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
5831:       DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t);
5832:     }
5833:     if (dmAux) {
5834:       PetscInt subcell;
5835:       DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5836:       DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x);
5837:       for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
5838:       DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x);
5839:     }
5840:     DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x);
5841:     for (i = 0; i < totDim; ++i) y[cind*totDim+i] = x[i];
5842:     DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x);
5843:   }
5844:   PetscArrayzero(elemMat, numCells*totDim*totDim);
5845:   if (hasDyn)  {PetscArrayzero(elemMatD, numCells*totDim*totDim);}
5846:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
5847:     PetscFE  fe;
5848:     PetscInt Nb;
5849:     /* Conforming batches */
5850:     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5851:     /* Remainder */
5852:     PetscInt Nr, offset, Nq;
5853:     PetscQuadrature qGeom = NULL;
5854:     PetscInt    maxDegree;
5855:     PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;

5857:     PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5858:     PetscFEGetQuadrature(fe, &quad);
5859:     PetscFEGetDimension(fe, &Nb);
5860:     PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5861:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
5862:     if (maxDegree <= 1) {DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);}
5863:     if (!qGeom) {
5864:       PetscFEGetQuadrature(fe,&qGeom);
5865:       PetscObjectReference((PetscObject)qGeom);
5866:     }
5867:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5868:     DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5869:     blockSize = Nb;
5870:     batchSize = numBlocks * blockSize;
5871:     PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5872:     numChunks = numCells / (numBatches*batchSize);
5873:     Ne        = numChunks*numBatches*batchSize;
5874:     Nr        = numCells % (numBatches*batchSize);
5875:     offset    = numCells - Nr;
5876:     PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);
5877:     PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);
5878:     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5879:       key.field = fieldI*Nf + fieldJ;
5880:       PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5881:       PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMat[offset*totDim*totDim]);
5882:       if (hasDyn) {
5883:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);
5884:         PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, X_tShift, &elemMatD[offset*totDim*totDim]);
5885:       }
5886:     }
5887:     PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);
5888:     PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);
5889:     DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);
5890:     PetscQuadratureDestroy(&qGeom);
5891:   }
5892:   if (hasDyn) {
5893:     for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];
5894:   }
5895:   for (c = cStart; c < cEnd; ++c) {
5896:     const PetscInt     cell = cells ? cells[c] : c;
5897:     const PetscInt     cind = c - cStart;
5898:     const PetscBLASInt M = totDim, one = 1;
5899:     const PetscScalar  a = 1.0, b = 0.0;

5901:     PetscStackCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind*totDim*totDim], &M, &y[cind*totDim], &one, &b, z, &one));
5902:     if (mesh->printFEM > 1) {
5903:       DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind*totDim*totDim]);
5904:       DMPrintCellVector(c, "Y",  totDim, &y[cind*totDim]);
5905:       DMPrintCellVector(c, "Z",  totDim, z);
5906:     }
5907:     DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES);
5908:   }
5909:   PetscFree6(u,u_t,elemMat,elemMatD,y,z);
5910:   if (mesh->printFEM) {
5911:     PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n");
5912:     VecView(Z, NULL);
5913:   }
5914:   PetscFree(a);
5915:   ISDestroy(&cellIS);
5916:   DMDestroy(&plexAux);
5917:   DMDestroy(&plex);
5918:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5919:   return(0);
5920: }