xref: /petsc/src/dm/impls/plex/plexfem.c (revision a1cb98fac0cdf0eb4d3e8a0c8b58f3fe8f800bc6)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I      "petscdmplex.h"   I*/
2da97024aSMatthew G. Knepley #include <petscsf.h>
3cb1e1211SMatthew G Knepley 
48e3a2eefSMatthew G. Knepley #include <petscblaslapack.h>
5e8f14785SLisandro Dalcin #include <petsc/private/hashsetij.h>
6af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h>
7af0996ceSBarry Smith #include <petsc/private/petscfvimpl.h>
8a0845e3aSMatthew G. Knepley 
95f0b18bfSMatthew G. Knepley PetscBool  Clementcite       = PETSC_FALSE;
105f0b18bfSMatthew G. Knepley const char ClementCitation[] = "@article{clement1975approximation,\n"
115f0b18bfSMatthew G. Knepley                                "  title   = {Approximation by finite element functions using local regularization},\n"
125f0b18bfSMatthew G. Knepley                                "  author  = {Philippe Cl{\\'e}ment},\n"
135f0b18bfSMatthew G. Knepley                                "  journal = {Revue fran{\\c{c}}aise d'automatique, informatique, recherche op{\\'e}rationnelle. Analyse num{\\'e}rique},\n"
145f0b18bfSMatthew G. Knepley                                "  volume  = {9},\n"
155f0b18bfSMatthew G. Knepley                                "  number  = {R2},\n"
165f0b18bfSMatthew G. Knepley                                "  pages   = {77--84},\n"
175f0b18bfSMatthew G. Knepley                                "  year    = {1975}\n}\n";
185f0b18bfSMatthew G. Knepley 
19d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy)
20d71ae5a4SJacob Faibussowitsch {
212f856554SMatthew G. Knepley   PetscBool isPlex;
222f856554SMatthew G. Knepley 
232f856554SMatthew G. Knepley   PetscFunctionBegin;
249566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
252f856554SMatthew G. Knepley   if (isPlex) {
262f856554SMatthew G. Knepley     *plex = dm;
279566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
282f856554SMatthew G. Knepley   } else {
299566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
302f856554SMatthew G. Knepley     if (!*plex) {
319566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
329566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
332f856554SMatthew G. Knepley       if (copy) {
342f856554SMatthew G. Knepley         DMSubDomainHookLink link;
359a2a23afSMatthew G. Knepley 
369566063dSJacob Faibussowitsch         PetscCall(DMCopyAuxiliaryVec(dm, *plex));
379a2a23afSMatthew G. Knepley         /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
382f856554SMatthew G. Knepley         for (link = dm->subdomainhook; link; link = link->next) {
399566063dSJacob Faibussowitsch           if (link->ddhook) PetscCall((*link->ddhook)(dm, *plex, link->ctx));
402f856554SMatthew G. Knepley         }
412f856554SMatthew G. Knepley       }
422f856554SMatthew G. Knepley     } else {
439566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)*plex));
442f856554SMatthew G. Knepley     }
452f856554SMatthew G. Knepley   }
462f856554SMatthew G. Knepley   PetscFunctionReturn(0);
472f856554SMatthew G. Knepley }
482f856554SMatthew G. Knepley 
49d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom(void *ctx)
50d71ae5a4SJacob Faibussowitsch {
519b6f715bSMatthew G. Knepley   PetscFEGeom *geom = (PetscFEGeom *)ctx;
529b6f715bSMatthew G. Knepley 
539b6f715bSMatthew G. Knepley   PetscFunctionBegin;
549566063dSJacob Faibussowitsch   PetscCall(PetscFEGeomDestroy(&geom));
559b6f715bSMatthew G. Knepley   PetscFunctionReturn(0);
569b6f715bSMatthew G. Knepley }
579b6f715bSMatthew G. Knepley 
58d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
59d71ae5a4SJacob Faibussowitsch {
609b6f715bSMatthew G. Knepley   char           composeStr[33] = {0};
619b6f715bSMatthew G. Knepley   PetscObjectId  id;
629b6f715bSMatthew G. Knepley   PetscContainer container;
639b6f715bSMatthew G. Knepley 
649b6f715bSMatthew G. Knepley   PetscFunctionBegin;
659566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetId((PetscObject)quad, &id));
6663a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id));
679566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container));
689b6f715bSMatthew G. Knepley   if (container) {
699566063dSJacob Faibussowitsch     PetscCall(PetscContainerGetPointer(container, (void **)geom));
709b6f715bSMatthew G. Knepley   } else {
719566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom));
729566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
739566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(container, (void *)*geom));
749566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom));
759566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container));
769566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&container));
779b6f715bSMatthew G. Knepley   }
789b6f715bSMatthew G. Knepley   PetscFunctionReturn(0);
799b6f715bSMatthew G. Knepley }
809b6f715bSMatthew G. Knepley 
81d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
82d71ae5a4SJacob Faibussowitsch {
839b6f715bSMatthew G. Knepley   PetscFunctionBegin;
849b6f715bSMatthew G. Knepley   *geom = NULL;
859b6f715bSMatthew G. Knepley   PetscFunctionReturn(0);
869b6f715bSMatthew G. Knepley }
879b6f715bSMatthew G. Knepley 
8846fa42a0SMatthew G. Knepley /*@
8946fa42a0SMatthew G. Knepley   DMPlexGetScale - Get the scale for the specified fundamental unit
9046fa42a0SMatthew G. Knepley 
9146fa42a0SMatthew G. Knepley   Not collective
9246fa42a0SMatthew G. Knepley 
934165533cSJose E. Roman   Input Parameters:
94*a1cb98faSBarry Smith + dm   - the `DM`
9546fa42a0SMatthew G. Knepley - unit - The SI unit
9646fa42a0SMatthew G. Knepley 
974165533cSJose E. Roman   Output Parameter:
9846fa42a0SMatthew G. Knepley . scale - The value used to scale all quantities with this unit
9946fa42a0SMatthew G. Knepley 
10046fa42a0SMatthew G. Knepley   Level: advanced
10146fa42a0SMatthew G. Knepley 
102*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit`
10346fa42a0SMatthew G. Knepley @*/
104d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
105d71ae5a4SJacob Faibussowitsch {
106cb1e1211SMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
107cb1e1211SMatthew G Knepley 
108cb1e1211SMatthew G Knepley   PetscFunctionBegin;
109cb1e1211SMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
110dadcf809SJacob Faibussowitsch   PetscValidRealPointer(scale, 3);
111cb1e1211SMatthew G Knepley   *scale = mesh->scale[unit];
112cb1e1211SMatthew G Knepley   PetscFunctionReturn(0);
113cb1e1211SMatthew G Knepley }
114cb1e1211SMatthew G Knepley 
11546fa42a0SMatthew G. Knepley /*@
11646fa42a0SMatthew G. Knepley   DMPlexSetScale - Set the scale for the specified fundamental unit
11746fa42a0SMatthew G. Knepley 
11846fa42a0SMatthew G. Knepley   Not collective
11946fa42a0SMatthew G. Knepley 
1204165533cSJose E. Roman   Input Parameters:
121*a1cb98faSBarry Smith + dm   - the `DM`
12246fa42a0SMatthew G. Knepley . unit - The SI unit
12346fa42a0SMatthew G. Knepley - scale - The value used to scale all quantities with this unit
12446fa42a0SMatthew G. Knepley 
12546fa42a0SMatthew G. Knepley   Level: advanced
12646fa42a0SMatthew G. Knepley 
127*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit`
12846fa42a0SMatthew G. Knepley @*/
129d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
130d71ae5a4SJacob Faibussowitsch {
131cb1e1211SMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
132cb1e1211SMatthew G Knepley 
133cb1e1211SMatthew G Knepley   PetscFunctionBegin;
134cb1e1211SMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
135cb1e1211SMatthew G Knepley   mesh->scale[unit] = scale;
136cb1e1211SMatthew G Knepley   PetscFunctionReturn(0);
137cb1e1211SMatthew G Knepley }
138cb1e1211SMatthew G Knepley 
139d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx)
140d71ae5a4SJacob Faibussowitsch {
1419371c9d4SSatish Balay   const PetscInt eps[3][3][3] = {
1429371c9d4SSatish Balay     {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
1439371c9d4SSatish Balay     {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
1449371c9d4SSatish Balay     {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
1459371c9d4SSatish Balay   };
146026175e5SToby Isaac   PetscInt *ctxInt = (PetscInt *)ctx;
147ad917190SMatthew G. Knepley   PetscInt  dim2   = ctxInt[0];
148026175e5SToby Isaac   PetscInt  d      = ctxInt[1];
149026175e5SToby Isaac   PetscInt  i, j, k = dim > 2 ? d - dim : d;
150026175e5SToby Isaac 
151ad917190SMatthew G. Knepley   PetscFunctionBegin;
15263a3b9bcSJacob Faibussowitsch   PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2);
153026175e5SToby Isaac   for (i = 0; i < dim; i++) mode[i] = 0.;
154026175e5SToby Isaac   if (d < dim) {
15512adca46SMatthew G. Knepley     mode[d] = 1.; /* Translation along axis d */
156ad917190SMatthew G. Knepley   } else {
157026175e5SToby Isaac     for (i = 0; i < dim; i++) {
1589371c9d4SSatish Balay       for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ }
159026175e5SToby Isaac     }
160026175e5SToby Isaac   }
161ad917190SMatthew G. Knepley   PetscFunctionReturn(0);
162026175e5SToby Isaac }
163026175e5SToby Isaac 
164cc4e42d9SMartin Diehl /*@
16512adca46SMatthew G. Knepley   DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation
166cb1e1211SMatthew G Knepley 
167d083f849SBarry Smith   Collective on dm
168cb1e1211SMatthew G Knepley 
1694165533cSJose E. Roman   Input Parameters:
170*a1cb98faSBarry Smith + dm - the `DM`
17156cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default
172cb1e1211SMatthew G Knepley 
1734165533cSJose E. Roman   Output Parameter:
174cb1e1211SMatthew G Knepley . sp - the null space
175cb1e1211SMatthew G Knepley 
176cb1e1211SMatthew G Knepley   Level: advanced
177cb1e1211SMatthew G Knepley 
178*a1cb98faSBarry Smith   Note:
179*a1cb98faSBarry Smith   This is necessary to provide a suitable coarse space for algebraic multigrid
180*a1cb98faSBarry Smith 
181*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG`
182cb1e1211SMatthew G Knepley @*/
183d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp)
184d71ae5a4SJacob Faibussowitsch {
18556cf3b9cSMatthew G. Knepley   PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
186cb1e1211SMatthew G Knepley   MPI_Comm     comm;
187026175e5SToby Isaac   Vec          mode[6];
188026175e5SToby Isaac   PetscSection section, globalSection;
18956cf3b9cSMatthew G. Knepley   PetscInt     dim, dimEmbed, Nf, n, m, mmin, d, i, j;
190cb1e1211SMatthew G Knepley 
191cb1e1211SMatthew G Knepley   PetscFunctionBegin;
1929566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1939566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
1949566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
1959566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
19663a3b9bcSJacob Faibussowitsch   PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf);
19756cf3b9cSMatthew G. Knepley   if (dim == 1 && Nf < 2) {
1989566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp));
199cb1e1211SMatthew G Knepley     PetscFunctionReturn(0);
200cb1e1211SMatthew G Knepley   }
2019566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
2029566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
2039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n));
2049566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Nf, &func));
205b247467aSMatthew G. Knepley   m = (dim * (dim + 1)) / 2;
2069566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &mode[0]));
2079566063dSJacob Faibussowitsch   PetscCall(VecSetType(mode[0], dm->vectype));
2089566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE));
2099566063dSJacob Faibussowitsch   PetscCall(VecSetUp(mode[0]));
2109566063dSJacob Faibussowitsch   PetscCall(VecGetSize(mode[0], &n));
211b247467aSMatthew G. Knepley   mmin        = PetscMin(m, n);
21256cf3b9cSMatthew G. Knepley   func[field] = DMPlexProjectRigidBody_Private;
2139566063dSJacob Faibussowitsch   for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i]));
214026175e5SToby Isaac   for (d = 0; d < m; d++) {
215330485fdSToby Isaac     PetscInt ctx[2];
216026175e5SToby Isaac     void    *voidctx = (void *)(&ctx[0]);
217cb1e1211SMatthew G Knepley 
2189d8fbdeaSMatthew G. Knepley     ctx[0] = dimEmbed;
219330485fdSToby Isaac     ctx[1] = d;
2209566063dSJacob Faibussowitsch     PetscCall(DMProjectFunction(dm, 0.0, func, &voidctx, INSERT_VALUES, mode[d]));
221cb1e1211SMatthew G Knepley   }
2223b2202bfSJacob Faibussowitsch   /* Orthonormalize system */
223b50a2c0aSJacob Faibussowitsch   for (i = 0; i < mmin; ++i) {
224b77f2eeeSJacob Faibussowitsch     PetscScalar dots[6];
225b50a2c0aSJacob Faibussowitsch 
2269566063dSJacob Faibussowitsch     PetscCall(VecNormalize(mode[i], NULL));
2279566063dSJacob Faibussowitsch     PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1));
228b50a2c0aSJacob Faibussowitsch     for (j = i + 1; j < mmin; ++j) {
229b77f2eeeSJacob Faibussowitsch       dots[j] *= -1.0;
2309566063dSJacob Faibussowitsch       PetscCall(VecAXPY(mode[j], dots[j], mode[i]));
231b50a2c0aSJacob Faibussowitsch     }
232cb1e1211SMatthew G Knepley   }
2339566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp));
2349566063dSJacob Faibussowitsch   for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i]));
2359566063dSJacob Faibussowitsch   PetscCall(PetscFree(func));
236cb1e1211SMatthew G Knepley   PetscFunctionReturn(0);
237cb1e1211SMatthew G Knepley }
238cb1e1211SMatthew G Knepley 
239cc4e42d9SMartin Diehl /*@
24012adca46SMatthew G. Knepley   DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation
24112adca46SMatthew G. Knepley 
242d083f849SBarry Smith   Collective on dm
24312adca46SMatthew G. Knepley 
2444165533cSJose E. Roman   Input Parameters:
245*a1cb98faSBarry Smith + dm    - the `DM`
24612adca46SMatthew G. Knepley . nb    - The number of bodies
247*a1cb98faSBarry Smith . label - The `DMLabel` marking each domain
24812adca46SMatthew G. Knepley . nids  - The number of ids per body
24912adca46SMatthew G. Knepley - ids   - An array of the label ids in sequence for each domain
25012adca46SMatthew G. Knepley 
2514165533cSJose E. Roman   Output Parameter:
25212adca46SMatthew G. Knepley . sp - the null space
25312adca46SMatthew G. Knepley 
25412adca46SMatthew G. Knepley   Level: advanced
25512adca46SMatthew G. Knepley 
256*a1cb98faSBarry Smith   Note:
257*a1cb98faSBarry Smith   This is necessary to provide a suitable coarse space for algebraic multigrid
258*a1cb98faSBarry Smith 
259*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`
26012adca46SMatthew G. Knepley @*/
261d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
262d71ae5a4SJacob Faibussowitsch {
26312adca46SMatthew G. Knepley   MPI_Comm     comm;
26412adca46SMatthew G. Knepley   PetscSection section, globalSection;
26512adca46SMatthew G. Knepley   Vec         *mode;
26612adca46SMatthew G. Knepley   PetscScalar *dots;
26712adca46SMatthew G. Knepley   PetscInt     dim, dimEmbed, n, m, b, d, i, j, off;
26812adca46SMatthew G. Knepley 
26912adca46SMatthew G. Knepley   PetscFunctionBegin;
2709566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
2729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
2739566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
2749566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
2759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n));
27612adca46SMatthew G. Knepley   m = nb * (dim * (dim + 1)) / 2;
2779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(m, &mode, m, &dots));
2789566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &mode[0]));
2799566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE));
2809566063dSJacob Faibussowitsch   PetscCall(VecSetUp(mode[0]));
2819566063dSJacob Faibussowitsch   for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i]));
28212adca46SMatthew G. Knepley   for (b = 0, off = 0; b < nb; ++b) {
28312adca46SMatthew G. Knepley     for (d = 0; d < m / nb; ++d) {
28412adca46SMatthew G. Knepley       PetscInt ctx[2];
28512adca46SMatthew G. Knepley       PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
28612adca46SMatthew G. Knepley       void *voidctx                                                                                   = (void *)(&ctx[0]);
28712adca46SMatthew G. Knepley 
28812adca46SMatthew G. Knepley       ctx[0] = dimEmbed;
28912adca46SMatthew G. Knepley       ctx[1] = d;
2909566063dSJacob Faibussowitsch       PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]));
29112adca46SMatthew G. Knepley       off += nids[b];
29212adca46SMatthew G. Knepley     }
29312adca46SMatthew G. Knepley   }
2943b2202bfSJacob Faibussowitsch   /* Orthonormalize system */
295606c1a1cSJacob Faibussowitsch   for (i = 0; i < m; ++i) {
296b77f2eeeSJacob Faibussowitsch     PetscScalar dots[6];
2975a0e29b9SJacob Faibussowitsch 
2989566063dSJacob Faibussowitsch     PetscCall(VecNormalize(mode[i], NULL));
2999566063dSJacob Faibussowitsch     PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1));
3005a0e29b9SJacob Faibussowitsch     for (j = i + 1; j < m; ++j) {
301b77f2eeeSJacob Faibussowitsch       dots[j] *= -1.0;
3029566063dSJacob Faibussowitsch       PetscCall(VecAXPY(mode[j], dots[j], mode[i]));
3035a0e29b9SJacob Faibussowitsch     }
30412adca46SMatthew G. Knepley   }
3059566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp));
3069566063dSJacob Faibussowitsch   for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i]));
3079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(mode, dots));
30812adca46SMatthew G. Knepley   PetscFunctionReturn(0);
30912adca46SMatthew G. Knepley }
31012adca46SMatthew G. Knepley 
311b29cfa1cSToby Isaac /*@
312b29cfa1cSToby Isaac   DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
313b29cfa1cSToby Isaac   are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
314b29cfa1cSToby Isaac   evaluating the dual space basis of that point.  A basis function is associated with the point in its
315b29cfa1cSToby Isaac   transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum
316b29cfa1cSToby Isaac   projection height, which is set with this function.  By default, the maximum projection height is zero, which means
317b29cfa1cSToby Isaac   that only mesh cells are used to project basis functions.  A height of one, for example, evaluates a cell-interior
318b29cfa1cSToby Isaac   basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face.
319b29cfa1cSToby Isaac 
320b29cfa1cSToby Isaac   Input Parameters:
321*a1cb98faSBarry Smith + dm - the `DMPLEX` object
322b29cfa1cSToby Isaac - height - the maximum projection height >= 0
323b29cfa1cSToby Isaac 
324b29cfa1cSToby Isaac   Level: advanced
325b29cfa1cSToby Isaac 
326*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
327b29cfa1cSToby Isaac @*/
328d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
329d71ae5a4SJacob Faibussowitsch {
330b29cfa1cSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
331b29cfa1cSToby Isaac 
332b29cfa1cSToby Isaac   PetscFunctionBegin;
333b29cfa1cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
334b29cfa1cSToby Isaac   plex->maxProjectionHeight = height;
335b29cfa1cSToby Isaac   PetscFunctionReturn(0);
336b29cfa1cSToby Isaac }
337b29cfa1cSToby Isaac 
338b29cfa1cSToby Isaac /*@
339b29cfa1cSToby Isaac   DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
340b29cfa1cSToby Isaac   DMPlexProjectXXXLocal() functions.
341b29cfa1cSToby Isaac 
342b29cfa1cSToby Isaac   Input Parameters:
343*a1cb98faSBarry Smith . dm - the `DMPLEX` object
344b29cfa1cSToby Isaac 
345b29cfa1cSToby Isaac   Output Parameters:
346b29cfa1cSToby Isaac . height - the maximum projection height
347b29cfa1cSToby Isaac 
348b29cfa1cSToby Isaac   Level: intermediate
349b29cfa1cSToby Isaac 
350*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
351b29cfa1cSToby Isaac @*/
352d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
353d71ae5a4SJacob Faibussowitsch {
354b29cfa1cSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
355b29cfa1cSToby Isaac 
356b29cfa1cSToby Isaac   PetscFunctionBegin;
357b29cfa1cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
358b29cfa1cSToby Isaac   *height = plex->maxProjectionHeight;
359b29cfa1cSToby Isaac   PetscFunctionReturn(0);
360b29cfa1cSToby Isaac }
361b29cfa1cSToby Isaac 
362ca3d3a14SMatthew G. Knepley typedef struct {
363ca3d3a14SMatthew G. Knepley   PetscReal    alpha; /* The first Euler angle, and in 2D the only one */
364ca3d3a14SMatthew G. Knepley   PetscReal    beta;  /* The second Euler angle */
365ca3d3a14SMatthew G. Knepley   PetscReal    gamma; /* The third Euler angle */
366ca3d3a14SMatthew G. Knepley   PetscInt     dim;   /* The dimension of R */
367ca3d3a14SMatthew G. Knepley   PetscScalar *R;     /* The rotation matrix, transforming a vector in the local basis to the global basis */
368ca3d3a14SMatthew G. Knepley   PetscScalar *RT;    /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
369ca3d3a14SMatthew G. Knepley } RotCtx;
370ca3d3a14SMatthew G. Knepley 
371ca3d3a14SMatthew G. Knepley /*
372ca3d3a14SMatthew G. Knepley   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
373ca3d3a14SMatthew G. Knepley   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:
374ca3d3a14SMatthew G. Knepley   $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
375ca3d3a14SMatthew G. Knepley   $ 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.
376ca3d3a14SMatthew G. Knepley   $ The XYZ system rotates a third time about the z axis by gamma.
377ca3d3a14SMatthew G. Knepley */
378d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx)
379d71ae5a4SJacob Faibussowitsch {
380ca3d3a14SMatthew G. Knepley   RotCtx   *rc  = (RotCtx *)ctx;
381ca3d3a14SMatthew G. Knepley   PetscInt  dim = rc->dim;
382ca3d3a14SMatthew G. Knepley   PetscReal c1, s1, c2, s2, c3, s3;
383ca3d3a14SMatthew G. Knepley 
384ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
3859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT));
386ca3d3a14SMatthew G. Knepley   switch (dim) {
387ca3d3a14SMatthew G. Knepley   case 2:
3889371c9d4SSatish Balay     c1       = PetscCosReal(rc->alpha);
3899371c9d4SSatish Balay     s1       = PetscSinReal(rc->alpha);
3909371c9d4SSatish Balay     rc->R[0] = c1;
3919371c9d4SSatish Balay     rc->R[1] = s1;
3929371c9d4SSatish Balay     rc->R[2] = -s1;
3939371c9d4SSatish Balay     rc->R[3] = c1;
3949566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim)));
395b458e8f1SJose E. Roman     DMPlex_Transpose2D_Internal(rc->RT);
396ca3d3a14SMatthew G. Knepley     break;
397ca3d3a14SMatthew G. Knepley   case 3:
3989371c9d4SSatish Balay     c1       = PetscCosReal(rc->alpha);
3999371c9d4SSatish Balay     s1       = PetscSinReal(rc->alpha);
4009371c9d4SSatish Balay     c2       = PetscCosReal(rc->beta);
4019371c9d4SSatish Balay     s2       = PetscSinReal(rc->beta);
4029371c9d4SSatish Balay     c3       = PetscCosReal(rc->gamma);
4039371c9d4SSatish Balay     s3       = PetscSinReal(rc->gamma);
4049371c9d4SSatish Balay     rc->R[0] = c1 * c3 - c2 * s1 * s3;
4059371c9d4SSatish Balay     rc->R[1] = c3 * s1 + c1 * c2 * s3;
4069371c9d4SSatish Balay     rc->R[2] = s2 * s3;
4079371c9d4SSatish Balay     rc->R[3] = -c1 * s3 - c2 * c3 * s1;
4089371c9d4SSatish Balay     rc->R[4] = c1 * c2 * c3 - s1 * s3;
4099371c9d4SSatish Balay     rc->R[5] = c3 * s2;
4109371c9d4SSatish Balay     rc->R[6] = s1 * s2;
4119371c9d4SSatish Balay     rc->R[7] = -c1 * s2;
4129371c9d4SSatish Balay     rc->R[8] = c2;
4139566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim)));
414b458e8f1SJose E. Roman     DMPlex_Transpose3D_Internal(rc->RT);
415ca3d3a14SMatthew G. Knepley     break;
416d71ae5a4SJacob Faibussowitsch   default:
417d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
418ca3d3a14SMatthew G. Knepley   }
419ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
420ca3d3a14SMatthew G. Knepley }
421ca3d3a14SMatthew G. Knepley 
422d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx)
423d71ae5a4SJacob Faibussowitsch {
424ca3d3a14SMatthew G. Knepley   RotCtx *rc = (RotCtx *)ctx;
425ca3d3a14SMatthew G. Knepley 
426ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
4279566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rc->R, rc->RT));
4289566063dSJacob Faibussowitsch   PetscCall(PetscFree(rc));
429ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
430ca3d3a14SMatthew G. Knepley }
431ca3d3a14SMatthew G. Knepley 
432d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx)
433d71ae5a4SJacob Faibussowitsch {
434ca3d3a14SMatthew G. Knepley   RotCtx *rc = (RotCtx *)ctx;
435ca3d3a14SMatthew G. Knepley 
436ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
437ca3d3a14SMatthew G. Knepley   PetscValidPointer(ctx, 5);
4389371c9d4SSatish Balay   if (l2g) {
4399371c9d4SSatish Balay     *A = rc->R;
4409371c9d4SSatish Balay   } else {
4419371c9d4SSatish Balay     *A = rc->RT;
4429371c9d4SSatish Balay   }
443ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
444ca3d3a14SMatthew G. Knepley }
445ca3d3a14SMatthew G. Knepley 
446d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx)
447d71ae5a4SJacob Faibussowitsch {
448ec277c0fSMatthew G. Knepley   PetscFunctionBegin;
449ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
450ab6a9622SMatthew G. Knepley   switch (dim) {
4519371c9d4SSatish Balay   case 2: {
45227104ee2SJacob Faibussowitsch     PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0};
453ab6a9622SMatthew G. Knepley 
4549566063dSJacob Faibussowitsch     PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx));
4559371c9d4SSatish Balay     z[0] = PetscRealPart(zt[0]);
4569371c9d4SSatish Balay     z[1] = PetscRealPart(zt[1]);
4579371c9d4SSatish Balay   } break;
4589371c9d4SSatish Balay   case 3: {
45927104ee2SJacob Faibussowitsch     PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0};
460ab6a9622SMatthew G. Knepley 
4619566063dSJacob Faibussowitsch     PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx));
4629371c9d4SSatish Balay     z[0] = PetscRealPart(zt[0]);
4639371c9d4SSatish Balay     z[1] = PetscRealPart(zt[1]);
4649371c9d4SSatish Balay     z[2] = PetscRealPart(zt[2]);
4659371c9d4SSatish Balay   } break;
466ab6a9622SMatthew G. Knepley   }
467ab6a9622SMatthew G. Knepley #else
4689566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx));
469ab6a9622SMatthew G. Knepley #endif
470ec277c0fSMatthew G. Knepley   PetscFunctionReturn(0);
471ab6a9622SMatthew G. Knepley }
472ab6a9622SMatthew G. Knepley 
473d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx)
474d71ae5a4SJacob Faibussowitsch {
475ca3d3a14SMatthew G. Knepley   const PetscScalar *A;
476ca3d3a14SMatthew G. Knepley 
477ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
4789566063dSJacob Faibussowitsch   PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx));
479ca3d3a14SMatthew G. Knepley   switch (dim) {
480d71ae5a4SJacob Faibussowitsch   case 2:
481d71ae5a4SJacob Faibussowitsch     DMPlex_Mult2D_Internal(A, 1, y, z);
482d71ae5a4SJacob Faibussowitsch     break;
483d71ae5a4SJacob Faibussowitsch   case 3:
484d71ae5a4SJacob Faibussowitsch     DMPlex_Mult3D_Internal(A, 1, y, z);
485d71ae5a4SJacob Faibussowitsch     break;
486ca3d3a14SMatthew G. Knepley   }
487ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
488ca3d3a14SMatthew G. Knepley }
489ca3d3a14SMatthew G. Knepley 
490d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
491d71ae5a4SJacob Faibussowitsch {
492ca3d3a14SMatthew G. Knepley   PetscSection       ts;
493ca3d3a14SMatthew G. Knepley   const PetscScalar *ta, *tva;
494ca3d3a14SMatthew G. Knepley   PetscInt           dof;
495ca3d3a14SMatthew G. Knepley 
496ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
4979566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
4989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
4999566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
5009566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva));
501ca3d3a14SMatthew G. Knepley   if (l2g) {
502ca3d3a14SMatthew G. Knepley     switch (dof) {
503d71ae5a4SJacob Faibussowitsch     case 4:
504d71ae5a4SJacob Faibussowitsch       DMPlex_Mult2D_Internal(tva, 1, a, a);
505d71ae5a4SJacob Faibussowitsch       break;
506d71ae5a4SJacob Faibussowitsch     case 9:
507d71ae5a4SJacob Faibussowitsch       DMPlex_Mult3D_Internal(tva, 1, a, a);
508d71ae5a4SJacob Faibussowitsch       break;
509ca3d3a14SMatthew G. Knepley     }
510ca3d3a14SMatthew G. Knepley   } else {
511ca3d3a14SMatthew G. Knepley     switch (dof) {
512d71ae5a4SJacob Faibussowitsch     case 4:
513d71ae5a4SJacob Faibussowitsch       DMPlex_MultTranspose2D_Internal(tva, 1, a, a);
514d71ae5a4SJacob Faibussowitsch       break;
515d71ae5a4SJacob Faibussowitsch     case 9:
516d71ae5a4SJacob Faibussowitsch       DMPlex_MultTranspose3D_Internal(tva, 1, a, a);
517d71ae5a4SJacob Faibussowitsch       break;
518ca3d3a14SMatthew G. Knepley     }
519ca3d3a14SMatthew G. Knepley   }
5209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
521ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
522ca3d3a14SMatthew G. Knepley }
523ca3d3a14SMatthew G. Knepley 
524d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a)
525d71ae5a4SJacob Faibussowitsch {
526ca3d3a14SMatthew G. Knepley   PetscSection       s, ts;
527ca3d3a14SMatthew G. Knepley   const PetscScalar *ta, *tvaf, *tvag;
528ca3d3a14SMatthew G. Knepley   PetscInt           fdof, gdof, fpdof, gpdof;
529ca3d3a14SMatthew G. Knepley 
530ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
5319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
5329566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
5339566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof));
5349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof));
5359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof));
5369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof));
5379566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
5389566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf));
5399566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag));
540ca3d3a14SMatthew G. Knepley   if (l2g) {
541ca3d3a14SMatthew G. Knepley     switch (fdof) {
542d71ae5a4SJacob Faibussowitsch     case 4:
543d71ae5a4SJacob Faibussowitsch       DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);
544d71ae5a4SJacob Faibussowitsch       break;
545d71ae5a4SJacob Faibussowitsch     case 9:
546d71ae5a4SJacob Faibussowitsch       DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);
547d71ae5a4SJacob Faibussowitsch       break;
548ca3d3a14SMatthew G. Knepley     }
549ca3d3a14SMatthew G. Knepley     switch (gdof) {
550d71ae5a4SJacob Faibussowitsch     case 4:
551d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);
552d71ae5a4SJacob Faibussowitsch       break;
553d71ae5a4SJacob Faibussowitsch     case 9:
554d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);
555d71ae5a4SJacob Faibussowitsch       break;
556ca3d3a14SMatthew G. Knepley     }
557ca3d3a14SMatthew G. Knepley   } else {
558ca3d3a14SMatthew G. Knepley     switch (fdof) {
559d71ae5a4SJacob Faibussowitsch     case 4:
560d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);
561d71ae5a4SJacob Faibussowitsch       break;
562d71ae5a4SJacob Faibussowitsch     case 9:
563d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);
564d71ae5a4SJacob Faibussowitsch       break;
565ca3d3a14SMatthew G. Knepley     }
566ca3d3a14SMatthew G. Knepley     switch (gdof) {
567d71ae5a4SJacob Faibussowitsch     case 4:
568d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);
569d71ae5a4SJacob Faibussowitsch       break;
570d71ae5a4SJacob Faibussowitsch     case 9:
571d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);
572d71ae5a4SJacob Faibussowitsch       break;
573ca3d3a14SMatthew G. Knepley     }
574ca3d3a14SMatthew G. Knepley   }
5759566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
576ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
577ca3d3a14SMatthew G. Knepley }
578ca3d3a14SMatthew G. Knepley 
579d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
580d71ae5a4SJacob Faibussowitsch {
581ca3d3a14SMatthew G. Knepley   PetscSection    s;
582ca3d3a14SMatthew G. Knepley   PetscSection    clSection;
583ca3d3a14SMatthew G. Knepley   IS              clPoints;
584ca3d3a14SMatthew G. Knepley   const PetscInt *clp;
585ca3d3a14SMatthew G. Knepley   PetscInt       *points = NULL;
586ca3d3a14SMatthew G. Knepley   PetscInt        Nf, f, Np, cp, dof, d = 0;
587ca3d3a14SMatthew G. Knepley 
588ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
5899566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
5909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
5919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
592ca3d3a14SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
593ca3d3a14SMatthew G. Knepley     for (cp = 0; cp < Np * 2; cp += 2) {
5949566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof));
595ca3d3a14SMatthew G. Knepley       if (!dof) continue;
5969566063dSJacob Faibussowitsch       if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]));
597ca3d3a14SMatthew G. Knepley       d += dof;
598ca3d3a14SMatthew G. Knepley     }
599ca3d3a14SMatthew G. Knepley   }
6009566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
601ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
602ca3d3a14SMatthew G. Knepley }
603ca3d3a14SMatthew G. Knepley 
604d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
605d71ae5a4SJacob Faibussowitsch {
606ca3d3a14SMatthew G. Knepley   PetscSection    s;
607ca3d3a14SMatthew G. Knepley   PetscSection    clSection;
608ca3d3a14SMatthew G. Knepley   IS              clPoints;
609ca3d3a14SMatthew G. Knepley   const PetscInt *clp;
610ca3d3a14SMatthew G. Knepley   PetscInt       *points = NULL;
6118bdb3c71SMatthew G. Knepley   PetscInt        Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
612ca3d3a14SMatthew G. Knepley 
613ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
6149566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
6159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
6169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
617ca3d3a14SMatthew G. Knepley   for (f = 0, r = 0; f < Nf; ++f) {
618ca3d3a14SMatthew G. Knepley     for (cpf = 0; cpf < Np * 2; cpf += 2) {
6199566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof));
620ca3d3a14SMatthew G. Knepley       for (g = 0, c = 0; g < Nf; ++g) {
621ca3d3a14SMatthew G. Knepley         for (cpg = 0; cpg < Np * 2; cpg += 2) {
6229566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof));
6239566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c]));
624ca3d3a14SMatthew G. Knepley           c += gdof;
625ca3d3a14SMatthew G. Knepley         }
626ca3d3a14SMatthew G. Knepley       }
62763a3b9bcSJacob Faibussowitsch       PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda);
628ca3d3a14SMatthew G. Knepley       r += fdof;
629ca3d3a14SMatthew G. Knepley     }
630ca3d3a14SMatthew G. Knepley   }
63163a3b9bcSJacob Faibussowitsch   PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda);
6329566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
633ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
634ca3d3a14SMatthew G. Knepley }
635ca3d3a14SMatthew G. Knepley 
636d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
637d71ae5a4SJacob Faibussowitsch {
638ca3d3a14SMatthew G. Knepley   DM                 tdm;
639ca3d3a14SMatthew G. Knepley   Vec                tv;
640ca3d3a14SMatthew G. Knepley   PetscSection       ts, s;
641ca3d3a14SMatthew G. Knepley   const PetscScalar *ta;
642ca3d3a14SMatthew G. Knepley   PetscScalar       *a, *va;
643ca3d3a14SMatthew G. Knepley   PetscInt           pStart, pEnd, p, Nf, f;
644ca3d3a14SMatthew G. Knepley 
645ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
6469566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
6479566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
6489566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
6499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
6509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
6519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
6529566063dSJacob Faibussowitsch   PetscCall(VecGetArray(lv, &a));
6539566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
654ca3d3a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
655ca3d3a14SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
6569566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va));
6579566063dSJacob Faibussowitsch       PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va));
658ca3d3a14SMatthew G. Knepley     }
659ca3d3a14SMatthew G. Knepley   }
6609566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(lv, &a));
6619566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
662ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
663ca3d3a14SMatthew G. Knepley }
664ca3d3a14SMatthew G. Knepley 
665ca3d3a14SMatthew G. Knepley /*@
666ca3d3a14SMatthew G. Knepley   DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis
667ca3d3a14SMatthew G. Knepley 
668ca3d3a14SMatthew G. Knepley   Input Parameters:
669*a1cb98faSBarry Smith + dm - The `DM`
670ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis
671ca3d3a14SMatthew G. Knepley 
672ca3d3a14SMatthew G. Knepley   Output Parameters:
673ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis
674ca3d3a14SMatthew G. Knepley 
675ca3d3a14SMatthew G. Knepley   Level: developer
676ca3d3a14SMatthew G. Knepley 
677*a1cb98faSBarry Smith   Note:
678*a1cb98faSBarry Smith   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.
679*a1cb98faSBarry Smith 
680*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
681ca3d3a14SMatthew G. Knepley @*/
682d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
683d71ae5a4SJacob Faibussowitsch {
684ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
685ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
686ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(lv, VEC_CLASSID, 2);
6879566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE));
688ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
689ca3d3a14SMatthew G. Knepley }
690ca3d3a14SMatthew G. Knepley 
691ca3d3a14SMatthew G. Knepley /*@
692ca3d3a14SMatthew G. Knepley   DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis
693ca3d3a14SMatthew G. Knepley 
694ca3d3a14SMatthew G. Knepley   Input Parameters:
695*a1cb98faSBarry Smith + dm - The `DM`
696ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis
697ca3d3a14SMatthew G. Knepley 
698ca3d3a14SMatthew G. Knepley   Output Parameters:
699ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis
700ca3d3a14SMatthew G. Knepley 
701ca3d3a14SMatthew G. Knepley   Level: developer
702ca3d3a14SMatthew G. Knepley 
703*a1cb98faSBarry Smith   Note:
704*a1cb98faSBarry Smith   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.
705*a1cb98faSBarry Smith 
706*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
707ca3d3a14SMatthew G. Knepley @*/
708d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
709d71ae5a4SJacob Faibussowitsch {
710ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
711ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
712ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(lv, VEC_CLASSID, 2);
7139566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE));
714ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
715ca3d3a14SMatthew G. Knepley }
716ca3d3a14SMatthew G. Knepley 
717ca3d3a14SMatthew G. Knepley /*@
718ca3d3a14SMatthew G. Knepley   DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions
719ca3d3a14SMatthew G. Knepley     and global solutions, to a local basis, appropriate for discretization integrals and assembly.
720ca3d3a14SMatthew G. Knepley 
721ca3d3a14SMatthew G. Knepley   Input Parameters:
722*a1cb98faSBarry Smith + dm    - The `DM`
723ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one
724ca3d3a14SMatthew G. Knepley . beta  - The second Euler angle
725f0fc11ceSJed Brown - gamma - The third Euler angle
726ca3d3a14SMatthew G. Knepley 
727ca3d3a14SMatthew G. Knepley   Level: developer
728ca3d3a14SMatthew G. Knepley 
729*a1cb98faSBarry Smith   Note:
730*a1cb98faSBarry Smith   Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
731*a1cb98faSBarry Smith   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
732*a1cb98faSBarry Smith .vb
733*a1cb98faSBarry Smith    The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis.
734*a1cb98faSBarry Smith    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.
735*a1cb98faSBarry Smith    The XYZ system rotates a third time about the z axis by gamma.
736*a1cb98faSBarry Smith .ve
737*a1cb98faSBarry Smith 
738*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`
739ca3d3a14SMatthew G. Knepley @*/
740d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
741d71ae5a4SJacob Faibussowitsch {
742ca3d3a14SMatthew G. Knepley   RotCtx  *rc;
743ca3d3a14SMatthew G. Knepley   PetscInt cdim;
744ca3d3a14SMatthew G. Knepley 
745362febeeSStefano Zampini   PetscFunctionBegin;
7469566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
7479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &rc));
748ca3d3a14SMatthew G. Knepley   dm->transformCtx       = rc;
749ca3d3a14SMatthew G. Knepley   dm->transformSetUp     = DMPlexBasisTransformSetUp_Rotation_Internal;
750ca3d3a14SMatthew G. Knepley   dm->transformDestroy   = DMPlexBasisTransformDestroy_Rotation_Internal;
751ca3d3a14SMatthew G. Knepley   dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
752ca3d3a14SMatthew G. Knepley   rc->dim                = cdim;
753ca3d3a14SMatthew G. Knepley   rc->alpha              = alpha;
754ca3d3a14SMatthew G. Knepley   rc->beta               = beta;
755ca3d3a14SMatthew G. Knepley   rc->gamma              = gamma;
7569566063dSJacob Faibussowitsch   PetscCall((*dm->transformSetUp)(dm, dm->transformCtx));
7579566063dSJacob Faibussowitsch   PetscCall(DMConstructBasisTransform_Internal(dm));
758ca3d3a14SMatthew G. Knepley   PetscFunctionReturn(0);
759ca3d3a14SMatthew G. Knepley }
760ca3d3a14SMatthew G. Knepley 
761b278463cSMatthew G. Knepley /*@C
762ece3a9fcSMatthew G. Knepley   DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates
763b278463cSMatthew G. Knepley 
764b278463cSMatthew G. Knepley   Input Parameters:
765*a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
766b278463cSMatthew G. Knepley . time   - The time
767b278463cSMatthew G. Knepley . field  - The field to constrain
7681c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
7691c531cf8SMatthew G. Knepley . comps  - An array of constrained component numbers, or NULL for all components
770*a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
771*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
772b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
773b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
774b278463cSMatthew G. Knepley - ctx    - An optional user context for bcFunc
775b278463cSMatthew G. Knepley 
776b278463cSMatthew G. Knepley   Output Parameter:
777b278463cSMatthew G. Knepley . locX   - A local vector to receives the boundary values
778b278463cSMatthew G. Knepley 
779b278463cSMatthew G. Knepley   Level: developer
780b278463cSMatthew G. Knepley 
781*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
782b278463cSMatthew G. Knepley @*/
783d71ae5a4SJacob Faibussowitsch 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)
784d71ae5a4SJacob Faibussowitsch {
7850163fd50SMatthew G. Knepley   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
78655f2e967SMatthew G. Knepley   void   **ctxs;
787d7ddef95SMatthew G. Knepley   PetscInt numFields;
788d7ddef95SMatthew G. Knepley 
789d7ddef95SMatthew G. Knepley   PetscFunctionBegin;
7909566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
7919566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
792d7ddef95SMatthew G. Knepley   funcs[field] = func;
793d7ddef95SMatthew G. Knepley   ctxs[field]  = ctx;
7949566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX));
7959566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
796d7ddef95SMatthew G. Knepley   PetscFunctionReturn(0);
797d7ddef95SMatthew G. Knepley }
798d7ddef95SMatthew G. Knepley 
799b278463cSMatthew G. Knepley /*@C
800ece3a9fcSMatthew G. Knepley   DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data
801b278463cSMatthew G. Knepley 
802b278463cSMatthew G. Knepley   Input Parameters:
803*a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
804b278463cSMatthew G. Knepley . time   - The time
805b278463cSMatthew G. Knepley . locU   - A local vector with the input solution values
806b278463cSMatthew G. Knepley . field  - The field to constrain
8071c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
8081c531cf8SMatthew G. Knepley . comps  - An array of constrained component numbers, or NULL for all components
809*a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
810*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
811b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
812b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
813b278463cSMatthew G. Knepley - ctx    - An optional user context for bcFunc
814b278463cSMatthew G. Knepley 
815b278463cSMatthew G. Knepley   Output Parameter:
816b278463cSMatthew G. Knepley . locX   - A local vector to receives the boundary values
817b278463cSMatthew G. Knepley 
818b278463cSMatthew G. Knepley   Level: developer
819b278463cSMatthew G. Knepley 
820*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
821b278463cSMatthew G. Knepley @*/
822d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX)
823d71ae5a4SJacob Faibussowitsch {
8249371c9d4SSatish Balay   void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
825c60e475cSMatthew G. Knepley   void   **ctxs;
826c60e475cSMatthew G. Knepley   PetscInt numFields;
827c60e475cSMatthew G. Knepley 
828c60e475cSMatthew G. Knepley   PetscFunctionBegin;
8299566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
8309566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
831c60e475cSMatthew G. Knepley   funcs[field] = func;
832c60e475cSMatthew G. Knepley   ctxs[field]  = ctx;
8339566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX));
8349566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
835c60e475cSMatthew G. Knepley   PetscFunctionReturn(0);
836c60e475cSMatthew G. Knepley }
837c60e475cSMatthew G. Knepley 
838b278463cSMatthew G. Knepley /*@C
839d5b43468SJose E. Roman   DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data
840ece3a9fcSMatthew G. Knepley 
841ece3a9fcSMatthew G. Knepley   Collective on dm
842ece3a9fcSMatthew G. Knepley 
843ece3a9fcSMatthew G. Knepley   Input Parameters:
844*a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
845ece3a9fcSMatthew G. Knepley . time   - The time
846ece3a9fcSMatthew G. Knepley . locU   - A local vector with the input solution values
847ece3a9fcSMatthew G. Knepley . field  - The field to constrain
848ece3a9fcSMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
849ece3a9fcSMatthew G. Knepley . comps  - An array of constrained component numbers, or NULL for all components
850*a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
851*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
852ece3a9fcSMatthew G. Knepley . ids    - An array of ids for constrained points
853ece3a9fcSMatthew G. Knepley . func   - A pointwise function giving boundary values, the calling sequence is given in DMProjectBdFieldLabelLocal()
854ece3a9fcSMatthew G. Knepley - ctx    - An optional user context for bcFunc
855ece3a9fcSMatthew G. Knepley 
856ece3a9fcSMatthew G. Knepley   Output Parameter:
857ece3a9fcSMatthew G. Knepley . locX   - A local vector to receive the boundary values
858ece3a9fcSMatthew G. Knepley 
859ece3a9fcSMatthew G. Knepley   Level: developer
860ece3a9fcSMatthew G. Knepley 
861*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
862ece3a9fcSMatthew G. Knepley @*/
863d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX)
864d71ae5a4SJacob Faibussowitsch {
8659371c9d4SSatish Balay   void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]);
866ece3a9fcSMatthew G. Knepley   void   **ctxs;
867ece3a9fcSMatthew G. Knepley   PetscInt numFields;
868ece3a9fcSMatthew G. Knepley 
869ece3a9fcSMatthew G. Knepley   PetscFunctionBegin;
8709566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
8719566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
872ece3a9fcSMatthew G. Knepley   funcs[field] = func;
873ece3a9fcSMatthew G. Knepley   ctxs[field]  = ctx;
8749566063dSJacob Faibussowitsch   PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX));
8759566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
876ece3a9fcSMatthew G. Knepley   PetscFunctionReturn(0);
877ece3a9fcSMatthew G. Knepley }
878ece3a9fcSMatthew G. Knepley 
879ece3a9fcSMatthew G. Knepley /*@C
880b278463cSMatthew G. Knepley   DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector
881b278463cSMatthew G. Knepley 
882b278463cSMatthew G. Knepley   Input Parameters:
883*a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
884b278463cSMatthew G. Knepley . time   - The time
885b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information
886b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information
887b278463cSMatthew G. Knepley . Grad         - A vector with the FVM cell gradient information
888b278463cSMatthew G. Knepley . field  - The field to constrain
8891c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
8901c531cf8SMatthew G. Knepley . comps  - An array of constrained component numbers, or NULL for all components
891*a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
892*a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
893b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
894b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
895b278463cSMatthew G. Knepley - ctx    - An optional user context for bcFunc
896b278463cSMatthew G. Knepley 
897b278463cSMatthew G. Knepley   Output Parameter:
898b278463cSMatthew G. Knepley . locX   - A local vector to receives the boundary values
899b278463cSMatthew G. Knepley 
900b278463cSMatthew G. Knepley   Level: developer
901b278463cSMatthew G. Knepley 
902*a1cb98faSBarry Smith   Note:
903*a1cb98faSBarry Smith   This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()`
904*a1cb98faSBarry Smith 
905*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
906b278463cSMatthew G. Knepley @*/
907d71ae5a4SJacob Faibussowitsch 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[], PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *), void *ctx, Vec locX)
908d71ae5a4SJacob Faibussowitsch {
90961f58d28SMatthew G. Knepley   PetscDS            prob;
910da97024aSMatthew G. Knepley   PetscSF            sf;
911d7ddef95SMatthew G. Knepley   DM                 dmFace, dmCell, dmGrad;
91220369375SToby Isaac   const PetscScalar *facegeom, *cellgeom = NULL, *grad;
913da97024aSMatthew G. Knepley   const PetscInt    *leaves;
914d7ddef95SMatthew G. Knepley   PetscScalar       *x, *fx;
915520b3818SMatthew G. Knepley   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
9165f80ce2aSJacob Faibussowitsch   PetscErrorCode     ierru = 0;
917d7ddef95SMatthew G. Knepley 
918d7ddef95SMatthew G. Knepley   PetscFunctionBegin;
9199566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
9209566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
921da97024aSMatthew G. Knepley   nleaves = PetscMax(0, nleaves);
9229566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
9249566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
9259566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
9269566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
92720369375SToby Isaac   if (cellGeometry) {
9289566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeometry, &dmCell));
9299566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
93020369375SToby Isaac   }
931d7ddef95SMatthew G. Knepley   if (Grad) {
932c0a6632aSMatthew G. Knepley     PetscFV fv;
933c0a6632aSMatthew G. Knepley 
9349566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv));
9359566063dSJacob Faibussowitsch     PetscCall(VecGetDM(Grad, &dmGrad));
9369566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(Grad, &grad));
9379566063dSJacob Faibussowitsch     PetscCall(PetscFVGetNumComponents(fv, &pdim));
9389566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx));
939d7ddef95SMatthew G. Knepley   }
9409566063dSJacob Faibussowitsch   PetscCall(VecGetArray(locX, &x));
941d7ddef95SMatthew G. Knepley   for (i = 0; i < numids; ++i) {
942d7ddef95SMatthew G. Knepley     IS              faceIS;
943d7ddef95SMatthew G. Knepley     const PetscInt *faces;
944d7ddef95SMatthew G. Knepley     PetscInt        numFaces, f;
945d7ddef95SMatthew G. Knepley 
9469566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS));
947d7ddef95SMatthew G. Knepley     if (!faceIS) continue; /* No points with that id on this process */
9489566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(faceIS, &numFaces));
9499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(faceIS, &faces));
950d7ddef95SMatthew G. Knepley     for (f = 0; f < numFaces; ++f) {
951d7ddef95SMatthew G. Knepley       const PetscInt   face = faces[f], *cells;
952640bce14SSatish Balay       PetscFVFaceGeom *fg;
953d7ddef95SMatthew G. Knepley 
954d7ddef95SMatthew G. Knepley       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
9559566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc));
956da97024aSMatthew G. Knepley       if (loc >= 0) continue;
9579566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
9589566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, face, &cells));
959d7ddef95SMatthew G. Knepley       if (Grad) {
960640bce14SSatish Balay         PetscFVCellGeom *cg;
961640bce14SSatish Balay         PetscScalar     *cx, *cgrad;
962d7ddef95SMatthew G. Knepley         PetscScalar     *xG;
963d7ddef95SMatthew G. Knepley         PetscReal        dx[3];
964d7ddef95SMatthew G. Knepley         PetscInt         d;
965d7ddef95SMatthew G. Knepley 
9669566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg));
9679566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx));
9689566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad));
9699566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG));
970d7ddef95SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
971d7ddef95SMatthew G. Knepley         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx);
9729566063dSJacob Faibussowitsch         PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx));
973d7ddef95SMatthew G. Knepley       } else {
974640bce14SSatish Balay         PetscScalar *xI;
975d7ddef95SMatthew G. Knepley         PetscScalar *xG;
976d7ddef95SMatthew G. Knepley 
9779566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI));
9789566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG));
979e735a8a9SMatthew G. Knepley         ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
980e735a8a9SMatthew G. Knepley         if (ierru) {
9819566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(faceIS, &faces));
9829566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&faceIS));
983e735a8a9SMatthew G. Knepley           goto cleanup;
984e735a8a9SMatthew G. Knepley         }
985d7ddef95SMatthew G. Knepley       }
986d7ddef95SMatthew G. Knepley     }
9879566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(faceIS, &faces));
9889566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&faceIS));
989d7ddef95SMatthew G. Knepley   }
990e735a8a9SMatthew G. Knepley cleanup:
9919566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(locX, &x));
992d7ddef95SMatthew G. Knepley   if (Grad) {
9939566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx));
9949566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(Grad, &grad));
995d7ddef95SMatthew G. Knepley   }
9969566063dSJacob Faibussowitsch   if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
9979566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
9989566063dSJacob Faibussowitsch   PetscCall(ierru);
999d7ddef95SMatthew G. Knepley   PetscFunctionReturn(0);
1000d7ddef95SMatthew G. Knepley }
1001d7ddef95SMatthew G. Knepley 
1002d71ae5a4SJacob Faibussowitsch static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1003d71ae5a4SJacob Faibussowitsch {
10040c364540SMatthew G. Knepley   PetscInt c;
10050c364540SMatthew G. Knepley   for (c = 0; c < Nc; ++c) u[c] = 0.0;
10060c364540SMatthew G. Knepley   return 0;
10070c364540SMatthew G. Knepley }
10080c364540SMatthew G. Knepley 
1009d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1010d71ae5a4SJacob Faibussowitsch {
10110c364540SMatthew G. Knepley   PetscObject isZero;
1012e5e52638SMatthew G. Knepley   PetscDS     prob;
1013d7ddef95SMatthew G. Knepley   PetscInt    numBd, b;
101455f2e967SMatthew G. Knepley 
101555f2e967SMatthew G. Knepley   PetscFunctionBegin;
10169566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
10179566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
10189566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero));
101955f2e967SMatthew G. Knepley   for (b = 0; b < numBd; ++b) {
102045480ffeSMatthew G. Knepley     PetscWeakForm           wf;
1021f971fd6bSMatthew G. Knepley     DMBoundaryConditionType type;
102245480ffeSMatthew G. Knepley     const char             *name;
1023d7ddef95SMatthew G. Knepley     DMLabel                 label;
10241c531cf8SMatthew G. Knepley     PetscInt                field, Nc;
10251c531cf8SMatthew G. Knepley     const PetscInt         *comps;
1026d7ddef95SMatthew G. Knepley     PetscObject             obj;
1027d7ddef95SMatthew G. Knepley     PetscClassId            id;
102845480ffeSMatthew G. Knepley     void (*bvfunc)(void);
1029d7ddef95SMatthew G. Knepley     PetscInt        numids;
1030d7ddef95SMatthew G. Knepley     const PetscInt *ids;
103155f2e967SMatthew G. Knepley     void           *ctx;
103255f2e967SMatthew G. Knepley 
10339566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
1034f971fd6bSMatthew G. Knepley     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
10359566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
10369566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
1037d7ddef95SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
1038c60e475cSMatthew G. Knepley       switch (type) {
1039c60e475cSMatthew G. Knepley         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
10409371c9d4SSatish Balay       case DM_BC_ESSENTIAL: {
104145480ffeSMatthew G. Knepley         PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc;
104245480ffeSMatthew G. Knepley 
104345480ffeSMatthew G. Knepley         if (isZero) func = zero;
10449566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
10459566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX));
10469566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
10479371c9d4SSatish Balay       } break;
10489371c9d4SSatish Balay       case DM_BC_ESSENTIAL_FIELD: {
104945480ffeSMatthew G. Knepley         PetscPointFunc func = (PetscPointFunc)bvfunc;
105045480ffeSMatthew G. Knepley 
10519566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
10529566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX));
10539566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
10549371c9d4SSatish Balay       } break;
1055d71ae5a4SJacob Faibussowitsch       default:
1056d71ae5a4SJacob Faibussowitsch         break;
1057c60e475cSMatthew G. Knepley       }
1058d7ddef95SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
105945480ffeSMatthew G. Knepley       {
106045480ffeSMatthew G. Knepley         PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc;
106145480ffeSMatthew G. Knepley 
106243ea7facSMatthew G. Knepley         if (!faceGeomFVM) continue;
10639566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX));
106445480ffeSMatthew G. Knepley       }
106563a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
106655f2e967SMatthew G. Knepley   }
106755f2e967SMatthew G. Knepley   PetscFunctionReturn(0);
106855f2e967SMatthew G. Knepley }
106955f2e967SMatthew G. Knepley 
1070d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1071d71ae5a4SJacob Faibussowitsch {
107256cf3b9cSMatthew G. Knepley   PetscObject isZero;
107356cf3b9cSMatthew G. Knepley   PetscDS     prob;
107456cf3b9cSMatthew G. Knepley   PetscInt    numBd, b;
107556cf3b9cSMatthew G. Knepley 
107656cf3b9cSMatthew G. Knepley   PetscFunctionBegin;
107756cf3b9cSMatthew G. Knepley   if (!locX) PetscFunctionReturn(0);
10789566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
10799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
10809566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero));
108156cf3b9cSMatthew G. Knepley   for (b = 0; b < numBd; ++b) {
108245480ffeSMatthew G. Knepley     PetscWeakForm           wf;
108356cf3b9cSMatthew G. Knepley     DMBoundaryConditionType type;
108445480ffeSMatthew G. Knepley     const char             *name;
108556cf3b9cSMatthew G. Knepley     DMLabel                 label;
108656cf3b9cSMatthew G. Knepley     PetscInt                field, Nc;
108756cf3b9cSMatthew G. Knepley     const PetscInt         *comps;
108856cf3b9cSMatthew G. Knepley     PetscObject             obj;
108956cf3b9cSMatthew G. Knepley     PetscClassId            id;
109056cf3b9cSMatthew G. Knepley     PetscInt                numids;
109156cf3b9cSMatthew G. Knepley     const PetscInt         *ids;
109245480ffeSMatthew G. Knepley     void (*bvfunc)(void);
109356cf3b9cSMatthew G. Knepley     void *ctx;
109456cf3b9cSMatthew G. Knepley 
10959566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx));
109656cf3b9cSMatthew G. Knepley     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
10979566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
10989566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
109956cf3b9cSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
110056cf3b9cSMatthew G. Knepley       switch (type) {
110156cf3b9cSMatthew G. Knepley         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
11029371c9d4SSatish Balay       case DM_BC_ESSENTIAL: {
110345480ffeSMatthew G. Knepley         PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc;
110445480ffeSMatthew G. Knepley 
110545480ffeSMatthew G. Knepley         if (isZero) func_t = zero;
11069566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
11079566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX));
11089566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
11099371c9d4SSatish Balay       } break;
11109371c9d4SSatish Balay       case DM_BC_ESSENTIAL_FIELD: {
111145480ffeSMatthew G. Knepley         PetscPointFunc func_t = (PetscPointFunc)bvfunc;
111245480ffeSMatthew G. Knepley 
11139566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
11149566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX));
11159566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
11169371c9d4SSatish Balay       } break;
1117d71ae5a4SJacob Faibussowitsch       default:
1118d71ae5a4SJacob Faibussowitsch         break;
111956cf3b9cSMatthew G. Knepley       }
112063a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
112156cf3b9cSMatthew G. Knepley   }
112256cf3b9cSMatthew G. Knepley   PetscFunctionReturn(0);
112356cf3b9cSMatthew G. Knepley }
112456cf3b9cSMatthew G. Knepley 
1125f1d73a7aSMatthew G. Knepley /*@
1126f1d73a7aSMatthew G. Knepley   DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector
1127f1d73a7aSMatthew G. Knepley 
1128ed808b8fSJed Brown   Not Collective
1129ed808b8fSJed Brown 
1130f1d73a7aSMatthew G. Knepley   Input Parameters:
1131*a1cb98faSBarry Smith + dm - The `DM`
1132f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1133f1d73a7aSMatthew G. Knepley . time - The time
1134f1d73a7aSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations
1135f1d73a7aSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations
1136f1d73a7aSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations
1137f1d73a7aSMatthew G. Knepley 
1138f1d73a7aSMatthew G. Knepley   Output Parameters:
1139f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values
1140f1d73a7aSMatthew G. Knepley 
1141ed808b8fSJed Brown   Level: intermediate
1142f1d73a7aSMatthew G. Knepley 
1143*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()`
1144f1d73a7aSMatthew G. Knepley @*/
1145d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1146d71ae5a4SJacob Faibussowitsch {
1147f1d73a7aSMatthew G. Knepley   PetscFunctionBegin;
1148f1d73a7aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1149064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
1150ad540459SPierre Jolivet   if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5);
1151ad540459SPierre Jolivet   if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6);
1152ad540459SPierre Jolivet   if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7);
1153cac4c232SBarry Smith   PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM));
1154f1d73a7aSMatthew G. Knepley   PetscFunctionReturn(0);
1155f1d73a7aSMatthew G. Knepley }
1156f1d73a7aSMatthew G. Knepley 
115756cf3b9cSMatthew G. Knepley /*@
1158a5b23f4aSJose E. Roman   DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector
115956cf3b9cSMatthew G. Knepley 
116056cf3b9cSMatthew G. Knepley   Input Parameters:
1161*a1cb98faSBarry Smith + dm - The `DM`
116256cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
116356cf3b9cSMatthew G. Knepley . time - The time
116456cf3b9cSMatthew G. Knepley . faceGeomFVM - Face geometry data for FV discretizations
116556cf3b9cSMatthew G. Knepley . cellGeomFVM - Cell geometry data for FV discretizations
116656cf3b9cSMatthew G. Knepley - gradFVM - Gradient reconstruction data for FV discretizations
116756cf3b9cSMatthew G. Knepley 
116856cf3b9cSMatthew G. Knepley   Output Parameters:
116956cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values
117056cf3b9cSMatthew G. Knepley 
117156cf3b9cSMatthew G. Knepley   Level: developer
117256cf3b9cSMatthew G. Knepley 
1173*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`
117456cf3b9cSMatthew G. Knepley @*/
1175d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1176d71ae5a4SJacob Faibussowitsch {
117756cf3b9cSMatthew G. Knepley   PetscFunctionBegin;
117856cf3b9cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1179ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3);
1180ad540459SPierre Jolivet   if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5);
1181ad540459SPierre Jolivet   if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6);
1182ad540459SPierre Jolivet   if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7);
1183cac4c232SBarry Smith   PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM));
118456cf3b9cSMatthew G. Knepley   PetscFunctionReturn(0);
118556cf3b9cSMatthew G. Knepley }
118656cf3b9cSMatthew G. Knepley 
1187d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1188d71ae5a4SJacob Faibussowitsch {
1189574a98acSMatthew G. Knepley   Vec localX;
1190574a98acSMatthew G. Knepley 
1191574a98acSMatthew G. Knepley   PetscFunctionBegin;
11929566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
11939566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL));
11949566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
11959566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
11969566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff));
11979566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
1198574a98acSMatthew G. Knepley   PetscFunctionReturn(0);
1199574a98acSMatthew G. Knepley }
1200574a98acSMatthew G. Knepley 
1201574a98acSMatthew G. Knepley /*@C
1202ca3d3a14SMatthew G. Knepley   DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
1203574a98acSMatthew G. Knepley 
1204d083f849SBarry Smith   Collective on dm
1205c0f8e1fdSMatthew G. Knepley 
1206574a98acSMatthew G. Knepley   Input Parameters:
1207*a1cb98faSBarry Smith + dm     - The `DM`
1208574a98acSMatthew G. Knepley . time   - The time
1209574a98acSMatthew G. Knepley . funcs  - The functions to evaluate for each field component
1210574a98acSMatthew G. Knepley . ctxs   - Optional array of contexts to pass to each function, or NULL.
1211574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector
1212574a98acSMatthew G. Knepley 
1213574a98acSMatthew G. Knepley   Output Parameter:
1214574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2
1215574a98acSMatthew G. Knepley 
1216574a98acSMatthew G. Knepley   Level: developer
1217574a98acSMatthew G. Knepley 
1218*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1219574a98acSMatthew G. Knepley @*/
1220d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
1221d71ae5a4SJacob Faibussowitsch {
12220f09c10fSMatthew G. Knepley   const PetscInt   debug = ((DM_Plex *)dm->data)->printL2;
1223ca3d3a14SMatthew G. Knepley   DM               tdm;
1224ca3d3a14SMatthew G. Knepley   Vec              tv;
1225cb1e1211SMatthew G Knepley   PetscSection     section;
1226c5bbbd5bSMatthew G. Knepley   PetscQuadrature  quad;
12274bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
122815496722SMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
12294bee2e38SMatthew G. Knepley   PetscReal       *coords, *gcoords;
1230cb1e1211SMatthew G Knepley   PetscReal        localDiff = 0.0;
12317318780aSToby Isaac   const PetscReal *quadWeights;
1232412e9a14SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset;
1233ca3d3a14SMatthew G. Knepley   PetscBool        transform;
1234cb1e1211SMatthew G Knepley 
1235cb1e1211SMatthew G Knepley   PetscFunctionBegin;
12369566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
12379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
12382a4e142eSMatthew G. Knepley   fegeom.dimEmbed = coordDim;
12399566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
12409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
12419566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
12429566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
12439566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
1244cb1e1211SMatthew G Knepley   for (field = 0; field < numFields; ++field) {
124515496722SMatthew G. Knepley     PetscObject  obj;
124615496722SMatthew G. Knepley     PetscClassId id;
1247c5bbbd5bSMatthew G. Knepley     PetscInt     Nc;
1248c5bbbd5bSMatthew G. Knepley 
12499566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
12509566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
125115496722SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
125215496722SMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
125315496722SMatthew G. Knepley 
12549566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
12559566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
125615496722SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
125715496722SMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
125815496722SMatthew G. Knepley 
12599566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
12609566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
126163a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1262c5bbbd5bSMatthew G. Knepley     numComponents += Nc;
1263cb1e1211SMatthew G Knepley   }
12649566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
126563a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
12669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
12679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
12689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
1269cb1e1211SMatthew G Knepley   for (c = cStart; c < cEnd; ++c) {
1270a1e44745SMatthew G. Knepley     PetscScalar *x        = NULL;
1271cb1e1211SMatthew G Knepley     PetscReal    elemDiff = 0.0;
12729c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1273cb1e1211SMatthew G Knepley 
12749566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
12759566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x));
1276cb1e1211SMatthew G Knepley 
127715496722SMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
127815496722SMatthew G. Knepley       PetscObject  obj;
127915496722SMatthew G. Knepley       PetscClassId id;
1280c110b1eeSGeoffrey Irving       void *const  ctx = ctxs ? ctxs[field] : NULL;
128115496722SMatthew G. Knepley       PetscInt     Nb, Nc, q, fc;
1282cb1e1211SMatthew G Knepley 
12839566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, &obj));
12849566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
12859371c9d4SSatish Balay       if (id == PETSCFE_CLASSID) {
12869371c9d4SSatish Balay         PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
12879371c9d4SSatish Balay         PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
12889371c9d4SSatish Balay       } else if (id == PETSCFV_CLASSID) {
12899371c9d4SSatish Balay         PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
12909371c9d4SSatish Balay         Nb = 1;
12919371c9d4SSatish Balay       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1292cb1e1211SMatthew G Knepley       if (debug) {
1293cb1e1211SMatthew G Knepley         char title[1024];
129463a3b9bcSJacob Faibussowitsch         PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field));
12959566063dSJacob Faibussowitsch         PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset]));
1296cb1e1211SMatthew G Knepley       }
12977318780aSToby Isaac       for (q = 0; q < Nq; ++q) {
12982a4e142eSMatthew G. Knepley         PetscFEGeom    qgeom;
1299d0609cedSBarry Smith         PetscErrorCode ierr;
13002a4e142eSMatthew G. Knepley 
13012a4e142eSMatthew G. Knepley         qgeom.dimEmbed = fegeom.dimEmbed;
13022a4e142eSMatthew G. Knepley         qgeom.J        = &fegeom.J[q * coordDim * coordDim];
13032a4e142eSMatthew G. Knepley         qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
13042a4e142eSMatthew G. Knepley         qgeom.detJ     = &fegeom.detJ[q];
130563a3b9bcSJacob Faibussowitsch         PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", point %" PetscInt_FMT, (double)fegeom.detJ[q], c, q);
1306d3a7d86cSMatthew G. Knepley         if (transform) {
1307d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * Nq];
13089566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx));
1309d3a7d86cSMatthew G. Knepley         } else {
1310d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * q];
1311d3a7d86cSMatthew G. Knepley         }
13129566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(funcVal, Nc));
1313ca3d3a14SMatthew G. Knepley         ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx);
1314e735a8a9SMatthew G. Knepley         if (ierr) {
13159566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
13169566063dSJacob Faibussowitsch           PetscCall(DMRestoreLocalVector(dm, &localX));
13179566063dSJacob Faibussowitsch           PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1318e735a8a9SMatthew G. Knepley         }
13199566063dSJacob Faibussowitsch         if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
13209566063dSJacob Faibussowitsch         if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant));
13219566063dSJacob Faibussowitsch         else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant));
13222df84da0SMatthew G. Knepley         else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
132315496722SMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
1324beaa55a6SMatthew G. Knepley           const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
13259371c9d4SSatish Balay           if (debug)
13269371c9d4SSatish Balay             PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elem %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g (%g, %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.),
13279371c9d4SSatish Balay                                   (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc])));
13284bee2e38SMatthew G. Knepley           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1329cb1e1211SMatthew G Knepley         }
1330cb1e1211SMatthew G Knepley       }
13319c3cf19fSMatthew G. Knepley       fieldOffset += Nb;
1332beaa55a6SMatthew G. Knepley       qc += Nc;
1333cb1e1211SMatthew G Knepley     }
13349566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
13359566063dSJacob Faibussowitsch     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff));
1336cb1e1211SMatthew G Knepley     localDiff += elemDiff;
1337cb1e1211SMatthew G Knepley   }
13389566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
13391c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
1340cb1e1211SMatthew G Knepley   *diff = PetscSqrtReal(*diff);
1341cb1e1211SMatthew G Knepley   PetscFunctionReturn(0);
1342cb1e1211SMatthew G Knepley }
1343cb1e1211SMatthew G Knepley 
1344d71ae5a4SJacob Faibussowitsch 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)
1345d71ae5a4SJacob Faibussowitsch {
13460f09c10fSMatthew G. Knepley   const PetscInt   debug = ((DM_Plex *)dm->data)->printL2;
1347ca3d3a14SMatthew G. Knepley   DM               tdm;
1348cb1e1211SMatthew G Knepley   PetscSection     section;
134940e14135SMatthew G. Knepley   PetscQuadrature  quad;
1350ca3d3a14SMatthew G. Knepley   Vec              localX, tv;
13519c3cf19fSMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
13522a4e142eSMatthew G. Knepley   const PetscReal *quadWeights;
13534bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
13544bee2e38SMatthew G. Knepley   PetscReal       *coords, *gcoords;
135540e14135SMatthew G. Knepley   PetscReal        localDiff = 0.0;
1356485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset;
1357ca3d3a14SMatthew G. Knepley   PetscBool        transform;
1358cb1e1211SMatthew G Knepley 
1359cb1e1211SMatthew G Knepley   PetscFunctionBegin;
13609566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13619566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
13624bee2e38SMatthew G. Knepley   fegeom.dimEmbed = coordDim;
13639566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
13649566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
13659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
13669566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
13679566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
13689566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
13699566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
13709566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
1371652b88e8SMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
13720f2d7e86SMatthew G. Knepley     PetscFE  fe;
137340e14135SMatthew G. Knepley     PetscInt Nc;
1374652b88e8SMatthew G. Knepley 
13759566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe));
13769566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &quad));
13779566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents(fe, &Nc));
137840e14135SMatthew G. Knepley     numComponents += Nc;
1379652b88e8SMatthew G. Knepley   }
13809566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
138163a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
13829566063dSJacob Faibussowitsch   /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */
13839566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(numComponents, &funcVal, coordDim * Nq, &coords, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ, numComponents * coordDim, &interpolant, Nq, &fegeom.detJ));
13849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
138540e14135SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
138640e14135SMatthew G. Knepley     PetscScalar *x        = NULL;
138740e14135SMatthew G. Knepley     PetscReal    elemDiff = 0.0;
13889c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1389652b88e8SMatthew G. Knepley 
13909566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
13919566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x));
139240e14135SMatthew G. Knepley 
13939c3cf19fSMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
13940f2d7e86SMatthew G. Knepley       PetscFE     fe;
139551259fa3SMatthew G. Knepley       void *const ctx = ctxs ? ctxs[field] : NULL;
13969c3cf19fSMatthew G. Knepley       PetscInt    Nb, Nc, q, fc;
139740e14135SMatthew G. Knepley 
13989566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe));
13999566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
14009566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
140140e14135SMatthew G. Knepley       if (debug) {
140240e14135SMatthew G. Knepley         char title[1024];
14039566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field));
14049566063dSJacob Faibussowitsch         PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset]));
1405652b88e8SMatthew G. Knepley       }
14069c3cf19fSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
14072a4e142eSMatthew G. Knepley         PetscFEGeom    qgeom;
1408d0609cedSBarry Smith         PetscErrorCode ierr;
14092a4e142eSMatthew G. Knepley 
14102a4e142eSMatthew G. Knepley         qgeom.dimEmbed = fegeom.dimEmbed;
14112a4e142eSMatthew G. Knepley         qgeom.J        = &fegeom.J[q * coordDim * coordDim];
14122a4e142eSMatthew G. Knepley         qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
14132a4e142eSMatthew G. Knepley         qgeom.detJ     = &fegeom.detJ[q];
14142df84da0SMatthew G. Knepley         PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], c, q);
1415d3a7d86cSMatthew G. Knepley         if (transform) {
1416d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * Nq];
14179566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx));
1418d3a7d86cSMatthew G. Knepley         } else {
1419d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * q];
1420d3a7d86cSMatthew G. Knepley         }
14219566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(funcVal, Nc));
14224bee2e38SMatthew G. Knepley         ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx);
1423e735a8a9SMatthew G. Knepley         if (ierr) {
14249566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
14259566063dSJacob Faibussowitsch           PetscCall(DMRestoreLocalVector(dm, &localX));
14269566063dSJacob Faibussowitsch           PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ));
1427e735a8a9SMatthew G. Knepley         }
14289566063dSJacob Faibussowitsch         if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
14299566063dSJacob Faibussowitsch         PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant));
14304bee2e38SMatthew G. Knepley         /* Overwrite with the dot product if the normal is given */
14314bee2e38SMatthew G. Knepley         if (n) {
14324bee2e38SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
14334bee2e38SMatthew G. Knepley             PetscScalar sum = 0.0;
14344bee2e38SMatthew G. Knepley             PetscInt    d;
14354bee2e38SMatthew G. Knepley             for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d];
14364bee2e38SMatthew G. Knepley             interpolant[fc] = sum;
14374bee2e38SMatthew G. Knepley           }
14384bee2e38SMatthew G. Knepley         }
14399c3cf19fSMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
1440beaa55a6SMatthew G. Knepley           const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
144163a3b9bcSJacob Faibussowitsch           if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elem %" PetscInt_FMT " fieldDer %" PetscInt_FMT ",%" PetscInt_FMT " diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q])));
14424bee2e38SMatthew G. Knepley           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
144340e14135SMatthew G. Knepley         }
144440e14135SMatthew G. Knepley       }
14459c3cf19fSMatthew G. Knepley       fieldOffset += Nb;
14469c3cf19fSMatthew G. Knepley       qc += Nc;
144740e14135SMatthew G. Knepley     }
14489566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
144963a3b9bcSJacob Faibussowitsch     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff));
145040e14135SMatthew G. Knepley     localDiff += elemDiff;
145140e14135SMatthew G. Knepley   }
14529566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ));
14539566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
14541c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
145540e14135SMatthew G. Knepley   *diff = PetscSqrtReal(*diff);
1456cb1e1211SMatthew G Knepley   PetscFunctionReturn(0);
1457cb1e1211SMatthew G Knepley }
1458cb1e1211SMatthew G Knepley 
1459d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1460d71ae5a4SJacob Faibussowitsch {
14610f09c10fSMatthew G. Knepley   const PetscInt debug = ((DM_Plex *)dm->data)->printL2;
1462ca3d3a14SMatthew G. Knepley   DM             tdm;
1463083401c6SMatthew G. Knepley   DMLabel        depthLabel;
146473d901b8SMatthew G. Knepley   PetscSection   section;
1465ca3d3a14SMatthew G. Knepley   Vec            localX, tv;
146673d901b8SMatthew G. Knepley   PetscReal     *localDiff;
1467083401c6SMatthew G. Knepley   PetscInt       dim, depth, dE, Nf, f, Nds, s;
1468ca3d3a14SMatthew G. Knepley   PetscBool      transform;
146973d901b8SMatthew G. Knepley 
147073d901b8SMatthew G. Knepley   PetscFunctionBegin;
14719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
14739566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
14749566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
14759566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
14769566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
14779566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
14789566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
14799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
14809566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(depthLabel, &depth));
1481083401c6SMatthew G. Knepley 
14829566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
14839566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
14849566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
14859566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX));
14869566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
14879566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Nf, &localDiff));
1488083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1489083401c6SMatthew G. Knepley     PetscDS          ds;
1490083401c6SMatthew G. Knepley     DMLabel          label;
1491083401c6SMatthew G. Knepley     IS               fieldIS, pointIS;
1492083401c6SMatthew G. Knepley     const PetscInt  *fields, *points = NULL;
1493083401c6SMatthew G. Knepley     PetscQuadrature  quad;
1494083401c6SMatthew G. Knepley     const PetscReal *quadPoints, *quadWeights;
1495083401c6SMatthew G. Knepley     PetscFEGeom      fegeom;
1496083401c6SMatthew G. Knepley     PetscReal       *coords, *gcoords;
1497083401c6SMatthew G. Knepley     PetscScalar     *funcVal, *interpolant;
14985fedec97SMatthew G. Knepley     PetscBool        isCohesive;
1499083401c6SMatthew G. Knepley     PetscInt         qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf;
150073d901b8SMatthew G. Knepley 
15019566063dSJacob Faibussowitsch     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
15029566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(fieldIS, &fields));
15039566063dSJacob Faibussowitsch     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
15049566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(ds, &dsNf));
15059566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalComponents(ds, &totNc));
15069566063dSJacob Faibussowitsch     PetscCall(PetscDSGetQuadrature(ds, &quad));
15079566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
150863a3b9bcSJacob Faibussowitsch     PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc);
15099566063dSJacob Faibussowitsch     PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ));
1510083401c6SMatthew G. Knepley     if (!label) {
15119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1512083401c6SMatthew G. Knepley     } else {
15139566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
15149566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pointIS, &cEnd));
15159566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pointIS, &points));
1516083401c6SMatthew G. Knepley     }
151773d901b8SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1518083401c6SMatthew G. Knepley       const PetscInt  cell = points ? points[c] : c;
151973d901b8SMatthew G. Knepley       PetscScalar    *x    = NULL;
15205fedec97SMatthew G. Knepley       const PetscInt *cone;
15215fedec97SMatthew G. Knepley       PetscInt        qc = 0, fOff = 0, dep;
152273d901b8SMatthew G. Knepley 
15239566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, cell, &dep));
1524083401c6SMatthew G. Knepley       if (dep != depth - 1) continue;
15255fedec97SMatthew G. Knepley       if (isCohesive) {
15269566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cell, &cone));
15279566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
152896959cd1SMatthew G. Knepley       } else {
15299566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
153096959cd1SMatthew G. Knepley       }
15319566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x));
15325fedec97SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
153315496722SMatthew G. Knepley         PetscObject  obj;
153415496722SMatthew G. Knepley         PetscClassId id;
1535083401c6SMatthew G. Knepley         void *const  ctx = ctxs ? ctxs[fields[f]] : NULL;
153615496722SMatthew G. Knepley         PetscInt     Nb, Nc, q, fc;
153715496722SMatthew G. Knepley         PetscReal    elemDiff = 0.0;
15385fedec97SMatthew G. Knepley         PetscBool    cohesive;
153915496722SMatthew G. Knepley 
15409566063dSJacob Faibussowitsch         PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
15415fedec97SMatthew G. Knepley         if (isCohesive && !cohesive) continue;
15429566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
15439566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
15449371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
15459371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
15469371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
15479371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
15489371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
15499371c9d4SSatish Balay           Nb = 1;
15509371c9d4SSatish Balay         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
155173d901b8SMatthew G. Knepley         if (debug) {
155273d901b8SMatthew G. Knepley           char title[1024];
155363a3b9bcSJacob Faibussowitsch           PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f]));
15549566063dSJacob Faibussowitsch           PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff]));
155573d901b8SMatthew G. Knepley         }
15567318780aSToby Isaac         for (q = 0; q < Nq; ++q) {
15572a4e142eSMatthew G. Knepley           PetscFEGeom    qgeom;
1558d0609cedSBarry Smith           PetscErrorCode ierr;
15592a4e142eSMatthew G. Knepley 
15602a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
1561083401c6SMatthew G. Knepley           qgeom.J        = &fegeom.J[q * dE * dE];
1562083401c6SMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * dE * dE];
15632a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
156463a3b9bcSJacob Faibussowitsch           PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for cell %" PetscInt_FMT ", quadrature point %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q);
1565d3a7d86cSMatthew G. Knepley           if (transform) {
1566083401c6SMatthew G. Knepley             gcoords = &coords[dE * Nq];
15679566063dSJacob Faibussowitsch             PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx));
1568d3a7d86cSMatthew G. Knepley           } else {
1569083401c6SMatthew G. Knepley             gcoords = &coords[dE * q];
1570d3a7d86cSMatthew G. Knepley           }
15712df84da0SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.;
1572083401c6SMatthew G. Knepley           ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx);
1573e735a8a9SMatthew G. Knepley           if (ierr) {
15749566063dSJacob Faibussowitsch             PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x));
15759566063dSJacob Faibussowitsch             PetscCall(DMRestoreLocalVector(dm, &localX));
15769566063dSJacob Faibussowitsch             PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1577e735a8a9SMatthew G. Knepley           }
15789566063dSJacob Faibussowitsch           if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
157996959cd1SMatthew G. Knepley           /* Call once for each face, except for lagrange field */
15809566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant));
15819566063dSJacob Faibussowitsch           else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant));
158263a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
158315496722SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
1584beaa55a6SMatthew G. Knepley             const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
15859371c9d4SSatish Balay             if (debug)
15869371c9d4SSatish Balay               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    cell %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " 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.),
15879371c9d4SSatish Balay                                     (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q])));
15884bee2e38SMatthew G. Knepley             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
158973d901b8SMatthew G. Knepley           }
159073d901b8SMatthew G. Knepley         }
1591083401c6SMatthew G. Knepley         fOff += Nb;
15929c3cf19fSMatthew G. Knepley         qc += Nc;
1593083401c6SMatthew G. Knepley         localDiff[fields[f]] += elemDiff;
159463a3b9bcSJacob Faibussowitsch         if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  cell %" PetscInt_FMT " field %" PetscInt_FMT " cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]]));
159573d901b8SMatthew G. Knepley       }
15969566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x));
1597083401c6SMatthew G. Knepley     }
1598083401c6SMatthew G. Knepley     if (label) {
15999566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pointIS, &points));
16009566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1601083401c6SMatthew G. Knepley     }
16029566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(fieldIS, &fields));
16039566063dSJacob Faibussowitsch     PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
160473d901b8SMatthew G. Knepley   }
16059566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
16061c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
16079566063dSJacob Faibussowitsch   PetscCall(PetscFree(localDiff));
1608083401c6SMatthew G. Knepley   for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]);
160973d901b8SMatthew G. Knepley   PetscFunctionReturn(0);
161073d901b8SMatthew G. Knepley }
161173d901b8SMatthew G. Knepley 
1612e729f68cSMatthew G. Knepley /*@C
1613e729f68cSMatthew G. Knepley   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.
1614e729f68cSMatthew G. Knepley 
1615d083f849SBarry Smith   Collective on dm
1616c0f8e1fdSMatthew G. Knepley 
1617e729f68cSMatthew G. Knepley   Input Parameters:
1618*a1cb98faSBarry Smith + dm    - The `DM`
16190163fd50SMatthew G. Knepley . time  - The time
1620ca3eba1bSToby Isaac . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation
1621e729f68cSMatthew G. Knepley . ctxs  - Optional array of contexts to pass to each function, or NULL.
1622e729f68cSMatthew G. Knepley - X     - The coefficient vector u_h
1623e729f68cSMatthew G. Knepley 
1624e729f68cSMatthew G. Knepley   Output Parameter:
1625e729f68cSMatthew G. Knepley . D - A Vec which holds the difference ||u - u_h||_2 for each cell
1626e729f68cSMatthew G. Knepley 
1627e729f68cSMatthew G. Knepley   Level: developer
1628e729f68cSMatthew G. Knepley 
1629*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1630e729f68cSMatthew G. Knepley @*/
1631d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1632d71ae5a4SJacob Faibussowitsch {
1633e729f68cSMatthew G. Knepley   PetscSection     section;
1634e729f68cSMatthew G. Knepley   PetscQuadrature  quad;
1635e729f68cSMatthew G. Knepley   Vec              localX;
16364bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
1637e729f68cSMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
16384bee2e38SMatthew G. Knepley   PetscReal       *coords;
1639e729f68cSMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
1640485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset;
1641e729f68cSMatthew G. Knepley 
1642e729f68cSMatthew G. Knepley   PetscFunctionBegin;
16439566063dSJacob Faibussowitsch   PetscCall(VecSet(D, 0.0));
16449566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
16459566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
16469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
16479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
16489566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
16499566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX));
16509566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
16519566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
1652e729f68cSMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
1653e729f68cSMatthew G. Knepley     PetscObject  obj;
1654e729f68cSMatthew G. Knepley     PetscClassId id;
1655e729f68cSMatthew G. Knepley     PetscInt     Nc;
1656e729f68cSMatthew G. Knepley 
16579566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
16589566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
1659e729f68cSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
1660e729f68cSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
1661e729f68cSMatthew G. Knepley 
16629566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
16639566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
1664e729f68cSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
1665e729f68cSMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
1666e729f68cSMatthew G. Knepley 
16679566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
16689566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
166963a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1670e729f68cSMatthew G. Knepley     numComponents += Nc;
1671e729f68cSMatthew G. Knepley   }
16729566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
167363a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
16749566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
16759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1676e729f68cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1677e729f68cSMatthew G. Knepley     PetscScalar *x        = NULL;
16786f288a59SMatthew G. Knepley     PetscScalar  elemDiff = 0.0;
16799c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1680e729f68cSMatthew G. Knepley 
16819566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
16829566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x));
1683e729f68cSMatthew G. Knepley 
1684e729f68cSMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1685e729f68cSMatthew G. Knepley       PetscObject  obj;
1686e729f68cSMatthew G. Knepley       PetscClassId id;
1687e729f68cSMatthew G. Knepley       void *const  ctx = ctxs ? ctxs[field] : NULL;
1688e729f68cSMatthew G. Knepley       PetscInt     Nb, Nc, q, fc;
1689e729f68cSMatthew G. Knepley 
16909566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, &obj));
16919566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
16929371c9d4SSatish Balay       if (id == PETSCFE_CLASSID) {
16939371c9d4SSatish Balay         PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
16949371c9d4SSatish Balay         PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
16959371c9d4SSatish Balay       } else if (id == PETSCFV_CLASSID) {
16969371c9d4SSatish Balay         PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
16979371c9d4SSatish Balay         Nb = 1;
16989371c9d4SSatish Balay       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
169923f34ed2SToby Isaac       if (funcs[field]) {
17007318780aSToby Isaac         for (q = 0; q < Nq; ++q) {
17012a4e142eSMatthew G. Knepley           PetscFEGeom qgeom;
17022a4e142eSMatthew G. Knepley 
17032a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
17042a4e142eSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * coordDim * coordDim];
17052a4e142eSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
17062a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
170763a3b9bcSJacob Faibussowitsch           PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], c, q);
17089566063dSJacob Faibussowitsch           PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx));
1709c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument)
1710e735a8a9SMatthew G. Knepley           if (ierr) {
17119566063dSJacob Faibussowitsch             PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
17129566063dSJacob Faibussowitsch             PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
17139566063dSJacob Faibussowitsch             PetscCall(DMRestoreLocalVector(dm, &localX));
1714e735a8a9SMatthew G. Knepley           }
1715c3e24edfSBarry Smith #endif
17169566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant));
17179566063dSJacob Faibussowitsch           else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant));
171863a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1719e729f68cSMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
1720beaa55a6SMatthew G. Knepley             const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
17214bee2e38SMatthew G. Knepley             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1722e729f68cSMatthew G. Knepley           }
1723e729f68cSMatthew G. Knepley         }
172423f34ed2SToby Isaac       }
1725beaa55a6SMatthew G. Knepley       fieldOffset += Nb;
17269c3cf19fSMatthew G. Knepley       qc += Nc;
1727e729f68cSMatthew G. Knepley     }
17289566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
17299566063dSJacob Faibussowitsch     PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES));
1730e729f68cSMatthew G. Knepley   }
17319566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
17329566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
17339566063dSJacob Faibussowitsch   PetscCall(VecSqrtAbs(D));
1734e729f68cSMatthew G. Knepley   PetscFunctionReturn(0);
1735e729f68cSMatthew G. Knepley }
1736e729f68cSMatthew G. Knepley 
17375f0b18bfSMatthew G. Knepley /*@
17385f0b18bfSMatthew G. Knepley   DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1, and stores it in a Vec.
17395f0b18bfSMatthew G. Knepley 
17405f0b18bfSMatthew G. Knepley   Collective on dm
17415f0b18bfSMatthew G. Knepley 
17425f0b18bfSMatthew G. Knepley   Input Parameters:
1743*a1cb98faSBarry Smith + dm - The `DM`
17445f0b18bfSMatthew G. Knepley - locX  - The coefficient vector u_h
17455f0b18bfSMatthew G. Knepley 
17465f0b18bfSMatthew G. Knepley   Output Parameter:
1747*a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function
17485f0b18bfSMatthew G. Knepley 
17495f0b18bfSMatthew G. Knepley   Level: developer
17505f0b18bfSMatthew G. Knepley 
1751*a1cb98faSBarry Smith   Note:
1752*a1cb98faSBarry Smith   $ u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume
1753*a1cb98faSBarry Smith 
1754*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
17555f0b18bfSMatthew G. Knepley @*/
1756d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC)
1757d71ae5a4SJacob Faibussowitsch {
17585f0b18bfSMatthew G. Knepley   PetscInt         debug = ((DM_Plex *)dm->data)->printFEM;
17595f0b18bfSMatthew G. Knepley   DM               dmc;
17605f0b18bfSMatthew G. Knepley   PetscQuadrature  quad;
17615f0b18bfSMatthew G. Knepley   PetscScalar     *interpolant, *valsum;
17625f0b18bfSMatthew G. Knepley   PetscFEGeom      fegeom;
17635f0b18bfSMatthew G. Knepley   PetscReal       *coords;
17645f0b18bfSMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
17655f0b18bfSMatthew G. Knepley   PetscInt         dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v;
17665f0b18bfSMatthew G. Knepley 
17675f0b18bfSMatthew G. Knepley   PetscFunctionBegin;
17689566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite));
17699566063dSJacob Faibussowitsch   PetscCall(VecGetDM(locC, &dmc));
17709566063dSJacob Faibussowitsch   PetscCall(VecSet(locC, 0.0));
17719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
17735f0b18bfSMatthew G. Knepley   fegeom.dimEmbed = cdim;
17749566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
17755f0b18bfSMatthew G. Knepley   PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
17765f0b18bfSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
17775f0b18bfSMatthew G. Knepley     PetscObject  obj;
17785f0b18bfSMatthew G. Knepley     PetscClassId id;
17795f0b18bfSMatthew G. Knepley     PetscInt     fNc;
17805f0b18bfSMatthew G. Knepley 
17819566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, f, NULL, &obj));
17829566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
17835f0b18bfSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
17845f0b18bfSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
17855f0b18bfSMatthew G. Knepley 
17869566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
17879566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &fNc));
17885f0b18bfSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
17895f0b18bfSMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
17905f0b18bfSMatthew G. Knepley 
17919566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
17929566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &fNc));
179363a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
17945f0b18bfSMatthew G. Knepley     Nc += fNc;
17955f0b18bfSMatthew G. Knepley   }
17969566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
179763a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc);
17989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ));
17999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
18009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
18015f0b18bfSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
18025f0b18bfSMatthew G. Knepley     PetscScalar volsum = 0.0;
18035f0b18bfSMatthew G. Knepley     PetscInt   *star   = NULL;
18045f0b18bfSMatthew G. Knepley     PetscInt    starSize, st, fc;
18055f0b18bfSMatthew G. Knepley 
18069566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(valsum, Nc));
18079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
18085f0b18bfSMatthew G. Knepley     for (st = 0; st < starSize * 2; st += 2) {
18095f0b18bfSMatthew G. Knepley       const PetscInt cell = star[st];
18105f0b18bfSMatthew G. Knepley       PetscScalar   *val  = &valsum[Nc];
18115f0b18bfSMatthew G. Knepley       PetscScalar   *x    = NULL;
18125f0b18bfSMatthew G. Knepley       PetscReal      vol  = 0.0;
18135f0b18bfSMatthew G. Knepley       PetscInt       foff = 0;
18145f0b18bfSMatthew G. Knepley 
18155f0b18bfSMatthew G. Knepley       if ((cell < cStart) || (cell >= cEnd)) continue;
18169566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
18179566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x));
18185f0b18bfSMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
18195f0b18bfSMatthew G. Knepley         PetscObject  obj;
18205f0b18bfSMatthew G. Knepley         PetscClassId id;
18215f0b18bfSMatthew G. Knepley         PetscInt     Nb, fNc, q;
18225f0b18bfSMatthew G. Knepley 
18239566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(val, Nc));
18249566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, f, NULL, &obj));
18259566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
18269371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
18279371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc));
18289371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
18299371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
18309371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc));
18319371c9d4SSatish Balay           Nb = 1;
18329371c9d4SSatish Balay         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
18335f0b18bfSMatthew G. Knepley         for (q = 0; q < Nq; ++q) {
18345f0b18bfSMatthew G. Knepley           const PetscReal wt = quadWeights[q] * fegeom.detJ[q];
18355f0b18bfSMatthew G. Knepley           PetscFEGeom     qgeom;
18365f0b18bfSMatthew G. Knepley 
18375f0b18bfSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
18385f0b18bfSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * cdim * cdim];
18395f0b18bfSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * cdim * cdim];
18405f0b18bfSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
184163a3b9bcSJacob Faibussowitsch           PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q);
18429566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant));
184363a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
18445f0b18bfSMatthew G. Knepley           for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt;
18455f0b18bfSMatthew G. Knepley           vol += wt;
18465f0b18bfSMatthew G. Knepley         }
18475f0b18bfSMatthew G. Knepley         foff += Nb;
18485f0b18bfSMatthew G. Knepley       }
18499566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x));
18505f0b18bfSMatthew G. Knepley       for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc];
18515f0b18bfSMatthew G. Knepley       volsum += vol;
18525f0b18bfSMatthew G. Knepley       if (debug) {
18539566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell));
18545f0b18bfSMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
18559566063dSJacob Faibussowitsch           if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
18569566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc])));
18575f0b18bfSMatthew G. Knepley         }
18589566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
18595f0b18bfSMatthew G. Knepley       }
18605f0b18bfSMatthew G. Knepley     }
18615f0b18bfSMatthew G. Knepley     for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum;
18629566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
18639566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES));
18645f0b18bfSMatthew G. Knepley   }
18659566063dSJacob Faibussowitsch   PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
18665f0b18bfSMatthew G. Knepley   PetscFunctionReturn(0);
18675f0b18bfSMatthew G. Knepley }
18685f0b18bfSMatthew G. Knepley 
18695f0b18bfSMatthew G. Knepley /*@
18701555c271SMatthew G. Knepley   DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec.
18711555c271SMatthew G. Knepley 
1872d083f849SBarry Smith   Collective on dm
1873c0f8e1fdSMatthew G. Knepley 
18741555c271SMatthew G. Knepley   Input Parameters:
1875*a1cb98faSBarry Smith + dm - The `DM`
18765f0b18bfSMatthew G. Knepley - locX  - The coefficient vector u_h
18771555c271SMatthew G. Knepley 
18781555c271SMatthew G. Knepley   Output Parameter:
1879*a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient
18801555c271SMatthew G. Knepley 
18811555c271SMatthew G. Knepley   Level: developer
18821555c271SMatthew G. Knepley 
1883*a1cb98faSBarry Smith   Note:
1884*a1cb98faSBarry Smith   $\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
1885*a1cb98faSBarry Smith 
1886*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
18871555c271SMatthew G. Knepley @*/
1888d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
1889d71ae5a4SJacob Faibussowitsch {
1890db1066baSMatthew G. Knepley   DM_Plex         *mesh  = (DM_Plex *)dm->data;
1891db1066baSMatthew G. Knepley   PetscInt         debug = mesh->printFEM;
18921555c271SMatthew G. Knepley   DM               dmC;
18931555c271SMatthew G. Knepley   PetscQuadrature  quad;
18941555c271SMatthew G. Knepley   PetscScalar     *interpolant, *gradsum;
18954bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
18964bee2e38SMatthew G. Knepley   PetscReal       *coords;
18971555c271SMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
1898485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
18991555c271SMatthew G. Knepley 
19001555c271SMatthew G. Knepley   PetscFunctionBegin;
19019566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite));
19029566063dSJacob Faibussowitsch   PetscCall(VecGetDM(locC, &dmC));
19039566063dSJacob Faibussowitsch   PetscCall(VecSet(locC, 0.0));
19049566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
19059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
19064bee2e38SMatthew G. Knepley   fegeom.dimEmbed = coordDim;
19079566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
19085f80ce2aSJacob Faibussowitsch   PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
19091555c271SMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
19101555c271SMatthew G. Knepley     PetscObject  obj;
19111555c271SMatthew G. Knepley     PetscClassId id;
19121555c271SMatthew G. Knepley     PetscInt     Nc;
19131555c271SMatthew G. Knepley 
19149566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
19159566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
19161555c271SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
19171555c271SMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
19181555c271SMatthew G. Knepley 
19199566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
19209566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
19211555c271SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
19221555c271SMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
19231555c271SMatthew G. Knepley 
19249566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
19259566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
192663a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
19271555c271SMatthew G. Knepley     numComponents += Nc;
19281555c271SMatthew G. Knepley   }
19299566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
193063a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
19319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(coordDim * numComponents * 2, &gradsum, coordDim * numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
19329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
19339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
19341555c271SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
19351555c271SMatthew G. Knepley     PetscScalar volsum = 0.0;
19361555c271SMatthew G. Knepley     PetscInt   *star   = NULL;
19371555c271SMatthew G. Knepley     PetscInt    starSize, st, d, fc;
19381555c271SMatthew G. Knepley 
19399566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gradsum, coordDim * numComponents));
19409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
19411555c271SMatthew G. Knepley     for (st = 0; st < starSize * 2; st += 2) {
19421555c271SMatthew G. Knepley       const PetscInt cell = star[st];
19431555c271SMatthew G. Knepley       PetscScalar   *grad = &gradsum[coordDim * numComponents];
19441555c271SMatthew G. Knepley       PetscScalar   *x    = NULL;
19451555c271SMatthew G. Knepley       PetscReal      vol  = 0.0;
19461555c271SMatthew G. Knepley 
19471555c271SMatthew G. Knepley       if ((cell < cStart) || (cell >= cEnd)) continue;
19489566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
19499566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x));
19501555c271SMatthew G. Knepley       for (field = 0, fieldOffset = 0; field < numFields; ++field) {
19511555c271SMatthew G. Knepley         PetscObject  obj;
19521555c271SMatthew G. Knepley         PetscClassId id;
19531555c271SMatthew G. Knepley         PetscInt     Nb, Nc, q, qc = 0;
19541555c271SMatthew G. Knepley 
19559566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(grad, coordDim * numComponents));
19569566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, field, NULL, &obj));
19579566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
19589371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
19599371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
19609371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
19619371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
19629371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
19639371c9d4SSatish Balay           Nb = 1;
19649371c9d4SSatish Balay         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
19651555c271SMatthew G. Knepley         for (q = 0; q < Nq; ++q) {
19662a4e142eSMatthew G. Knepley           PetscFEGeom qgeom;
19672a4e142eSMatthew G. Knepley 
19682a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
19692a4e142eSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * coordDim * coordDim];
19702a4e142eSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
19712a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
197263a3b9bcSJacob Faibussowitsch           PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q);
19739566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant));
197463a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
19751555c271SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
197653d2db2dSJoe Wallwork             const PetscReal wt = quadWeights[q * qNc + qc];
19771555c271SMatthew G. Knepley 
19784bee2e38SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q];
19791555c271SMatthew G. Knepley           }
19804bee2e38SMatthew G. Knepley           vol += quadWeights[q * qNc] * fegeom.detJ[q];
19811555c271SMatthew G. Knepley         }
19821555c271SMatthew G. Knepley         fieldOffset += Nb;
19831555c271SMatthew G. Knepley         qc += Nc;
19841555c271SMatthew G. Knepley       }
19859566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x));
1986f8527842SMatthew G. Knepley       for (fc = 0; fc < numComponents; ++fc) {
1987ad540459SPierre Jolivet         for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d];
1988f8527842SMatthew G. Knepley       }
1989f8527842SMatthew G. Knepley       volsum += vol;
1990db1066baSMatthew G. Knepley       if (debug) {
19919566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell));
19921555c271SMatthew G. Knepley         for (fc = 0; fc < numComponents; ++fc) {
19931555c271SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) {
19949566063dSJacob Faibussowitsch             if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
19959566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d])));
19961555c271SMatthew G. Knepley           }
19971555c271SMatthew G. Knepley         }
19989566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
1999db1066baSMatthew G. Knepley       }
20001555c271SMatthew G. Knepley     }
20011555c271SMatthew G. Knepley     for (fc = 0; fc < numComponents; ++fc) {
20021555c271SMatthew G. Knepley       for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum;
20031555c271SMatthew G. Knepley     }
20049566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
20059566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES));
20061555c271SMatthew G. Knepley   }
20079566063dSJacob Faibussowitsch   PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
20081555c271SMatthew G. Knepley   PetscFunctionReturn(0);
20091555c271SMatthew G. Knepley }
20101555c271SMatthew G. Knepley 
2011d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
2012d71ae5a4SJacob Faibussowitsch {
2013338f77d5SMatthew G. Knepley   DM           dmAux = NULL;
201461aaff12SToby Isaac   PetscDS      prob, probAux = NULL;
201573d901b8SMatthew G. Knepley   PetscSection section, sectionAux;
2016338f77d5SMatthew G. Knepley   Vec          locX, locA;
2017c330f8ffSToby Isaac   PetscInt     dim, numCells = cEnd - cStart, c, f;
2018c330f8ffSToby Isaac   PetscBool    useFVM = PETSC_FALSE;
2019338f77d5SMatthew G. Knepley   /* DS */
2020338f77d5SMatthew G. Knepley   PetscInt           Nf, totDim, *uOff, *uOff_x, numConstants;
2021338f77d5SMatthew G. Knepley   PetscInt           NfAux, totDimAux, *aOff;
2022338f77d5SMatthew G. Knepley   PetscScalar       *u, *a;
2023338f77d5SMatthew G. Knepley   const PetscScalar *constants;
2024338f77d5SMatthew G. Knepley   /* Geometry */
2025c330f8ffSToby Isaac   PetscFEGeom       *cgeomFEM;
2026338f77d5SMatthew G. Knepley   DM                 dmGrad;
2027c330f8ffSToby Isaac   PetscQuadrature    affineQuad      = NULL;
2028338f77d5SMatthew G. Knepley   Vec                cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
2029b5a3613cSMatthew G. Knepley   PetscFVCellGeom   *cgeomFVM;
2030338f77d5SMatthew G. Knepley   const PetscScalar *lgrad;
2031b7260050SToby Isaac   PetscInt           maxDegree;
2032c330f8ffSToby Isaac   DMField            coordField;
2033c330f8ffSToby Isaac   IS                 cellIS;
203473d901b8SMatthew G. Knepley 
203573d901b8SMatthew G. Knepley   PetscFunctionBegin;
20369566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
20379566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
20389566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
20399566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
2040338f77d5SMatthew G. Knepley   /* Determine which discretizations we have */
2041b5a3613cSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
2042b5a3613cSMatthew G. Knepley     PetscObject  obj;
2043b5a3613cSMatthew G. Knepley     PetscClassId id;
2044b5a3613cSMatthew G. Knepley 
20459566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
20469566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
2047338f77d5SMatthew G. Knepley     if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
2048338f77d5SMatthew G. Knepley   }
2049338f77d5SMatthew G. Knepley   /* Get local solution with boundary values */
20509566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &locX));
20519566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
20529566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
20539566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
2054338f77d5SMatthew G. Knepley   /* Read DS information */
20559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
20569566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(prob, &uOff));
20579566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x));
20589566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS));
20599566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(prob, &numConstants, &constants));
2060338f77d5SMatthew G. Knepley   /* Read Auxiliary DS information */
20619566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
20629a2a23afSMatthew G. Knepley   if (locA) {
20639566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
20649566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
20659566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(probAux, &NfAux));
20669566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
20679566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
20689566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(probAux, &aOff));
2069338f77d5SMatthew G. Knepley   }
2070338f77d5SMatthew G. Knepley   /* Allocate data  arrays */
20719566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells * totDim, &u));
20729566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
2073338f77d5SMatthew G. Knepley   /* Read out geometry */
20749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
20759566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
2076b7260050SToby Isaac   if (maxDegree <= 1) {
20779566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
207848a46eb9SPierre Jolivet     if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM));
2079b5a3613cSMatthew G. Knepley   }
2080b5a3613cSMatthew G. Knepley   if (useFVM) {
2081338f77d5SMatthew G. Knepley     PetscFV   fv = NULL;
2082b5a3613cSMatthew G. Knepley     Vec       grad;
2083b5a3613cSMatthew G. Knepley     PetscInt  fStart, fEnd;
2084b5a3613cSMatthew G. Knepley     PetscBool compGrad;
2085b5a3613cSMatthew G. Knepley 
2086338f77d5SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
2087338f77d5SMatthew G. Knepley       PetscObject  obj;
2088338f77d5SMatthew G. Knepley       PetscClassId id;
2089338f77d5SMatthew G. Knepley 
20909566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
20919566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
20929371c9d4SSatish Balay       if (id == PETSCFV_CLASSID) {
20939371c9d4SSatish Balay         fv = (PetscFV)obj;
20949371c9d4SSatish Balay         break;
20959371c9d4SSatish Balay       }
2096338f77d5SMatthew G. Knepley     }
20979566063dSJacob Faibussowitsch     PetscCall(PetscFVGetComputeGradients(fv, &compGrad));
20989566063dSJacob Faibussowitsch     PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE));
20999566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM));
21009566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad));
21019566063dSJacob Faibussowitsch     PetscCall(PetscFVSetComputeGradients(fv, compGrad));
21029566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
2103b5a3613cSMatthew G. Knepley     /* Reconstruct and limit cell gradients */
21049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
21059566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmGrad, &grad));
21069566063dSJacob Faibussowitsch     PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad));
2107b5a3613cSMatthew G. Knepley     /* Communicate gradient values */
21089566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmGrad, &locGrad));
21099566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad));
21109566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad));
21119566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
2112b5a3613cSMatthew G. Knepley     /* Handle non-essential (e.g. outflow) boundary values */
21139566063dSJacob Faibussowitsch     PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad));
21149566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &lgrad));
2115b5a3613cSMatthew G. Knepley   }
2116338f77d5SMatthew G. Knepley   /* Read out data from inputs */
211773d901b8SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
211873d901b8SMatthew G. Knepley     PetscScalar *x = NULL;
211973d901b8SMatthew G. Knepley     PetscInt     i;
212073d901b8SMatthew G. Knepley 
21219566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x));
21220f2d7e86SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
21239566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x));
212473d901b8SMatthew G. Knepley     if (dmAux) {
21259566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x));
21260f2d7e86SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
21279566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x));
212873d901b8SMatthew G. Knepley     }
212973d901b8SMatthew G. Knepley   }
2130338f77d5SMatthew G. Knepley   /* Do integration for each field */
213173d901b8SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
2132c1f031eeSMatthew G. Knepley     PetscObject  obj;
2133c1f031eeSMatthew G. Knepley     PetscClassId id;
2134c1f031eeSMatthew G. Knepley     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
213573d901b8SMatthew G. Knepley 
21369566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
21379566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
2138c1f031eeSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
2139c1f031eeSMatthew G. Knepley       PetscFE         fe = (PetscFE)obj;
2140c1f031eeSMatthew G. Knepley       PetscQuadrature q;
2141c330f8ffSToby Isaac       PetscFEGeom    *chunkGeom = NULL;
2142c1f031eeSMatthew G. Knepley       PetscInt        Nq, Nb;
2143c1f031eeSMatthew G. Knepley 
21449566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
21459566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &q));
21469566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
21479566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
2148c1f031eeSMatthew G. Knepley       blockSize = Nb * Nq;
214973d901b8SMatthew G. Knepley       batchSize = numBlocks * blockSize;
21509566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
215173d901b8SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
215273d901b8SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
215373d901b8SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
215473d901b8SMatthew G. Knepley       offset    = numCells - Nr;
215548a46eb9SPierre Jolivet       if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM));
21569566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
21579566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral));
21589566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom));
21599566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf]));
21609566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom));
216148a46eb9SPierre Jolivet       if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM));
2162c1f031eeSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
2163c1f031eeSMatthew G. Knepley       PetscInt       foff;
2164420e96edSMatthew G. Knepley       PetscPointFunc obj_func;
2165b69edc29SMatthew G. Knepley       PetscScalar    lint;
2166c1f031eeSMatthew G. Knepley 
21679566063dSJacob Faibussowitsch       PetscCall(PetscDSGetObjective(prob, f, &obj_func));
21689566063dSJacob Faibussowitsch       PetscCall(PetscDSGetFieldOffset(prob, f, &foff));
2169c1f031eeSMatthew G. Knepley       if (obj_func) {
2170c1f031eeSMatthew G. Knepley         for (c = 0; c < numCells; ++c) {
2171b5a3613cSMatthew G. Knepley           PetscScalar *u_x;
2172b5a3613cSMatthew G. Knepley 
21739566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x));
2174338f77d5SMatthew G. Knepley           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);
2175338f77d5SMatthew G. Knepley           cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume;
217673d901b8SMatthew G. Knepley         }
2177c1f031eeSMatthew G. Knepley       }
217863a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
2179c1f031eeSMatthew G. Knepley   }
2180338f77d5SMatthew G. Knepley   /* Cleanup data arrays */
2181b5a3613cSMatthew G. Knepley   if (useFVM) {
21829566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(locGrad, &lgrad));
21839566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
21849566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
21859566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&faceGeometryFVM));
21869566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellGeometryFVM));
21879566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmGrad));
2188b5a3613cSMatthew G. Knepley   }
21899566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscFree(a));
21909566063dSJacob Faibussowitsch   PetscCall(PetscFree(u));
2191338f77d5SMatthew G. Knepley   /* Cleanup */
219248a46eb9SPierre Jolivet   if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM));
21939566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&affineQuad));
21949566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
21959566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &locX));
2196338f77d5SMatthew G. Knepley   PetscFunctionReturn(0);
2197338f77d5SMatthew G. Knepley }
2198338f77d5SMatthew G. Knepley 
2199338f77d5SMatthew G. Knepley /*@
2200338f77d5SMatthew G. Knepley   DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user
2201338f77d5SMatthew G. Knepley 
2202338f77d5SMatthew G. Knepley   Input Parameters:
2203338f77d5SMatthew G. Knepley + dm - The mesh
2204338f77d5SMatthew G. Knepley . X  - Global input vector
2205338f77d5SMatthew G. Knepley - user - The user context
2206338f77d5SMatthew G. Knepley 
2207338f77d5SMatthew G. Knepley   Output Parameter:
2208338f77d5SMatthew G. Knepley . integral - Integral for each field
2209338f77d5SMatthew G. Knepley 
2210338f77d5SMatthew G. Knepley   Level: developer
2211338f77d5SMatthew G. Knepley 
2212*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2213338f77d5SMatthew G. Knepley @*/
2214d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
2215d71ae5a4SJacob Faibussowitsch {
2216338f77d5SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dm->data;
2217b8feb594SMatthew G. Knepley   PetscScalar *cintegral, *lintegral;
2218412e9a14SMatthew G. Knepley   PetscInt     Nf, f, cellHeight, cStart, cEnd, cell;
2219338f77d5SMatthew G. Knepley 
2220338f77d5SMatthew G. Knepley   PetscFunctionBegin;
2221338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2222338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2223dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(integral, 3);
22249566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
22259566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
22269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
22279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2228338f77d5SMatthew G. Knepley   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
22299566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral));
22309566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user));
2231338f77d5SMatthew G. Knepley   /* Sum up values */
2232338f77d5SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
2233338f77d5SMatthew G. Knepley     const PetscInt c = cell - cStart;
2234338f77d5SMatthew G. Knepley 
22359566063dSJacob Faibussowitsch     if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]));
2236b8feb594SMatthew G. Knepley     for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f];
2237338f77d5SMatthew G. Knepley   }
22381c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
223973d901b8SMatthew G. Knepley   if (mesh->printFEM) {
22409566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:"));
22419566063dSJacob Faibussowitsch     for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f])));
22429566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n"));
224373d901b8SMatthew G. Knepley   }
22449566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lintegral, cintegral));
22459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
2246338f77d5SMatthew G. Knepley   PetscFunctionReturn(0);
2247338f77d5SMatthew G. Knepley }
2248338f77d5SMatthew G. Knepley 
2249338f77d5SMatthew G. Knepley /*@
2250338f77d5SMatthew G. Knepley   DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user
2251338f77d5SMatthew G. Knepley 
2252338f77d5SMatthew G. Knepley   Input Parameters:
2253338f77d5SMatthew G. Knepley + dm - The mesh
2254338f77d5SMatthew G. Knepley . X  - Global input vector
2255338f77d5SMatthew G. Knepley - user - The user context
2256338f77d5SMatthew G. Knepley 
2257338f77d5SMatthew G. Knepley   Output Parameter:
2258338f77d5SMatthew G. Knepley . integral - Cellwise integrals for each field
2259338f77d5SMatthew G. Knepley 
2260338f77d5SMatthew G. Knepley   Level: developer
2261338f77d5SMatthew G. Knepley 
2262*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2263338f77d5SMatthew G. Knepley @*/
2264d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
2265d71ae5a4SJacob Faibussowitsch {
2266338f77d5SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dm->data;
2267338f77d5SMatthew G. Knepley   DM           dmF;
2268338f77d5SMatthew G. Knepley   PetscSection sectionF;
2269338f77d5SMatthew G. Knepley   PetscScalar *cintegral, *af;
2270412e9a14SMatthew G. Knepley   PetscInt     Nf, f, cellHeight, cStart, cEnd, cell;
2271338f77d5SMatthew G. Knepley 
2272338f77d5SMatthew G. Knepley   PetscFunctionBegin;
2273338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2274338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2275338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
22769566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
22779566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
22789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
22799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2280338f77d5SMatthew G. Knepley   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
22819566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral));
22829566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user));
2283338f77d5SMatthew G. Knepley   /* Put values in F*/
22849566063dSJacob Faibussowitsch   PetscCall(VecGetDM(F, &dmF));
22859566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmF, &sectionF));
22869566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &af));
2287338f77d5SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
2288338f77d5SMatthew G. Knepley     const PetscInt c = cell - cStart;
2289338f77d5SMatthew G. Knepley     PetscInt       dof, off;
2290338f77d5SMatthew G. Knepley 
22919566063dSJacob Faibussowitsch     if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]));
22929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(sectionF, cell, &dof));
22939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(sectionF, cell, &off));
229463a3b9bcSJacob Faibussowitsch     PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf);
2295338f77d5SMatthew G. Knepley     for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f];
2296338f77d5SMatthew G. Knepley   }
22979566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &af));
22989566063dSJacob Faibussowitsch   PetscCall(PetscFree(cintegral));
22999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
230073d901b8SMatthew G. Knepley   PetscFunctionReturn(0);
230173d901b8SMatthew G. Knepley }
230273d901b8SMatthew G. Knepley 
2303d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *fintegral, void *user)
2304d71ae5a4SJacob Faibussowitsch {
23059b6f715bSMatthew G. Knepley   DM                 plex = NULL, plexA = NULL;
2306a6e0b375SMatthew G. Knepley   DMEnclosureType    encAux;
23079b6f715bSMatthew G. Knepley   PetscDS            prob, probAux       = NULL;
23089b6f715bSMatthew G. Knepley   PetscSection       section, sectionAux = NULL;
23099b6f715bSMatthew G. Knepley   Vec                locA = NULL;
23109b6f715bSMatthew G. Knepley   DMField            coordField;
23119b6f715bSMatthew G. Knepley   PetscInt           Nf, totDim, *uOff, *uOff_x;
23129b6f715bSMatthew G. Knepley   PetscInt           NfAux = 0, totDimAux = 0, *aOff = NULL;
23139b6f715bSMatthew G. Knepley   PetscScalar       *u, *a = NULL;
231464c72086SMatthew G. Knepley   const PetscScalar *constants;
23159b6f715bSMatthew G. Knepley   PetscInt           numConstants, f;
231664c72086SMatthew G. Knepley 
231764c72086SMatthew G. Knepley   PetscFunctionBegin;
23189566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
23199566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
23209566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
23219566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
23229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
232364c72086SMatthew G. Knepley   /* Determine which discretizations we have */
23249b6f715bSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
232564c72086SMatthew G. Knepley     PetscObject  obj;
232664c72086SMatthew G. Knepley     PetscClassId id;
232764c72086SMatthew G. Knepley 
23289566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
23299566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
233063a3b9bcSJacob Faibussowitsch     PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f);
233164c72086SMatthew G. Knepley   }
233264c72086SMatthew G. Knepley   /* Read DS information */
23339566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
23349566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(prob, &uOff));
23359566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x));
23369566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(prob, &numConstants, &constants));
233764c72086SMatthew G. Knepley   /* Read Auxiliary DS information */
23389566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
23399b6f715bSMatthew G. Knepley   if (locA) {
23409b6f715bSMatthew G. Knepley     DM dmAux;
23419b6f715bSMatthew G. Knepley 
23429566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
23439566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
23449566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
23459566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
23469566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(probAux, &NfAux));
23479566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
23489566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
23499566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(probAux, &aOff));
235064c72086SMatthew G. Knepley   }
23519b6f715bSMatthew G. Knepley   /* Integrate over points */
23529b6f715bSMatthew G. Knepley   {
23539b6f715bSMatthew G. Knepley     PetscFEGeom    *fgeom, *chunkGeom = NULL;
2354b7260050SToby Isaac     PetscInt        maxDegree;
23559b6f715bSMatthew G. Knepley     PetscQuadrature qGeom = NULL;
23569b6f715bSMatthew G. Knepley     const PetscInt *points;
23579b6f715bSMatthew G. Knepley     PetscInt        numFaces, face, Nq, field;
23589b6f715bSMatthew G. Knepley     PetscInt        numChunks, chunkSize, chunk, Nr, offset;
235964c72086SMatthew G. Knepley 
23609566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
23619566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
23629566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a));
23639566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
236464c72086SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
236564c72086SMatthew G. Knepley       PetscFE fe;
236664c72086SMatthew G. Knepley 
23679566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe));
23689566063dSJacob Faibussowitsch       if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
23699b6f715bSMatthew G. Knepley       if (!qGeom) {
23709566063dSJacob Faibussowitsch         PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
23719566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)qGeom));
23729b6f715bSMatthew G. Knepley       }
23739566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
23749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
23759b6f715bSMatthew G. Knepley       for (face = 0; face < numFaces; ++face) {
2376f15274beSMatthew Knepley         const PetscInt point = points[face], *support;
23779b6f715bSMatthew G. Knepley         PetscScalar   *x     = NULL;
2378f15274beSMatthew Knepley         PetscInt       i;
23799b6f715bSMatthew G. Knepley 
23809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, point, &support));
23819566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
23829b6f715bSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
23839566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
23849b6f715bSMatthew G. Knepley         if (locA) {
23859b6f715bSMatthew G. Knepley           PetscInt subp;
23869566063dSJacob Faibussowitsch           PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
23879566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
23889b6f715bSMatthew G. Knepley           for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i];
23899566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
23909b6f715bSMatthew G. Knepley         }
23919b6f715bSMatthew G. Knepley       }
23929b6f715bSMatthew G. Knepley       /* Get blocking */
23939b6f715bSMatthew G. Knepley       {
23949b6f715bSMatthew G. Knepley         PetscQuadrature q;
23959b6f715bSMatthew G. Knepley         PetscInt        numBatches, batchSize, numBlocks, blockSize;
23969b6f715bSMatthew G. Knepley         PetscInt        Nq, Nb;
23979b6f715bSMatthew G. Knepley 
23989566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
23999566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &q));
24009566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
24019566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
240264c72086SMatthew G. Knepley         blockSize = Nb * Nq;
240364c72086SMatthew G. Knepley         batchSize = numBlocks * blockSize;
24049b6f715bSMatthew G. Knepley         chunkSize = numBatches * batchSize;
24059566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
24069b6f715bSMatthew G. Knepley         numChunks = numFaces / chunkSize;
24079b6f715bSMatthew G. Knepley         Nr        = numFaces % chunkSize;
240864c72086SMatthew G. Knepley         offset    = numFaces - Nr;
240964c72086SMatthew G. Knepley       }
24109b6f715bSMatthew G. Knepley       /* Do integration for each field */
24119b6f715bSMatthew G. Knepley       for (chunk = 0; chunk < numChunks; ++chunk) {
24129566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom));
24139566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral));
24149566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom));
241564c72086SMatthew G. Knepley       }
24169566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
24179566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf]));
24189566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
241964c72086SMatthew G. Knepley       /* Cleanup data arrays */
24209566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
24219566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&qGeom));
24229566063dSJacob Faibussowitsch       PetscCall(PetscFree2(u, a));
24239566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pointIS, &points));
242464c72086SMatthew G. Knepley     }
242564c72086SMatthew G. Knepley   }
24269566063dSJacob Faibussowitsch   if (plex) PetscCall(DMDestroy(&plex));
24279566063dSJacob Faibussowitsch   if (plexA) PetscCall(DMDestroy(&plexA));
24289b6f715bSMatthew G. Knepley   PetscFunctionReturn(0);
24299b6f715bSMatthew G. Knepley }
24309b6f715bSMatthew G. Knepley 
24319b6f715bSMatthew G. Knepley /*@
24329b6f715bSMatthew G. Knepley   DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
24339b6f715bSMatthew G. Knepley 
24349b6f715bSMatthew G. Knepley   Input Parameters:
24359b6f715bSMatthew G. Knepley + dm      - The mesh
24369b6f715bSMatthew G. Knepley . X       - Global input vector
2437*a1cb98faSBarry Smith . label   - The boundary `DMLabel`
2438*a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values
2439*a1cb98faSBarry Smith . vals    - The label values to use, or NULL for all values
244067b8a455SSatish Balay . func    - The function to integrate along the boundary
24419b6f715bSMatthew G. Knepley - user    - The user context
24429b6f715bSMatthew G. Knepley 
24439b6f715bSMatthew G. Knepley   Output Parameter:
24449b6f715bSMatthew G. Knepley . integral - Integral for each field
24459b6f715bSMatthew G. Knepley 
24469b6f715bSMatthew G. Knepley   Level: developer
24479b6f715bSMatthew G. Knepley 
2448*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()`
24499b6f715bSMatthew G. Knepley @*/
2450d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *integral, void *user)
2451d71ae5a4SJacob Faibussowitsch {
24529b6f715bSMatthew G. Knepley   Vec          locX;
24539b6f715bSMatthew G. Knepley   PetscSection section;
24549b6f715bSMatthew G. Knepley   DMLabel      depthLabel;
24559b6f715bSMatthew G. Knepley   IS           facetIS;
24569b6f715bSMatthew G. Knepley   PetscInt     dim, Nf, f, v;
24579b6f715bSMatthew G. Knepley 
24589b6f715bSMatthew G. Knepley   PetscFunctionBegin;
24599b6f715bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
24609b6f715bSMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
24619b6f715bSMatthew G. Knepley   PetscValidPointer(label, 3);
2462dadcf809SJacob Faibussowitsch   if (vals) PetscValidIntPointer(vals, 5);
2463dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(integral, 7);
24649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
24659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
24669566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
24679566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
24689566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
24699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
24709b6f715bSMatthew G. Knepley   /* Get local solution with boundary values */
24719566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &locX));
24729566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
24739566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
24749566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
24759b6f715bSMatthew G. Knepley   /* Loop over label values */
24769566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(integral, Nf));
24779b6f715bSMatthew G. Knepley   for (v = 0; v < numVals; ++v) {
24789b6f715bSMatthew G. Knepley     IS           pointIS;
24799b6f715bSMatthew G. Knepley     PetscInt     numFaces, face;
24809b6f715bSMatthew G. Knepley     PetscScalar *fintegral;
24819b6f715bSMatthew G. Knepley 
24829566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS));
24839b6f715bSMatthew G. Knepley     if (!pointIS) continue; /* No points with that id on this process */
24849b6f715bSMatthew G. Knepley     {
24859b6f715bSMatthew G. Knepley       IS isectIS;
24869b6f715bSMatthew G. Knepley 
24879b6f715bSMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
24889566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
24899566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
24909b6f715bSMatthew G. Knepley       pointIS = isectIS;
24919b6f715bSMatthew G. Knepley     }
24929566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
24939566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numFaces * Nf, &fintegral));
24949566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user));
24959b6f715bSMatthew G. Knepley     /* Sum point contributions into integral */
24969371c9d4SSatish Balay     for (f = 0; f < Nf; ++f)
24979371c9d4SSatish Balay       for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f];
24989566063dSJacob Faibussowitsch     PetscCall(PetscFree(fintegral));
24999566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
25009b6f715bSMatthew G. Knepley   }
25019566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &locX));
25029566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
25039566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
250464c72086SMatthew G. Knepley   PetscFunctionReturn(0);
250564c72086SMatthew G. Knepley }
250664c72086SMatthew G. Knepley 
2507d69c5d34SMatthew G. Knepley /*@
2508*a1cb98faSBarry Smith   DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`.
2509d69c5d34SMatthew G. Knepley 
2510d69c5d34SMatthew G. Knepley   Input Parameters:
2511cf51de39SMatthew G. Knepley + dmc  - The coarse mesh
2512cf51de39SMatthew G. Knepley . dmf  - The fine mesh
2513cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology
2514d69c5d34SMatthew G. Knepley - user - The user context
2515d69c5d34SMatthew G. Knepley 
2516d69c5d34SMatthew G. Knepley   Output Parameter:
2517934789fcSMatthew G. Knepley . In  - The interpolation matrix
2518d69c5d34SMatthew G. Knepley 
2519d69c5d34SMatthew G. Knepley   Level: developer
2520d69c5d34SMatthew G. Knepley 
2521*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()`
2522d69c5d34SMatthew G. Knepley @*/
2523d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user)
2524d71ae5a4SJacob Faibussowitsch {
2525d69c5d34SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmc->data;
2526d69c5d34SMatthew G. Knepley   const char  *name = "Interpolator";
2527d69c5d34SMatthew G. Knepley   PetscFE     *feRef;
252897c42addSMatthew G. Knepley   PetscFV     *fvRef;
2529d69c5d34SMatthew G. Knepley   PetscSection fsection, fglobalSection;
2530d69c5d34SMatthew G. Knepley   PetscSection csection, cglobalSection;
2531d69c5d34SMatthew G. Knepley   PetscScalar *elemMat;
2532485ad865SMatthew G. Knepley   PetscInt     dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
25332ea9c922SToby Isaac   PetscInt     cTotDim = 0, rTotDim = 0;
2534d69c5d34SMatthew G. Knepley 
2535d69c5d34SMatthew G. Knepley   PetscFunctionBegin;
25369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
25379566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmf, &dim));
25389566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
25399566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &fglobalSection));
25409566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
25419566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
25429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &Nf));
25439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd));
25449566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef));
2545d69c5d34SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
25462ea9c922SToby Isaac     PetscObject  obj, objc;
25472ea9c922SToby Isaac     PetscClassId id, idc;
25482ea9c922SToby Isaac     PetscInt     rNb = 0, Nc = 0, cNb = 0;
2549d69c5d34SMatthew G. Knepley 
25509566063dSJacob Faibussowitsch     PetscCall(DMGetField(dmf, f, NULL, &obj));
25519566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
255297c42addSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
255397c42addSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
255497c42addSMatthew G. Knepley 
2555cf51de39SMatthew G. Knepley       if (isRefined) {
25569566063dSJacob Faibussowitsch         PetscCall(PetscFERefine(fe, &feRef[f]));
2557cf51de39SMatthew G. Knepley       } else {
25589566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)fe));
2559cf51de39SMatthew G. Knepley         feRef[f] = fe;
2560cf51de39SMatthew G. Knepley       }
25619566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feRef[f], &rNb));
25629566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
256397c42addSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
256497c42addSMatthew G. Knepley       PetscFV        fv = (PetscFV)obj;
256597c42addSMatthew G. Knepley       PetscDualSpace Q;
256697c42addSMatthew G. Knepley 
2567cf51de39SMatthew G. Knepley       if (isRefined) {
25689566063dSJacob Faibussowitsch         PetscCall(PetscFVRefine(fv, &fvRef[f]));
2569cf51de39SMatthew G. Knepley       } else {
25709566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)fv));
2571cf51de39SMatthew G. Knepley         fvRef[f] = fv;
2572cf51de39SMatthew G. Knepley       }
25739566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[f], &Q));
25749566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &rNb));
25759566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &Q));
25769566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
257797c42addSMatthew G. Knepley     }
25789566063dSJacob Faibussowitsch     PetscCall(DMGetField(dmc, f, NULL, &objc));
25799566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(objc, &idc));
25802ea9c922SToby Isaac     if (idc == PETSCFE_CLASSID) {
25812ea9c922SToby Isaac       PetscFE fe = (PetscFE)objc;
25822ea9c922SToby Isaac 
25839566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &cNb));
25842ea9c922SToby Isaac     } else if (id == PETSCFV_CLASSID) {
25852ea9c922SToby Isaac       PetscFV        fv = (PetscFV)obj;
25862ea9c922SToby Isaac       PetscDualSpace Q;
25872ea9c922SToby Isaac 
25889566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &Q));
25899566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &cNb));
2590d69c5d34SMatthew G. Knepley     }
25912ea9c922SToby Isaac     rTotDim += rNb;
25922ea9c922SToby Isaac     cTotDim += cNb;
25932ea9c922SToby Isaac   }
25949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat));
25959566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim));
2596d69c5d34SMatthew G. Knepley   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2597d69c5d34SMatthew G. Knepley     PetscDualSpace   Qref;
2598d69c5d34SMatthew G. Knepley     PetscQuadrature  f;
2599d69c5d34SMatthew G. Knepley     const PetscReal *qpoints, *qweights;
2600d69c5d34SMatthew G. Knepley     PetscReal       *points;
2601d69c5d34SMatthew G. Knepley     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;
2602d69c5d34SMatthew G. Knepley 
2603d69c5d34SMatthew G. Knepley     /* Compose points from all dual basis functionals */
260497c42addSMatthew G. Knepley     if (feRef[fieldI]) {
26059566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref));
26069566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc));
260797c42addSMatthew G. Knepley     } else {
26089566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref));
26099566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc));
261097c42addSMatthew G. Knepley     }
26119566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim));
2612d69c5d34SMatthew G. Knepley     for (i = 0; i < fpdim; ++i) {
26139566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
26149566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL));
2615d69c5d34SMatthew G. Knepley       npoints += Np;
2616d69c5d34SMatthew G. Knepley     }
26179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(npoints * dim, &points));
2618d69c5d34SMatthew G. Knepley     for (i = 0, k = 0; i < fpdim; ++i) {
26199566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
26209566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL));
26219371c9d4SSatish Balay       for (p = 0; p < Np; ++p, ++k)
26229371c9d4SSatish Balay         for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d];
2623d69c5d34SMatthew G. Knepley     }
2624d69c5d34SMatthew G. Knepley 
2625d69c5d34SMatthew G. Knepley     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
262697c42addSMatthew G. Knepley       PetscObject  obj;
262797c42addSMatthew G. Knepley       PetscClassId id;
26289c3cf19fSMatthew G. Knepley       PetscInt     NcJ = 0, cpdim = 0, j, qNc;
2629d69c5d34SMatthew G. Knepley 
26309566063dSJacob Faibussowitsch       PetscCall(DMGetField(dmc, fieldJ, NULL, &obj));
26319566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
263297c42addSMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
263397c42addSMatthew G. Knepley         PetscFE         fe = (PetscFE)obj;
2634ef0bb6c7SMatthew G. Knepley         PetscTabulation T  = NULL;
2635d69c5d34SMatthew G. Knepley 
2636d69c5d34SMatthew G. Knepley         /* Evaluate basis at points */
26379566063dSJacob Faibussowitsch         PetscCall(PetscFEGetNumComponents(fe, &NcJ));
26389566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &cpdim));
2639ffe73a53SMatthew G. Knepley         /* For now, fields only interpolate themselves */
2640ffe73a53SMatthew G. Knepley         if (fieldI == fieldJ) {
264163a3b9bcSJacob Faibussowitsch           PetscCheck(Nc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, Nc, NcJ);
26429566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T));
2643d69c5d34SMatthew G. Knepley           for (i = 0, k = 0; i < fpdim; ++i) {
26449566063dSJacob Faibussowitsch             PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
26459566063dSJacob Faibussowitsch             PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights));
264663a3b9bcSJacob Faibussowitsch             PetscCheck(qNc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, NcJ);
2647d69c5d34SMatthew G. Knepley             for (p = 0; p < Np; ++p, ++k) {
264836a6d9c0SMatthew G. Knepley               for (j = 0; j < cpdim; ++j) {
2649d172c84bSMatthew G. Knepley                 /*
2650d172c84bSMatthew G. Knepley                    cTotDim:            Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
2651d172c84bSMatthew G. Knepley                    offsetI, offsetJ:   Offsets into the larger element interpolation matrix for different fields
2652d172c84bSMatthew G. Knepley                    fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
2653d172c84bSMatthew G. Knepley                    qNC, Nc, Ncj, c:    Number of components in this field
2654d172c84bSMatthew G. Knepley                    Np, p:              Number of quad points in the fine grid functional i
2655d172c84bSMatthew G. Knepley                    k:                  i*Np + p, overall point number for the interpolation
2656d172c84bSMatthew G. Knepley                 */
2657ef0bb6c7SMatthew G. Knepley                 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];
265836a6d9c0SMatthew G. Knepley               }
2659d69c5d34SMatthew G. Knepley             }
2660d69c5d34SMatthew G. Knepley           }
26619566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&T));
2662ffe73a53SMatthew G. Knepley         }
266397c42addSMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
266497c42addSMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
266597c42addSMatthew G. Knepley 
266697c42addSMatthew G. Knepley         /* Evaluate constant function at points */
26679566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &NcJ));
266897c42addSMatthew G. Knepley         cpdim = 1;
266997c42addSMatthew G. Knepley         /* For now, fields only interpolate themselves */
267097c42addSMatthew G. Knepley         if (fieldI == fieldJ) {
267163a3b9bcSJacob Faibussowitsch           PetscCheck(Nc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, Nc, NcJ);
267297c42addSMatthew G. Knepley           for (i = 0, k = 0; i < fpdim; ++i) {
26739566063dSJacob Faibussowitsch             PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
26749566063dSJacob Faibussowitsch             PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights));
267563a3b9bcSJacob Faibussowitsch             PetscCheck(qNc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, NcJ);
267697c42addSMatthew G. Knepley             for (p = 0; p < Np; ++p, ++k) {
267797c42addSMatthew G. Knepley               for (j = 0; j < cpdim; ++j) {
2678458eb97cSMatthew G. Knepley                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c];
267997c42addSMatthew G. Knepley               }
268097c42addSMatthew G. Knepley             }
268197c42addSMatthew G. Knepley           }
268297c42addSMatthew G. Knepley         }
268397c42addSMatthew G. Knepley       }
2684d172c84bSMatthew G. Knepley       offsetJ += cpdim;
2685d69c5d34SMatthew G. Knepley     }
2686d172c84bSMatthew G. Knepley     offsetI += fpdim;
26879566063dSJacob Faibussowitsch     PetscCall(PetscFree(points));
2688d69c5d34SMatthew G. Knepley   }
26899566063dSJacob Faibussowitsch   if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat));
26907f5b169aSMatthew G. Knepley   /* Preallocate matrix */
26917f5b169aSMatthew G. Knepley   {
2692c094ef40SMatthew G. Knepley     Mat          preallocator;
2693c094ef40SMatthew G. Knepley     PetscScalar *vals;
2694c094ef40SMatthew G. Knepley     PetscInt    *cellCIndices, *cellFIndices;
2695c094ef40SMatthew G. Knepley     PetscInt     locRows, locCols, cell;
26967f5b169aSMatthew G. Knepley 
26979566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(In, &locRows, &locCols));
26989566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator));
26999566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
27009566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE));
27019566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
27029566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices));
27037f5b169aSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
2704cf51de39SMatthew G. Knepley       if (isRefined) {
27059566063dSJacob Faibussowitsch         PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices));
27069566063dSJacob Faibussowitsch         PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES));
2707cf51de39SMatthew G. Knepley       } else {
27089566063dSJacob Faibussowitsch         PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES));
2709cf51de39SMatthew G. Knepley       }
27107f5b169aSMatthew G. Knepley     }
27119566063dSJacob Faibussowitsch     PetscCall(PetscFree3(vals, cellCIndices, cellFIndices));
27129566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
27139566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
27149566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In));
27159566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
27167f5b169aSMatthew G. Knepley   }
27177f5b169aSMatthew G. Knepley   /* Fill matrix */
27189566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(In));
2719d69c5d34SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
2720cf51de39SMatthew G. Knepley     if (isRefined) {
27219566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES));
2722cf51de39SMatthew G. Knepley     } else {
27239566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES));
2724cf51de39SMatthew G. Knepley     }
2725d69c5d34SMatthew G. Knepley   }
27269566063dSJacob Faibussowitsch   for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f]));
27279566063dSJacob Faibussowitsch   PetscCall(PetscFree2(feRef, fvRef));
27289566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
27299566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY));
27309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY));
27319318fe57SMatthew G. Knepley   if (mesh->printFEM > 1) {
27329566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name));
27339566063dSJacob Faibussowitsch     PetscCall(MatChop(In, 1.0e-10));
27349566063dSJacob Faibussowitsch     PetscCall(MatView(In, NULL));
2735d69c5d34SMatthew G. Knepley   }
27369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
2737d69c5d34SMatthew G. Knepley   PetscFunctionReturn(0);
2738d69c5d34SMatthew G. Knepley }
27396c73c22cSMatthew G. Knepley 
2740d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2741d71ae5a4SJacob Faibussowitsch {
2742bd041c0cSMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness");
2743bd041c0cSMatthew G. Knepley }
2744bd041c0cSMatthew G. Knepley 
274568132eb9SMatthew G. Knepley /*@
2746*a1cb98faSBarry Smith   DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`.
274768132eb9SMatthew G. Knepley 
274868132eb9SMatthew G. Knepley   Input Parameters:
274968132eb9SMatthew G. Knepley + dmf  - The fine mesh
275068132eb9SMatthew G. Knepley . dmc  - The coarse mesh
275168132eb9SMatthew G. Knepley - user - The user context
275268132eb9SMatthew G. Knepley 
275368132eb9SMatthew G. Knepley   Output Parameter:
275468132eb9SMatthew G. Knepley . In  - The interpolation matrix
275568132eb9SMatthew G. Knepley 
275668132eb9SMatthew G. Knepley   Level: developer
275768132eb9SMatthew G. Knepley 
2758*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()`
275968132eb9SMatthew G. Knepley @*/
2760d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
2761d71ae5a4SJacob Faibussowitsch {
276264e98e1dSMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmf->data;
276364e98e1dSMatthew G. Knepley   const char  *name = "Interpolator";
27644ef9d792SMatthew G. Knepley   PetscDS      prob;
2765a0806964SMatthew G. Knepley   Mat          interp;
2766a0806964SMatthew G. Knepley   PetscSection fsection, globalFSection;
2767a0806964SMatthew G. Knepley   PetscSection csection, globalCSection;
2768a0806964SMatthew G. Knepley   PetscInt     locRows, locCols;
27694ef9d792SMatthew G. Knepley   PetscReal   *x, *v0, *J, *invJ, detJ;
27704ef9d792SMatthew G. Knepley   PetscReal   *v0c, *Jc, *invJc, detJc;
27714ef9d792SMatthew G. Knepley   PetscScalar *elemMat;
2772a0806964SMatthew G. Knepley   PetscInt     dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s;
27734ef9d792SMatthew G. Knepley 
27744ef9d792SMatthew G. Knepley   PetscFunctionBegin;
27759566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
27769566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmc, &dim));
27779566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
27789566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL));
27799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
27809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
27819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc));
27829566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
27839566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
27849566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
27859566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &globalCSection));
2786a0806964SMatthew G. Knepley   PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd));
27879566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
27889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(totDim, &elemMat));
27894ef9d792SMatthew G. Knepley 
2790a0806964SMatthew G. Knepley   PetscCall(MatGetLocalSize(In, &locRows, &locCols));
2791a0806964SMatthew G. Knepley   PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp));
2792a0806964SMatthew G. Knepley   PetscCall(MatSetType(interp, MATPREALLOCATOR));
2793a0806964SMatthew G. Knepley   PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE));
2794a0806964SMatthew G. Knepley   PetscCall(MatSetUp(interp));
2795a0806964SMatthew G. Knepley   for (s = 0; s < 2; ++s) {
27964ef9d792SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
27974ef9d792SMatthew G. Knepley       PetscObject      obj;
27984ef9d792SMatthew G. Knepley       PetscClassId     id;
2799c0d7054bSMatthew G. Knepley       PetscDualSpace   Q = NULL;
2800ef0bb6c7SMatthew G. Knepley       PetscTabulation  T = NULL;
28014ef9d792SMatthew G. Knepley       PetscQuadrature  f;
28024ef9d792SMatthew G. Knepley       const PetscReal *qpoints, *qweights;
2803d0f6233fSMatthew G. Knepley       PetscInt         Nc, qNc, Np, fpdim, off, i, d;
28044ef9d792SMatthew G. Knepley 
2805d0f6233fSMatthew G. Knepley       PetscCall(PetscDSGetFieldOffset(prob, field, &off));
28069566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, &obj));
28079566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
28084ef9d792SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
28094ef9d792SMatthew G. Knepley         PetscFE fe = (PetscFE)obj;
28104ef9d792SMatthew G. Knepley 
28119566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &Q));
28129566063dSJacob Faibussowitsch         PetscCall(PetscFEGetNumComponents(fe, &Nc));
2813a0806964SMatthew G. Knepley         if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T));
28144ef9d792SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
28154ef9d792SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
28164ef9d792SMatthew G. Knepley 
28179566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace(fv, &Q));
28184ef9d792SMatthew G. Knepley         Nc = 1;
281963a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
28209566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &fpdim));
28214ef9d792SMatthew G. Knepley       /* For each fine grid cell */
28224ef9d792SMatthew G. Knepley       for (cell = cStart; cell < cEnd; ++cell) {
28234ef9d792SMatthew G. Knepley         PetscInt *findices, *cindices;
28244ef9d792SMatthew G. Knepley         PetscInt  numFIndices, numCIndices;
28254ef9d792SMatthew G. Knepley 
28269566063dSJacob Faibussowitsch         PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
28279566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
2828d0f6233fSMatthew G. Knepley         PetscCheck(numFIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %" PetscInt_FMT " != %" PetscInt_FMT " dual basis vecs", numFIndices, totDim);
28294ef9d792SMatthew G. Knepley         for (i = 0; i < fpdim; ++i) {
28304ef9d792SMatthew G. Knepley           Vec                pointVec;
28314ef9d792SMatthew G. Knepley           PetscScalar       *pV;
283212111d7cSToby Isaac           PetscSF            coarseCellSF = NULL;
28333a93e3b7SToby Isaac           const PetscSFNode *coarseCells;
2834d0f6233fSMatthew G. Knepley           PetscInt           numCoarseCells, cpdim, row = findices[i + off], q, c, j;
28354ef9d792SMatthew G. Knepley 
28364ef9d792SMatthew G. Knepley           /* Get points from the dual basis functional quadrature */
28379566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(Q, i, &f));
28389566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights));
283963a3b9bcSJacob Faibussowitsch           PetscCheck(qNc == Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, Nc);
28409566063dSJacob Faibussowitsch           PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec));
28419566063dSJacob Faibussowitsch           PetscCall(VecSetBlockSize(pointVec, dim));
28429566063dSJacob Faibussowitsch           PetscCall(VecGetArray(pointVec, &pV));
28434ef9d792SMatthew G. Knepley           for (q = 0; q < Np; ++q) {
2844c330f8ffSToby Isaac             const PetscReal xi0[3] = {-1., -1., -1.};
2845c330f8ffSToby Isaac 
28464ef9d792SMatthew G. Knepley             /* Transform point to real space */
2847c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
28484ef9d792SMatthew G. Knepley             for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
28494ef9d792SMatthew G. Knepley           }
28509566063dSJacob Faibussowitsch           PetscCall(VecRestoreArray(pointVec, &pV));
28514ef9d792SMatthew G. Knepley           /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
28521555c271SMatthew G. Knepley           /* OPT: Read this out from preallocation information */
28539566063dSJacob Faibussowitsch           PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
28544ef9d792SMatthew G. Knepley           /* Update preallocation info */
28559566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
28565f80ce2aSJacob Faibussowitsch           PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
28579566063dSJacob Faibussowitsch           PetscCall(VecGetArray(pointVec, &pV));
28584ef9d792SMatthew G. Knepley           for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2859826eb36dSMatthew G. Knepley             PetscReal       pVReal[3];
2860c330f8ffSToby Isaac             const PetscReal xi0[3] = {-1., -1., -1.};
2861826eb36dSMatthew G. Knepley 
28629566063dSJacob Faibussowitsch             PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
2863a0806964SMatthew G. Knepley             if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim));
2864a0806964SMatthew G. Knepley             else cpdim = 1;
2865a0806964SMatthew G. Knepley 
2866a0806964SMatthew G. Knepley             if (s) {
28674ef9d792SMatthew G. Knepley               /* Transform points from real space to coarse reference space */
28689566063dSJacob Faibussowitsch               PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc));
2869e2d86523SMatthew G. Knepley               for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
2870c330f8ffSToby Isaac               CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
28714ef9d792SMatthew G. Knepley 
28724ef9d792SMatthew G. Knepley               if (id == PETSCFE_CLASSID) {
28734ef9d792SMatthew G. Knepley                 /* Evaluate coarse basis on contained point */
2874a0806964SMatthew G. Knepley                 PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T));
28759566063dSJacob Faibussowitsch                 PetscCall(PetscArrayzero(elemMat, cpdim));
28764ef9d792SMatthew G. Knepley                 /* Get elemMat entries by multiplying by weight */
28774ef9d792SMatthew G. Knepley                 for (j = 0; j < cpdim; ++j) {
2878ef0bb6c7SMatthew G. Knepley                   for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c];
28794ef9d792SMatthew G. Knepley                 }
28804ef9d792SMatthew G. Knepley               } else {
28814ef9d792SMatthew G. Knepley                 for (j = 0; j < cpdim; ++j) {
28829c3cf19fSMatthew G. Knepley                   for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c];
28834ef9d792SMatthew G. Knepley                 }
28844ef9d792SMatthew G. Knepley               }
28859566063dSJacob Faibussowitsch               if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
2886a0806964SMatthew G. Knepley             }
2887a0806964SMatthew G. Knepley             /* Update interpolator */
2888d0f6233fSMatthew G. Knepley             PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim);
2889a0806964SMatthew G. Knepley             PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES));
28909566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
28914ef9d792SMatthew G. Knepley           }
28929566063dSJacob Faibussowitsch           PetscCall(VecRestoreArray(pointVec, &pV));
28939566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseCellSF));
28949566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&pointVec));
28954ef9d792SMatthew G. Knepley         }
28969566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
28974ef9d792SMatthew G. Knepley       }
2898a0806964SMatthew G. Knepley       if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T));
2899a0806964SMatthew G. Knepley     }
2900a0806964SMatthew G. Knepley     if (!s) {
2901a0806964SMatthew G. Knepley       PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY));
2902a0806964SMatthew G. Knepley       PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY));
2903a0806964SMatthew G. Knepley       PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In));
2904a0806964SMatthew G. Knepley       PetscCall(MatDestroy(&interp));
2905a0806964SMatthew G. Knepley       interp = In;
2906a0806964SMatthew G. Knepley     }
29074ef9d792SMatthew G. Knepley   }
29089566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
29099566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0c, Jc, invJc));
29109566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
29119566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY));
29129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY));
29139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
29144ef9d792SMatthew G. Knepley   PetscFunctionReturn(0);
29154ef9d792SMatthew G. Knepley }
29164ef9d792SMatthew G. Knepley 
291746fa42a0SMatthew G. Knepley /*@
2918*a1cb98faSBarry Smith   DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`.
2919bd041c0cSMatthew G. Knepley 
2920bd041c0cSMatthew G. Knepley   Input Parameters:
2921bd041c0cSMatthew G. Knepley + dmf  - The fine mesh
2922bd041c0cSMatthew G. Knepley . dmc  - The coarse mesh
2923bd041c0cSMatthew G. Knepley - user - The user context
2924bd041c0cSMatthew G. Knepley 
2925bd041c0cSMatthew G. Knepley   Output Parameter:
2926bd041c0cSMatthew G. Knepley . mass  - The mass matrix
2927bd041c0cSMatthew G. Knepley 
2928bd041c0cSMatthew G. Knepley   Level: developer
2929bd041c0cSMatthew G. Knepley 
2930*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()`
2931bd041c0cSMatthew G. Knepley @*/
2932d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
2933d71ae5a4SJacob Faibussowitsch {
2934bd041c0cSMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmf->data;
2935bd041c0cSMatthew G. Knepley   const char  *name = "Mass Matrix";
2936bd041c0cSMatthew G. Knepley   PetscDS      prob;
2937bd041c0cSMatthew G. Knepley   PetscSection fsection, csection, globalFSection, globalCSection;
2938e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
2939bd041c0cSMatthew G. Knepley   PetscLayout  rLayout;
2940bd041c0cSMatthew G. Knepley   PetscInt    *dnz, *onz;
2941bd041c0cSMatthew G. Knepley   PetscInt     locRows, rStart, rEnd;
2942bd041c0cSMatthew G. Knepley   PetscReal   *x, *v0, *J, *invJ, detJ;
2943bd041c0cSMatthew G. Knepley   PetscReal   *v0c, *Jc, *invJc, detJc;
2944bd041c0cSMatthew G. Knepley   PetscScalar *elemMat;
2945bd041c0cSMatthew G. Knepley   PetscInt     dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
2946bd041c0cSMatthew G. Knepley 
2947bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
29489566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmc, &dim));
29499566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
29509566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL));
29519566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
29529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
29539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc));
29549566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
29559566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
29569566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
29579566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &globalCSection));
29589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
29599566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
29609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(totDim, &elemMat));
2961bd041c0cSMatthew G. Knepley 
29629566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, NULL));
29639566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout));
29649566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
29659566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
29669566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
29679566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd));
29689566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
29699566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
29709566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
2971bd041c0cSMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
2972bd041c0cSMatthew G. Knepley     PetscObject      obj;
2973bd041c0cSMatthew G. Knepley     PetscClassId     id;
2974bd041c0cSMatthew G. Knepley     PetscQuadrature  quad;
2975bd041c0cSMatthew G. Knepley     const PetscReal *qpoints;
2976bd041c0cSMatthew G. Knepley     PetscInt         Nq, Nc, i, d;
2977bd041c0cSMatthew G. Knepley 
29789566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
29799566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
29809566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad));
29819566063dSJacob Faibussowitsch     else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad));
29829566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL));
2983bd041c0cSMatthew G. Knepley     /* For each fine grid cell */
2984bd041c0cSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
2985bd041c0cSMatthew G. Knepley       Vec                pointVec;
2986bd041c0cSMatthew G. Knepley       PetscScalar       *pV;
2987bd041c0cSMatthew G. Knepley       PetscSF            coarseCellSF = NULL;
2988bd041c0cSMatthew G. Knepley       const PetscSFNode *coarseCells;
2989bd041c0cSMatthew G. Knepley       PetscInt           numCoarseCells, q, c;
2990bd041c0cSMatthew G. Knepley       PetscInt          *findices, *cindices;
2991bd041c0cSMatthew G. Knepley       PetscInt           numFIndices, numCIndices;
2992bd041c0cSMatthew G. Knepley 
29939566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
29949566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
2995bd041c0cSMatthew G. Knepley       /* Get points from the quadrature */
29969566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec));
29979566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(pointVec, dim));
29989566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
2999bd041c0cSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
3000c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3001c330f8ffSToby Isaac 
3002bd041c0cSMatthew G. Knepley         /* Transform point to real space */
3003c330f8ffSToby Isaac         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3004bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3005bd041c0cSMatthew G. Knepley       }
30069566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
3007bd041c0cSMatthew G. Knepley       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
30089566063dSJacob Faibussowitsch       PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
30099566063dSJacob Faibussowitsch       PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view"));
3010bd041c0cSMatthew G. Knepley       /* Update preallocation info */
30119566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
30125f80ce2aSJacob Faibussowitsch       PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
3013bd041c0cSMatthew G. Knepley       {
3014e8f14785SLisandro Dalcin         PetscHashIJKey key;
3015e8f14785SLisandro Dalcin         PetscBool      missing;
3016bd041c0cSMatthew G. Knepley 
3017bd041c0cSMatthew G. Knepley         for (i = 0; i < numFIndices; ++i) {
3018e8f14785SLisandro Dalcin           key.i = findices[i];
3019e8f14785SLisandro Dalcin           if (key.i >= 0) {
3020bd041c0cSMatthew G. Knepley             /* Get indices for coarse elements */
3021bd041c0cSMatthew G. Knepley             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
30229566063dSJacob Faibussowitsch               PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3023bd041c0cSMatthew G. Knepley               for (c = 0; c < numCIndices; ++c) {
3024e8f14785SLisandro Dalcin                 key.j = cindices[c];
3025e8f14785SLisandro Dalcin                 if (key.j < 0) continue;
30269566063dSJacob Faibussowitsch                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
3027bd041c0cSMatthew G. Knepley                 if (missing) {
3028e8f14785SLisandro Dalcin                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart];
3029e8f14785SLisandro Dalcin                   else ++onz[key.i - rStart];
3030bd041c0cSMatthew G. Knepley                 }
3031bd041c0cSMatthew G. Knepley               }
30329566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3033bd041c0cSMatthew G. Knepley             }
3034bd041c0cSMatthew G. Knepley           }
3035bd041c0cSMatthew G. Knepley         }
3036bd041c0cSMatthew G. Knepley       }
30379566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coarseCellSF));
30389566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&pointVec));
30399566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3040bd041c0cSMatthew G. Knepley     }
3041bd041c0cSMatthew G. Knepley   }
30429566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
30439566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
30449566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
30459566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
3046bd041c0cSMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3047bd041c0cSMatthew G. Knepley     PetscObject      obj;
3048bd041c0cSMatthew G. Knepley     PetscClassId     id;
3049ef0bb6c7SMatthew G. Knepley     PetscTabulation  T, Tfine;
3050bd041c0cSMatthew G. Knepley     PetscQuadrature  quad;
3051bd041c0cSMatthew G. Knepley     const PetscReal *qpoints, *qweights;
3052bd041c0cSMatthew G. Knepley     PetscInt         Nq, Nc, i, d;
3053bd041c0cSMatthew G. Knepley 
30549566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
30559566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
3056ef0bb6c7SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
30579566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad));
30589566063dSJacob Faibussowitsch       PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine));
30599566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T));
3060ef0bb6c7SMatthew G. Knepley     } else {
30619566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad));
3062ef0bb6c7SMatthew G. Knepley     }
30639566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights));
3064bd041c0cSMatthew G. Knepley     /* For each fine grid cell */
3065bd041c0cSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3066bd041c0cSMatthew G. Knepley       Vec                pointVec;
3067bd041c0cSMatthew G. Knepley       PetscScalar       *pV;
3068bd041c0cSMatthew G. Knepley       PetscSF            coarseCellSF = NULL;
3069bd041c0cSMatthew G. Knepley       const PetscSFNode *coarseCells;
3070bd041c0cSMatthew G. Knepley       PetscInt           numCoarseCells, cpdim, q, c, j;
3071bd041c0cSMatthew G. Knepley       PetscInt          *findices, *cindices;
3072bd041c0cSMatthew G. Knepley       PetscInt           numFIndices, numCIndices;
3073bd041c0cSMatthew G. Knepley 
30749566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
30759566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3076bd041c0cSMatthew G. Knepley       /* Get points from the quadrature */
30779566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec));
30789566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(pointVec, dim));
30799566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3080bd041c0cSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
3081c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3082c330f8ffSToby Isaac 
3083bd041c0cSMatthew G. Knepley         /* Transform point to real space */
3084c330f8ffSToby Isaac         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3085bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3086bd041c0cSMatthew G. Knepley       }
30879566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
3088bd041c0cSMatthew G. Knepley       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
30899566063dSJacob Faibussowitsch       PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
3090bd041c0cSMatthew G. Knepley       /* Update matrix */
30919566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
30925f80ce2aSJacob Faibussowitsch       PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
30939566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3094bd041c0cSMatthew G. Knepley       for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3095bd041c0cSMatthew G. Knepley         PetscReal       pVReal[3];
3096c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3097c330f8ffSToby Isaac 
30989566063dSJacob Faibussowitsch         PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3099bd041c0cSMatthew G. Knepley         /* Transform points from real space to coarse reference space */
31009566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc));
3101bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
3102c330f8ffSToby Isaac         CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
3103bd041c0cSMatthew G. Knepley 
3104bd041c0cSMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
3105bd041c0cSMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
3106bd041c0cSMatthew G. Knepley 
3107bd041c0cSMatthew G. Knepley           /* Evaluate coarse basis on contained point */
31089566063dSJacob Faibussowitsch           PetscCall(PetscFEGetDimension(fe, &cpdim));
31099566063dSJacob Faibussowitsch           PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T));
3110bd041c0cSMatthew G. Knepley           /* Get elemMat entries by multiplying by weight */
3111bd041c0cSMatthew G. Knepley           for (i = 0; i < numFIndices; ++i) {
31129566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(elemMat, cpdim));
3113bd041c0cSMatthew G. Knepley             for (j = 0; j < cpdim; ++j) {
3114ef0bb6c7SMatthew G. Knepley               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;
3115bd041c0cSMatthew G. Knepley             }
3116bd041c0cSMatthew G. Knepley             /* Update interpolator */
31179566063dSJacob Faibussowitsch             if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
311863a3b9bcSJacob Faibussowitsch             PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim);
31199566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES));
3120bd041c0cSMatthew G. Knepley           }
3121bd041c0cSMatthew G. Knepley         } else {
3122bd041c0cSMatthew G. Knepley           cpdim = 1;
3123bd041c0cSMatthew G. Knepley           for (i = 0; i < numFIndices; ++i) {
31249566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(elemMat, cpdim));
3125bd041c0cSMatthew G. Knepley             for (j = 0; j < cpdim; ++j) {
3126bd041c0cSMatthew G. Knepley               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ;
3127bd041c0cSMatthew G. Knepley             }
3128bd041c0cSMatthew G. Knepley             /* Update interpolator */
31299566063dSJacob Faibussowitsch             if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
313063a3b9bcSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "Nq: %" PetscInt_FMT " %" PetscInt_FMT " Nf: %" PetscInt_FMT " %" PetscInt_FMT " Nc: %" PetscInt_FMT " %" PetscInt_FMT "\n", ccell, Nq, i, numFIndices, j, numCIndices));
313163a3b9bcSJacob Faibussowitsch             PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim);
31329566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES));
3133bd041c0cSMatthew G. Knepley           }
3134bd041c0cSMatthew G. Knepley         }
31359566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3136bd041c0cSMatthew G. Knepley       }
31379566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
31389566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coarseCellSF));
31399566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&pointVec));
31409566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3141bd041c0cSMatthew G. Knepley     }
31429566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T));
3143bd041c0cSMatthew G. Knepley   }
31449566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
31459566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0c, Jc, invJc));
31469566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
31479566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
31489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
3149bd041c0cSMatthew G. Knepley   PetscFunctionReturn(0);
3150bd041c0cSMatthew G. Knepley }
3151bd041c0cSMatthew G. Knepley 
3152bd041c0cSMatthew G. Knepley /*@
315346fa42a0SMatthew G. Knepley   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
315446fa42a0SMatthew G. Knepley 
315546fa42a0SMatthew G. Knepley   Input Parameters:
315646fa42a0SMatthew G. Knepley + dmc  - The coarse mesh
315746fa42a0SMatthew G. Knepley - dmf  - The fine mesh
315846fa42a0SMatthew G. Knepley - user - The user context
315946fa42a0SMatthew G. Knepley 
316046fa42a0SMatthew G. Knepley   Output Parameter:
316146fa42a0SMatthew G. Knepley . sc   - The mapping
316246fa42a0SMatthew G. Knepley 
316346fa42a0SMatthew G. Knepley   Level: developer
316446fa42a0SMatthew G. Knepley 
3165*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()`
316646fa42a0SMatthew G. Knepley @*/
3167d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
3168d71ae5a4SJacob Faibussowitsch {
3169e9d4ef1bSMatthew G. Knepley   PetscDS      prob;
31707c927364SMatthew G. Knepley   PetscFE     *feRef;
317197c42addSMatthew G. Knepley   PetscFV     *fvRef;
31727c927364SMatthew G. Knepley   Vec          fv, cv;
31737c927364SMatthew G. Knepley   IS           fis, cis;
31747c927364SMatthew G. Knepley   PetscSection fsection, fglobalSection, csection, cglobalSection;
31757c927364SMatthew G. Knepley   PetscInt    *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3176485ad865SMatthew G. Knepley   PetscInt     cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
31776f3d3cbcSMatthew G. Knepley   PetscBool   *needAvg;
31787c927364SMatthew G. Knepley 
31797c927364SMatthew G. Knepley   PetscFunctionBegin;
31809566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0));
31819566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmf, &dim));
31829566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
31839566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &fglobalSection));
31849566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
31859566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
31869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &Nf));
31879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd));
31889566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
31899566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg));
31907c927364SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
319197c42addSMatthew G. Knepley     PetscObject  obj;
319297c42addSMatthew G. Knepley     PetscClassId id;
3193aa7890ccSMatthew G. Knepley     PetscInt     fNb = 0, Nc = 0;
31947c927364SMatthew G. Knepley 
31959566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
31969566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
319797c42addSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
319897c42addSMatthew G. Knepley       PetscFE    fe = (PetscFE)obj;
31996f3d3cbcSMatthew G. Knepley       PetscSpace sp;
32009b2fc754SMatthew G. Knepley       PetscInt   maxDegree;
320197c42addSMatthew G. Knepley 
32029566063dSJacob Faibussowitsch       PetscCall(PetscFERefine(fe, &feRef[f]));
32039566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feRef[f], &fNb));
32049566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
32059566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &sp));
32069566063dSJacob Faibussowitsch       PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree));
32079b2fc754SMatthew G. Knepley       if (!maxDegree) needAvg[f] = PETSC_TRUE;
320897c42addSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
320997c42addSMatthew G. Knepley       PetscFV        fv = (PetscFV)obj;
321097c42addSMatthew G. Knepley       PetscDualSpace Q;
321197c42addSMatthew G. Knepley 
32129566063dSJacob Faibussowitsch       PetscCall(PetscFVRefine(fv, &fvRef[f]));
32139566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[f], &Q));
32149566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &fNb));
32159566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
32166f3d3cbcSMatthew G. Knepley       needAvg[f] = PETSC_TRUE;
321797c42addSMatthew G. Knepley     }
3218d172c84bSMatthew G. Knepley     fTotDim += fNb;
32197c927364SMatthew G. Knepley   }
32209566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &cTotDim));
32219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cTotDim, &cmap));
32227c927364SMatthew G. Knepley   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
32237c927364SMatthew G. Knepley     PetscFE        feC;
322497c42addSMatthew G. Knepley     PetscFV        fvC;
32257c927364SMatthew G. Knepley     PetscDualSpace QF, QC;
3226d172c84bSMatthew G. Knepley     PetscInt       order = -1, NcF, NcC, fpdim, cpdim;
32277c927364SMatthew G. Knepley 
322897c42addSMatthew G. Knepley     if (feRef[field]) {
32299566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC));
32309566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feC, &NcC));
32319566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feRef[field], &NcF));
32329566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feRef[field], &QF));
32339566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetOrder(QF, &order));
32349566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QF, &fpdim));
32359566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feC, &QC));
32369566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QC, &cpdim));
323797c42addSMatthew G. Knepley     } else {
32389566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC));
32399566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvC, &NcC));
32409566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF));
32419566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[field], &QF));
32429566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QF, &fpdim));
32439566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvC, &QC));
32449566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QC, &cpdim));
324597c42addSMatthew G. Knepley     }
324663a3b9bcSJacob Faibussowitsch     PetscCheck(NcF == NcC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, NcF, NcC);
32477c927364SMatthew G. Knepley     for (c = 0; c < cpdim; ++c) {
32487c927364SMatthew G. Knepley       PetscQuadrature  cfunc;
3249d172c84bSMatthew G. Knepley       const PetscReal *cqpoints, *cqweights;
3250d172c84bSMatthew G. Knepley       PetscInt         NqcC, NpC;
325197c42addSMatthew G. Knepley       PetscBool        found = PETSC_FALSE;
32527c927364SMatthew G. Knepley 
32539566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc));
32549566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights));
325563a3b9bcSJacob Faibussowitsch       PetscCheck(NqcC == NcC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %" PetscInt_FMT " must match number of field components %" PetscInt_FMT, NqcC, NcC);
32561dca8a05SBarry Smith       PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
32577c927364SMatthew G. Knepley       for (f = 0; f < fpdim; ++f) {
32587c927364SMatthew G. Knepley         PetscQuadrature  ffunc;
3259d172c84bSMatthew G. Knepley         const PetscReal *fqpoints, *fqweights;
32607c927364SMatthew G. Knepley         PetscReal        sum = 0.0;
3261d172c84bSMatthew G. Knepley         PetscInt         NqcF, NpF;
32627c927364SMatthew G. Knepley 
32639566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc));
32649566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights));
326563a3b9bcSJacob Faibussowitsch         PetscCheck(NqcF == NcF, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %" PetscInt_FMT " must match number of field components %" PetscInt_FMT, NqcF, NcF);
32667c927364SMatthew G. Knepley         if (NpC != NpF) continue;
32677c927364SMatthew G. Knepley         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
32687c927364SMatthew G. Knepley         if (sum > 1.0e-9) continue;
3269d172c84bSMatthew G. Knepley         for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]);
3270d172c84bSMatthew G. Knepley         if (sum < 1.0e-9) continue;
3271d172c84bSMatthew G. Knepley         cmap[offsetC + c] = offsetF + f;
327297c42addSMatthew G. Knepley         found             = PETSC_TRUE;
32737c927364SMatthew G. Knepley         break;
32747c927364SMatthew G. Knepley       }
327597c42addSMatthew G. Knepley       if (!found) {
327697c42addSMatthew G. Knepley         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3277d172c84bSMatthew G. Knepley         if (fvRef[field] || (feRef[field] && order == 0)) {
3278d172c84bSMatthew G. Knepley           cmap[offsetC + c] = offsetF + 0;
327997c42addSMatthew G. Knepley         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
328097c42addSMatthew G. Knepley       }
32817c927364SMatthew G. Knepley     }
3282d172c84bSMatthew G. Knepley     offsetC += cpdim;
3283d172c84bSMatthew G. Knepley     offsetF += fpdim;
32847c927364SMatthew G. Knepley   }
32859371c9d4SSatish Balay   for (f = 0; f < Nf; ++f) {
32869371c9d4SSatish Balay     PetscCall(PetscFEDestroy(&feRef[f]));
32879371c9d4SSatish Balay     PetscCall(PetscFVDestroy(&fvRef[f]));
32889371c9d4SSatish Balay   }
32899566063dSJacob Faibussowitsch   PetscCall(PetscFree3(feRef, fvRef, needAvg));
32907c927364SMatthew G. Knepley 
32919566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmf, &fv));
32929566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmc, &cv));
32939566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(cv, &startC, &endC));
32949566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m));
32959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices));
32969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &cindices));
32979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &findices));
32987c927364SMatthew G. Knepley   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
32997c927364SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
33009566063dSJacob Faibussowitsch     PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices));
33017c927364SMatthew G. Knepley     for (d = 0; d < cTotDim; ++d) {
33020bd915a7SMatthew G. Knepley       if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
330363a3b9bcSJacob Faibussowitsch       PetscCheck(!(findices[cellCIndices[d] - startC] >= 0) || !(findices[cellCIndices[d] - startC] != cellFIndices[cmap[d]]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %" PetscInt_FMT " maps to both %" PetscInt_FMT " and %" PetscInt_FMT, cindices[cellCIndices[d] - startC], findices[cellCIndices[d] - startC], cellFIndices[cmap[d]]);
33047c927364SMatthew G. Knepley       cindices[cellCIndices[d] - startC] = cellCIndices[d];
33057c927364SMatthew G. Knepley       findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]];
33067c927364SMatthew G. Knepley     }
33077c927364SMatthew G. Knepley   }
33089566063dSJacob Faibussowitsch   PetscCall(PetscFree(cmap));
33099566063dSJacob Faibussowitsch   PetscCall(PetscFree2(cellCIndices, cellFIndices));
33107c927364SMatthew G. Knepley 
33119566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis));
33129566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis));
33139566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(cv, cis, fv, fis, sc));
33149566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
33159566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
33169566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmf, &fv));
33179566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmc, &cv));
33189566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0));
3319cb1e1211SMatthew G Knepley   PetscFunctionReturn(0);
3320cb1e1211SMatthew G Knepley }
3321a1cf66bbSMatthew G. Knepley 
33222f856554SMatthew G. Knepley /*@C
33232f856554SMatthew G. Knepley   DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
33242f856554SMatthew G. Knepley 
33252f856554SMatthew G. Knepley   Input Parameters:
3326*a1cb98faSBarry Smith + dm     - The `DM`
33272f856554SMatthew G. Knepley . cellIS - The cells to include
33282f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
33292f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL
33302f856554SMatthew G. Knepley - locA   - A local vector with auxiliary fields, or NULL
33312f856554SMatthew G. Knepley 
33322f856554SMatthew G. Knepley   Output Parameters:
33332f856554SMatthew G. Knepley + u   - The field coefficients
33342f856554SMatthew G. Knepley . u_t - The fields derivative coefficients
33352f856554SMatthew G. Knepley - a   - The auxiliary field coefficients
33362f856554SMatthew G. Knepley 
33372f856554SMatthew G. Knepley   Level: developer
33382f856554SMatthew G. Knepley 
3339*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
33402f856554SMatthew G. Knepley @*/
3341d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3342d71ae5a4SJacob Faibussowitsch {
33432f856554SMatthew G. Knepley   DM              plex, plexA = NULL;
3344a6e0b375SMatthew G. Knepley   DMEnclosureType encAux;
33452f856554SMatthew G. Knepley   PetscSection    section, sectionAux;
33462f856554SMatthew G. Knepley   PetscDS         prob;
33472f856554SMatthew G. Knepley   const PetscInt *cells;
33482f856554SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, totDim, totDimAux, c;
33492f856554SMatthew G. Knepley 
33502f856554SMatthew G. Knepley   PetscFunctionBegin;
33512f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3352064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
3353ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4);
3354ad540459SPierre Jolivet   if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5);
3355064a246eSJacob Faibussowitsch   PetscValidPointer(u, 6);
3356064a246eSJacob Faibussowitsch   PetscValidPointer(u_t, 7);
3357064a246eSJacob Faibussowitsch   PetscValidPointer(a, 8);
33589566063dSJacob Faibussowitsch   PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE));
33599566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
33609566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
33619566063dSJacob Faibussowitsch   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob));
33629566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
33632f856554SMatthew G. Knepley   if (locA) {
33642f856554SMatthew G. Knepley     DM      dmAux;
33652f856554SMatthew G. Knepley     PetscDS probAux;
33662f856554SMatthew G. Knepley 
33679566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
33689566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
33699566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE));
33709566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
33719566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
33729566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
33732f856554SMatthew G. Knepley   }
33742f856554SMatthew G. Knepley   numCells = cEnd - cStart;
33759566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u));
33769371c9d4SSatish Balay   if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t));
3377ad540459SPierre Jolivet   else *u_t = NULL;
33789371c9d4SSatish Balay   if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a));
3379ad540459SPierre Jolivet   else *a = NULL;
33802f856554SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
33812f856554SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
33822f856554SMatthew G. Knepley     const PetscInt cind = c - cStart;
33832f856554SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
33842f856554SMatthew G. Knepley     PetscInt       i;
33852f856554SMatthew G. Knepley 
33869566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x));
33872f856554SMatthew G. Knepley     for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i];
33889566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x));
33892f856554SMatthew G. Knepley     if (locX_t) {
33909566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t));
33912f856554SMatthew G. Knepley       for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i];
33929566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t));
33932f856554SMatthew G. Knepley     }
33942f856554SMatthew G. Knepley     if (locA) {
33952f856554SMatthew G. Knepley       PetscInt subcell;
33969566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell));
33979566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x));
33982f856554SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i];
33999566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x));
34002f856554SMatthew G. Knepley     }
34012f856554SMatthew G. Knepley   }
34029566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
34039566063dSJacob Faibussowitsch   if (locA) PetscCall(DMDestroy(&plexA));
34049566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
34052f856554SMatthew G. Knepley   PetscFunctionReturn(0);
34062f856554SMatthew G. Knepley }
34072f856554SMatthew G. Knepley 
34082f856554SMatthew G. Knepley /*@C
34092f856554SMatthew G. Knepley   DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
34102f856554SMatthew G. Knepley 
34112f856554SMatthew G. Knepley   Input Parameters:
3412*a1cb98faSBarry Smith + dm     - The `DM`
34132f856554SMatthew G. Knepley . cellIS - The cells to include
34142f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
34152f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL
34162f856554SMatthew G. Knepley - locA   - A local vector with auxiliary fields, or NULL
34172f856554SMatthew G. Knepley 
34182f856554SMatthew G. Knepley   Output Parameters:
34192f856554SMatthew G. Knepley + u   - The field coefficients
34202f856554SMatthew G. Knepley . u_t - The fields derivative coefficients
34212f856554SMatthew G. Knepley - a   - The auxiliary field coefficients
34222f856554SMatthew G. Knepley 
34232f856554SMatthew G. Knepley   Level: developer
34242f856554SMatthew G. Knepley 
3425*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
34262f856554SMatthew G. Knepley @*/
3427d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3428d71ae5a4SJacob Faibussowitsch {
34292f856554SMatthew G. Knepley   PetscFunctionBegin;
34309566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u));
34319566063dSJacob Faibussowitsch   if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t));
34329566063dSJacob Faibussowitsch   if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a));
34332f856554SMatthew G. Knepley   PetscFunctionReturn(0);
34342f856554SMatthew G. Knepley }
34352f856554SMatthew G. Knepley 
3436faff4f7fSMatthew G. Knepley /*
3437faff4f7fSMatthew G. Knepley   Get the auxiliary field vectors for the negative side (s = 0) and positive side (s = 1) of the interfaace
3438faff4f7fSMatthew G. Knepley */
3439d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridAuxFields(DM dm, DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[])
3440d71ae5a4SJacob Faibussowitsch {
344104c51a94SMatthew G. Knepley   DM              plexA[2];
3442148442b3SMatthew G. Knepley   DMEnclosureType encAux[2];
344304c51a94SMatthew G. Knepley   PetscSection    sectionAux[2];
34446528b96dSMatthew G. Knepley   const PetscInt *cells;
3445148442b3SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, c, s, totDimAux[2];
34466528b96dSMatthew G. Knepley 
34476528b96dSMatthew G. Knepley   PetscFunctionBegin;
3448148442b3SMatthew G. Knepley   PetscValidPointer(locA, 5);
344904c51a94SMatthew G. Knepley   if (!locA[0] || !locA[1]) PetscFunctionReturn(0);
3450148442b3SMatthew G. Knepley   PetscValidPointer(dmAux, 2);
3451148442b3SMatthew G. Knepley   PetscValidPointer(dsAux, 3);
3452148442b3SMatthew G. Knepley   PetscValidPointer(a, 6);
34539566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
34546528b96dSMatthew G. Knepley   numCells = cEnd - cStart;
3455148442b3SMatthew G. Knepley   for (s = 0; s < 2; ++s) {
3456148442b3SMatthew G. Knepley     PetscValidHeaderSpecific(dmAux[s], DM_CLASSID, 2);
3457148442b3SMatthew G. Knepley     PetscValidHeaderSpecific(dsAux[s], PETSCDS_CLASSID, 3);
3458148442b3SMatthew G. Knepley     PetscValidHeaderSpecific(locA[s], VEC_CLASSID, 5);
34599566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertPlex(dmAux[s], &plexA[s], PETSC_FALSE));
34609566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux[s], dm, &encAux[s]));
34619566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux[s], &sectionAux[s]));
34629566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[s], &totDimAux[s]));
34639566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dmAux[s], numCells * totDimAux[s], MPIU_SCALAR, &a[s]));
346404c51a94SMatthew G. Knepley   }
3465148442b3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
34666528b96dSMatthew G. Knepley     const PetscInt  cell = cells ? cells[c] : c;
34676528b96dSMatthew G. Knepley     const PetscInt  cind = c - cStart;
34686528b96dSMatthew G. Knepley     const PetscInt *cone, *ornt;
34696528b96dSMatthew G. Knepley 
34709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, cell, &cone));
34719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
3472148442b3SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
34735fedec97SMatthew G. Knepley       const PetscInt *support;
3474148442b3SMatthew G. Knepley       PetscScalar    *x = NULL, *al = a[s];
3475148442b3SMatthew G. Knepley       const PetscInt  tdA = totDimAux[s];
34765fedec97SMatthew G. Knepley       PetscInt        ssize, scell;
3477148442b3SMatthew G. Knepley       PetscInt        subface, Na, i;
34786528b96dSMatthew G. Knepley 
34799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, cone[s], &support));
34809566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupportSize(dm, cone[s], &ssize));
348163a3b9bcSJacob Faibussowitsch       PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[s], cell, ssize);
34825fedec97SMatthew G. Knepley       if (support[0] == cell) scell = support[1];
34835fedec97SMatthew G. Knepley       else if (support[1] == cell) scell = support[0];
348463a3b9bcSJacob Faibussowitsch       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[s], cell);
34855fedec97SMatthew G. Knepley 
34869566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(plexA[s], dm, encAux[s], scell, &subface));
34879566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x));
34886528b96dSMatthew G. Knepley       for (i = 0; i < Na; ++i) al[cind * tdA + i] = x[i];
34899566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x));
34906528b96dSMatthew G. Knepley     }
34916528b96dSMatthew G. Knepley   }
34929566063dSJacob Faibussowitsch   for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexA[s]));
34939566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
34946528b96dSMatthew G. Knepley   PetscFunctionReturn(0);
34956528b96dSMatthew G. Knepley }
34966528b96dSMatthew G. Knepley 
3497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[])
3498d71ae5a4SJacob Faibussowitsch {
34996528b96dSMatthew G. Knepley   PetscFunctionBegin;
350004c51a94SMatthew G. Knepley   if (!locA[0] || !locA[1]) PetscFunctionReturn(0);
35019566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0]));
35029566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1]));
35036528b96dSMatthew G. Knepley   PetscFunctionReturn(0);
35046528b96dSMatthew G. Knepley }
35056528b96dSMatthew G. Knepley 
35062f856554SMatthew G. Knepley /*@C
35072f856554SMatthew G. Knepley   DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
35082f856554SMatthew G. Knepley 
35092f856554SMatthew G. Knepley   Input Parameters:
3510*a1cb98faSBarry Smith + dm     - The `DM`
35112f856554SMatthew G. Knepley . fStart - The first face to include
35122f856554SMatthew G. Knepley . fEnd   - The first face to exclude
35132f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
35142f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL
35152f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
35162f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry
35172f856554SMatthew G. Knepley - locaGrad - A local vector with field gradients, or NULL
35182f856554SMatthew G. Knepley 
35192f856554SMatthew G. Knepley   Output Parameters:
35202f856554SMatthew G. Knepley + Nface - The number of faces with field values
35212f856554SMatthew G. Knepley . uL - The field values at the left side of the face
35222f856554SMatthew G. Knepley - uR - The field values at the right side of the face
35232f856554SMatthew G. Knepley 
35242f856554SMatthew G. Knepley   Level: developer
35252f856554SMatthew G. Knepley 
3526*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
35272f856554SMatthew G. Knepley @*/
3528d71ae5a4SJacob Faibussowitsch 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)
3529d71ae5a4SJacob Faibussowitsch {
35302f856554SMatthew G. Knepley   DM                 dmFace, dmCell, dmGrad = NULL;
35312f856554SMatthew G. Knepley   PetscSection       section;
35322f856554SMatthew G. Knepley   PetscDS            prob;
35332f856554SMatthew G. Knepley   DMLabel            ghostLabel;
35342f856554SMatthew G. Knepley   const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
35352f856554SMatthew G. Knepley   PetscBool         *isFE;
35362f856554SMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
35372f856554SMatthew G. Knepley 
35382f856554SMatthew G. Knepley   PetscFunctionBegin;
35392f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
35402f856554SMatthew G. Knepley   PetscValidHeaderSpecific(locX, VEC_CLASSID, 4);
3541ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);
35422f856554SMatthew G. Knepley   PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6);
35432f856554SMatthew G. Knepley   PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7);
3544ad540459SPierre Jolivet   if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);
3545064a246eSJacob Faibussowitsch   PetscValidPointer(uL, 10);
3546064a246eSJacob Faibussowitsch   PetscValidPointer(uR, 11);
35479566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
35489566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
35499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
35509566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
35519566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(prob, &Nc));
35529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(Nf, &isFE));
35532f856554SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
35542f856554SMatthew G. Knepley     PetscObject  obj;
35552f856554SMatthew G. Knepley     PetscClassId id;
35562f856554SMatthew G. Knepley 
35579566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
35589566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
35599371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
35609371c9d4SSatish Balay       isFE[f] = PETSC_TRUE;
35619371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
35629371c9d4SSatish Balay       isFE[f] = PETSC_FALSE;
35639371c9d4SSatish Balay     } else {
35649371c9d4SSatish Balay       isFE[f] = PETSC_FALSE;
35659371c9d4SSatish Balay     }
35662f856554SMatthew G. Knepley   }
35679566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
35689566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(locX, &x));
35699566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
35709566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
35719566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
35729566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
35732f856554SMatthew G. Knepley   if (locGrad) {
35749566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locGrad, &dmGrad));
35759566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &lgrad));
35762f856554SMatthew G. Knepley   }
35779566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL));
35789566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR));
35792f856554SMatthew G. Knepley   /* Right now just eat the extra work for FE (could make a cell loop) */
35802f856554SMatthew G. Knepley   for (face = fStart, iface = 0; face < fEnd; ++face) {
35812f856554SMatthew G. Knepley     const PetscInt  *cells;
35822f856554SMatthew G. Knepley     PetscFVFaceGeom *fg;
35832f856554SMatthew G. Knepley     PetscFVCellGeom *cgL, *cgR;
35842f856554SMatthew G. Knepley     PetscScalar     *xL, *xR, *gL, *gR;
35852f856554SMatthew G. Knepley     PetscScalar     *uLl = *uL, *uRl = *uR;
35862f856554SMatthew G. Knepley     PetscInt         ghost, nsupp, nchild;
35872f856554SMatthew G. Knepley 
35889566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
35899566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
35909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
35912f856554SMatthew G. Knepley     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
35929566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
35939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, face, &cells));
35949566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL));
35959566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR));
35962f856554SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
35972f856554SMatthew G. Knepley       PetscInt off;
35982f856554SMatthew G. Knepley 
35999566063dSJacob Faibussowitsch       PetscCall(PetscDSGetComponentOffset(prob, f, &off));
36002f856554SMatthew G. Knepley       if (isFE[f]) {
36012f856554SMatthew G. Knepley         const PetscInt *cone;
36022f856554SMatthew G. Knepley         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
36032f856554SMatthew G. Knepley 
36042f856554SMatthew G. Knepley         xL = xR = NULL;
36059566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldComponents(section, f, &comp));
36069566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL));
36079566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR));
36089566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cells[0], &cone));
36099566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL));
36109371c9d4SSatish Balay         for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL)
36119371c9d4SSatish Balay           if (cone[faceLocL] == face) break;
36129566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cells[1], &cone));
36139566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR));
36149371c9d4SSatish Balay         for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR)
36159371c9d4SSatish Balay           if (cone[faceLocR] == face) break;
36161dca8a05SBarry Smith         PetscCheck(faceLocL != coneSizeL || faceLocR != coneSizeR, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %" PetscInt_FMT " in cone of cell %" PetscInt_FMT " or cell %" PetscInt_FMT, face, cells[0], cells[1]);
36172f856554SMatthew G. Knepley         /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
36182f856554SMatthew G. Knepley         /* TODO: this is a hack that might not be right for nonconforming */
36192f856554SMatthew G. Knepley         if (faceLocL < coneSizeL) {
36209566063dSJacob Faibussowitsch           PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off]));
36219566063dSJacob Faibussowitsch           if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]));
36222f856554SMatthew G. Knepley           else {
36239371c9d4SSatish Balay             for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d];
36249371c9d4SSatish Balay           }
36259371c9d4SSatish Balay         } else {
36269566063dSJacob Faibussowitsch           PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]));
36279566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldComponents(section, f, &comp));
36282f856554SMatthew G. Knepley           for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d];
36292f856554SMatthew G. Knepley         }
36309566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL));
36319566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR));
36322f856554SMatthew G. Knepley       } else {
36332f856554SMatthew G. Knepley         PetscFV  fv;
36342f856554SMatthew G. Knepley         PetscInt numComp, c;
36352f856554SMatthew G. Knepley 
36369566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv));
36379566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numComp));
36389566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL));
36399566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR));
36402f856554SMatthew G. Knepley         if (dmGrad) {
36412f856554SMatthew G. Knepley           PetscReal dxL[3], dxR[3];
36422f856554SMatthew G. Knepley 
36439566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL));
36449566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR));
36452f856554SMatthew G. Knepley           DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
36462f856554SMatthew G. Knepley           DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
36472f856554SMatthew G. Knepley           for (c = 0; c < numComp; ++c) {
36482f856554SMatthew G. Knepley             uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL);
36492f856554SMatthew G. Knepley             uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR);
36502f856554SMatthew G. Knepley           }
36512f856554SMatthew G. Knepley         } else {
36522f856554SMatthew G. Knepley           for (c = 0; c < numComp; ++c) {
36532f856554SMatthew G. Knepley             uLl[iface * Nc + off + c] = xL[c];
36542f856554SMatthew G. Knepley             uRl[iface * Nc + off + c] = xR[c];
36552f856554SMatthew G. Knepley           }
36562f856554SMatthew G. Knepley         }
36572f856554SMatthew G. Knepley       }
36582f856554SMatthew G. Knepley     }
36592f856554SMatthew G. Knepley     ++iface;
36602f856554SMatthew G. Knepley   }
36612f856554SMatthew G. Knepley   *Nface = iface;
36629566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(locX, &x));
36639566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
36649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
366548a46eb9SPierre Jolivet   if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad));
36669566063dSJacob Faibussowitsch   PetscCall(PetscFree(isFE));
36672f856554SMatthew G. Knepley   PetscFunctionReturn(0);
36682f856554SMatthew G. Knepley }
36692f856554SMatthew G. Knepley 
36702f856554SMatthew G. Knepley /*@C
36712f856554SMatthew G. Knepley   DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
36722f856554SMatthew G. Knepley 
36732f856554SMatthew G. Knepley   Input Parameters:
3674*a1cb98faSBarry Smith + dm     - The `DM`
36752f856554SMatthew G. Knepley . fStart - The first face to include
36762f856554SMatthew G. Knepley . fEnd   - The first face to exclude
36772f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
36782f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL
36792f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
36802f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry
36812f856554SMatthew G. Knepley - locaGrad - A local vector with field gradients, or NULL
36822f856554SMatthew G. Knepley 
36832f856554SMatthew G. Knepley   Output Parameters:
36842f856554SMatthew G. Knepley + Nface - The number of faces with field values
36852f856554SMatthew G. Knepley . uL - The field values at the left side of the face
36862f856554SMatthew G. Knepley - uR - The field values at the right side of the face
36872f856554SMatthew G. Knepley 
36882f856554SMatthew G. Knepley   Level: developer
36892f856554SMatthew G. Knepley 
3690*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
36912f856554SMatthew G. Knepley @*/
3692d71ae5a4SJacob Faibussowitsch 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)
3693d71ae5a4SJacob Faibussowitsch {
36942f856554SMatthew G. Knepley   PetscFunctionBegin;
36959566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL));
36969566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR));
36972f856554SMatthew G. Knepley   PetscFunctionReturn(0);
36982f856554SMatthew G. Knepley }
36992f856554SMatthew G. Knepley 
37002f856554SMatthew G. Knepley /*@C
37012f856554SMatthew G. Knepley   DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
37022f856554SMatthew G. Knepley 
37032f856554SMatthew G. Knepley   Input Parameters:
3704*a1cb98faSBarry Smith + dm     - The `DM`
37052f856554SMatthew G. Knepley . fStart - The first face to include
37062f856554SMatthew G. Knepley . fEnd   - The first face to exclude
37072f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
37082f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry
37092f856554SMatthew G. Knepley 
37102f856554SMatthew G. Knepley   Output Parameters:
37112f856554SMatthew G. Knepley + Nface - The number of faces with field values
37122f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal
37132f856554SMatthew G. Knepley - vol   - The cell volume
37142f856554SMatthew G. Knepley 
37152f856554SMatthew G. Knepley   Level: developer
37162f856554SMatthew G. Knepley 
3717*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
37182f856554SMatthew G. Knepley @*/
3719d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3720d71ae5a4SJacob Faibussowitsch {
37212f856554SMatthew G. Knepley   DM                 dmFace, dmCell;
37222f856554SMatthew G. Knepley   DMLabel            ghostLabel;
37232f856554SMatthew G. Knepley   const PetscScalar *facegeom, *cellgeom;
37242f856554SMatthew G. Knepley   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
37252f856554SMatthew G. Knepley 
37262f856554SMatthew G. Knepley   PetscFunctionBegin;
37272f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
37282f856554SMatthew G. Knepley   PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4);
37292f856554SMatthew G. Knepley   PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5);
3730064a246eSJacob Faibussowitsch   PetscValidPointer(fgeom, 7);
3731064a246eSJacob Faibussowitsch   PetscValidPointer(vol, 8);
37329566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
37339566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
37349566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
37359566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
37369566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
37379566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
37389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFaces, fgeom));
37399566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol));
37402f856554SMatthew G. Knepley   for (face = fStart, iface = 0; face < fEnd; ++face) {
37412f856554SMatthew G. Knepley     const PetscInt  *cells;
37422f856554SMatthew G. Knepley     PetscFVFaceGeom *fg;
37432f856554SMatthew G. Knepley     PetscFVCellGeom *cgL, *cgR;
37442f856554SMatthew G. Knepley     PetscFVFaceGeom *fgeoml = *fgeom;
37452f856554SMatthew G. Knepley     PetscReal       *voll   = *vol;
37462f856554SMatthew G. Knepley     PetscInt         ghost, d, nchild, nsupp;
37472f856554SMatthew G. Knepley 
37489566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
37499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
37509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
37512f856554SMatthew G. Knepley     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
37529566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
37539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, face, &cells));
37549566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL));
37559566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR));
37562f856554SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
37572f856554SMatthew G. Knepley       fgeoml[iface].centroid[d] = fg->centroid[d];
37582f856554SMatthew G. Knepley       fgeoml[iface].normal[d]   = fg->normal[d];
37592f856554SMatthew G. Knepley     }
37602f856554SMatthew G. Knepley     voll[iface * 2 + 0] = cgL->volume;
37612f856554SMatthew G. Knepley     voll[iface * 2 + 1] = cgR->volume;
37622f856554SMatthew G. Knepley     ++iface;
37632f856554SMatthew G. Knepley   }
37642f856554SMatthew G. Knepley   *Nface = iface;
37659566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
37669566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
37672f856554SMatthew G. Knepley   PetscFunctionReturn(0);
37682f856554SMatthew G. Knepley }
37692f856554SMatthew G. Knepley 
37702f856554SMatthew G. Knepley /*@C
37712f856554SMatthew G. Knepley   DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
37722f856554SMatthew G. Knepley 
37732f856554SMatthew G. Knepley   Input Parameters:
3774*a1cb98faSBarry Smith + dm     - The `DM`
37752f856554SMatthew G. Knepley . fStart - The first face to include
37762f856554SMatthew G. Knepley . fEnd   - The first face to exclude
37772f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
37782f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry
37792f856554SMatthew G. Knepley 
37802f856554SMatthew G. Knepley   Output Parameters:
37812f856554SMatthew G. Knepley + Nface - The number of faces with field values
37822f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal
37832f856554SMatthew G. Knepley - vol   - The cell volume
37842f856554SMatthew G. Knepley 
37852f856554SMatthew G. Knepley   Level: developer
37862f856554SMatthew G. Knepley 
3787*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
37882f856554SMatthew G. Knepley @*/
3789d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3790d71ae5a4SJacob Faibussowitsch {
37912f856554SMatthew G. Knepley   PetscFunctionBegin;
37929566063dSJacob Faibussowitsch   PetscCall(PetscFree(*fgeom));
37939566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol));
37942f856554SMatthew G. Knepley   PetscFunctionReturn(0);
37952f856554SMatthew G. Knepley }
37962f856554SMatthew G. Knepley 
3797d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3798d71ae5a4SJacob Faibussowitsch {
3799a1cf66bbSMatthew G. Knepley   char           composeStr[33] = {0};
3800a1cf66bbSMatthew G. Knepley   PetscObjectId  id;
3801a1cf66bbSMatthew G. Knepley   PetscContainer container;
3802a1cf66bbSMatthew G. Knepley 
3803a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
38049566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetId((PetscObject)quad, &id));
380563a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id));
38069566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container));
3807a1cf66bbSMatthew G. Knepley   if (container) {
38089566063dSJacob Faibussowitsch     PetscCall(PetscContainerGetPointer(container, (void **)geom));
3809a1cf66bbSMatthew G. Knepley   } else {
38109566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom));
38119566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
38129566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(container, (void *)*geom));
38139566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom));
38149566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container));
38159566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&container));
3816a1cf66bbSMatthew G. Knepley   }
3817a1cf66bbSMatthew G. Knepley   PetscFunctionReturn(0);
3818a1cf66bbSMatthew G. Knepley }
3819a1cf66bbSMatthew G. Knepley 
3820d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
3821d71ae5a4SJacob Faibussowitsch {
3822a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
3823a1cf66bbSMatthew G. Knepley   *geom = NULL;
3824a1cf66bbSMatthew G. Knepley   PetscFunctionReturn(0);
3825a1cf66bbSMatthew G. Knepley }
3826a1cf66bbSMatthew G. Knepley 
3827d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
3828d71ae5a4SJacob Faibussowitsch {
382992d50984SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
383092d50984SMatthew G. Knepley   const char     *name       = "Residual";
383192d50984SMatthew G. Knepley   DM              dmAux      = NULL;
383292d50984SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
383392d50984SMatthew G. Knepley   PetscDS         prob       = NULL;
383492d50984SMatthew G. Knepley   PetscDS         probAux    = NULL;
383592d50984SMatthew G. Knepley   PetscBool       useFEM     = PETSC_FALSE;
383692d50984SMatthew G. Knepley   PetscBool       isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
383792d50984SMatthew G. Knepley   DMField         coordField = NULL;
3838c0006e53SPatrick Farrell   Vec             locA;
3839c0006e53SPatrick Farrell   PetscScalar    *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
384092d50984SMatthew G. Knepley   IS              chunkIS;
384192d50984SMatthew G. Knepley   const PetscInt *cells;
384292d50984SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
3843364207b6SKarl Rupp   PetscInt        Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
384492d50984SMatthew G. Knepley   PetscInt        maxDegree = PETSC_MAX_INT;
384506ad1575SMatthew G. Knepley   PetscFormKey    key;
384692d50984SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
384792d50984SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
384892d50984SMatthew G. Knepley 
384992d50984SMatthew G. Knepley   PetscFunctionBegin;
38509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
385192d50984SMatthew G. Knepley   /* FEM+FVM */
385292d50984SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
38539566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
38549566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
38559566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
38569566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
38579566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
385892d50984SMatthew G. Knepley   if (locA) {
38599566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
38609566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
38619566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
386292d50984SMatthew G. Knepley   }
386392d50984SMatthew G. Knepley   /* 2: Get geometric data */
386492d50984SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
386592d50984SMatthew G. Knepley     PetscObject  obj;
386692d50984SMatthew G. Knepley     PetscClassId id;
386792d50984SMatthew G. Knepley     PetscBool    fimp;
386892d50984SMatthew G. Knepley 
38699566063dSJacob Faibussowitsch     PetscCall(PetscDSGetImplicit(prob, f, &fimp));
387092d50984SMatthew G. Knepley     if (isImplicit != fimp) continue;
38719566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
38729566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
3873ad540459SPierre Jolivet     if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
38745f80ce2aSJacob Faibussowitsch     PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented");
387592d50984SMatthew G. Knepley   }
387692d50984SMatthew G. Knepley   if (useFEM) {
38779566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
38789566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
387992d50984SMatthew G. Knepley     if (maxDegree <= 1) {
38809566063dSJacob Faibussowitsch       PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
388148a46eb9SPierre Jolivet       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
388292d50984SMatthew G. Knepley     } else {
38839566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
388492d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
388592d50984SMatthew G. Knepley         PetscObject  obj;
388692d50984SMatthew G. Knepley         PetscClassId id;
388792d50984SMatthew G. Knepley         PetscBool    fimp;
388892d50984SMatthew G. Knepley 
38899566063dSJacob Faibussowitsch         PetscCall(PetscDSGetImplicit(prob, f, &fimp));
389092d50984SMatthew G. Knepley         if (isImplicit != fimp) continue;
38919566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, &obj));
38929566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
389392d50984SMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
389492d50984SMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
389592d50984SMatthew G. Knepley 
38969566063dSJacob Faibussowitsch           PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
38979566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)quads[f]));
38989566063dSJacob Faibussowitsch           PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
389992d50984SMatthew G. Knepley         }
390092d50984SMatthew G. Knepley       }
390192d50984SMatthew G. Knepley     }
390292d50984SMatthew G. Knepley   }
390392d50984SMatthew G. Knepley   /* Loop over chunks */
39049566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
39059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
39069566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS));
390792d50984SMatthew G. Knepley   numCells      = cEnd - cStart;
390892d50984SMatthew G. Knepley   numChunks     = 1;
390992d50984SMatthew G. Knepley   cellChunkSize = numCells / numChunks;
391092d50984SMatthew G. Knepley   numChunks     = PetscMin(1, numCells);
39116528b96dSMatthew G. Knepley   key.label     = NULL;
39126528b96dSMatthew G. Knepley   key.value     = 0;
391306ad1575SMatthew G. Knepley   key.part      = 0;
391492d50984SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
3915c0006e53SPatrick Farrell     PetscScalar     *elemVec, *fluxL = NULL, *fluxR = NULL;
3916c0006e53SPatrick Farrell     PetscReal       *vol   = NULL;
3917c0006e53SPatrick Farrell     PetscFVFaceGeom *fgeom = NULL;
391892d50984SMatthew G. Knepley     PetscInt         cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
3919c0006e53SPatrick Farrell     PetscInt         numFaces = 0;
392092d50984SMatthew G. Knepley 
392192d50984SMatthew G. Knepley     /* Extract field coefficients */
392292d50984SMatthew G. Knepley     if (useFEM) {
39239566063dSJacob Faibussowitsch       PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells));
39249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
39259566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
39269566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemVec, numCells * totDim));
392792d50984SMatthew G. Knepley     }
392892d50984SMatthew G. Knepley     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
392992d50984SMatthew G. Knepley     /* Loop over fields */
393092d50984SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
393192d50984SMatthew G. Knepley       PetscObject  obj;
393292d50984SMatthew G. Knepley       PetscClassId id;
393392d50984SMatthew G. Knepley       PetscBool    fimp;
393492d50984SMatthew G. Knepley       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
393592d50984SMatthew G. Knepley 
39366528b96dSMatthew G. Knepley       key.field = f;
39379566063dSJacob Faibussowitsch       PetscCall(PetscDSGetImplicit(prob, f, &fimp));
393892d50984SMatthew G. Knepley       if (isImplicit != fimp) continue;
39399566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
39409566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
394192d50984SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
394292d50984SMatthew G. Knepley         PetscFE         fe        = (PetscFE)obj;
394392d50984SMatthew G. Knepley         PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
394492d50984SMatthew G. Knepley         PetscFEGeom    *chunkGeom = NULL;
394592d50984SMatthew G. Knepley         PetscQuadrature quad      = affineQuad ? affineQuad : quads[f];
394692d50984SMatthew G. Knepley         PetscInt        Nq, Nb;
394792d50984SMatthew G. Knepley 
39489566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
39499566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
39509566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
395192d50984SMatthew G. Knepley         blockSize = Nb;
395292d50984SMatthew G. Knepley         batchSize = numBlocks * blockSize;
39539566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
395492d50984SMatthew G. Knepley         numChunks = numCells / (numBatches * batchSize);
395592d50984SMatthew G. Knepley         Ne        = numChunks * numBatches * batchSize;
395692d50984SMatthew G. Knepley         Nr        = numCells % (numBatches * batchSize);
395792d50984SMatthew G. Knepley         offset    = numCells - Nr;
395892d50984SMatthew G. Knepley         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
395992d50984SMatthew G. Knepley         /*   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) */
39609566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
39619566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec));
39629566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom));
39639566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim]));
39649566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom));
396592d50984SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
396692d50984SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
396792d50984SMatthew G. Knepley 
396892d50984SMatthew G. Knepley         Ne = numFaces;
396992d50984SMatthew G. Knepley         /* Riemann solve over faces (need fields at face centroids) */
397092d50984SMatthew G. Knepley         /*   We need to evaluate FE fields at those coordinates */
39719566063dSJacob Faibussowitsch         PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR));
397263a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
397392d50984SMatthew G. Knepley     }
397492d50984SMatthew G. Knepley     /* Loop over domain */
397592d50984SMatthew G. Knepley     if (useFEM) {
397692d50984SMatthew G. Knepley       /* Add elemVec to locX */
397792d50984SMatthew G. Knepley       for (c = cS; c < cE; ++c) {
397892d50984SMatthew G. Knepley         const PetscInt cell = cells ? cells[c] : c;
397992d50984SMatthew G. Knepley         const PetscInt cind = c - cStart;
398092d50984SMatthew G. Knepley 
39819566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
398292d50984SMatthew G. Knepley         if (ghostLabel) {
398392d50984SMatthew G. Knepley           PetscInt ghostVal;
398492d50984SMatthew G. Knepley 
39859566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
398692d50984SMatthew G. Knepley           if (ghostVal > 0) continue;
398792d50984SMatthew G. Knepley         }
39889566063dSJacob Faibussowitsch         PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
398992d50984SMatthew G. Knepley       }
399092d50984SMatthew G. Knepley     }
399192d50984SMatthew G. Knepley     /* Handle time derivative */
399292d50984SMatthew G. Knepley     if (locX_t) {
399392d50984SMatthew G. Knepley       PetscScalar *x_t, *fa;
399492d50984SMatthew G. Knepley 
39959566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
39969566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locX_t, &x_t));
399792d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
399892d50984SMatthew G. Knepley         PetscFV      fv;
399992d50984SMatthew G. Knepley         PetscObject  obj;
400092d50984SMatthew G. Knepley         PetscClassId id;
400192d50984SMatthew G. Knepley         PetscInt     pdim, d;
400292d50984SMatthew G. Knepley 
40039566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, &obj));
40049566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
400592d50984SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
400692d50984SMatthew G. Knepley         fv = (PetscFV)obj;
40079566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
400892d50984SMatthew G. Knepley         for (c = cS; c < cE; ++c) {
400992d50984SMatthew G. Knepley           const PetscInt cell = cells ? cells[c] : c;
401092d50984SMatthew G. Knepley           PetscScalar   *u_t, *r;
401192d50984SMatthew G. Knepley 
401292d50984SMatthew G. Knepley           if (ghostLabel) {
401392d50984SMatthew G. Knepley             PetscInt ghostVal;
401492d50984SMatthew G. Knepley 
40159566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
401692d50984SMatthew G. Knepley             if (ghostVal > 0) continue;
401792d50984SMatthew G. Knepley           }
40189566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t));
40199566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r));
402092d50984SMatthew G. Knepley           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
402192d50984SMatthew G. Knepley         }
402292d50984SMatthew G. Knepley       }
40239566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locX_t, &x_t));
40249566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
402592d50984SMatthew G. Knepley     }
402692d50984SMatthew G. Knepley     if (useFEM) {
40279566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
40289566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
402992d50984SMatthew G. Knepley     }
403092d50984SMatthew G. Knepley   }
40319566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISDestroy(&chunkIS));
40329566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
403392d50984SMatthew G. Knepley   /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
403492d50984SMatthew G. Knepley   if (useFEM) {
403592d50984SMatthew G. Knepley     if (maxDegree <= 1) {
40369566063dSJacob Faibussowitsch       PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
40379566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&affineQuad));
403892d50984SMatthew G. Knepley     } else {
403992d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
40409566063dSJacob Faibussowitsch         PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
40419566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureDestroy(&quads[f]));
404292d50984SMatthew G. Knepley       }
40439566063dSJacob Faibussowitsch       PetscCall(PetscFree2(quads, geoms));
404492d50984SMatthew G. Knepley     }
404592d50984SMatthew G. Knepley   }
40469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
404792d50984SMatthew G. Knepley   PetscFunctionReturn(0);
404892d50984SMatthew G. Knepley }
404992d50984SMatthew G. Knepley 
4050a1cf66bbSMatthew G. Knepley /*
4051a1cf66bbSMatthew G. Knepley   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
4052a1cf66bbSMatthew G. Knepley 
4053a1cf66bbSMatthew G. Knepley   X   - The local solution vector
4054a5b23f4aSJose E. Roman   X_t - The local solution time derivative vector, or NULL
4055a1cf66bbSMatthew G. Knepley */
4056d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx)
4057d71ae5a4SJacob Faibussowitsch {
4058a1cf66bbSMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
4059a1cf66bbSMatthew G. Knepley   const char     *name = "Jacobian", *nameP = "JacobianPre";
4060a1cf66bbSMatthew G. Knepley   DM              dmAux = NULL;
4061a1cf66bbSMatthew G. Knepley   PetscDS         prob, probAux = NULL;
4062a1cf66bbSMatthew G. Knepley   PetscSection    sectionAux = NULL;
4063a1cf66bbSMatthew G. Knepley   Vec             A;
4064a1cf66bbSMatthew G. Knepley   DMField         coordField;
4065a1cf66bbSMatthew G. Knepley   PetscFEGeom    *cgeomFEM;
4066a1cf66bbSMatthew G. Knepley   PetscQuadrature qGeom = NULL;
4067a1cf66bbSMatthew G. Knepley   Mat             J = Jac, JP = JacP;
4068a1cf66bbSMatthew G. Knepley   PetscScalar    *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
4069e432b41dSStefano Zampini   PetscBool       hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE;
4070a1cf66bbSMatthew G. Knepley   const PetscInt *cells;
407106ad1575SMatthew G. Knepley   PetscFormKey    key;
40729b2fc754SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
4073a1cf66bbSMatthew G. Knepley 
4074a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
40759566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
40769566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
40779566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
40789566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
40799566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A));
40809a2a23afSMatthew G. Knepley   if (A) {
40819566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
40829566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
40839566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
4084a1cf66bbSMatthew G. Knepley   }
4085a1cf66bbSMatthew G. Knepley   /* Get flags */
40869566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
40879566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE));
4088a1cf66bbSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
4089a1cf66bbSMatthew G. Knepley     PetscObject  disc;
4090a1cf66bbSMatthew G. Knepley     PetscClassId id;
40919566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc));
40929566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
40939371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
40949371c9d4SSatish Balay       isFE[fieldI] = PETSC_TRUE;
40959371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
40969371c9d4SSatish Balay       hasFV        = PETSC_TRUE;
40979371c9d4SSatish Balay       isFE[fieldI] = PETSC_FALSE;
40989371c9d4SSatish Balay     }
4099a1cf66bbSMatthew G. Knepley   }
41009566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(prob, &hasJac));
41019566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
41029566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
4103a1cf66bbSMatthew G. Knepley   assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
4104a1cf66bbSMatthew G. Knepley   hasDyn      = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
41059566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */
41069566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
41079566063dSJacob Faibussowitsch   if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
4108a1cf66bbSMatthew G. Knepley   /* Compute batch sizes */
4109a1cf66bbSMatthew G. Knepley   if (isFE[0]) {
4110a1cf66bbSMatthew G. Knepley     PetscFE         fe;
4111a1cf66bbSMatthew G. Knepley     PetscQuadrature q;
4112a1cf66bbSMatthew G. Knepley     PetscInt        numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
4113a1cf66bbSMatthew G. Knepley 
41149566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe));
41159566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &q));
41169566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL));
41179566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
41189566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
4119a1cf66bbSMatthew G. Knepley     blockSize = Nb * numQuadPoints;
4120a1cf66bbSMatthew G. Knepley     batchSize = numBlocks * blockSize;
4121a1cf66bbSMatthew G. Knepley     chunkSize = numBatches * batchSize;
4122a1cf66bbSMatthew G. Knepley     numChunks = numCells / chunkSize + numCells % chunkSize;
41239566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
4124a1cf66bbSMatthew G. Knepley   } else {
4125a1cf66bbSMatthew G. Knepley     chunkSize = numCells;
4126a1cf66bbSMatthew G. Knepley     numChunks = 1;
4127a1cf66bbSMatthew G. Knepley   }
4128a1cf66bbSMatthew G. Knepley   /* Get work space */
4129a1cf66bbSMatthew G. Knepley   wsz = (((X ? 1 : 0) + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize;
41309566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work));
41319566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(work, wsz));
4132a1cf66bbSMatthew G. Knepley   off      = 0;
4133a1cf66bbSMatthew G. Knepley   u        = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4134a1cf66bbSMatthew G. Knepley   u_t      = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4135a1cf66bbSMatthew G. Knepley   a        = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL;
4136a1cf66bbSMatthew G. Knepley   elemMat  = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4137a1cf66bbSMatthew G. Knepley   elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4138a1cf66bbSMatthew G. Knepley   elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
413963a3b9bcSJacob Faibussowitsch   PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz);
4140a1cf66bbSMatthew G. Knepley   /* Setup geometry */
41419566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
41429566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
41439566063dSJacob Faibussowitsch   if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
4144a1cf66bbSMatthew G. Knepley   if (!qGeom) {
4145a1cf66bbSMatthew G. Knepley     PetscFE fe;
4146a1cf66bbSMatthew G. Knepley 
41479566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe));
41489566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &qGeom));
41499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)qGeom));
4150a1cf66bbSMatthew G. Knepley   }
41519566063dSJacob Faibussowitsch   PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
4152a1cf66bbSMatthew G. Knepley   /* Compute volume integrals */
41539566063dSJacob Faibussowitsch   if (assembleJac) PetscCall(MatZeroEntries(J));
41549566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(JP));
41556528b96dSMatthew G. Knepley   key.label = NULL;
41566528b96dSMatthew G. Knepley   key.value = 0;
415706ad1575SMatthew G. Knepley   key.part  = 0;
4158a1cf66bbSMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4159a1cf66bbSMatthew G. Knepley     const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
4160a1cf66bbSMatthew G. Knepley     PetscInt       c;
4161a1cf66bbSMatthew G. Knepley 
4162a1cf66bbSMatthew G. Knepley     /* Extract values */
4163a1cf66bbSMatthew G. Knepley     for (c = 0; c < Ncell; ++c) {
4164a1cf66bbSMatthew G. Knepley       const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4165a1cf66bbSMatthew G. Knepley       PetscScalar   *x = NULL, *x_t = NULL;
4166a1cf66bbSMatthew G. Knepley       PetscInt       i;
4167a1cf66bbSMatthew G. Knepley 
4168a1cf66bbSMatthew G. Knepley       if (X) {
41699566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x));
4170a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
41719566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x));
4172a1cf66bbSMatthew G. Knepley       }
4173a1cf66bbSMatthew G. Knepley       if (X_t) {
41749566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t));
4175a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i];
41769566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t));
4177a1cf66bbSMatthew G. Knepley       }
4178a1cf66bbSMatthew G. Knepley       if (dmAux) {
41799566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x));
4180a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
41819566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x));
4182a1cf66bbSMatthew G. Knepley       }
4183a1cf66bbSMatthew G. Knepley     }
4184a1cf66bbSMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
4185a1cf66bbSMatthew G. Knepley       PetscFE fe;
41869566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
4187a1cf66bbSMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
41886528b96dSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
41899566063dSJacob Faibussowitsch         if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat));
41909566063dSJacob Faibussowitsch         if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP));
41919566063dSJacob Faibussowitsch         if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD));
4192a1cf66bbSMatthew G. Knepley       }
4193a1cf66bbSMatthew G. Knepley       /* For finite volume, add the identity */
4194a1cf66bbSMatthew G. Knepley       if (!isFE[fieldI]) {
4195a1cf66bbSMatthew G. Knepley         PetscFV  fv;
4196a1cf66bbSMatthew G. Knepley         PetscInt eOffset = 0, Nc, fc, foff;
4197a1cf66bbSMatthew G. Knepley 
41989566063dSJacob Faibussowitsch         PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff));
41999566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv));
42009566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &Nc));
4201a1cf66bbSMatthew G. Knepley         for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) {
4202a1cf66bbSMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
4203a1cf66bbSMatthew G. Knepley             const PetscInt i = foff + fc;
4204ad540459SPierre Jolivet             if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
4205ad540459SPierre Jolivet             if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0;
4206a1cf66bbSMatthew G. Knepley           }
4207a1cf66bbSMatthew G. Knepley         }
4208a1cf66bbSMatthew G. Knepley       }
4209a1cf66bbSMatthew G. Knepley     }
4210a1cf66bbSMatthew G. Knepley     /*   Add contribution from X_t */
42119371c9d4SSatish Balay     if (hasDyn) {
42129371c9d4SSatish Balay       for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
42139371c9d4SSatish Balay     }
4214a1cf66bbSMatthew G. Knepley     /* Insert values into matrix */
4215a1cf66bbSMatthew G. Knepley     for (c = 0; c < Ncell; ++c) {
4216a1cf66bbSMatthew G. Knepley       const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4217a1cf66bbSMatthew G. Knepley       if (mesh->printFEM > 1) {
42189566063dSJacob Faibussowitsch         if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim]));
42199566063dSJacob Faibussowitsch         if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim]));
4220a1cf66bbSMatthew G. Knepley       }
42219566063dSJacob Faibussowitsch       if (assembleJac) PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES));
42229566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES));
4223a1cf66bbSMatthew G. Knepley     }
4224a1cf66bbSMatthew G. Knepley   }
4225a1cf66bbSMatthew G. Knepley   /* Cleanup */
42269566063dSJacob Faibussowitsch   PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
42279566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&qGeom));
42289566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
42299566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE));
42309566063dSJacob Faibussowitsch   PetscCall(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));
4231a1cf66bbSMatthew G. Knepley   /* Compute boundary integrals */
42329566063dSJacob Faibussowitsch   /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */
4233a1cf66bbSMatthew G. Knepley   /* Assemble matrix */
42349371c9d4SSatish Balay   if (assembleJac) {
42359371c9d4SSatish Balay     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
42369371c9d4SSatish Balay     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
42379371c9d4SSatish Balay   }
42389371c9d4SSatish Balay   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
42399371c9d4SSatish Balay   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
42409566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
4241a1cf66bbSMatthew G. Knepley   PetscFunctionReturn(0);
4242a1cf66bbSMatthew G. Knepley }
42433e9753d6SMatthew G. Knepley 
42443e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/
42453e9753d6SMatthew G. Knepley 
4246d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4247d71ae5a4SJacob Faibussowitsch {
42483e9753d6SMatthew G. Knepley   PetscBool isPlex;
42493e9753d6SMatthew G. Knepley 
42503e9753d6SMatthew G. Knepley   PetscFunctionBegin;
42519566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
42523e9753d6SMatthew G. Knepley   if (isPlex) {
42533e9753d6SMatthew G. Knepley     *plex = dm;
42549566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
42553e9753d6SMatthew G. Knepley   } else {
42569566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
42573e9753d6SMatthew G. Knepley     if (!*plex) {
42589566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
42599566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
42601baa6e33SBarry Smith       if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex));
42613e9753d6SMatthew G. Knepley     } else {
42629566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)*plex));
42633e9753d6SMatthew G. Knepley     }
42643e9753d6SMatthew G. Knepley   }
42653e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
42663e9753d6SMatthew G. Knepley }
42673e9753d6SMatthew G. Knepley 
42683e9753d6SMatthew G. Knepley /*@
42693e9753d6SMatthew G. Knepley   DMPlexGetGeometryFVM - Return precomputed geometric data
42703e9753d6SMatthew G. Knepley 
4271*a1cb98faSBarry Smith   Collective on dm
42723e9753d6SMatthew G. Knepley 
42733e9753d6SMatthew G. Knepley   Input Parameter:
4274*a1cb98faSBarry Smith . dm - The `DM`
42753e9753d6SMatthew G. Knepley 
42763e9753d6SMatthew G. Knepley   Output Parameters:
42773e9753d6SMatthew G. Knepley + facegeom - The values precomputed from face geometry
42783e9753d6SMatthew G. Knepley . cellgeom - The values precomputed from cell geometry
42793e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell
42803e9753d6SMatthew G. Knepley 
42813e9753d6SMatthew G. Knepley   Level: developer
42823e9753d6SMatthew G. Knepley 
4283*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()`
42843e9753d6SMatthew G. Knepley @*/
4285d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4286d71ae5a4SJacob Faibussowitsch {
42873e9753d6SMatthew G. Knepley   DM plex;
42883e9753d6SMatthew G. Knepley 
42893e9753d6SMatthew G. Knepley   PetscFunctionBegin;
42903e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42919566063dSJacob Faibussowitsch   PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE));
42929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL));
42939566063dSJacob Faibussowitsch   if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius));
42949566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
42953e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
42963e9753d6SMatthew G. Knepley }
42973e9753d6SMatthew G. Knepley 
42983e9753d6SMatthew G. Knepley /*@
42993e9753d6SMatthew G. Knepley   DMPlexGetGradientDM - Return gradient data layout
43003e9753d6SMatthew G. Knepley 
4301*a1cb98faSBarry Smith   Collective on dm
43023e9753d6SMatthew G. Knepley 
43033e9753d6SMatthew G. Knepley   Input Parameters:
4304*a1cb98faSBarry Smith + dm - The `DM`
43053e9753d6SMatthew G. Knepley - fv - The PetscFV
43063e9753d6SMatthew G. Knepley 
43073e9753d6SMatthew G. Knepley   Output Parameter:
43083e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values
43093e9753d6SMatthew G. Knepley 
43103e9753d6SMatthew G. Knepley   Level: developer
43113e9753d6SMatthew G. Knepley 
4312*a1cb98faSBarry Smith .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()`
43133e9753d6SMatthew G. Knepley @*/
4314d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4315d71ae5a4SJacob Faibussowitsch {
43163e9753d6SMatthew G. Knepley   DM        plex;
43173e9753d6SMatthew G. Knepley   PetscBool computeGradients;
43183e9753d6SMatthew G. Knepley 
43193e9753d6SMatthew G. Knepley   PetscFunctionBegin;
43203e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43213e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
43223e9753d6SMatthew G. Knepley   PetscValidPointer(dmGrad, 3);
43239566063dSJacob Faibussowitsch   PetscCall(PetscFVGetComputeGradients(fv, &computeGradients));
43249371c9d4SSatish Balay   if (!computeGradients) {
43259371c9d4SSatish Balay     *dmGrad = NULL;
43269371c9d4SSatish Balay     PetscFunctionReturn(0);
43279371c9d4SSatish Balay   }
43289566063dSJacob Faibussowitsch   PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE));
43299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad));
43309566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
43313e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
43323e9753d6SMatthew G. Knepley }
43333e9753d6SMatthew G. Knepley 
4334d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS)
4335d71ae5a4SJacob Faibussowitsch {
43363e9753d6SMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
43373e9753d6SMatthew G. Knepley   DM              plex = NULL, plexA = NULL;
43383e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
43393e9753d6SMatthew G. Knepley   PetscDS         prob, probAux       = NULL;
43403e9753d6SMatthew G. Knepley   PetscSection    section, sectionAux = NULL;
43413e9753d6SMatthew G. Knepley   Vec             locA = NULL;
43423e9753d6SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
43433e9753d6SMatthew G. Knepley   PetscInt        totDim, totDimAux = 0;
43443e9753d6SMatthew G. Knepley 
43453e9753d6SMatthew G. Knepley   PetscFunctionBegin;
43469566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
43479566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
43489566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
43499566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
43509566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA));
43513e9753d6SMatthew G. Knepley   if (locA) {
43523e9753d6SMatthew G. Knepley     DM dmAux;
43533e9753d6SMatthew G. Knepley 
43549566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
43559566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
43569566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
43579566063dSJacob Faibussowitsch     PetscCall(DMGetDS(plexA, &probAux));
43589566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
43599566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexA, &sectionAux));
43603e9753d6SMatthew G. Knepley   }
43610c290148SMatthew G. Knepley   {
43623e9753d6SMatthew G. Knepley     PetscFEGeom    *fgeom;
43633e9753d6SMatthew G. Knepley     PetscInt        maxDegree;
43643e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
43653e9753d6SMatthew G. Knepley     IS              pointIS;
43663e9753d6SMatthew G. Knepley     const PetscInt *points;
43673e9753d6SMatthew G. Knepley     PetscInt        numFaces, face, Nq;
43683e9753d6SMatthew G. Knepley 
43699566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
43700c290148SMatthew G. Knepley     if (!pointIS) goto end; /* No points with that id on this process */
43713e9753d6SMatthew G. Knepley     {
43723e9753d6SMatthew G. Knepley       IS isectIS;
43733e9753d6SMatthew G. Knepley 
43743e9753d6SMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
43759566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
43769566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
43773e9753d6SMatthew G. Knepley       pointIS = isectIS;
43783e9753d6SMatthew G. Knepley     }
43799566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
43809566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
43819566063dSJacob Faibussowitsch     PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a));
43829566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
438348a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
43843e9753d6SMatthew G. Knepley     if (!qGeom) {
43853e9753d6SMatthew G. Knepley       PetscFE fe;
43863e9753d6SMatthew G. Knepley 
43879566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe));
43889566063dSJacob Faibussowitsch       PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
43899566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
43903e9753d6SMatthew G. Knepley     }
43919566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
43929566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
43933e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
4394f15274beSMatthew Knepley       const PetscInt point = points[face], *support;
43953e9753d6SMatthew G. Knepley       PetscScalar   *x     = NULL;
4396f15274beSMatthew Knepley       PetscInt       i;
43973e9753d6SMatthew G. Knepley 
43989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, point, &support));
43999566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
44003e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
44019566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
44023e9753d6SMatthew G. Knepley       if (locX_t) {
44039566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x));
44043e9753d6SMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
44059566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x));
44063e9753d6SMatthew G. Knepley       }
44073e9753d6SMatthew G. Knepley       if (locA) {
44083e9753d6SMatthew G. Knepley         PetscInt subp;
44093e9753d6SMatthew G. Knepley 
44109566063dSJacob Faibussowitsch         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
44119566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
44123e9753d6SMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
44139566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
44143e9753d6SMatthew G. Knepley       }
44153e9753d6SMatthew G. Knepley     }
44169566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(elemVec, numFaces * totDim));
44173e9753d6SMatthew G. Knepley     {
44183e9753d6SMatthew G. Knepley       PetscFE      fe;
44193e9753d6SMatthew G. Knepley       PetscInt     Nb;
44203e9753d6SMatthew G. Knepley       PetscFEGeom *chunkGeom = NULL;
44213e9753d6SMatthew G. Knepley       /* Conforming batches */
44223e9753d6SMatthew G. Knepley       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
44233e9753d6SMatthew G. Knepley       /* Remainder */
44243e9753d6SMatthew G. Knepley       PetscInt Nr, offset;
44253e9753d6SMatthew G. Knepley 
44269566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe));
44279566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
44289566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
44293e9753d6SMatthew G. Knepley       /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
44303e9753d6SMatthew G. Knepley       blockSize = Nb;
44313e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
44329566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
44333e9753d6SMatthew G. Knepley       numChunks = numFaces / (numBatches * batchSize);
44343e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
44353e9753d6SMatthew G. Knepley       Nr        = numFaces % (numBatches * batchSize);
44363e9753d6SMatthew G. Knepley       offset    = numFaces - Nr;
44379566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom));
44389566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec));
44399566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom));
44409566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
44419566063dSJacob Faibussowitsch       PetscCall(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]));
44429566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
44433e9753d6SMatthew G. Knepley     }
44443e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
44453e9753d6SMatthew G. Knepley       const PetscInt point = points[face], *support;
44463e9753d6SMatthew G. Knepley 
44479566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim]));
44489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(plex, point, &support));
44499566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES));
44503e9753d6SMatthew G. Knepley     }
44519566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
44529566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
44539566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
44549566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
44559566063dSJacob Faibussowitsch     PetscCall(PetscFree4(u, u_t, elemVec, a));
44563e9753d6SMatthew G. Knepley   }
44570c290148SMatthew G. Knepley end:
44589566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
44599566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plexA));
44603e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
44613e9753d6SMatthew G. Knepley }
44623e9753d6SMatthew G. Knepley 
4463d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF)
4464d71ae5a4SJacob Faibussowitsch {
44653e9753d6SMatthew G. Knepley   DMField  coordField;
44663e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
44673e9753d6SMatthew G. Knepley   IS       facetIS;
44683e9753d6SMatthew G. Knepley   PetscInt dim;
44693e9753d6SMatthew G. Knepley 
44703e9753d6SMatthew G. Knepley   PetscFunctionBegin;
44719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
44729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
44739566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
44749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
44759566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS));
44769566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
44773e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
44783e9753d6SMatthew G. Knepley }
44793e9753d6SMatthew G. Knepley 
4480d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4481d71ae5a4SJacob Faibussowitsch {
44823e9753d6SMatthew G. Knepley   PetscDS  prob;
44833e9753d6SMatthew G. Knepley   PetscInt numBd, bd;
44843e9753d6SMatthew G. Knepley   DMField  coordField = NULL;
44853e9753d6SMatthew G. Knepley   IS       facetIS    = NULL;
44863e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
44873e9753d6SMatthew G. Knepley   PetscInt dim;
44883e9753d6SMatthew G. Knepley 
44893e9753d6SMatthew G. Knepley   PetscFunctionBegin;
44909566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
44919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
44929566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
44939566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
44949566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
44953e9753d6SMatthew G. Knepley   for (bd = 0; bd < numBd; ++bd) {
449645480ffeSMatthew G. Knepley     PetscWeakForm           wf;
44973e9753d6SMatthew G. Knepley     DMBoundaryConditionType type;
44983e9753d6SMatthew G. Knepley     DMLabel                 label;
44993e9753d6SMatthew G. Knepley     const PetscInt         *values;
45000c290148SMatthew G. Knepley     PetscInt                field, numValues, v;
45013e9753d6SMatthew G. Knepley     PetscObject             obj;
45023e9753d6SMatthew G. Knepley     PetscClassId            id;
45030c290148SMatthew G. Knepley     PetscFormKey            key;
45043e9753d6SMatthew G. Knepley 
45059566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL));
45063d3e5d66SMatthew G. Knepley     if (type & DM_BC_ESSENTIAL) continue;
45079566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
45089566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
45093d3e5d66SMatthew G. Knepley     if (id != PETSCFE_CLASSID) continue;
45103e9753d6SMatthew G. Knepley     if (!facetIS) {
45113e9753d6SMatthew G. Knepley       DMLabel  depthLabel;
45123e9753d6SMatthew G. Knepley       PetscInt dim;
45133e9753d6SMatthew G. Knepley 
45149566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
45159566063dSJacob Faibussowitsch       PetscCall(DMGetDimension(dm, &dim));
45169566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
45173e9753d6SMatthew G. Knepley     }
45189566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
45190c290148SMatthew G. Knepley     for (v = 0; v < numValues; ++v) {
45200c290148SMatthew G. Knepley       key.label = label;
45210c290148SMatthew G. Knepley       key.value = values[v];
45220c290148SMatthew G. Knepley       key.field = field;
45230c290148SMatthew G. Knepley       key.part  = 0;
45249566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS));
45250c290148SMatthew G. Knepley     }
45263e9753d6SMatthew G. Knepley   }
45279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
45283e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
45293e9753d6SMatthew G. Knepley }
45303e9753d6SMatthew G. Knepley 
4531d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4532d71ae5a4SJacob Faibussowitsch {
45333e9753d6SMatthew G. Knepley   DM_Plex         *mesh       = (DM_Plex *)dm->data;
45343e9753d6SMatthew G. Knepley   const char      *name       = "Residual";
45353e9753d6SMatthew G. Knepley   DM               dmAux      = NULL;
45363e9753d6SMatthew G. Knepley   DM               dmGrad     = NULL;
45373e9753d6SMatthew G. Knepley   DMLabel          ghostLabel = NULL;
45386528b96dSMatthew G. Knepley   PetscDS          ds         = NULL;
45396528b96dSMatthew G. Knepley   PetscDS          dsAux      = NULL;
45403e9753d6SMatthew G. Knepley   PetscSection     section    = NULL;
45413e9753d6SMatthew G. Knepley   PetscBool        useFEM     = PETSC_FALSE;
45423e9753d6SMatthew G. Knepley   PetscBool        useFVM     = PETSC_FALSE;
45433e9753d6SMatthew G. Knepley   PetscBool        isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
45443e9753d6SMatthew G. Knepley   PetscFV          fvm        = NULL;
45453e9753d6SMatthew G. Knepley   PetscFVCellGeom *cgeomFVM   = NULL;
45463e9753d6SMatthew G. Knepley   PetscFVFaceGeom *fgeomFVM   = NULL;
45473e9753d6SMatthew G. Knepley   DMField          coordField = NULL;
45483e9753d6SMatthew G. Knepley   Vec              locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
45493e9753d6SMatthew G. Knepley   PetscScalar     *u = NULL, *u_t, *a, *uL, *uR;
45503e9753d6SMatthew G. Knepley   IS               chunkIS;
45513e9753d6SMatthew G. Knepley   const PetscInt  *cells;
45523e9753d6SMatthew G. Knepley   PetscInt         cStart, cEnd, numCells;
45533e9753d6SMatthew G. Knepley   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
45543e9753d6SMatthew G. Knepley   PetscInt         maxDegree  = PETSC_MAX_INT;
45553e9753d6SMatthew G. Knepley   PetscQuadrature  affineQuad = NULL, *quads = NULL;
45563e9753d6SMatthew G. Knepley   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
45573e9753d6SMatthew G. Knepley 
45583e9753d6SMatthew G. Knepley   PetscFunctionBegin;
4559e04ae0b4SMatthew G. Knepley   if (!cellIS) PetscFunctionReturn(0);
45609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
45613e9753d6SMatthew G. Knepley   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
45623e9753d6SMatthew G. Knepley   /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
45633e9753d6SMatthew G. Knepley   /* FEM+FVM */
45649566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
45659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
45663e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
45679566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
45689566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
45699566063dSJacob Faibussowitsch   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds));
45709566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
45719566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
45729566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA));
45733e9753d6SMatthew G. Knepley   if (locA) {
45743e9753d6SMatthew G. Knepley     PetscInt subcell;
45759566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
45761059d808SMatthew G. Knepley     PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell));
45779566063dSJacob Faibussowitsch     PetscCall(DMGetCellDS(dmAux, subcell, &dsAux));
45789566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
45793e9753d6SMatthew G. Knepley   }
45803e9753d6SMatthew G. Knepley   /* 2: Get geometric data */
45813e9753d6SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
45823e9753d6SMatthew G. Knepley     PetscObject  obj;
45833e9753d6SMatthew G. Knepley     PetscClassId id;
45843e9753d6SMatthew G. Knepley     PetscBool    fimp;
45853e9753d6SMatthew G. Knepley 
45869566063dSJacob Faibussowitsch     PetscCall(PetscDSGetImplicit(ds, f, &fimp));
45873e9753d6SMatthew G. Knepley     if (isImplicit != fimp) continue;
45889566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
45899566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
4590ad540459SPierre Jolivet     if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
45919371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) {
45929371c9d4SSatish Balay       useFVM = PETSC_TRUE;
45939371c9d4SSatish Balay       fvm    = (PetscFV)obj;
45949371c9d4SSatish Balay     }
45953e9753d6SMatthew G. Knepley   }
45963e9753d6SMatthew G. Knepley   if (useFEM) {
45979566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
45989566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
45993e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
46009566063dSJacob Faibussowitsch       PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
460148a46eb9SPierre Jolivet       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
46023e9753d6SMatthew G. Knepley     } else {
46039566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
46043e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
46053e9753d6SMatthew G. Knepley         PetscObject  obj;
46063e9753d6SMatthew G. Knepley         PetscClassId id;
46073e9753d6SMatthew G. Knepley         PetscBool    fimp;
46083e9753d6SMatthew G. Knepley 
46099566063dSJacob Faibussowitsch         PetscCall(PetscDSGetImplicit(ds, f, &fimp));
46103e9753d6SMatthew G. Knepley         if (isImplicit != fimp) continue;
46119566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
46129566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
46133e9753d6SMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
46143e9753d6SMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
46153e9753d6SMatthew G. Knepley 
46169566063dSJacob Faibussowitsch           PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
46179566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)quads[f]));
46189566063dSJacob Faibussowitsch           PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
46193e9753d6SMatthew G. Knepley         }
46203e9753d6SMatthew G. Knepley       }
46213e9753d6SMatthew G. Knepley     }
46223e9753d6SMatthew G. Knepley   }
46233e9753d6SMatthew G. Knepley   if (useFVM) {
46249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL));
46259566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM));
46269566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
46273e9753d6SMatthew G. Knepley     /* Reconstruct and limit cell gradients */
46289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad));
46293e9753d6SMatthew G. Knepley     if (dmGrad) {
46309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
46319566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
46329566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad));
46333e9753d6SMatthew G. Knepley       /* Communicate gradient values */
46349566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dmGrad, &locGrad));
46359566063dSJacob Faibussowitsch       PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad));
46369566063dSJacob Faibussowitsch       PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad));
46379566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
46383e9753d6SMatthew G. Knepley     }
46393e9753d6SMatthew G. Knepley     /* Handle non-essential (e.g. outflow) boundary values */
46409566063dSJacob Faibussowitsch     PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad));
46413e9753d6SMatthew G. Knepley   }
46423e9753d6SMatthew G. Knepley   /* Loop over chunks */
46439566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS));
46443e9753d6SMatthew G. Knepley   numCells      = cEnd - cStart;
46453e9753d6SMatthew G. Knepley   numChunks     = 1;
46463e9753d6SMatthew G. Knepley   cellChunkSize = numCells / numChunks;
46473e9753d6SMatthew G. Knepley   faceChunkSize = (fEnd - fStart) / numChunks;
46483e9753d6SMatthew G. Knepley   numChunks     = PetscMin(1, numCells);
46493e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
46503e9753d6SMatthew G. Knepley     PetscScalar     *elemVec, *fluxL, *fluxR;
46513e9753d6SMatthew G. Knepley     PetscReal       *vol;
46523e9753d6SMatthew G. Knepley     PetscFVFaceGeom *fgeom;
46533e9753d6SMatthew G. Knepley     PetscInt         cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
46543e9753d6SMatthew G. Knepley     PetscInt         fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face;
46553e9753d6SMatthew G. Knepley 
46563e9753d6SMatthew G. Knepley     /* Extract field coefficients */
46573e9753d6SMatthew G. Knepley     if (useFEM) {
46589566063dSJacob Faibussowitsch       PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells));
46599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
46609566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
46619566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemVec, numCells * totDim));
46623e9753d6SMatthew G. Knepley     }
46633e9753d6SMatthew G. Knepley     if (useFVM) {
46649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR));
46659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol));
46669566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL));
46679566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR));
46689566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(fluxL, numFaces * totDim));
46699566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(fluxR, numFaces * totDim));
46703e9753d6SMatthew G. Knepley     }
46713e9753d6SMatthew G. Knepley     /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */
46723e9753d6SMatthew G. Knepley     /* Loop over fields */
46733e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
46743e9753d6SMatthew G. Knepley       PetscObject  obj;
46753e9753d6SMatthew G. Knepley       PetscClassId id;
46763e9753d6SMatthew G. Knepley       PetscBool    fimp;
46773e9753d6SMatthew G. Knepley       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
46783e9753d6SMatthew G. Knepley 
46796528b96dSMatthew G. Knepley       key.field = f;
46809566063dSJacob Faibussowitsch       PetscCall(PetscDSGetImplicit(ds, f, &fimp));
46813e9753d6SMatthew G. Knepley       if (isImplicit != fimp) continue;
46829566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &obj));
46839566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
46843e9753d6SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
46853e9753d6SMatthew G. Knepley         PetscFE         fe        = (PetscFE)obj;
46863e9753d6SMatthew G. Knepley         PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
46873e9753d6SMatthew G. Knepley         PetscFEGeom    *chunkGeom = NULL;
46883e9753d6SMatthew G. Knepley         PetscQuadrature quad      = affineQuad ? affineQuad : quads[f];
46893e9753d6SMatthew G. Knepley         PetscInt        Nq, Nb;
46903e9753d6SMatthew G. Knepley 
46919566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
46929566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
46939566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
46943e9753d6SMatthew G. Knepley         blockSize = Nb;
46953e9753d6SMatthew G. Knepley         batchSize = numBlocks * blockSize;
46969566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
46973e9753d6SMatthew G. Knepley         numChunks = numCells / (numBatches * batchSize);
46983e9753d6SMatthew G. Knepley         Ne        = numChunks * numBatches * batchSize;
46993e9753d6SMatthew G. Knepley         Nr        = numCells % (numBatches * batchSize);
47003e9753d6SMatthew G. Knepley         offset    = numCells - Nr;
47013e9753d6SMatthew G. Knepley         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
47023e9753d6SMatthew G. Knepley         /*   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) */
47039566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
47049566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec));
47059566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom));
47069566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, &a[offset * totDimAux], t, &elemVec[offset * totDim]));
47079566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom));
47083e9753d6SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
47093e9753d6SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
47103e9753d6SMatthew G. Knepley 
47113e9753d6SMatthew G. Knepley         Ne = numFaces;
47123e9753d6SMatthew G. Knepley         /* Riemann solve over faces (need fields at face centroids) */
47133e9753d6SMatthew G. Knepley         /*   We need to evaluate FE fields at those coordinates */
47149566063dSJacob Faibussowitsch         PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR));
471563a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
47163e9753d6SMatthew G. Knepley     }
47173e9753d6SMatthew G. Knepley     /* Loop over domain */
47183e9753d6SMatthew G. Knepley     if (useFEM) {
47193e9753d6SMatthew G. Knepley       /* Add elemVec to locX */
47203e9753d6SMatthew G. Knepley       for (c = cS; c < cE; ++c) {
47213e9753d6SMatthew G. Knepley         const PetscInt cell = cells ? cells[c] : c;
47223e9753d6SMatthew G. Knepley         const PetscInt cind = c - cStart;
47233e9753d6SMatthew G. Knepley 
47249566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
47253e9753d6SMatthew G. Knepley         if (ghostLabel) {
47263e9753d6SMatthew G. Knepley           PetscInt ghostVal;
47273e9753d6SMatthew G. Knepley 
47289566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
47293e9753d6SMatthew G. Knepley           if (ghostVal > 0) continue;
47303e9753d6SMatthew G. Knepley         }
47319566063dSJacob Faibussowitsch         PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
47323e9753d6SMatthew G. Knepley       }
47333e9753d6SMatthew G. Knepley     }
47343e9753d6SMatthew G. Knepley     if (useFVM) {
47353e9753d6SMatthew G. Knepley       PetscScalar *fa;
47363e9753d6SMatthew G. Knepley       PetscInt     iface;
47373e9753d6SMatthew G. Knepley 
47389566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
47393e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
47403e9753d6SMatthew G. Knepley         PetscFV      fv;
47413e9753d6SMatthew G. Knepley         PetscObject  obj;
47423e9753d6SMatthew G. Knepley         PetscClassId id;
47433e9753d6SMatthew G. Knepley         PetscInt     foff, pdim;
47443e9753d6SMatthew G. Knepley 
47459566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
47469566063dSJacob Faibussowitsch         PetscCall(PetscDSGetFieldOffset(ds, f, &foff));
47479566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
47483e9753d6SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
47493e9753d6SMatthew G. Knepley         fv = (PetscFV)obj;
47509566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
47513e9753d6SMatthew G. Knepley         /* Accumulate fluxes to cells */
47523e9753d6SMatthew G. Knepley         for (face = fS, iface = 0; face < fE; ++face) {
47533e9753d6SMatthew G. Knepley           const PetscInt *scells;
47543e9753d6SMatthew G. Knepley           PetscScalar    *fL = NULL, *fR = NULL;
47553e9753d6SMatthew G. Knepley           PetscInt        ghost, d, nsupp, nchild;
47563e9753d6SMatthew G. Knepley 
47579566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
47589566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
47599566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
47603e9753d6SMatthew G. Knepley           if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
47619566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupport(dm, face, &scells));
47629566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost));
47639566063dSJacob Faibussowitsch           if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL));
47649566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost));
47659566063dSJacob Faibussowitsch           if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR));
47663e9753d6SMatthew G. Knepley           for (d = 0; d < pdim; ++d) {
47673e9753d6SMatthew G. Knepley             if (fL) fL[d] -= fluxL[iface * totDim + foff + d];
47683e9753d6SMatthew G. Knepley             if (fR) fR[d] += fluxR[iface * totDim + foff + d];
47693e9753d6SMatthew G. Knepley           }
47703e9753d6SMatthew G. Knepley           ++iface;
47713e9753d6SMatthew G. Knepley         }
47723e9753d6SMatthew G. Knepley       }
47739566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
47743e9753d6SMatthew G. Knepley     }
47753e9753d6SMatthew G. Knepley     /* Handle time derivative */
47763e9753d6SMatthew G. Knepley     if (locX_t) {
47773e9753d6SMatthew G. Knepley       PetscScalar *x_t, *fa;
47783e9753d6SMatthew G. Knepley 
47799566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
47809566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locX_t, &x_t));
47813e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
47823e9753d6SMatthew G. Knepley         PetscFV      fv;
47833e9753d6SMatthew G. Knepley         PetscObject  obj;
47843e9753d6SMatthew G. Knepley         PetscClassId id;
47853e9753d6SMatthew G. Knepley         PetscInt     pdim, d;
47863e9753d6SMatthew G. Knepley 
47879566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
47889566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
47893e9753d6SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
47903e9753d6SMatthew G. Knepley         fv = (PetscFV)obj;
47919566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
47923e9753d6SMatthew G. Knepley         for (c = cS; c < cE; ++c) {
47933e9753d6SMatthew G. Knepley           const PetscInt cell = cells ? cells[c] : c;
47943e9753d6SMatthew G. Knepley           PetscScalar   *u_t, *r;
47953e9753d6SMatthew G. Knepley 
47963e9753d6SMatthew G. Knepley           if (ghostLabel) {
47973e9753d6SMatthew G. Knepley             PetscInt ghostVal;
47983e9753d6SMatthew G. Knepley 
47999566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
48003e9753d6SMatthew G. Knepley             if (ghostVal > 0) continue;
48013e9753d6SMatthew G. Knepley           }
48029566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t));
48039566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r));
48043e9753d6SMatthew G. Knepley           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
48053e9753d6SMatthew G. Knepley         }
48063e9753d6SMatthew G. Knepley       }
48079566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locX_t, &x_t));
48089566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
48093e9753d6SMatthew G. Knepley     }
48103e9753d6SMatthew G. Knepley     if (useFEM) {
48119566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
48129566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
48133e9753d6SMatthew G. Knepley     }
48143e9753d6SMatthew G. Knepley     if (useFVM) {
48159566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR));
48169566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol));
48179566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL));
48189566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR));
48199566063dSJacob Faibussowitsch       if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
48203e9753d6SMatthew G. Knepley     }
48213e9753d6SMatthew G. Knepley   }
48229566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISDestroy(&chunkIS));
48239566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
48243e9753d6SMatthew G. Knepley 
48253e9753d6SMatthew G. Knepley   if (useFEM) {
48269566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user));
48273e9753d6SMatthew G. Knepley 
48283e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
48299566063dSJacob Faibussowitsch       PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
48309566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&affineQuad));
48313e9753d6SMatthew G. Knepley     } else {
48323e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
48339566063dSJacob Faibussowitsch         PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
48349566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureDestroy(&quads[f]));
48353e9753d6SMatthew G. Knepley       }
48369566063dSJacob Faibussowitsch       PetscCall(PetscFree2(quads, geoms));
48373e9753d6SMatthew G. Knepley     }
48383e9753d6SMatthew G. Knepley   }
48393e9753d6SMatthew G. Knepley 
48403e9753d6SMatthew G. Knepley   /* FEM */
48413e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
48423e9753d6SMatthew G. Knepley   /* 2: Get geometric data */
48433e9753d6SMatthew G. Knepley   /* 3: Handle boundary values */
48443e9753d6SMatthew G. Knepley   /* 4: Loop over domain */
48453e9753d6SMatthew G. Knepley   /*   Extract coefficients */
48463e9753d6SMatthew G. Knepley   /* Loop over fields */
48473e9753d6SMatthew G. Knepley   /*   Set tiling for FE*/
48483e9753d6SMatthew G. Knepley   /*   Integrate FE residual to get elemVec */
48493e9753d6SMatthew G. Knepley   /*     Loop over subdomain */
48503e9753d6SMatthew G. Knepley   /*       Loop over quad points */
48513e9753d6SMatthew G. Knepley   /*         Transform coords to real space */
48523e9753d6SMatthew G. Knepley   /*         Evaluate field and aux fields at point */
48533e9753d6SMatthew G. Knepley   /*         Evaluate residual at point */
48543e9753d6SMatthew G. Knepley   /*         Transform residual to real space */
48553e9753d6SMatthew G. Knepley   /*       Add residual to elemVec */
48563e9753d6SMatthew G. Knepley   /* Loop over domain */
48573e9753d6SMatthew G. Knepley   /*   Add elemVec to locX */
48583e9753d6SMatthew G. Knepley 
48593e9753d6SMatthew G. Knepley   /* FVM */
48603e9753d6SMatthew G. Knepley   /* Get geometric data */
48613e9753d6SMatthew G. Knepley   /* If using gradients */
48623e9753d6SMatthew G. Knepley   /*   Compute gradient data */
48633e9753d6SMatthew G. Knepley   /*   Loop over domain faces */
48643e9753d6SMatthew G. Knepley   /*     Count computational faces */
48653e9753d6SMatthew G. Knepley   /*     Reconstruct cell gradient */
48663e9753d6SMatthew G. Knepley   /*   Loop over domain cells */
48673e9753d6SMatthew G. Knepley   /*     Limit cell gradients */
48683e9753d6SMatthew G. Knepley   /* Handle boundary values */
48693e9753d6SMatthew G. Knepley   /* Loop over domain faces */
48703e9753d6SMatthew G. Knepley   /*   Read out field, centroid, normal, volume for each side of face */
48713e9753d6SMatthew G. Knepley   /* Riemann solve over faces */
48723e9753d6SMatthew G. Knepley   /* Loop over domain faces */
48733e9753d6SMatthew G. Knepley   /*   Accumulate fluxes to cells */
48743e9753d6SMatthew G. Knepley   /* TODO Change printFEM to printDisc here */
48753e9753d6SMatthew G. Knepley   if (mesh->printFEM) {
48763e9753d6SMatthew G. Knepley     Vec          locFbc;
48773e9753d6SMatthew G. Knepley     PetscInt     pStart, pEnd, p, maxDof;
48783e9753d6SMatthew G. Knepley     PetscScalar *zeroes;
48793e9753d6SMatthew G. Knepley 
48809566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(locF, &locFbc));
48819566063dSJacob Faibussowitsch     PetscCall(VecCopy(locF, locFbc));
48829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
48839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(section, &maxDof));
48849566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxDof, &zeroes));
488548a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES));
48869566063dSJacob Faibussowitsch     PetscCall(PetscFree(zeroes));
48879566063dSJacob Faibussowitsch     PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc));
48889566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locFbc));
48893e9753d6SMatthew G. Knepley   }
48909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
48913e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
48923e9753d6SMatthew G. Knepley }
48933e9753d6SMatthew G. Knepley 
48946528b96dSMatthew G. Knepley /*
48956528b96dSMatthew G. Knepley   1) Allow multiple kernels for BdResidual for hybrid DS
48966528b96dSMatthew G. Knepley 
48976528b96dSMatthew G. Knepley   DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux
48986528b96dSMatthew G. Knepley 
48996528b96dSMatthew G. Knepley   DONE 3) Change DMGetCellFields() to get different aux data a[] for each side
49006528b96dSMatthew G. Knepley      - I think I just need to replace a[] with the closure from each face
49016528b96dSMatthew G. Knepley 
49026528b96dSMatthew G. Knepley   4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before
49036528b96dSMatthew G. Knepley */
4904d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4905d71ae5a4SJacob Faibussowitsch {
49063e9753d6SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
49073e9753d6SMatthew G. Knepley   const char     *name       = "Hybrid Residual";
490804c51a94SMatthew G. Knepley   DM              dmAux[3]   = {NULL, NULL, NULL};
49093e9753d6SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
49106528b96dSMatthew G. Knepley   PetscDS         ds         = NULL;
49116528b96dSMatthew G. Knepley   PetscDS         dsAux[3]   = {NULL, NULL, NULL};
491204c51a94SMatthew G. Knepley   Vec             locA[3]    = {NULL, NULL, NULL};
4913b2ab40e6SMatthew G. Knepley   PetscScalar    *a[3]       = {NULL, NULL, NULL};
49143e9753d6SMatthew G. Knepley   PetscSection    section    = NULL;
49153e9753d6SMatthew G. Knepley   DMField         coordField = NULL;
4916b2ab40e6SMatthew G. Knepley   PetscScalar    *u          = NULL, *u_t;
49173e9753d6SMatthew G. Knepley   PetscScalar    *elemVec;
49183e9753d6SMatthew G. Knepley   IS              chunkIS;
49193e9753d6SMatthew G. Knepley   const PetscInt *cells;
49203e9753d6SMatthew G. Knepley   PetscInt       *faces;
49213e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
49226528b96dSMatthew G. Knepley   PetscInt        Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
49233e9753d6SMatthew G. Knepley   PetscInt        maxDegree  = PETSC_MAX_INT;
49243e9753d6SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
49253e9753d6SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
49263e9753d6SMatthew G. Knepley 
49273e9753d6SMatthew G. Knepley   PetscFunctionBegin;
49285fedec97SMatthew G. Knepley   if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
49295fedec97SMatthew G. Knepley     const char *name;
49309566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name));
493163a3b9bcSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part);
49325fedec97SMatthew G. Knepley   }
49339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
49343e9753d6SMatthew G. Knepley   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
49353e9753d6SMatthew G. Knepley   /* FEM */
49369566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
49379566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
49383e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
49399566063dSJacob Faibussowitsch   PetscCall(DMGetSection(dm, &section));
49409566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
49411059d808SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds));
49429566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
49439566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
49449566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]));
494504c51a94SMatthew G. Knepley   if (locA[2]) {
49461059d808SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
49471059d808SMatthew G. Knepley 
49489566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA[2], &dmAux[2]));
49491059d808SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2]));
49509566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]));
49516528b96dSMatthew G. Knepley     {
49526528b96dSMatthew G. Knepley       const PetscInt *cone;
49536528b96dSMatthew G. Knepley       PetscInt        c;
49546528b96dSMatthew G. Knepley 
49551059d808SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
49566528b96dSMatthew G. Knepley       for (c = 0; c < 2; ++c) {
49576528b96dSMatthew G. Knepley         const PetscInt *support;
49586528b96dSMatthew G. Knepley         PetscInt        ssize, s;
49596528b96dSMatthew G. Knepley 
49609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
49619566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
49621059d808SMatthew G. Knepley         PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[c], cellStart, ssize);
49631059d808SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
49641059d808SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
49651059d808SMatthew G. Knepley         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart);
49669566063dSJacob Faibussowitsch         PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]));
4967c75bfeddSPierre Jolivet         PetscCheck(locA[c], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must have auxiliary vector for (%p, %" PetscInt_FMT ", %" PetscInt_FMT ")", (void *)key[c].label, key[c].value, key[c].part);
49689566063dSJacob Faibussowitsch         if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c]));
4969ad540459SPierre Jolivet         else dmAux[c] = dmAux[2];
49709566063dSJacob Faibussowitsch         PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c]));
49719566063dSJacob Faibussowitsch         PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]));
49726528b96dSMatthew G. Knepley       }
49736528b96dSMatthew G. Knepley     }
49743e9753d6SMatthew G. Knepley   }
49753e9753d6SMatthew G. Knepley   /* 2: Setup geometric data */
49769566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
49779566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
49783e9753d6SMatthew G. Knepley   if (maxDegree > 1) {
49799566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
49803e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
49813e9753d6SMatthew G. Knepley       PetscFE fe;
49823e9753d6SMatthew G. Knepley 
49839566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
49843e9753d6SMatthew G. Knepley       if (fe) {
49859566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
49869566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)quads[f]));
49873e9753d6SMatthew G. Knepley       }
49883e9753d6SMatthew G. Knepley     }
49893e9753d6SMatthew G. Knepley   }
49903e9753d6SMatthew G. Knepley   /* Loop over chunks */
49913e9753d6SMatthew G. Knepley   cellChunkSize = numCells;
49923e9753d6SMatthew G. Knepley   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
4993a4158a15SMatthew G. Knepley   PetscCall(PetscCalloc1(1 * cellChunkSize, &faces));
4994a4158a15SMatthew G. Knepley   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS));
49953e9753d6SMatthew G. Knepley   /* Extract field coefficients */
49963e9753d6SMatthew G. Knepley   /* NOTE This needs the end cap faces to have identical orientations */
49979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
49989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a));
49999566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVec));
50003e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
50013e9753d6SMatthew G. Knepley     PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
50023e9753d6SMatthew G. Knepley 
50039566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(elemVec, cellChunkSize * totDim * sizeof(PetscScalar)));
50043e9753d6SMatthew G. Knepley     /* Get faces */
50053e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
50063e9753d6SMatthew G. Knepley       const PetscInt  cell = cells ? cells[c] : c;
50073e9753d6SMatthew G. Knepley       const PetscInt *cone;
50089566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cell, &cone));
5009a4158a15SMatthew G. Knepley       faces[0 * cellChunkSize + (c - cS)] = cone[0];
5010a4158a15SMatthew G. Knepley       /*faces[1*cellChunkSize+(c-cS)] = cone[1];*/
50113e9753d6SMatthew G. Knepley     }
5012a4158a15SMatthew G. Knepley     PetscCall(ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER));
50133e9753d6SMatthew G. Knepley     /* Get geometric data */
50143e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
50159566063dSJacob Faibussowitsch       if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad));
50169566063dSJacob Faibussowitsch       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom));
50173e9753d6SMatthew G. Knepley     } else {
50183e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
50199566063dSJacob Faibussowitsch         if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]));
50203e9753d6SMatthew G. Knepley       }
50213e9753d6SMatthew G. Knepley     }
50223e9753d6SMatthew G. Knepley     /* Loop over fields */
50233e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
50243e9753d6SMatthew G. Knepley       PetscFE         fe;
50253e9753d6SMatthew G. Knepley       PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
5026148442b3SMatthew G. Knepley       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
50273e9753d6SMatthew G. Knepley       PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
50283e9753d6SMatthew G. Knepley       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
50295fedec97SMatthew G. Knepley       PetscBool       isCohesiveField;
50303e9753d6SMatthew G. Knepley 
50319566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
50323e9753d6SMatthew G. Knepley       if (!fe) continue;
50339566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
50349566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
50359566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
50363e9753d6SMatthew G. Knepley       blockSize = Nb;
50373e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
50389566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
50393e9753d6SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
50403e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
50413e9753d6SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
50423e9753d6SMatthew G. Knepley       offset    = numCells - Nr;
50439566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
50449566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &remGeom));
50459566063dSJacob Faibussowitsch       PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
50465fedec97SMatthew G. Knepley       chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE;
50476528b96dSMatthew G. Knepley       key[0].field                                = f;
50486528b96dSMatthew G. Knepley       key[1].field                                = f;
50495fedec97SMatthew G. Knepley       key[2].field                                = f;
50509566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec));
50519566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVec[offset * totDim]));
50529566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec));
50539566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVec[offset * totDim]));
50549566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec));
50559566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVec[offset * totDim]));
50569566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom));
50579566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom));
50583e9753d6SMatthew G. Knepley     }
50593e9753d6SMatthew G. Knepley     /* Add elemVec to locX */
50603e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
50613e9753d6SMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
50623e9753d6SMatthew G. Knepley       const PetscInt cind = c - cStart;
50633e9753d6SMatthew G. Knepley 
50649566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
50653e9753d6SMatthew G. Knepley       if (ghostLabel) {
50663e9753d6SMatthew G. Knepley         PetscInt ghostVal;
50673e9753d6SMatthew G. Knepley 
50689566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
50693e9753d6SMatthew G. Knepley         if (ghostVal > 0) continue;
50703e9753d6SMatthew G. Knepley       }
50719566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
50723e9753d6SMatthew G. Knepley     }
50733e9753d6SMatthew G. Knepley   }
50749566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
50759566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a));
50769566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
50779566063dSJacob Faibussowitsch   PetscCall(PetscFree(faces));
50789566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&chunkIS));
50799566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
50803e9753d6SMatthew G. Knepley   if (maxDegree <= 1) {
50819566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
50829566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&affineQuad));
50833e9753d6SMatthew G. Knepley   } else {
50843e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
50859566063dSJacob Faibussowitsch       if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
50869566063dSJacob Faibussowitsch       if (quads) PetscCall(PetscQuadratureDestroy(&quads[f]));
50873e9753d6SMatthew G. Knepley     }
50889566063dSJacob Faibussowitsch     PetscCall(PetscFree2(quads, geoms));
50893e9753d6SMatthew G. Knepley   }
50909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
50913e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
50923e9753d6SMatthew G. Knepley }
50933e9753d6SMatthew G. Knepley 
5094d71ae5a4SJacob Faibussowitsch 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)
5095d71ae5a4SJacob Faibussowitsch {
50963e9753d6SMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
50973e9753d6SMatthew G. Knepley   DM              plex = NULL, plexA = NULL, tdm;
50983e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
50993e9753d6SMatthew G. Knepley   PetscDS         prob, probAux       = NULL;
51003e9753d6SMatthew G. Knepley   PetscSection    section, sectionAux = NULL;
5101e432b41dSStefano Zampini   PetscSection    globalSection;
51023e9753d6SMatthew G. Knepley   Vec             locA = NULL, tv;
51033e9753d6SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
51043e9753d6SMatthew G. Knepley   PetscInt        v;
51053e9753d6SMatthew G. Knepley   PetscInt        Nf, totDim, totDimAux = 0;
5106e432b41dSStefano Zampini   PetscBool       transform;
51073e9753d6SMatthew G. Knepley 
51083e9753d6SMatthew G. Knepley   PetscFunctionBegin;
51099566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
51109566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
51119566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
51129566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
51139566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
51149566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
51159566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
51169566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
51179566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA));
51183e9753d6SMatthew G. Knepley   if (locA) {
51193e9753d6SMatthew G. Knepley     DM dmAux;
51203e9753d6SMatthew G. Knepley 
51219566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
51229566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
51239566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
51249566063dSJacob Faibussowitsch     PetscCall(DMGetDS(plexA, &probAux));
51259566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
51269566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexA, &sectionAux));
51273e9753d6SMatthew G. Knepley   }
51283e9753d6SMatthew G. Knepley 
51299566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
51303e9753d6SMatthew G. Knepley   for (v = 0; v < numValues; ++v) {
51313e9753d6SMatthew G. Knepley     PetscFEGeom    *fgeom;
51323e9753d6SMatthew G. Knepley     PetscInt        maxDegree;
51333e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
51343e9753d6SMatthew G. Knepley     IS              pointIS;
51353e9753d6SMatthew G. Knepley     const PetscInt *points;
513606ad1575SMatthew G. Knepley     PetscFormKey    key;
51373e9753d6SMatthew G. Knepley     PetscInt        numFaces, face, Nq;
51383e9753d6SMatthew G. Knepley 
513945480ffeSMatthew G. Knepley     key.label = label;
514045480ffeSMatthew G. Knepley     key.value = values[v];
514106ad1575SMatthew G. Knepley     key.part  = 0;
51429566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
51433e9753d6SMatthew G. Knepley     if (!pointIS) continue; /* No points with that id on this process */
51443e9753d6SMatthew G. Knepley     {
51453e9753d6SMatthew G. Knepley       IS isectIS;
51463e9753d6SMatthew G. Knepley 
51473e9753d6SMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
51489566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
51499566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
51503e9753d6SMatthew G. Knepley       pointIS = isectIS;
51513e9753d6SMatthew G. Knepley     }
51529566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
51539566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
51549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a));
51559566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
515648a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
51573e9753d6SMatthew G. Knepley     if (!qGeom) {
51583e9753d6SMatthew G. Knepley       PetscFE fe;
51593e9753d6SMatthew G. Knepley 
51609566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
51619566063dSJacob Faibussowitsch       PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
51629566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
51633e9753d6SMatthew G. Knepley     }
51649566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
51659566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
51663e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
5167f15274beSMatthew Knepley       const PetscInt point = points[face], *support;
51683e9753d6SMatthew G. Knepley       PetscScalar   *x     = NULL;
5169f15274beSMatthew Knepley       PetscInt       i;
51703e9753d6SMatthew G. Knepley 
51719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, point, &support));
51729566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
51733e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
51749566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
51753e9753d6SMatthew G. Knepley       if (locX_t) {
51769566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x));
51773e9753d6SMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
51789566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x));
51793e9753d6SMatthew G. Knepley       }
51803e9753d6SMatthew G. Knepley       if (locA) {
51813e9753d6SMatthew G. Knepley         PetscInt subp;
51829566063dSJacob Faibussowitsch         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
51839566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
51843e9753d6SMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
51859566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
51863e9753d6SMatthew G. Knepley       }
51873e9753d6SMatthew G. Knepley     }
51889566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim));
51893e9753d6SMatthew G. Knepley     {
51903e9753d6SMatthew G. Knepley       PetscFE  fe;
51913e9753d6SMatthew G. Knepley       PetscInt Nb;
51923e9753d6SMatthew G. Knepley       /* Conforming batches */
51933e9753d6SMatthew G. Knepley       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
51943e9753d6SMatthew G. Knepley       /* Remainder */
51953e9753d6SMatthew G. Knepley       PetscFEGeom *chunkGeom = NULL;
51963e9753d6SMatthew G. Knepley       PetscInt     fieldJ, Nr, offset;
51973e9753d6SMatthew G. Knepley 
51989566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
51999566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
52009566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
52013e9753d6SMatthew G. Knepley       blockSize = Nb;
52023e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
52039566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
52043e9753d6SMatthew G. Knepley       numChunks = numFaces / (numBatches * batchSize);
52053e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
52063e9753d6SMatthew G. Knepley       Nr        = numFaces % (numBatches * batchSize);
52073e9753d6SMatthew G. Knepley       offset    = numFaces - Nr;
52089566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom));
52093e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
521045480ffeSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
52119566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
52123e9753d6SMatthew G. Knepley       }
52139566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
52143e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
521545480ffeSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
52169566063dSJacob Faibussowitsch         PetscCall(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]));
52173e9753d6SMatthew G. Knepley       }
52189566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
52193e9753d6SMatthew G. Knepley     }
52203e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
52213e9753d6SMatthew G. Knepley       const PetscInt point = points[face], *support;
52223e9753d6SMatthew G. Knepley 
52233e9753d6SMatthew G. Knepley       /* Transform to global basis before insertion in Jacobian */
52249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(plex, point, &support));
52259566063dSJacob Faibussowitsch       if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim]));
52269566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim]));
52279566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES));
52283e9753d6SMatthew G. Knepley     }
52299566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
52309566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
52319566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
52329566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
52339566063dSJacob Faibussowitsch     PetscCall(PetscFree4(u, u_t, elemMat, a));
52343e9753d6SMatthew G. Knepley   }
52359566063dSJacob Faibussowitsch   if (plex) PetscCall(DMDestroy(&plex));
52369566063dSJacob Faibussowitsch   if (plexA) PetscCall(DMDestroy(&plexA));
52373e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
52383e9753d6SMatthew G. Knepley }
52393e9753d6SMatthew G. Knepley 
5240d71ae5a4SJacob Faibussowitsch 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)
5241d71ae5a4SJacob Faibussowitsch {
52423e9753d6SMatthew G. Knepley   DMField  coordField;
52433e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
52443e9753d6SMatthew G. Knepley   IS       facetIS;
52453e9753d6SMatthew G. Knepley   PetscInt dim;
52463e9753d6SMatthew G. Knepley 
52473e9753d6SMatthew G. Knepley   PetscFunctionBegin;
52489566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
52499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
52509566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
52519566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
52529566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS));
52539566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
52543e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
52553e9753d6SMatthew G. Knepley }
52563e9753d6SMatthew G. Knepley 
5257d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5258d71ae5a4SJacob Faibussowitsch {
52593e9753d6SMatthew G. Knepley   PetscDS  prob;
52603e9753d6SMatthew G. Knepley   PetscInt dim, numBd, bd;
52613e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
52623e9753d6SMatthew G. Knepley   DMField  coordField = NULL;
52633e9753d6SMatthew G. Knepley   IS       facetIS;
52643e9753d6SMatthew G. Knepley 
52653e9753d6SMatthew G. Knepley   PetscFunctionBegin;
52669566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
52679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
52689566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
52699566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
52709566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
52719566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
52723e9753d6SMatthew G. Knepley   for (bd = 0; bd < numBd; ++bd) {
527345480ffeSMatthew G. Knepley     PetscWeakForm           wf;
52743e9753d6SMatthew G. Knepley     DMBoundaryConditionType type;
52753e9753d6SMatthew G. Knepley     DMLabel                 label;
52763e9753d6SMatthew G. Knepley     const PetscInt         *values;
52773e9753d6SMatthew G. Knepley     PetscInt                fieldI, numValues;
52783e9753d6SMatthew G. Knepley     PetscObject             obj;
52793e9753d6SMatthew G. Knepley     PetscClassId            id;
52803e9753d6SMatthew G. Knepley 
52819566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL));
52823d3e5d66SMatthew G. Knepley     if (type & DM_BC_ESSENTIAL) continue;
52839566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj));
52849566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
52853d3e5d66SMatthew G. Knepley     if (id != PETSCFE_CLASSID) continue;
52869566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS));
52873e9753d6SMatthew G. Knepley   }
52889566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
52893e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
52903e9753d6SMatthew G. Knepley }
52913e9753d6SMatthew G. Knepley 
5292d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *user)
5293d71ae5a4SJacob Faibussowitsch {
52943e9753d6SMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
52953e9753d6SMatthew G. Knepley   const char     *name  = "Jacobian";
52969a2a23afSMatthew G. Knepley   DM              dmAux = NULL, plex, tdm;
52973e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
52983e9753d6SMatthew G. Knepley   Vec             A, tv;
52993e9753d6SMatthew G. Knepley   DMField         coordField;
53003e9753d6SMatthew G. Knepley   PetscDS         prob, probAux = NULL;
5301e432b41dSStefano Zampini   PetscSection    section, globalSection, sectionAux;
53023e9753d6SMatthew G. Knepley   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
53033e9753d6SMatthew G. Knepley   const PetscInt *cells;
53043e9753d6SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ;
530528351e22SJed Brown   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
5306e04ae0b4SMatthew G. Knepley   PetscBool       hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform;
53073e9753d6SMatthew G. Knepley 
53083e9753d6SMatthew G. Knepley   PetscFunctionBegin;
5309e04ae0b4SMatthew G. Knepley   if (!cellIS) goto end;
53109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
53119566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
53129566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
53139566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
53149566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
53159566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
53169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
53179566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
53189566063dSJacob Faibussowitsch   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob));
53199566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
53209566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
53219566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(prob, &hasJac));
53229566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
53233e9753d6SMatthew G. Knepley   /* user passed in the same matrix, avoid double contributions and
53243e9753d6SMatthew G. Knepley      only assemble the Jacobian */
53253e9753d6SMatthew G. Knepley   if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
53269566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
53273e9753d6SMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
53289566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A));
53299a2a23afSMatthew G. Knepley   if (A) {
53309566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
53319566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
53329566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plex));
53339566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plex, &sectionAux));
53349566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
53359566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
53363e9753d6SMatthew G. Knepley   }
53379566063dSJacob Faibussowitsch   PetscCall(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));
53389566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
53399566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
53403e9753d6SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
53413e9753d6SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
53423e9753d6SMatthew G. Knepley     const PetscInt cind = c - cStart;
53433e9753d6SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
53443e9753d6SMatthew G. Knepley     PetscInt       i;
53453e9753d6SMatthew G. Knepley 
53469566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x));
53473e9753d6SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
53489566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x));
53493e9753d6SMatthew G. Knepley     if (X_t) {
53509566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t));
53513e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
53529566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t));
53533e9753d6SMatthew G. Knepley     }
53543e9753d6SMatthew G. Knepley     if (dmAux) {
53553e9753d6SMatthew G. Knepley       PetscInt subcell;
53569566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell));
53579566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x));
53583e9753d6SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
53599566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x));
53603e9753d6SMatthew G. Knepley     }
53613e9753d6SMatthew G. Knepley   }
53629566063dSJacob Faibussowitsch   if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim));
53639566063dSJacob Faibussowitsch   if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim));
53649566063dSJacob Faibussowitsch   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim));
53653e9753d6SMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
53663e9753d6SMatthew G. Knepley     PetscClassId    id;
53673e9753d6SMatthew G. Knepley     PetscFE         fe;
53683e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
53693e9753d6SMatthew G. Knepley     PetscInt        Nb;
53703e9753d6SMatthew G. Knepley     /* Conforming batches */
53713e9753d6SMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
53723e9753d6SMatthew G. Knepley     /* Remainder */
53733e9753d6SMatthew G. Knepley     PetscInt     Nr, offset, Nq;
53743e9753d6SMatthew G. Knepley     PetscInt     maxDegree;
53753e9753d6SMatthew G. Knepley     PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
53763e9753d6SMatthew G. Knepley 
53779566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
53789566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
53799371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) {
53809371c9d4SSatish Balay       hasFV = PETSC_TRUE;
53819371c9d4SSatish Balay       continue;
53829371c9d4SSatish Balay     }
53839566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
53849566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
53859566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
538648a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
53873e9753d6SMatthew G. Knepley     if (!qGeom) {
53889566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
53899566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
53903e9753d6SMatthew G. Knepley     }
53919566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
53929566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
53933e9753d6SMatthew G. Knepley     blockSize = Nb;
53943e9753d6SMatthew G. Knepley     batchSize = numBlocks * blockSize;
53959566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
53963e9753d6SMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
53973e9753d6SMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
53983e9753d6SMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
53993e9753d6SMatthew G. Knepley     offset    = numCells - Nr;
54009566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
54019566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
54023e9753d6SMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
54036528b96dSMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
54043e9753d6SMatthew G. Knepley       if (hasJac) {
54059566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
54069566063dSJacob Faibussowitsch         PetscCall(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]));
54073e9753d6SMatthew G. Knepley       }
54083e9753d6SMatthew G. Knepley       if (hasPrec) {
54099566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP));
54109566063dSJacob Faibussowitsch         PetscCall(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]));
54113e9753d6SMatthew G. Knepley       }
54123e9753d6SMatthew G. Knepley       if (hasDyn) {
54139566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD));
54149566063dSJacob Faibussowitsch         PetscCall(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]));
54153e9753d6SMatthew G. Knepley       }
54163e9753d6SMatthew G. Knepley     }
54179566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
54189566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
54199566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
54209566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
54213e9753d6SMatthew G. Knepley   }
54223e9753d6SMatthew G. Knepley   /*   Add contribution from X_t */
54239371c9d4SSatish Balay   if (hasDyn) {
54249371c9d4SSatish Balay     for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
54259371c9d4SSatish Balay   }
54263e9753d6SMatthew G. Knepley   if (hasFV) {
54273e9753d6SMatthew G. Knepley     PetscClassId id;
54283e9753d6SMatthew G. Knepley     PetscFV      fv;
54293e9753d6SMatthew G. Knepley     PetscInt     offsetI, NcI, NbI = 1, fc, f;
54303e9753d6SMatthew G. Knepley 
54313e9753d6SMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
54329566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv));
54339566063dSJacob Faibussowitsch       PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI));
54349566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId((PetscObject)fv, &id));
54353e9753d6SMatthew G. Knepley       if (id != PETSCFV_CLASSID) continue;
54363e9753d6SMatthew G. Knepley       /* Put in the identity */
54379566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &NcI));
54383e9753d6SMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
54393e9753d6SMatthew G. Knepley         const PetscInt cind    = c - cStart;
54403e9753d6SMatthew G. Knepley         const PetscInt eOffset = cind * totDim * totDim;
54413e9753d6SMatthew G. Knepley         for (fc = 0; fc < NcI; ++fc) {
54423e9753d6SMatthew G. Knepley           for (f = 0; f < NbI; ++f) {
54433e9753d6SMatthew G. Knepley             const PetscInt i = offsetI + f * NcI + fc;
54443e9753d6SMatthew G. Knepley             if (hasPrec) {
5445ad540459SPierre Jolivet               if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
54463e9753d6SMatthew G. Knepley               elemMatP[eOffset + i * totDim + i] = 1.0;
54479371c9d4SSatish Balay             } else {
54489371c9d4SSatish Balay               elemMat[eOffset + i * totDim + i] = 1.0;
54499371c9d4SSatish Balay             }
54503e9753d6SMatthew G. Knepley           }
54513e9753d6SMatthew G. Knepley         }
54523e9753d6SMatthew G. Knepley       }
54533e9753d6SMatthew G. Knepley     }
54543e9753d6SMatthew G. Knepley     /* No allocated space for FV stuff, so ignore the zero entries */
54559566063dSJacob Faibussowitsch     PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
54563e9753d6SMatthew G. Knepley   }
54573e9753d6SMatthew G. Knepley   /* Insert values into matrix */
54583e9753d6SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
54593e9753d6SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
54603e9753d6SMatthew G. Knepley     const PetscInt cind = c - cStart;
54613e9753d6SMatthew G. Knepley 
54623e9753d6SMatthew G. Knepley     /* Transform to global basis before insertion in Jacobian */
54639566063dSJacob Faibussowitsch     if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim]));
54643e9753d6SMatthew G. Knepley     if (hasPrec) {
54653e9753d6SMatthew G. Knepley       if (hasJac) {
54669566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
54679566063dSJacob Faibussowitsch         PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
54683e9753d6SMatthew G. Knepley       }
54699566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim]));
54709566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES));
54713e9753d6SMatthew G. Knepley     } else {
54723e9753d6SMatthew G. Knepley       if (hasJac) {
54739566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
54749566063dSJacob Faibussowitsch         PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
54753e9753d6SMatthew G. Knepley       }
54763e9753d6SMatthew G. Knepley     }
54773e9753d6SMatthew G. Knepley   }
54789566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
54799566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
54809566063dSJacob Faibussowitsch   PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD));
54813e9753d6SMatthew G. Knepley   if (dmAux) {
54829566063dSJacob Faibussowitsch     PetscCall(PetscFree(a));
54839566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&plex));
54843e9753d6SMatthew G. Knepley   }
54853e9753d6SMatthew G. Knepley   /* Compute boundary integrals */
54869566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user));
54873e9753d6SMatthew G. Knepley   /* Assemble matrix */
54889371c9d4SSatish Balay end : {
5489e04ae0b4SMatthew G. Knepley   PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp;
5490e04ae0b4SMatthew G. Knepley 
5491e04ae0b4SMatthew G. Knepley   PetscCallMPI(MPI_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
54923e9753d6SMatthew G. Knepley   if (hasJac && hasPrec) {
54939566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
54949566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
54953e9753d6SMatthew G. Knepley   }
5496e04ae0b4SMatthew G. Knepley }
54979566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
54989566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
54999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
55003e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
55013e9753d6SMatthew G. Knepley }
55023e9753d6SMatthew G. Knepley 
5503d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user)
5504d71ae5a4SJacob Faibussowitsch {
55053e9753d6SMatthew G. Knepley   DM_Plex        *mesh          = (DM_Plex *)dm->data;
55063e9753d6SMatthew G. Knepley   const char     *name          = "Hybrid Jacobian";
5507148442b3SMatthew G. Knepley   DM              dmAux[3]      = {NULL, NULL, NULL};
5508148442b3SMatthew G. Knepley   DMLabel         ghostLabel    = NULL;
55093e9753d6SMatthew G. Knepley   DM              plex          = NULL;
55103e9753d6SMatthew G. Knepley   DM              plexA         = NULL;
5511148442b3SMatthew G. Knepley   PetscDS         ds            = NULL;
5512148442b3SMatthew G. Knepley   PetscDS         dsAux[3]      = {NULL, NULL, NULL};
5513148442b3SMatthew G. Knepley   Vec             locA[3]       = {NULL, NULL, NULL};
55143e9753d6SMatthew G. Knepley   PetscSection    section       = NULL;
5515148442b3SMatthew G. Knepley   PetscSection    sectionAux[3] = {NULL, NULL, NULL};
55163e9753d6SMatthew G. Knepley   DMField         coordField    = NULL;
5517148442b3SMatthew G. Knepley   PetscScalar    *u             = NULL, *u_t, *a[3];
55183e9753d6SMatthew G. Knepley   PetscScalar    *elemMat, *elemMatP;
5519e432b41dSStefano Zampini   PetscSection    globalSection;
55203e9753d6SMatthew G. Knepley   IS              chunkIS;
55213e9753d6SMatthew G. Knepley   const PetscInt *cells;
55223e9753d6SMatthew G. Knepley   PetscInt       *faces;
55233e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
5524148442b3SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk;
55253e9753d6SMatthew G. Knepley   PetscInt        maxDegree  = PETSC_MAX_INT;
55263e9753d6SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
55273e9753d6SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
5528e432b41dSStefano Zampini   PetscBool       hasBdJac, hasBdPrec;
55293e9753d6SMatthew G. Knepley 
55303e9753d6SMatthew G. Knepley   PetscFunctionBegin;
55315fedec97SMatthew G. Knepley   if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
55325fedec97SMatthew G. Knepley     const char *name;
55339566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name));
553463a3b9bcSJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part);
55355fedec97SMatthew G. Knepley   }
55369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
55379566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
55389566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
55399566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
55409566063dSJacob Faibussowitsch   PetscCall(DMGetSection(dm, &section));
55419566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
55429566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
55431059d808SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds));
55449566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
55459566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
55469566063dSJacob Faibussowitsch   PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac));
55479566063dSJacob Faibussowitsch   PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec));
55489566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]));
5549148442b3SMatthew G. Knepley   if (locA[2]) {
55501059d808SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
55511059d808SMatthew G. Knepley 
55529566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA[2], &dmAux[2]));
55539566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA));
55549566063dSJacob Faibussowitsch     PetscCall(DMGetSection(dmAux[2], &sectionAux[2]));
55551059d808SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2]));
55569566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]));
5557148442b3SMatthew G. Knepley     {
5558148442b3SMatthew G. Knepley       const PetscInt *cone;
5559148442b3SMatthew G. Knepley       PetscInt        c;
5560148442b3SMatthew G. Knepley 
55611059d808SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
5562148442b3SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
5563148442b3SMatthew G. Knepley         const PetscInt *support;
5564148442b3SMatthew G. Knepley         PetscInt        ssize, s;
5565148442b3SMatthew G. Knepley 
55669566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
55679566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
55681059d808SMatthew G. Knepley         PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[c], cellStart, ssize);
55691059d808SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
55701059d808SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
55711059d808SMatthew G. Knepley         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart);
55729566063dSJacob Faibussowitsch         PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]));
55739566063dSJacob Faibussowitsch         if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c]));
5574ad540459SPierre Jolivet         else dmAux[c] = dmAux[2];
55759566063dSJacob Faibussowitsch         PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c]));
55769566063dSJacob Faibussowitsch         PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]));
5577148442b3SMatthew G. Knepley       }
5578148442b3SMatthew G. Knepley     }
55793e9753d6SMatthew G. Knepley   }
55809566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
55819566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
55823e9753d6SMatthew G. Knepley   if (maxDegree > 1) {
55833e9753d6SMatthew G. Knepley     PetscInt f;
55849566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
55853e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
55863e9753d6SMatthew G. Knepley       PetscFE fe;
55873e9753d6SMatthew G. Knepley 
55889566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
55893e9753d6SMatthew G. Knepley       if (fe) {
55909566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
55919566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)quads[f]));
55923e9753d6SMatthew G. Knepley       }
55933e9753d6SMatthew G. Knepley     }
55943e9753d6SMatthew G. Knepley   }
55953e9753d6SMatthew G. Knepley   cellChunkSize = numCells;
55963e9753d6SMatthew G. Knepley   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
5597a4158a15SMatthew G. Knepley   PetscCall(PetscCalloc1(1 * cellChunkSize, &faces));
5598a4158a15SMatthew G. Knepley   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS));
55999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
56009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a));
56019566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat));
56029566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP));
56033e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
56043e9753d6SMatthew G. Knepley     PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
56053e9753d6SMatthew G. Knepley 
56069566063dSJacob Faibussowitsch     if (hasBdJac) PetscCall(PetscMemzero(elemMat, numCells * totDim * totDim * sizeof(PetscScalar)));
56079566063dSJacob Faibussowitsch     if (hasBdPrec) PetscCall(PetscMemzero(elemMatP, numCells * totDim * totDim * sizeof(PetscScalar)));
56083e9753d6SMatthew G. Knepley     /* Get faces */
56093e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
56103e9753d6SMatthew G. Knepley       const PetscInt  cell = cells ? cells[c] : c;
56113e9753d6SMatthew G. Knepley       const PetscInt *cone;
56129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(plex, cell, &cone));
5613a4158a15SMatthew G. Knepley       faces[0 * cellChunkSize + (c - cS)] = cone[0];
5614a4158a15SMatthew G. Knepley       /*faces[2*cellChunkSize+(c-cS)] = cone[1];*/
56153e9753d6SMatthew G. Knepley     }
5616a4158a15SMatthew G. Knepley     PetscCall(ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER));
56173e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
56189566063dSJacob Faibussowitsch       if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad));
56199566063dSJacob Faibussowitsch       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom));
56203e9753d6SMatthew G. Knepley     } else {
56213e9753d6SMatthew G. Knepley       PetscInt f;
56223e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
56239566063dSJacob Faibussowitsch         if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]));
56243e9753d6SMatthew G. Knepley       }
56253e9753d6SMatthew G. Knepley     }
56263e9753d6SMatthew G. Knepley 
56273e9753d6SMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
56283e9753d6SMatthew G. Knepley       PetscFE         feI;
56293e9753d6SMatthew G. Knepley       PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[fieldI];
56303e9753d6SMatthew G. Knepley       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
56313e9753d6SMatthew G. Knepley       PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
56323e9753d6SMatthew G. Knepley       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
56335fedec97SMatthew G. Knepley       PetscBool       isCohesiveField;
56343e9753d6SMatthew G. Knepley 
56359566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
56363e9753d6SMatthew G. Knepley       if (!feI) continue;
56379566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches));
56389566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
56399566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feI, &Nb));
56403e9753d6SMatthew G. Knepley       blockSize = Nb;
56413e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
56429566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches));
56433e9753d6SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
56443e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
56453e9753d6SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
56463e9753d6SMatthew G. Knepley       offset    = numCells - Nr;
56479566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
56489566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &remGeom));
56499566063dSJacob Faibussowitsch       PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField));
56503e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
56513e9753d6SMatthew G. Knepley         PetscFE feJ;
56523e9753d6SMatthew G. Knepley 
56539566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
56543e9753d6SMatthew G. Knepley         if (!feJ) continue;
5655148442b3SMatthew G. Knepley         key[0].field = fieldI * Nf + fieldJ;
5656148442b3SMatthew G. Knepley         key[1].field = fieldI * Nf + fieldJ;
56575fedec97SMatthew G. Knepley         key[2].field = fieldI * Nf + fieldJ;
5658148442b3SMatthew G. Knepley         if (hasBdJac) {
56599566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat));
56609566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMat[offset * totDim * totDim]));
56619566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat));
56629566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMat[offset * totDim * totDim]));
5663148442b3SMatthew G. Knepley         }
5664148442b3SMatthew G. Knepley         if (hasBdPrec) {
56659566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP));
56669566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatP[offset * totDim * totDim]));
56679566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP));
56689566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatP[offset * totDim * totDim]));
5669148442b3SMatthew G. Knepley         }
56705fedec97SMatthew G. Knepley         if (hasBdJac) {
56719566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat));
56729566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMat[offset * totDim * totDim]));
5673148442b3SMatthew G. Knepley         }
56745fedec97SMatthew G. Knepley         if (hasBdPrec) {
56759566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP));
56769566063dSJacob Faibussowitsch           PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatP[offset * totDim * totDim]));
56773e9753d6SMatthew G. Knepley         }
56783e9753d6SMatthew G. Knepley       }
56799566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom));
56809566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom));
56813e9753d6SMatthew G. Knepley     }
56823e9753d6SMatthew G. Knepley     /* Insert values into matrix */
56833e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
56843e9753d6SMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
56853e9753d6SMatthew G. Knepley       const PetscInt cind = c - cS;
56863e9753d6SMatthew G. Knepley 
56873e9753d6SMatthew G. Knepley       if (hasBdPrec) {
56883e9753d6SMatthew G. Knepley         if (hasBdJac) {
56899566063dSJacob Faibussowitsch           if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
56909566063dSJacob Faibussowitsch           PetscCall(DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
56913e9753d6SMatthew G. Knepley         }
56929566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim]));
56939566063dSJacob Faibussowitsch         PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES));
56943e9753d6SMatthew G. Knepley       } else if (hasBdJac) {
56959566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
56969566063dSJacob Faibussowitsch         PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
56973e9753d6SMatthew G. Knepley       }
56983e9753d6SMatthew G. Knepley     }
56993e9753d6SMatthew G. Knepley   }
57009566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
57019566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a));
57029566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat));
57039566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP));
57049566063dSJacob Faibussowitsch   PetscCall(PetscFree(faces));
57059566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&chunkIS));
57069566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
57073e9753d6SMatthew G. Knepley   if (maxDegree <= 1) {
57089566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
57099566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&affineQuad));
57103e9753d6SMatthew G. Knepley   } else {
57113e9753d6SMatthew G. Knepley     PetscInt f;
57123e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
57139566063dSJacob Faibussowitsch       if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
57149566063dSJacob Faibussowitsch       if (quads) PetscCall(PetscQuadratureDestroy(&quads[f]));
57153e9753d6SMatthew G. Knepley     }
57169566063dSJacob Faibussowitsch     PetscCall(PetscFree2(quads, geoms));
57173e9753d6SMatthew G. Knepley   }
57189566063dSJacob Faibussowitsch   if (dmAux[2]) PetscCall(DMDestroy(&plexA));
57199566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
57209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
57213e9753d6SMatthew G. Knepley   PetscFunctionReturn(0);
57223e9753d6SMatthew G. Knepley }
57238e3a2eefSMatthew G. Knepley 
57248e3a2eefSMatthew G. Knepley /*
57258e3a2eefSMatthew G. Knepley   DMPlexComputeJacobian_Action_Internal - Form the local portion of the Jacobian action Z = J(X) Y at the local solution X using pointwise functions specified by the user.
57268e3a2eefSMatthew G. Knepley 
57278e3a2eefSMatthew G. Knepley   Input Parameters:
57288e3a2eefSMatthew G. Knepley + dm     - The mesh
57298e3a2eefSMatthew G. Knepley . key    - The PetscWeakFormKey indcating where integration should happen
573006ad1575SMatthew G. Knepley . cellIS - The cells to integrate over
57318e3a2eefSMatthew G. Knepley . t      - The time
57328e3a2eefSMatthew G. Knepley . X_tShift - The multiplier for the Jacobian with repsect to X_t
57338e3a2eefSMatthew G. Knepley . X      - Local solution vector
57348e3a2eefSMatthew G. Knepley . X_t    - Time-derivative of the local solution vector
57358e3a2eefSMatthew G. Knepley . Y      - Local input vector
573606ad1575SMatthew G. Knepley - user   - the user context
57378e3a2eefSMatthew G. Knepley 
57388e3a2eefSMatthew G. Knepley   Output Parameter:
57398e3a2eefSMatthew G. Knepley . Z - Local output vector
57408e3a2eefSMatthew G. Knepley 
57418e3a2eefSMatthew G. Knepley   Note:
57428e3a2eefSMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
57438e3a2eefSMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
57448e3a2eefSMatthew G. Knepley */
5745d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeJacobian_Action_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Vec Y, Vec Z, void *user)
5746d71ae5a4SJacob Faibussowitsch {
57478e3a2eefSMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
57488e3a2eefSMatthew G. Knepley   const char     *name  = "Jacobian";
57498e3a2eefSMatthew G. Knepley   DM              dmAux = NULL, plex, plexAux = NULL;
57508e3a2eefSMatthew G. Knepley   DMEnclosureType encAux;
57518e3a2eefSMatthew G. Knepley   Vec             A;
57528e3a2eefSMatthew G. Knepley   DMField         coordField;
57538e3a2eefSMatthew G. Knepley   PetscDS         prob, probAux = NULL;
57548e3a2eefSMatthew G. Knepley   PetscQuadrature quad;
57558e3a2eefSMatthew G. Knepley   PetscSection    section, globalSection, sectionAux;
57568e3a2eefSMatthew G. Knepley   PetscScalar    *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z;
57578e3a2eefSMatthew G. Knepley   const PetscInt *cells;
57588e3a2eefSMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ;
57598e3a2eefSMatthew G. Knepley   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
57608e3a2eefSMatthew G. Knepley   PetscBool       hasDyn;
57618e3a2eefSMatthew G. Knepley 
57628e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
57639566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
57649566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
57658e3a2eefSMatthew G. Knepley   if (!cellIS) {
57668e3a2eefSMatthew G. Knepley     PetscInt depth;
57678e3a2eefSMatthew G. Knepley 
57689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(plex, &depth));
57699566063dSJacob Faibussowitsch     PetscCall(DMGetStratumIS(plex, "dim", depth, &cellIS));
57709566063dSJacob Faibussowitsch     if (!cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &cellIS));
57718e3a2eefSMatthew G. Knepley   } else {
57729566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)cellIS));
57738e3a2eefSMatthew G. Knepley   }
57749566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
57759566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
57769566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
57779566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
57789566063dSJacob Faibussowitsch   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob));
57799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
57809566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
57819566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
57828e3a2eefSMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
57839566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A));
57848e3a2eefSMatthew G. Knepley   if (A) {
57859566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
57869566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
57879566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexAux));
57889566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexAux, &sectionAux));
57899566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
57909566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
57918e3a2eefSMatthew G. Knepley   }
57929566063dSJacob Faibussowitsch   PetscCall(VecSet(Z, 0.0));
57939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, numCells * totDim * totDim, &elemMat, hasDyn ? numCells * totDim * totDim : 0, &elemMatD, numCells * totDim, &y, totDim, &z));
57949566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
57959566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
57968e3a2eefSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
57978e3a2eefSMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
57988e3a2eefSMatthew G. Knepley     const PetscInt cind = c - cStart;
57998e3a2eefSMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
58008e3a2eefSMatthew G. Knepley     PetscInt       i;
58018e3a2eefSMatthew G. Knepley 
58029566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x));
58038e3a2eefSMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
58049566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x));
58058e3a2eefSMatthew G. Knepley     if (X_t) {
58069566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t));
58078e3a2eefSMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
58089566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t));
58098e3a2eefSMatthew G. Knepley     }
58108e3a2eefSMatthew G. Knepley     if (dmAux) {
58118e3a2eefSMatthew G. Knepley       PetscInt subcell;
58129566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell));
58139566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x));
58148e3a2eefSMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
58159566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x));
58168e3a2eefSMatthew G. Knepley     }
58179566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x));
58188e3a2eefSMatthew G. Knepley     for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i];
58199566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x));
58208e3a2eefSMatthew G. Knepley   }
58219566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim));
58229566063dSJacob Faibussowitsch   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim));
58238e3a2eefSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
58248e3a2eefSMatthew G. Knepley     PetscFE  fe;
58258e3a2eefSMatthew G. Knepley     PetscInt Nb;
58268e3a2eefSMatthew G. Knepley     /* Conforming batches */
58278e3a2eefSMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
58288e3a2eefSMatthew G. Knepley     /* Remainder */
58298e3a2eefSMatthew G. Knepley     PetscInt        Nr, offset, Nq;
58308e3a2eefSMatthew G. Knepley     PetscQuadrature qGeom = NULL;
58318e3a2eefSMatthew G. Knepley     PetscInt        maxDegree;
58328e3a2eefSMatthew G. Knepley     PetscFEGeom    *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
58338e3a2eefSMatthew G. Knepley 
58349566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
58359566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &quad));
58369566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
58379566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
58389566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
58399566063dSJacob Faibussowitsch     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
58408e3a2eefSMatthew G. Knepley     if (!qGeom) {
58419566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
58429566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
58438e3a2eefSMatthew G. Knepley     }
58449566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
58459566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
58468e3a2eefSMatthew G. Knepley     blockSize = Nb;
58478e3a2eefSMatthew G. Knepley     batchSize = numBlocks * blockSize;
58489566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
58498e3a2eefSMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
58508e3a2eefSMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
58518e3a2eefSMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
58528e3a2eefSMatthew G. Knepley     offset    = numCells - Nr;
58539566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
58549566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
58558e3a2eefSMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
58568e3a2eefSMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
58579566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
58589566063dSJacob Faibussowitsch       PetscCall(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]));
58598e3a2eefSMatthew G. Knepley       if (hasDyn) {
58609566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD));
58619566063dSJacob Faibussowitsch         PetscCall(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]));
58628e3a2eefSMatthew G. Knepley       }
58638e3a2eefSMatthew G. Knepley     }
58649566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
58659566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
58669566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
58679566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
58688e3a2eefSMatthew G. Knepley   }
58698e3a2eefSMatthew G. Knepley   if (hasDyn) {
58708e3a2eefSMatthew G. Knepley     for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
58718e3a2eefSMatthew G. Knepley   }
58728e3a2eefSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
58738e3a2eefSMatthew G. Knepley     const PetscInt     cell = cells ? cells[c] : c;
58748e3a2eefSMatthew G. Knepley     const PetscInt     cind = c - cStart;
58758e3a2eefSMatthew G. Knepley     const PetscBLASInt M = totDim, one = 1;
58768e3a2eefSMatthew G. Knepley     const PetscScalar  a = 1.0, b = 0.0;
58778e3a2eefSMatthew G. Knepley 
5878792fecdfSBarry Smith     PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one));
58798e3a2eefSMatthew G. Knepley     if (mesh->printFEM > 1) {
58809566063dSJacob Faibussowitsch       PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
58819566063dSJacob Faibussowitsch       PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim]));
58829566063dSJacob Faibussowitsch       PetscCall(DMPrintCellVector(c, "Z", totDim, z));
58838e3a2eefSMatthew G. Knepley     }
58849566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES));
58858e3a2eefSMatthew G. Knepley   }
58869566063dSJacob Faibussowitsch   PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z));
58878e3a2eefSMatthew G. Knepley   if (mesh->printFEM) {
58889566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n"));
58899566063dSJacob Faibussowitsch     PetscCall(VecView(Z, NULL));
58908e3a2eefSMatthew G. Knepley   }
58911059d808SMatthew G. Knepley   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
58929566063dSJacob Faibussowitsch   PetscCall(PetscFree(a));
58939566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
58949566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plexAux));
58959566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
58969566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
58978e3a2eefSMatthew G. Knepley   PetscFunctionReturn(0);
58988e3a2eefSMatthew G. Knepley }
5899