Actual source code: plexfem.c

petsc-main 2021-04-20
Report Typos and Errors
  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petscsf.h>

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

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

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

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

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

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

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

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

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

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

 83:   Not collective

 85:   Input Arguments:
 86: + dm   - the DM
 87: - unit - The SI unit

 89:   Output Argument:
 90: . scale - The value used to scale all quantities with this unit

 92:   Level: advanced

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

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

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

110:   Not collective

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

117:   Level: advanced

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

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

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

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

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

157:   Collective on dm

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

163:   Output Argument:
164: . sp - the null space

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

168:   Level: advanced

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

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

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

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

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

231:   Collective on dm

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

240:   Output Argument:
241: . sp - the null space

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

245:   Level: advanced

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

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

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

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

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

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

313:   Level: advanced

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

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

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

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

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

337:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

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

432:       yt[0] = y[0]; yt[1] = y[1];
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], zt[3] = {0.0,0.0,0.0};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

635:   Level: developer

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

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

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

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

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

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

662:   Level: developer

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

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

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

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

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

693:   Level: developer

695: .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis()
696: @*/
697: PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
698: {
699:   RotCtx        *rc;
700:   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 derviative 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:   PetscSection     section;
1743:   PetscQuadrature  quad;
1744:   PetscScalar     *interpolant, *gradsum;
1745:   PetscFEGeom      fegeom;
1746:   PetscReal       *coords;
1747:   const PetscReal *quadPoints, *quadWeights;
1748:   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
1749:   PetscErrorCode   ierr;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2071:   Level: developer

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

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

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

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

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

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

2122:   Level: developer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2315:   Level: developer

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

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

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

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

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

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

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

2393:   Level: developer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2630:   Level: developer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2887:   Level: developer

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

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

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

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

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

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

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

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

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

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


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

3065:         if (id == PETSCFE_CLASSID) {
3066:           PetscFE fe = (PetscFE) obj;

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

3113: /*@
3114:   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns

3116:   Input Parameters:
3117: + dmc  - The coarse mesh
3118: - dmf  - The fine mesh
3119: - user - The user context

3121:   Output Parameter:
3122: . sc   - The mapping

3124:   Level: developer

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

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

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

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

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

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

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

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

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

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

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

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

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

3296:   Level: developer

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

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

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

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

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

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

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

3381:   Level: developer

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

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

3396: static PetscErrorCode DMPlexGetHybridAuxFields(DM dmAux, PetscDS dsAux[], IS cellIS, Vec locA, PetscScalar *a[])
3397: {
3398:   DM              plexA;
3399:   PetscSection    sectionAux;
3400:   const PetscInt *cells;
3401:   PetscInt        cStart, cEnd, numCells, c, totDimAux[2];
3402:   PetscErrorCode  ierr;

3405:   if (!locA) return(0);
3410:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
3411:   DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);
3412:   DMGetLocalSection(dmAux, &sectionAux);
3413:   numCells = cEnd - cStart;
3414:   PetscDSGetTotalDimension(dsAux[0], &totDimAux[0]);
3415:   DMGetWorkArray(dmAux, numCells*totDimAux[0], MPIU_SCALAR, &a[0]);
3416:   PetscDSGetTotalDimension(dsAux[1], &totDimAux[1]);
3417:   DMGetWorkArray(dmAux, numCells*totDimAux[1], MPIU_SCALAR, &a[1]);
3418:   for (c = cStart; c < cEnd; ++c) {
3419:     const PetscInt  cell = cells ? cells[c] : c;
3420:     const PetscInt  cind = c - cStart;
3421:     const PetscInt *cone, *ornt;
3422:     PetscInt        c;

3424:     DMPlexGetCone(dmAux, cell, &cone);
3425:     DMPlexGetConeOrientation(dmAux, cell, &ornt);
3426:     for (c = 0; c < 2; ++c) {
3427:       PetscScalar   *x = NULL, *al = a[c];
3428:       const PetscInt tdA = totDimAux[c];
3429:       PetscInt       Na, i;

3431:       if (ornt[c]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %D in hybrid cell %D has orientation %D != 0", cone[c], cell, ornt[c]);
3432:       DMPlexVecGetClosure(plexA, sectionAux, locA, cone[c], &Na, &x);
3433:       for (i = 0; i < Na; ++i) al[cind*tdA+i] = x[i];
3434:       DMPlexVecRestoreClosure(plexA, sectionAux, locA, cone[c], &Na, &x);
3435:     }
3436:   }
3437:   DMDestroy(&plexA);
3438:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
3439:   return(0);
3440: }

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

3447:   if (!locA) return(0);
3448:   DMRestoreWorkArray(dmAux, 0, MPIU_SCALAR, &a[0]);
3449:   DMRestoreWorkArray(dmAux, 0, MPIU_SCALAR, &a[1]);
3450:   return(0);
3451: }

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

3456:   Input Parameters:
3457: + dm     - The DM
3458: . fStart - The first face to include
3459: . fEnd   - The first face to exclude
3460: . locX   - A local vector with the solution fields
3461: . locX_t - A local vector with solution field time derivatives, or NULL
3462: . faceGeometry - A local vector with face geometry
3463: . cellGeometry - A local vector with cell geometry
3464: - locaGrad - A local vector with field gradients, or NULL

3466:   Output Parameters:
3467: + Nface - The number of faces with field values
3468: . uL - The field values at the left side of the face
3469: - uR - The field values at the right side of the face

3471:   Level: developer

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

3495:   DMGetDimension(dm, &dim);
3496:   DMGetDS(dm, &prob);
3497:   DMGetLocalSection(dm, &section);
3498:   PetscDSGetNumFields(prob, &Nf);
3499:   PetscDSGetTotalComponents(prob, &Nc);
3500:   PetscMalloc1(Nf, &isFE);
3501:   for (f = 0; f < Nf; ++f) {
3502:     PetscObject  obj;
3503:     PetscClassId id;

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

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

3543:       PetscDSGetComponentOffset(prob, f, &off);
3544:       if (isFE[f]) {
3545:         const PetscInt *cone;
3546:         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;

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

3577:         PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);
3578:         PetscFVGetNumComponents(fv, &numComp);
3579:         DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);
3580:         DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);
3581:         if (dmGrad) {
3582:           PetscReal dxL[3], dxR[3];

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

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

3616:   Input Parameters:
3617: + dm     - The DM
3618: . fStart - The first face to include
3619: . fEnd   - The first face to exclude
3620: . locX   - A local vector with the solution fields
3621: . locX_t - A local vector with solution field time derivatives, or NULL
3622: . faceGeometry - A local vector with face geometry
3623: . cellGeometry - A local vector with cell geometry
3624: - locaGrad - A local vector with field gradients, or NULL

3626:   Output Parameters:
3627: + Nface - The number of faces with field values
3628: . uL - The field values at the left side of the face
3629: - uR - The field values at the right side of the face

3631:   Level: developer

3633: .seealso: DMPlexGetFaceFields()
3634: @*/
3635: 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)
3636: {

3640:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);
3641:   DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);
3642:   return(0);
3643: }

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

3648:   Input Parameters:
3649: + dm     - The DM
3650: . fStart - The first face to include
3651: . fEnd   - The first face to exclude
3652: . faceGeometry - A local vector with face geometry
3653: - cellGeometry - A local vector with cell geometry

3655:   Output Parameters:
3656: + Nface - The number of faces with field values
3657: . fgeom - The extract the face centroid and normal
3658: - vol   - The cell volume

3660:   Level: developer

3662: .seealso: DMPlexGetCellFields()
3663: @*/
3664: PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3665: {
3666:   DM                 dmFace, dmCell;
3667:   DMLabel            ghostLabel;
3668:   const PetscScalar *facegeom, *cellgeom;
3669:   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
3670:   PetscErrorCode     ierr;

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

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

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

3719:   Input Parameters:
3720: + dm     - The DM
3721: . fStart - The first face to include
3722: . fEnd   - The first face to exclude
3723: . faceGeometry - A local vector with face geometry
3724: - cellGeometry - A local vector with cell geometry

3726:   Output Parameters:
3727: + Nface - The number of faces with field values
3728: . fgeom - The extract the face centroid and normal
3729: - vol   - The cell volume

3731:   Level: developer

3733: .seealso: DMPlexGetFaceFields()
3734: @*/
3735: PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3736: {

3740:   PetscFree(*fgeom);
3741:   DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);
3742:   return(0);
3743: }

3745: PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3746: {
3747:   char            composeStr[33] = {0};
3748:   PetscObjectId   id;
3749:   PetscContainer  container;
3750:   PetscErrorCode  ierr;

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

3769: PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3770: {
3772:   *geom = NULL;
3773:   return(0);
3774: }

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

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

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

3841:         PetscDSGetImplicit(prob, f, &fimp);
3842:         if (isImplicit != fimp) continue;
3843:         PetscDSGetDiscretization(prob, f, &obj);
3844:         PetscObjectGetClassId(obj, &id);
3845:         if (id == PETSCFE_CLASSID) {
3846:           PetscFE fe = (PetscFE) obj;

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

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

3887:       key.field = f;
3888:       PetscDSGetImplicit(prob, f, &fimp);
3889:       if (isImplicit != fimp) continue;
3890:       PetscDSGetDiscretization(prob, f, &obj);
3891:       PetscObjectGetClassId(obj, &id);
3892:       if (id == PETSCFE_CLASSID) {
3893:         PetscFE         fe = (PetscFE) obj;
3894:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
3895:         PetscFEGeom    *chunkGeom = NULL;
3896:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
3897:         PetscInt        Nq, Nb;

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

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

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

3936:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
3937:           if (ghostVal > 0) continue;
3938:         }
3939:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
3940:       }
3941:     }
3942:     /* Handle time derivative */
3943:     if (locX_t) {
3944:       PetscScalar *x_t, *fa;

3946:       VecGetArray(locF, &fa);
3947:       VecGetArray(locX_t, &x_t);
3948:       for (f = 0; f < Nf; ++f) {
3949:         PetscFV      fv;
3950:         PetscObject  obj;
3951:         PetscClassId id;
3952:         PetscInt     pdim, d;

3954:         PetscDSGetDiscretization(prob, f, &obj);
3955:         PetscObjectGetClassId(obj, &id);
3956:         if (id != PETSCFV_CLASSID) continue;
3957:         fv   = (PetscFV) obj;
3958:         PetscFVGetNumComponents(fv, &pdim);
3959:         for (c = cS; c < cE; ++c) {
3960:           const PetscInt cell = cells ? cells[c] : c;
3961:           PetscScalar   *u_t, *r;

3963:           if (ghostLabel) {
3964:             PetscInt ghostVal;

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

4001: /*
4002:   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

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

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

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

4102:     PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);
4103:     PetscFEGetQuadrature(fe, &qGeom);
4104:     PetscObjectReference((PetscObject) qGeom);
4105:   }
4106:   DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);
4107:   /* Compute volume integrals */
4108:   if (assembleJac) {MatZeroEntries(J);}
4109:   MatZeroEntries(JP);
4110:   key.label = NULL;
4111:   key.value = 0;
4112:   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4113:     const PetscInt   Ncell = PetscMin(chunkSize, numCells - offCell);
4114:     PetscInt         c;

4116:     /* Extract values */
4117:     for (c = 0; c < Ncell; ++c) {
4118:       const PetscInt cell = cells ? cells[c+offCell] : c+offCell;
4119:       PetscScalar   *x = NULL,  *x_t = NULL;
4120:       PetscInt       i;

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

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

4192: /******** FEM Assembly Function ********/

4194: static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4195: {
4196:   PetscBool      isPlex;

4200:   PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);
4201:   if (isPlex) {
4202:     *plex = dm;
4203:     PetscObjectReference((PetscObject) dm);
4204:   } else {
4205:     PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);
4206:     if (!*plex) {
4207:       DMConvert(dm,DMPLEX,plex);
4208:       PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);
4209:       if (copy) {
4210:         DMCopyAuxiliaryVec(dm, *plex);
4211:       }
4212:     } else {
4213:       PetscObjectReference((PetscObject) *plex);
4214:     }
4215:   }
4216:   return(0);
4217: }

4219: /*@
4220:   DMPlexGetGeometryFVM - Return precomputed geometric data

4222:   Collective on DM

4224:   Input Parameter:
4225: . dm - The DM

4227:   Output Parameters:
4228: + facegeom - The values precomputed from face geometry
4229: . cellgeom - The values precomputed from cell geometry
4230: - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell

4232:   Level: developer

4234: .seealso: DMTSSetRHSFunctionLocal()
4235: @*/
4236: PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4237: {
4238:   DM             plex;

4243:   DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4244:   DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);
4245:   if (minRadius) {DMPlexGetMinRadius(plex, minRadius);}
4246:   DMDestroy(&plex);
4247:   return(0);
4248: }

4250: /*@
4251:   DMPlexGetGradientDM - Return gradient data layout

4253:   Collective on DM

4255:   Input Parameters:
4256: + dm - The DM
4257: - fv - The PetscFV

4259:   Output Parameter:
4260: . dmGrad - The layout for gradient values

4262:   Level: developer

4264: .seealso: DMPlexGetGeometryFVM()
4265: @*/
4266: PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4267: {
4268:   DM             plex;
4269:   PetscBool      computeGradients;

4276:   PetscFVGetComputeGradients(fv, &computeGradients);
4277:   if (!computeGradients) {*dmGrad = NULL; return(0);}
4278:   DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);
4279:   DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);
4280:   DMDestroy(&plex);
4281:   return(0);
4282: }

4284: static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS)
4285: {
4286:   DM_Plex         *mesh = (DM_Plex *) dm->data;
4287:   DM               plex = NULL, plexA = NULL;
4288:   DMEnclosureType  encAux;
4289:   PetscDS          prob, probAux = NULL;
4290:   PetscSection     section, sectionAux = NULL;
4291:   Vec              locA = NULL;
4292:   PetscScalar     *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
4293:   PetscInt         v;
4294:   PetscInt         totDim, totDimAux = 0;
4295:   PetscErrorCode   ierr;

4298:   DMConvert(dm, DMPLEX, &plex);
4299:   DMGetLocalSection(dm, &section);
4300:   DMGetDS(dm, &prob);
4301:   PetscDSGetTotalDimension(prob, &totDim);
4302:   DMGetAuxiliaryVec(dm, NULL, 0, &locA);
4303:   if (locA) {
4304:     DM dmAux;

4306:     VecGetDM(locA, &dmAux);
4307:     DMGetEnclosureRelation(dmAux, dm, &encAux);
4308:     DMConvert(dmAux, DMPLEX, &plexA);
4309:     DMGetDS(plexA, &probAux);
4310:     PetscDSGetTotalDimension(probAux, &totDimAux);
4311:     DMGetLocalSection(plexA, &sectionAux);
4312:   }
4313:   for (v = 0; v < numValues; ++v) {
4314:     PetscFEGeom     *fgeom;
4315:     PetscInt         maxDegree;
4316:     PetscQuadrature  qGeom = NULL;
4317:     IS               pointIS;
4318:     const PetscInt  *points;
4319:     PetscHashFormKey key;
4320:     PetscInt         numFaces, face, Nq;

4322:     key.label = label;
4323:     key.value = values[v];
4324:     key.field = field;
4325:     DMLabelGetStratumIS(label, values[v], &pointIS);
4326:     if (!pointIS) continue; /* No points with that id on this process */
4327:     {
4328:       IS isectIS;

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

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

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

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

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

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

4420: PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF)
4421: {
4422:   DMField        coordField;
4423:   DMLabel        depthLabel;
4424:   IS             facetIS;
4425:   PetscInt       dim;

4429:   DMGetDimension(dm, &dim);
4430:   DMPlexGetDepthLabel(dm, &depthLabel);
4431:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
4432:   DMGetCoordinateField(dm, &coordField);
4433:   DMPlexComputeBdResidual_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4434:   ISDestroy(&facetIS);
4435:   return(0);
4436: }

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

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

4463:     PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL);
4464:     PetscDSGetDiscretization(prob, field, &obj);
4465:     PetscObjectGetClassId(obj, &id);
4466:     if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
4467:     if (!facetIS) {
4468:       DMLabel  depthLabel;
4469:       PetscInt dim;

4471:       DMPlexGetDepthLabel(dm, &depthLabel);
4472:       DMGetDimension(dm, &dim);
4473:       DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);
4474:     }
4475:     DMGetCoordinateField(dm, &coordField);
4476:     DMPlexComputeBdResidual_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);
4477:   }
4478:   ISDestroy(&facetIS);
4479:   return(0);
4480: }

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

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

4537:     PetscDSGetImplicit(ds, f, &fimp);
4538:     if (isImplicit != fimp) continue;
4539:     PetscDSGetDiscretization(ds, f, &obj);
4540:     PetscObjectGetClassId(obj, &id);
4541:     if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;}
4542:     if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;}
4543:   }
4544:   if (useFEM) {
4545:     DMGetCoordinateField(dm, &coordField);
4546:     DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);
4547:     if (maxDegree <= 1) {
4548:       DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);
4549:       if (affineQuad) {
4550:         DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4551:       }
4552:     } else {
4553:       PetscCalloc2(Nf,&quads,Nf,&geoms);
4554:       for (f = 0; f < Nf; ++f) {
4555:         PetscObject  obj;
4556:         PetscClassId id;
4557:         PetscBool    fimp;

4559:         PetscDSGetImplicit(ds, f, &fimp);
4560:         if (isImplicit != fimp) continue;
4561:         PetscDSGetDiscretization(ds, f, &obj);
4562:         PetscObjectGetClassId(obj, &id);
4563:         if (id == PETSCFE_CLASSID) {
4564:           PetscFE fe = (PetscFE) obj;

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

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

4629:       key.field = f;
4630:       PetscDSGetImplicit(ds, f, &fimp);
4631:       if (isImplicit != fimp) continue;
4632:       PetscDSGetDiscretization(ds, f, &obj);
4633:       PetscObjectGetClassId(obj, &id);
4634:       if (id == PETSCFE_CLASSID) {
4635:         PetscFE         fe = (PetscFE) obj;
4636:         PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
4637:         PetscFEGeom    *chunkGeom = NULL;
4638:         PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4639:         PetscInt        Nq, Nb;

4641:         PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4642:         PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4643:         PetscFEGetDimension(fe, &Nb);
4644:         blockSize = Nb;
4645:         batchSize = numBlocks * blockSize;
4646:         PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4647:         numChunks = numCells / (numBatches*batchSize);
4648:         Ne        = numChunks*numBatches*batchSize;
4649:         Nr        = numCells % (numBatches*batchSize);
4650:         offset    = numCells - Nr;
4651:         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
4652:         /*   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) */
4653:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4654:         PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec);
4655:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4656:         PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);
4657:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4658:       } else if (id == PETSCFV_CLASSID) {
4659:         PetscFV fv = (PetscFV) obj;

4661:         Ne = numFaces;
4662:         /* Riemann solve over faces (need fields at face centroids) */
4663:         /*   We need to evaluate FE fields at those coordinates */
4664:         PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);
4665:       } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
4666:     }
4667:     /* Loop over domain */
4668:     if (useFEM) {
4669:       /* Add elemVec to locX */
4670:       for (c = cS; c < cE; ++c) {
4671:         const PetscInt cell = cells ? cells[c] : c;
4672:         const PetscInt cind = c - cStart;

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

4678:           DMLabelGetValue(ghostLabel,cell,&ghostVal);
4679:           if (ghostVal > 0) continue;
4680:         }
4681:         DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
4682:       }
4683:     }
4684:     if (useFVM) {
4685:       PetscScalar *fa;
4686:       PetscInt     iface;

4688:       VecGetArray(locF, &fa);
4689:       for (f = 0; f < Nf; ++f) {
4690:         PetscFV      fv;
4691:         PetscObject  obj;
4692:         PetscClassId id;
4693:         PetscInt     foff, pdim;

4695:         PetscDSGetDiscretization(ds, f, &obj);
4696:         PetscDSGetFieldOffset(ds, f, &foff);
4697:         PetscObjectGetClassId(obj, &id);
4698:         if (id != PETSCFV_CLASSID) continue;
4699:         fv   = (PetscFV) obj;
4700:         PetscFVGetNumComponents(fv, &pdim);
4701:         /* Accumulate fluxes to cells */
4702:         for (face = fS, iface = 0; face < fE; ++face) {
4703:           const PetscInt *scells;
4704:           PetscScalar    *fL = NULL, *fR = NULL;
4705:           PetscInt        ghost, d, nsupp, nchild;

4707:           DMLabelGetValue(ghostLabel, face, &ghost);
4708:           DMPlexGetSupportSize(dm, face, &nsupp);
4709:           DMPlexGetTreeChildren(dm, face, &nchild, NULL);
4710:           if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
4711:           DMPlexGetSupport(dm, face, &scells);
4712:           DMLabelGetValue(ghostLabel,scells[0],&ghost);
4713:           if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);}
4714:           DMLabelGetValue(ghostLabel,scells[1],&ghost);
4715:           if (ghost <= 0) {DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);}
4716:           for (d = 0; d < pdim; ++d) {
4717:             if (fL) fL[d] -= fluxL[iface*totDim+foff+d];
4718:             if (fR) fR[d] += fluxR[iface*totDim+foff+d];
4719:           }
4720:           ++iface;
4721:         }
4722:       }
4723:       VecRestoreArray(locF, &fa);
4724:     }
4725:     /* Handle time derivative */
4726:     if (locX_t) {
4727:       PetscScalar *x_t, *fa;

4729:       VecGetArray(locF, &fa);
4730:       VecGetArray(locX_t, &x_t);
4731:       for (f = 0; f < Nf; ++f) {
4732:         PetscFV      fv;
4733:         PetscObject  obj;
4734:         PetscClassId id;
4735:         PetscInt     pdim, d;

4737:         PetscDSGetDiscretization(ds, f, &obj);
4738:         PetscObjectGetClassId(obj, &id);
4739:         if (id != PETSCFV_CLASSID) continue;
4740:         fv   = (PetscFV) obj;
4741:         PetscFVGetNumComponents(fv, &pdim);
4742:         for (c = cS; c < cE; ++c) {
4743:           const PetscInt cell = cells ? cells[c] : c;
4744:           PetscScalar   *u_t, *r;

4746:           if (ghostLabel) {
4747:             PetscInt ghostVal;

4749:             DMLabelGetValue(ghostLabel, cell, &ghostVal);
4750:             if (ghostVal > 0) continue;
4751:           }
4752:           DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);
4753:           DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);
4754:           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
4755:         }
4756:       }
4757:       VecRestoreArray(locX_t, &x_t);
4758:       VecRestoreArray(locF, &fa);
4759:     }
4760:     if (useFEM) {
4761:       DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);
4762:       DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
4763:     }
4764:     if (useFVM) {
4765:       DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);
4766:       DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);
4767:       DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);
4768:       DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);
4769:       if (dmGrad) {DMRestoreLocalVector(dmGrad, &locGrad);}
4770:     }
4771:   }
4772:   if (useFEM) {ISDestroy(&chunkIS);}
4773:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);

4775:   if (useFEM) {
4776:     DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);

4778:     if (maxDegree <= 1) {
4779:       DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
4780:       PetscQuadratureDestroy(&affineQuad);
4781:     } else {
4782:       for (f = 0; f < Nf; ++f) {
4783:         DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);
4784:         PetscQuadratureDestroy(&quads[f]);
4785:       }
4786:       PetscFree2(quads,geoms);
4787:     }
4788:   }

4790:   /* FEM */
4791:   /* 1: Get sizes from dm and dmAux */
4792:   /* 2: Get geometric data */
4793:   /* 3: Handle boundary values */
4794:   /* 4: Loop over domain */
4795:   /*   Extract coefficients */
4796:   /* Loop over fields */
4797:   /*   Set tiling for FE*/
4798:   /*   Integrate FE residual to get elemVec */
4799:   /*     Loop over subdomain */
4800:   /*       Loop over quad points */
4801:   /*         Transform coords to real space */
4802:   /*         Evaluate field and aux fields at point */
4803:   /*         Evaluate residual at point */
4804:   /*         Transform residual to real space */
4805:   /*       Add residual to elemVec */
4806:   /* Loop over domain */
4807:   /*   Add elemVec to locX */

4809:   /* FVM */
4810:   /* Get geometric data */
4811:   /* If using gradients */
4812:   /*   Compute gradient data */
4813:   /*   Loop over domain faces */
4814:   /*     Count computational faces */
4815:   /*     Reconstruct cell gradient */
4816:   /*   Loop over domain cells */
4817:   /*     Limit cell gradients */
4818:   /* Handle boundary values */
4819:   /* Loop over domain faces */
4820:   /*   Read out field, centroid, normal, volume for each side of face */
4821:   /* Riemann solve over faces */
4822:   /* Loop over domain faces */
4823:   /*   Accumulate fluxes to cells */
4824:   /* TODO Change printFEM to printDisc here */
4825:   if (mesh->printFEM) {
4826:     Vec         locFbc;
4827:     PetscInt    pStart, pEnd, p, maxDof;
4828:     PetscScalar *zeroes;

4830:     VecDuplicate(locF,&locFbc);
4831:     VecCopy(locF,locFbc);
4832:     PetscSectionGetChart(section,&pStart,&pEnd);
4833:     PetscSectionGetMaxDof(section,&maxDof);
4834:     PetscCalloc1(maxDof,&zeroes);
4835:     for (p = pStart; p < pEnd; p++) {
4836:       VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES);
4837:     }
4838:     PetscFree(zeroes);
4839:     DMPrintLocalVec(dm, name, mesh->printTol, locFbc);
4840:     VecDestroy(&locFbc);
4841:   }
4842:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
4843:   return(0);
4844: }

4846: /*
4847:   1) Allow multiple kernels for BdResidual for hybrid DS

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

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

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

4880:   PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);
4881:   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
4882:   /* FEM */
4883:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
4884:   /* 1: Get sizes from dm and dmAux */
4885:   DMGetSection(dm, &section);
4886:   DMGetLabel(dm, "ghost", &ghostLabel);
4887:   DMGetCellDS(dm, cStart, &ds);
4888:   PetscDSGetNumFields(ds, &Nf);
4889:   PetscDSGetTotalDimension(ds, &totDim);
4890:   DMGetAuxiliaryVec(dm, NULL, 0, &locA);
4891:   if (locA) {
4892:     VecGetDM(locA, &dmAux);
4893:     DMGetCellDS(dmAux, cStart, &dsAux[2]);
4894:     PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]);
4895:     {
4896:       const PetscInt *cone;
4897:       PetscInt        c;

4899:       DMPlexGetCone(dm, cStart, &cone);
4900:       for (c = 0; c < 2; ++c) {
4901:         const PetscInt *support;
4902:         PetscInt ssize, s;

4904:         DMPlexGetSupport(dm, cone[c], &support);
4905:         DMPlexGetSupportSize(dm, cone[c], &ssize);
4906:         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);
4907:         if      (support[0] == cStart) s = 1;
4908:         else if (support[1] == cStart) s = 0;
4909:         else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[c], cStart);
4910:         DMGetCellDS(dmAux, support[s], &dsAux[c]);
4911:         PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]);
4912:       }
4913:     }
4914:   }
4915:   /* 2: Setup geometric data */
4916:   DMGetCoordinateField(dm, &coordField);
4917:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
4918:   if (maxDegree > 1) {
4919:     PetscCalloc2(Nf, &quads, Nf, &geoms);
4920:     for (f = 0; f < Nf; ++f) {
4921:       PetscFE fe;

4923:       PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
4924:       if (fe) {
4925:         PetscFEGetQuadrature(fe, &quads[f]);
4926:         PetscObjectReference((PetscObject) quads[f]);
4927:       }
4928:     }
4929:   }
4930:   /* Loop over chunks */
4931:   numCells      = cEnd - cStart;
4932:   cellChunkSize = numCells;
4933:   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
4934:   PetscCalloc1(2*cellChunkSize, &faces);
4935:   ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
4936:   /* Extract field coefficients */
4937:   /* NOTE This needs the end cap faces to have identical orientations */
4938:   DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a[2]);
4939:   DMPlexGetHybridAuxFields(dm, dsAux, cellIS, locA, a);
4940:   DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec);
4941:   for (chunk = 0; chunk < numChunks; ++chunk) {
4942:     PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;

4944:     PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar));
4945:     /* Get faces */
4946:     for (c = cS; c < cE; ++c) {
4947:       const PetscInt  cell = cells ? cells[c] : c;
4948:       const PetscInt *cone;
4949:       DMPlexGetCone(dm, cell, &cone);
4950:       faces[(c-cS)*2+0] = cone[0];
4951:       faces[(c-cS)*2+1] = cone[1];
4952:     }
4953:     ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
4954:     /* Get geometric data */
4955:     if (maxDegree <= 1) {
4956:       if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
4957:       if (affineQuad)  {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
4958:     } else {
4959:       for (f = 0; f < Nf; ++f) {
4960:         if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
4961:       }
4962:     }
4963:     /* Loop over fields */
4964:     for (f = 0; f < Nf; ++f) {
4965:       PetscFE         fe;
4966:       PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[f];
4967:       PetscFEGeom    *chunkGeom = NULL;
4968:       PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
4969:       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;

4971:       PetscDSGetDiscretization(ds, f, (PetscObject *) &fe);
4972:       if (!fe) continue;
4973:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
4974:       PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
4975:       PetscFEGetDimension(fe, &Nb);
4976:       blockSize = Nb;
4977:       batchSize = numBlocks * blockSize;
4978:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
4979:       numChunks = numCells / (numBatches*batchSize);
4980:       Ne        = numChunks*numBatches*batchSize;
4981:       Nr        = numCells % (numBatches*batchSize);
4982:       offset    = numCells - Nr;
4983:       if (f == Nf-1) {
4984:         key[2].field = f;
4985:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4986:         PetscFEIntegrateHybridResidual(ds, key[2], Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec);
4987:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4988:         PetscFEIntegrateHybridResidual(ds, key[2], Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[2], &a[2][offset*totDimAux[2]], t, &elemVec[offset*totDim]);
4989:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
4990:       } else {
4991:         key[0].field = f;
4992:         key[1].field = f;
4993:         PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
4994:         PetscFEIntegrateHybridResidual(ds, key[0], Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec);
4995:         PetscFEIntegrateHybridResidual(ds, key[1], Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec);
4996:         PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);
4997:         PetscFEIntegrateHybridResidual(ds, key[0], Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[0], &a[0][offset*totDimAux[0]], t, &elemVec[offset*totDim]);
4998:         PetscFEIntegrateHybridResidual(ds, key[1], Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux[1], &a[1][offset*totDimAux[1]], t, &elemVec[offset*totDim]);
4999:         PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);
5000:       }
5001:     }
5002:     /* Add elemVec to locX */
5003:     for (c = cS; c < cE; ++c) {
5004:       const PetscInt cell = cells ? cells[c] : c;
5005:       const PetscInt cind = c - cStart;

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

5011:         DMLabelGetValue(ghostLabel,cell,&ghostVal);
5012:         if (ghostVal > 0) continue;
5013:       }
5014:       DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);
5015:     }
5016:   }
5017:   DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a[2]);
5018:   DMPlexRestoreHybridAuxFields(dm, dsAux, cellIS, locA, a);
5019:   DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);
5020:   PetscFree(faces);
5021:   ISDestroy(&chunkIS);
5022:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5023:   if (maxDegree <= 1) {
5024:     DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5025:     PetscQuadratureDestroy(&affineQuad);
5026:   } else {
5027:     for (f = 0; f < Nf; ++f) {
5028:       if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);}
5029:       if (quads) {PetscQuadratureDestroy(&quads[f]);}
5030:     }
5031:     PetscFree2(quads,geoms);
5032:   }
5033:   PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);
5034:   return(0);
5035: }

5037: 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)
5038: {
5039:   DM_Plex        *mesh = (DM_Plex *) dm->data;
5040:   DM              plex = NULL, plexA = NULL, tdm;
5041:   DMEnclosureType encAux;
5042:   PetscDS         prob, probAux = NULL;
5043:   PetscSection    section, sectionAux = NULL;
5044:   PetscSection    globalSection, subSection = NULL;
5045:   Vec             locA = NULL, tv;
5046:   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
5047:   PetscInt        v;
5048:   PetscInt        Nf, totDim, totDimAux = 0;
5049:   PetscBool       isMatISP, transform;
5050:   PetscErrorCode  ierr;

5053:   DMConvert(dm, DMPLEX, &plex);
5054:   DMHasBasisTransform(dm, &transform);
5055:   DMGetBasisTransformDM_Internal(dm, &tdm);
5056:   DMGetBasisTransformVec_Internal(dm, &tv);
5057:   DMGetLocalSection(dm, &section);
5058:   DMGetDS(dm, &prob);
5059:   PetscDSGetNumFields(prob, &Nf);
5060:   PetscDSGetTotalDimension(prob, &totDim);
5061:   DMGetAuxiliaryVec(dm, NULL, 0, &locA);
5062:   if (locA) {
5063:     DM dmAux;

5065:     VecGetDM(locA, &dmAux);
5066:     DMGetEnclosureRelation(dmAux, dm, &encAux);
5067:     DMConvert(dmAux, DMPLEX, &plexA);
5068:     DMGetDS(plexA, &probAux);
5069:     PetscDSGetTotalDimension(probAux, &totDimAux);
5070:     DMGetLocalSection(plexA, &sectionAux);
5071:   }

5073:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5074:   DMGetGlobalSection(dm, &globalSection);
5075:   if (isMatISP) {DMPlexGetSubdomainSection(dm, &subSection);}
5076:   for (v = 0; v < numValues; ++v) {
5077:     PetscFEGeom     *fgeom;
5078:     PetscInt         maxDegree;
5079:     PetscQuadrature  qGeom = NULL;
5080:     IS               pointIS;
5081:     const PetscInt  *points;
5082:     PetscHashFormKey key;
5083:     PetscInt         numFaces, face, Nq;

5085:     key.label = label;
5086:     key.value = values[v];
5087:     DMLabelGetStratumIS(label, values[v], &pointIS);
5088:     if (!pointIS) continue; /* No points with that id on this process */
5089:     {
5090:       IS isectIS;

5092:       /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
5093:       ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);
5094:       ISDestroy(&pointIS);
5095:       pointIS = isectIS;
5096:     }
5097:     ISGetLocalSize(pointIS, &numFaces);
5098:     ISGetIndices(pointIS, &points);
5099:     PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a);
5100:     DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);
5101:     if (maxDegree <= 1) {
5102:       DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);
5103:     }
5104:     if (!qGeom) {
5105:       PetscFE fe;

5107:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5108:       PetscFEGetFaceQuadrature(fe, &qGeom);
5109:       PetscObjectReference((PetscObject)qGeom);
5110:     }
5111:     PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);
5112:     DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5113:     for (face = 0; face < numFaces; ++face) {
5114:       const PetscInt point = points[face], *support;
5115:       PetscScalar   *x     = NULL;
5116:       PetscInt       i;

5118:       DMPlexGetSupport(dm, point, &support);
5119:       DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);
5120:       for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i];
5121:       DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);
5122:       if (locX_t) {
5123:         DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);
5124:         for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i];
5125:         DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);
5126:       }
5127:       if (locA) {
5128:         PetscInt subp;
5129:         DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);
5130:         DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);
5131:         for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i];
5132:         DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);
5133:       }
5134:     }
5135:     PetscArrayzero(elemMat, numFaces*totDim*totDim);
5136:     {
5137:       PetscFE         fe;
5138:       PetscInt        Nb;
5139:       /* Conforming batches */
5140:       PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5141:       /* Remainder */
5142:       PetscFEGeom    *chunkGeom = NULL;
5143:       PetscInt        fieldJ, Nr, offset;

5145:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);
5146:       PetscFEGetDimension(fe, &Nb);
5147:       PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);
5148:       blockSize = Nb;
5149:       batchSize = numBlocks * blockSize;
5150:       PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);
5151:       numChunks = numFaces / (numBatches*batchSize);
5152:       Ne        = numChunks*numBatches*batchSize;
5153:       Nr        = numFaces % (numBatches*batchSize);
5154:       offset    = numFaces - Nr;
5155:       PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);
5156:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5157:         key.field = fieldI*Nf+fieldJ;
5158:         PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5159:       }
5160:       PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);
5161:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5162:         key.field = fieldI*Nf+fieldJ;
5163:         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]);
5164:       }
5165:       PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);
5166:     }
5167:     for (face = 0; face < numFaces; ++face) {
5168:       const PetscInt point = points[face], *support;

5170:       /* Transform to global basis before insertion in Jacobian */
5171:       DMPlexGetSupport(plex, point, &support);
5172:       if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim]);}
5173:       if (mesh->printFEM > 1) {DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim]);}
5174:       if (!isMatISP) {
5175:         DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5176:       } else {
5177:         Mat lJ;

5179:         MatISGetLocalMat(JacP, &lJ);
5180:         DMPlexMatSetClosure(plex, section, subSection, lJ, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);
5181:       }
5182:     }
5183:     DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);
5184:     PetscQuadratureDestroy(&qGeom);
5185:     ISRestoreIndices(pointIS, &points);
5186:     ISDestroy(&pointIS);
5187:     PetscFree4(u, u_t, elemMat, a);
5188:   }
5189:   if (plex)  {DMDestroy(&plex);}
5190:   if (plexA) {DMDestroy(&plexA);}
5191:   return(0);
5192: }

5194: 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)
5195: {
5196:   DMField        coordField;
5197:   DMLabel        depthLabel;
5198:   IS             facetIS;
5199:   PetscInt       dim;

5203:   DMGetDimension(dm, &dim);
5204:   DMPlexGetDepthLabel(dm, &depthLabel);
5205:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5206:   DMGetCoordinateField(dm, &coordField);
5207:   DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5208:   ISDestroy(&facetIS);
5209:   return(0);
5210: }

5212: PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5213: {
5214:   PetscDS          prob;
5215:   PetscInt         dim, numBd, bd;
5216:   DMLabel          depthLabel;
5217:   DMField          coordField = NULL;
5218:   IS               facetIS;
5219:   PetscErrorCode   ierr;

5222:   DMGetDS(dm, &prob);
5223:   DMPlexGetDepthLabel(dm, &depthLabel);
5224:   DMGetDimension(dm, &dim);
5225:   DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);
5226:   PetscDSGetNumBoundary(prob, &numBd);
5227:   DMGetCoordinateField(dm, &coordField);
5228:   for (bd = 0; bd < numBd; ++bd) {
5229:     PetscWeakForm           wf;
5230:     DMBoundaryConditionType type;
5231:     DMLabel                 label;
5232:     const PetscInt         *values;
5233:     PetscInt                fieldI, numValues;
5234:     PetscObject             obj;
5235:     PetscClassId            id;

5237:     PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL);
5238:     PetscDSGetDiscretization(prob, fieldI, &obj);
5239:     PetscObjectGetClassId(obj, &id);
5240:     if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue;
5241:     DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);
5242:   }
5243:   ISDestroy(&facetIS);
5244:   return(0);
5245: }

5247: PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscHashFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP,void *user)
5248: {
5249:   DM_Plex        *mesh  = (DM_Plex *) dm->data;
5250:   const char     *name  = "Jacobian";
5251:   DM              dmAux = NULL, plex, tdm;
5252:   DMEnclosureType encAux;
5253:   Vec             A, tv;
5254:   DMField         coordField;
5255:   PetscDS         prob, probAux = NULL;
5256:   PetscSection    section, globalSection, subSection, sectionAux;
5257:   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
5258:   const PetscInt *cells;
5259:   PetscInt        Nf, fieldI, fieldJ;
5260:   PetscInt        totDim, totDimAux, cStart, cEnd, numCells, c;
5261:   PetscBool       isMatIS, isMatISP, hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform;
5262:   PetscErrorCode  ierr;

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

5305:     DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);
5306:     for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i];
5307:     DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);
5308:     if (X_t) {
5309:       DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);
5310:       for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i];
5311:       DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);
5312:     }
5313:     if (dmAux) {
5314:       PetscInt subcell;
5315:       DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);
5316:       DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);
5317:       for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i];
5318:       DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);
5319:     }
5320:   }
5321:   if (hasJac)  {PetscArrayzero(elemMat,  numCells*totDim*totDim);}
5322:   if (hasPrec) {PetscArrayzero(elemMatP, numCells*totDim*totDim);}
5323:   if (hasDyn)  {PetscArrayzero(elemMatD, numCells*totDim*totDim);}
5324:   for (fieldI = 0; fieldI < Nf; ++fieldI) {
5325:     PetscClassId    id;
5326:     PetscFE         fe;
5327:     PetscQuadrature qGeom = NULL;
5328:     PetscInt        Nb;
5329:     /* Conforming batches */
5330:     PetscInt        numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
5331:     /* Remainder */
5332:     PetscInt        Nr, offset, Nq;
5333:     PetscInt        maxDegree;
5334:     PetscFEGeom     *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;

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

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

5423:     /* Transform to global basis before insertion in Jacobian */
5424:     if (transform) {DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim]);}
5425:     if (hasPrec) {
5426:       if (hasJac) {
5427:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5428:         if (!isMatIS) {
5429:           DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5430:         } else {
5431:           Mat lJ;

5433:           MatISGetLocalMat(Jac,&lJ);
5434:           DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5435:         }
5436:       }
5437:       if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5438:       if (!isMatISP) {
5439:         DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5440:       } else {
5441:         Mat lJ;

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

5454:           MatISGetLocalMat(JacP,&lJ);
5455:           DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5456:         }
5457:       }
5458:     }
5459:   }
5460:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5461:   if (hasFV) {MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);}
5462:   PetscFree5(u,u_t,elemMat,elemMatP,elemMatD);
5463:   if (dmAux) {
5464:     PetscFree(a);
5465:     DMDestroy(&plex);
5466:   }
5467:   /* Compute boundary integrals */
5468:   DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);
5469:   /* Assemble matrix */
5470:   if (hasJac && hasPrec) {
5471:     MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5472:     MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5473:   }
5474:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5475:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5476:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5477:   return(0);
5478: }

5480: PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5481: {
5482:   DM_Plex         *mesh       = (DM_Plex *) dm->data;
5483:   const char      *name       = "Hybrid Jacobian";
5484:   DM               dmAux      = NULL;
5485:   DM               plex       = NULL;
5486:   DM               plexA      = NULL;
5487:   DMLabel          ghostLabel = NULL;
5488:   PetscDS          prob       = NULL;
5489:   PetscDS          probAux    = NULL;
5490:   PetscSection     section    = NULL;
5491:   DMField          coordField = NULL;
5492:   Vec              locA;
5493:   PetscScalar     *u = NULL, *u_t, *a = NULL;
5494:   PetscScalar     *elemMat, *elemMatP;
5495:   PetscSection     globalSection, subSection, sectionAux;
5496:   IS               chunkIS;
5497:   const PetscInt  *cells;
5498:   PetscInt        *faces;
5499:   PetscHashFormKey key;
5500:   PetscInt         cStart, cEnd, numCells;
5501:   PetscInt         Nf, fieldI, fieldJ, totDim, totDimAux, numChunks, cellChunkSize, chunk;
5502:   PetscInt         maxDegree = PETSC_MAX_INT;
5503:   PetscQuadrature  affineQuad = NULL, *quads = NULL;
5504:   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
5505:   PetscBool        isMatIS = PETSC_FALSE, isMatISP = PETSC_FALSE, hasBdJac, hasBdPrec;
5506:   PetscErrorCode   ierr;

5509:   PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);
5510:   ISGetLocalSize(cellIS, &numCells);
5511:   ISGetPointRange(cellIS, &cStart, &cEnd, &cells);
5512:   DMConvert(dm, DMPLEX, &plex);
5513:   DMGetSection(dm, &section);
5514:   DMGetGlobalSection(dm, &globalSection);
5515:   DMGetLabel(dm, "ghost", &ghostLabel);
5516:   DMGetCellDS(dm, cStart, &prob);
5517:   PetscDSGetNumFields(prob, &Nf);
5518:   PetscDSGetTotalDimension(prob, &totDim);
5519:   PetscDSHasBdJacobian(prob, &hasBdJac);
5520:   PetscDSHasBdJacobianPreconditioner(prob, &hasBdPrec);
5521:   PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);
5522:   if (isMatISP) {DMPlexGetSubdomainSection(plex, &subSection);}
5523:   if (hasBdPrec && hasBdJac) {PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);}
5524:   if (isMatIS && !subSection) {DMPlexGetSubdomainSection(plex, &subSection);}
5525:   DMGetAuxiliaryVec(dm, NULL, 0, &locA);
5526:   if (locA) {
5527:     VecGetDM(locA, &dmAux);
5528:     DMConvert(dmAux, DMPLEX, &plexA);
5529:     DMGetSection(dmAux, &sectionAux);
5530:     DMGetCellDS(dmAux, cStart, &probAux);
5531:     PetscDSGetTotalDimension(probAux, &totDimAux);
5532:   }
5533:   DMGetCoordinateField(dm, &coordField);
5534:   DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);
5535:   if (maxDegree > 1) {
5536:     PetscInt f;
5537:     PetscCalloc2(Nf,&quads,Nf,&geoms);
5538:     for (f = 0; f < Nf; ++f) {
5539:       PetscFE fe;

5541:       PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);
5542:       if (fe) {
5543:         PetscFEGetQuadrature(fe, &quads[f]);
5544:         PetscObjectReference((PetscObject) quads[f]);
5545:       }
5546:     }
5547:   }
5548:   cellChunkSize = numCells;
5549:   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize);
5550:   PetscCalloc1(2*cellChunkSize, &faces);
5551:   ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);
5552:   DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5553:   DMGetWorkArray(dm, hasBdJac  ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5554:   DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5555:   for (chunk = 0; chunk < numChunks; ++chunk) {
5556:     PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c;

5558:     if (hasBdJac)  {PetscMemzero(elemMat,  numCells*totDim*totDim * sizeof(PetscScalar));}
5559:     if (hasBdPrec) {PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar));}
5560:     /* Get faces */
5561:     for (c = cS; c < cE; ++c) {
5562:       const PetscInt  cell = cells ? cells[c] : c;
5563:       const PetscInt *cone;
5564:       DMPlexGetCone(plex, cell, &cone);
5565:       faces[(c-cS)*2+0] = cone[0];
5566:       faces[(c-cS)*2+1] = cone[1];
5567:     }
5568:     ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);
5569:     if (maxDegree <= 1) {
5570:       if (!affineQuad) {DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);}
5571:       if (affineQuad)  {DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);}
5572:     } else {
5573:       PetscInt f;
5574:       for (f = 0; f < Nf; ++f) {
5575:         if (quads[f]) {DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);}
5576:       }
5577:     }

5579:     key.label = NULL;
5580:     key.value = 0;
5581:     for (fieldI = 0; fieldI < Nf; ++fieldI) {
5582:       PetscFE         feI;
5583:       PetscFEGeom    *geom = affineGeom ? affineGeom : geoms[fieldI];
5584:       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
5585:       PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
5586:       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;

5588:       PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &feI);
5589:       if (!feI) continue;
5590:       PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);
5591:       PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);
5592:       PetscFEGetDimension(feI, &Nb);
5593:       blockSize = Nb;
5594:       batchSize = numBlocks * blockSize;
5595:       PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);
5596:       numChunks = numCells / (numBatches*batchSize);
5597:       Ne        = numChunks*numBatches*batchSize;
5598:       Nr        = numCells % (numBatches*batchSize);
5599:       offset    = numCells - Nr;
5600:       PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);
5601:       PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);
5602:       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
5603:         PetscFE feJ;

5605:         PetscDSGetDiscretization(prob, fieldJ, (PetscObject *) &feJ);
5606:         if (!feJ) continue;
5607:         key.field = fieldI*Nf+fieldJ;
5608:         if (hasBdJac) {
5609:           PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);
5610:           PetscFEIntegrateHybridJacobian(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]);
5611:         }
5612:         if (hasBdPrec) {
5613:           PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);
5614:           PetscFEIntegrateHybridJacobian(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]);
5615:         }
5616:       }
5617:       PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);
5618:       PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);
5619:     }
5620:     /* Insert values into matrix */
5621:     for (c = cS; c < cE; ++c) {
5622:       const PetscInt cell = cells ? cells[c] : c;
5623:       const PetscInt cind = c - cS;

5625:       if (hasBdPrec) {
5626:         if (hasBdJac) {
5627:           if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5628:           if (!isMatIS) {
5629:             DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5630:           } else {
5631:             Mat lJ;

5633:             MatISGetLocalMat(Jac,&lJ);
5634:             DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5635:           }
5636:         }
5637:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);}
5638:         if (!isMatISP) {
5639:           DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5640:         } else {
5641:           Mat lJ;

5643:           MatISGetLocalMat(JacP,&lJ);
5644:           DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);
5645:         }
5646:       } else if (hasBdJac) {
5647:         if (mesh->printFEM > 1) {DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);}
5648:         if (!isMatISP) {
5649:           DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5650:         } else {
5651:           Mat lJ;

5653:           MatISGetLocalMat(JacP,&lJ);
5654:           DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);
5655:         }
5656:       }
5657:     }
5658:   }
5659:   DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);
5660:   DMRestoreWorkArray(dm, hasBdJac  ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);
5661:   DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);
5662:   PetscFree(faces);
5663:   ISDestroy(&chunkIS);
5664:   ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);
5665:   if (maxDegree <= 1) {
5666:     DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);
5667:     PetscQuadratureDestroy(&affineQuad);
5668:   } else {
5669:     PetscInt f;
5670:     for (f = 0; f < Nf; ++f) {
5671:       if (geoms) {DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f]);}
5672:       if (quads) {PetscQuadratureDestroy(&quads[f]);}
5673:     }
5674:     PetscFree2(quads,geoms);
5675:   }
5676:   if (dmAux) {DMDestroy(&plexA);}
5677:   DMDestroy(&plex);
5678:   /* Assemble matrix */
5679:   if (hasBdJac && hasBdPrec) {
5680:     MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);
5681:     MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);
5682:   }
5683:   MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);
5684:   MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);
5685:   PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);
5686:   return(0);
5687: }