xref: /petsc/src/dm/impls/plex/plexfem.c (revision fe8e7ddd93caa3d7f6fe6c2e358c1c3f5a39763e)
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   }
463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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   }
783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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;
853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
869b6f715bSMatthew G. Knepley }
879b6f715bSMatthew G. Knepley 
8846fa42a0SMatthew G. Knepley /*@
8946fa42a0SMatthew G. Knepley   DMPlexGetScale - Get the scale for the specified fundamental unit
9046fa42a0SMatthew G. Knepley 
9120f4b53cSBarry Smith   Not Collective
9246fa42a0SMatthew G. Knepley 
934165533cSJose E. Roman   Input Parameters:
94a1cb98faSBarry 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 
1021cc06b55SBarry Smith .seealso: [](ch_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);
1104f572ea9SToby Isaac   PetscAssertPointer(scale, 3);
111cb1e1211SMatthew G Knepley   *scale = mesh->scale[unit];
1123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
113cb1e1211SMatthew G Knepley }
114cb1e1211SMatthew G Knepley 
11546fa42a0SMatthew G. Knepley /*@
11646fa42a0SMatthew G. Knepley   DMPlexSetScale - Set the scale for the specified fundamental unit
11746fa42a0SMatthew G. Knepley 
11820f4b53cSBarry Smith   Not Collective
11946fa42a0SMatthew G. Knepley 
1204165533cSJose E. Roman   Input Parameters:
121a1cb98faSBarry 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 
1271cc06b55SBarry Smith .seealso: [](ch_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;
1363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
137cb1e1211SMatthew G Knepley }
138cb1e1211SMatthew G Knepley 
139d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed_Plex(DM dm, PetscBool *useCeed)
140d2b2dc1eSMatthew G. Knepley {
141d2b2dc1eSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
142d2b2dc1eSMatthew G. Knepley 
143d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
144d2b2dc1eSMatthew G. Knepley   *useCeed = mesh->useCeed;
145d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
146d2b2dc1eSMatthew G. Knepley }
147d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed_Plex(DM dm, PetscBool useCeed)
148d2b2dc1eSMatthew G. Knepley {
149d2b2dc1eSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
150d2b2dc1eSMatthew G. Knepley 
151d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
152d2b2dc1eSMatthew G. Knepley   mesh->useCeed = useCeed;
153d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
154d2b2dc1eSMatthew G. Knepley }
155d2b2dc1eSMatthew G. Knepley 
156d2b2dc1eSMatthew G. Knepley /*@
157d2b2dc1eSMatthew G. Knepley   DMPlexGetUseCeed - Get flag for using the LibCEED backend
158d2b2dc1eSMatthew G. Knepley 
159d2b2dc1eSMatthew G. Knepley   Not collective
160d2b2dc1eSMatthew G. Knepley 
161d2b2dc1eSMatthew G. Knepley   Input Parameter:
162d2b2dc1eSMatthew G. Knepley . dm - The `DM`
163d2b2dc1eSMatthew G. Knepley 
164d2b2dc1eSMatthew G. Knepley   Output Parameter:
165d2b2dc1eSMatthew G. Knepley . useCeed - The flag
166d2b2dc1eSMatthew G. Knepley 
167d2b2dc1eSMatthew G. Knepley   Level: intermediate
168d2b2dc1eSMatthew G. Knepley 
169d2b2dc1eSMatthew G. Knepley .seealso: `DMPlexSetUseCeed()`
170d2b2dc1eSMatthew G. Knepley @*/
171d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed(DM dm, PetscBool *useCeed)
172d2b2dc1eSMatthew G. Knepley {
173d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
174d2b2dc1eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
175d2b2dc1eSMatthew G. Knepley   PetscAssertPointer(useCeed, 2);
176d2b2dc1eSMatthew G. Knepley   *useCeed = PETSC_FALSE;
177d2b2dc1eSMatthew G. Knepley   PetscTryMethod(dm, "DMPlexGetUseCeed_C", (DM, PetscBool *), (dm, useCeed));
178d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
179d2b2dc1eSMatthew G. Knepley }
180d2b2dc1eSMatthew G. Knepley 
181d2b2dc1eSMatthew G. Knepley /*@
182d2b2dc1eSMatthew G. Knepley   DMPlexSetUseCeed - Set flag for using the LibCEED backend
183d2b2dc1eSMatthew G. Knepley 
184d2b2dc1eSMatthew G. Knepley   Not collective
185d2b2dc1eSMatthew G. Knepley 
186d2b2dc1eSMatthew G. Knepley   Input Parameters:
187d2b2dc1eSMatthew G. Knepley + dm      - The `DM`
188d2b2dc1eSMatthew G. Knepley - useCeed - The flag
189d2b2dc1eSMatthew G. Knepley 
190d2b2dc1eSMatthew G. Knepley   Level: intermediate
191d2b2dc1eSMatthew G. Knepley 
192*fe8e7dddSPierre Jolivet .seealso: `DMPlexGetUseCeed()`
193d2b2dc1eSMatthew G. Knepley @*/
194d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed(DM dm, PetscBool useCeed)
195d2b2dc1eSMatthew G. Knepley {
196d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
197d2b2dc1eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
198d2b2dc1eSMatthew G. Knepley   PetscValidLogicalCollectiveBool(dm, useCeed, 2);
199d2b2dc1eSMatthew G. Knepley   PetscUseMethod(dm, "DMPlexSetUseCeed_C", (DM, PetscBool), (dm, useCeed));
200d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
201d2b2dc1eSMatthew G. Knepley }
202d2b2dc1eSMatthew G. Knepley 
203e8e188d2SZach Atkins /*@
204e8e188d2SZach Atkins   DMPlexGetUseMatClosurePermutation - Get flag for using a closure permutation for matrix insertion
205e8e188d2SZach Atkins 
206e8e188d2SZach Atkins   Not collective
207e8e188d2SZach Atkins 
208e8e188d2SZach Atkins   Input Parameter:
209e8e188d2SZach Atkins . dm - The `DM`
210e8e188d2SZach Atkins 
211e8e188d2SZach Atkins   Output Parameter:
212e8e188d2SZach Atkins . useClPerm - The flag
213e8e188d2SZach Atkins 
214e8e188d2SZach Atkins   Level: intermediate
215e8e188d2SZach Atkins 
216e8e188d2SZach Atkins .seealso: `DMPlexSetUseMatClosurePermutation()`
217e8e188d2SZach Atkins @*/
218e8e188d2SZach Atkins PetscErrorCode DMPlexGetUseMatClosurePermutation(DM dm, PetscBool *useClPerm)
219e8e188d2SZach Atkins {
220e8e188d2SZach Atkins   DM_Plex *mesh = (DM_Plex *)dm->data;
221e8e188d2SZach Atkins 
222e8e188d2SZach Atkins   PetscFunctionBegin;
223e8e188d2SZach Atkins   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
224e8e188d2SZach Atkins   PetscAssertPointer(useClPerm, 2);
225e8e188d2SZach Atkins   *useClPerm = mesh->useMatClPerm;
226e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
227e8e188d2SZach Atkins }
228e8e188d2SZach Atkins 
229e8e188d2SZach Atkins /*@
230e8e188d2SZach Atkins   DMPlexSetUseMatClosurePermutation - Set flag for using a closure permutation for matrix insertion
231e8e188d2SZach Atkins 
232e8e188d2SZach Atkins   Not collective
233e8e188d2SZach Atkins 
234e8e188d2SZach Atkins   Input Parameters:
235e8e188d2SZach Atkins + dm        - The `DM`
236e8e188d2SZach Atkins - useClPerm - The flag
237e8e188d2SZach Atkins 
238e8e188d2SZach Atkins   Level: intermediate
239e8e188d2SZach Atkins 
240e8e188d2SZach Atkins .seealso: `DMPlexGetUseMatClosurePermutation()`
241e8e188d2SZach Atkins @*/
242e8e188d2SZach Atkins PetscErrorCode DMPlexSetUseMatClosurePermutation(DM dm, PetscBool useClPerm)
243e8e188d2SZach Atkins {
244e8e188d2SZach Atkins   DM_Plex *mesh = (DM_Plex *)dm->data;
245e8e188d2SZach Atkins 
246e8e188d2SZach Atkins   PetscFunctionBegin;
247e8e188d2SZach Atkins   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
248e8e188d2SZach Atkins   PetscValidLogicalCollectiveBool(dm, useClPerm, 2);
249e8e188d2SZach Atkins   mesh->useMatClPerm = useClPerm;
250e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
251e8e188d2SZach Atkins }
252e8e188d2SZach Atkins 
253d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx)
254d71ae5a4SJacob Faibussowitsch {
2559371c9d4SSatish Balay   const PetscInt eps[3][3][3] = {
2569371c9d4SSatish Balay     {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
2579371c9d4SSatish Balay     {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
2589371c9d4SSatish Balay     {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
2599371c9d4SSatish Balay   };
260026175e5SToby Isaac   PetscInt *ctxInt = (PetscInt *)ctx;
261ad917190SMatthew G. Knepley   PetscInt  dim2   = ctxInt[0];
262026175e5SToby Isaac   PetscInt  d      = ctxInt[1];
263026175e5SToby Isaac   PetscInt  i, j, k = dim > 2 ? d - dim : d;
264026175e5SToby Isaac 
265ad917190SMatthew G. Knepley   PetscFunctionBegin;
26663a3b9bcSJacob Faibussowitsch   PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2);
267026175e5SToby Isaac   for (i = 0; i < dim; i++) mode[i] = 0.;
268026175e5SToby Isaac   if (d < dim) {
26912adca46SMatthew G. Knepley     mode[d] = 1.; /* Translation along axis d */
270ad917190SMatthew G. Knepley   } else {
271026175e5SToby Isaac     for (i = 0; i < dim; i++) {
2729371c9d4SSatish Balay       for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ }
273026175e5SToby Isaac     }
274026175e5SToby Isaac   }
2753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
276026175e5SToby Isaac }
277026175e5SToby Isaac 
278cc4e42d9SMartin Diehl /*@
27912adca46SMatthew G. Knepley   DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation
280cb1e1211SMatthew G Knepley 
28120f4b53cSBarry Smith   Collective
282cb1e1211SMatthew G Knepley 
2834165533cSJose E. Roman   Input Parameters:
284a1cb98faSBarry Smith + dm    - the `DM`
28556cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default
286cb1e1211SMatthew G Knepley 
2874165533cSJose E. Roman   Output Parameter:
288cb1e1211SMatthew G Knepley . sp - the null space
289cb1e1211SMatthew G Knepley 
290cb1e1211SMatthew G Knepley   Level: advanced
291cb1e1211SMatthew G Knepley 
292a1cb98faSBarry Smith   Note:
293a1cb98faSBarry Smith   This is necessary to provide a suitable coarse space for algebraic multigrid
294a1cb98faSBarry Smith 
2951cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG`
296cb1e1211SMatthew G Knepley @*/
297d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp)
298d71ae5a4SJacob Faibussowitsch {
29956cf3b9cSMatthew G. Knepley   PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
300cb1e1211SMatthew G Knepley   MPI_Comm     comm;
301026175e5SToby Isaac   Vec          mode[6];
302026175e5SToby Isaac   PetscSection section, globalSection;
30356cf3b9cSMatthew G. Knepley   PetscInt     dim, dimEmbed, Nf, n, m, mmin, d, i, j;
304db14aad5SMatthew G. Knepley   void       **ctxs;
305cb1e1211SMatthew G Knepley 
306cb1e1211SMatthew G Knepley   PetscFunctionBegin;
3079566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3089566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
3109566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
31163a3b9bcSJacob Faibussowitsch   PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf);
31256cf3b9cSMatthew G. Knepley   if (dim == 1 && Nf < 2) {
3139566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp));
3143ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
315cb1e1211SMatthew G Knepley   }
3169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
3179566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
3189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n));
319db14aad5SMatthew G. Knepley   PetscCall(PetscCalloc2(Nf, &func, Nf, &ctxs));
320b247467aSMatthew G. Knepley   m = (dim * (dim + 1)) / 2;
3219566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &mode[0]));
3229566063dSJacob Faibussowitsch   PetscCall(VecSetType(mode[0], dm->vectype));
3239566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE));
3249566063dSJacob Faibussowitsch   PetscCall(VecSetUp(mode[0]));
3259566063dSJacob Faibussowitsch   PetscCall(VecGetSize(mode[0], &n));
326b247467aSMatthew G. Knepley   mmin        = PetscMin(m, n);
32756cf3b9cSMatthew G. Knepley   func[field] = DMPlexProjectRigidBody_Private;
3289566063dSJacob Faibussowitsch   for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i]));
329026175e5SToby Isaac   for (d = 0; d < m; d++) {
330330485fdSToby Isaac     PetscInt ctx[2];
331cb1e1211SMatthew G Knepley 
332db14aad5SMatthew G. Knepley     ctxs[field] = (void *)(&ctx[0]);
3339d8fbdeaSMatthew G. Knepley     ctx[0]      = dimEmbed;
334330485fdSToby Isaac     ctx[1]      = d;
335db14aad5SMatthew G. Knepley     PetscCall(DMProjectFunction(dm, 0.0, func, ctxs, INSERT_VALUES, mode[d]));
336cb1e1211SMatthew G Knepley   }
3373b2202bfSJacob Faibussowitsch   /* Orthonormalize system */
338b50a2c0aSJacob Faibussowitsch   for (i = 0; i < mmin; ++i) {
339b77f2eeeSJacob Faibussowitsch     PetscScalar dots[6];
340b50a2c0aSJacob Faibussowitsch 
3419566063dSJacob Faibussowitsch     PetscCall(VecNormalize(mode[i], NULL));
3429566063dSJacob Faibussowitsch     PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1));
343b50a2c0aSJacob Faibussowitsch     for (j = i + 1; j < mmin; ++j) {
344b77f2eeeSJacob Faibussowitsch       dots[j] *= -1.0;
3459566063dSJacob Faibussowitsch       PetscCall(VecAXPY(mode[j], dots[j], mode[i]));
346b50a2c0aSJacob Faibussowitsch     }
347cb1e1211SMatthew G Knepley   }
3489566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp));
3499566063dSJacob Faibussowitsch   for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i]));
350db14aad5SMatthew G. Knepley   PetscCall(PetscFree2(func, ctxs));
3513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
352cb1e1211SMatthew G Knepley }
353cb1e1211SMatthew G Knepley 
354cc4e42d9SMartin Diehl /*@
35512adca46SMatthew G. Knepley   DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation
35612adca46SMatthew G. Knepley 
35720f4b53cSBarry Smith   Collective
35812adca46SMatthew G. Knepley 
3594165533cSJose E. Roman   Input Parameters:
360a1cb98faSBarry Smith + dm    - the `DM`
36112adca46SMatthew G. Knepley . nb    - The number of bodies
362a1cb98faSBarry Smith . label - The `DMLabel` marking each domain
36312adca46SMatthew G. Knepley . nids  - The number of ids per body
36412adca46SMatthew G. Knepley - ids   - An array of the label ids in sequence for each domain
36512adca46SMatthew G. Knepley 
3664165533cSJose E. Roman   Output Parameter:
36712adca46SMatthew G. Knepley . sp - the null space
36812adca46SMatthew G. Knepley 
36912adca46SMatthew G. Knepley   Level: advanced
37012adca46SMatthew G. Knepley 
371a1cb98faSBarry Smith   Note:
372a1cb98faSBarry Smith   This is necessary to provide a suitable coarse space for algebraic multigrid
373a1cb98faSBarry Smith 
3741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`
37512adca46SMatthew G. Knepley @*/
376d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
377d71ae5a4SJacob Faibussowitsch {
37812adca46SMatthew G. Knepley   MPI_Comm     comm;
37912adca46SMatthew G. Knepley   PetscSection section, globalSection;
38012adca46SMatthew G. Knepley   Vec         *mode;
38112adca46SMatthew G. Knepley   PetscScalar *dots;
38212adca46SMatthew G. Knepley   PetscInt     dim, dimEmbed, n, m, b, d, i, j, off;
38312adca46SMatthew G. Knepley 
38412adca46SMatthew G. Knepley   PetscFunctionBegin;
3859566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3869566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3879566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
3889566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
3899566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
3909566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n));
39112adca46SMatthew G. Knepley   m = nb * (dim * (dim + 1)) / 2;
3929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(m, &mode, m, &dots));
3939566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &mode[0]));
3949566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE));
3959566063dSJacob Faibussowitsch   PetscCall(VecSetUp(mode[0]));
3969566063dSJacob Faibussowitsch   for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i]));
39712adca46SMatthew G. Knepley   for (b = 0, off = 0; b < nb; ++b) {
39812adca46SMatthew G. Knepley     for (d = 0; d < m / nb; ++d) {
39912adca46SMatthew G. Knepley       PetscInt ctx[2];
40012adca46SMatthew G. Knepley       PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
40112adca46SMatthew G. Knepley       void *voidctx                                                                                   = (void *)(&ctx[0]);
40212adca46SMatthew G. Knepley 
40312adca46SMatthew G. Knepley       ctx[0] = dimEmbed;
40412adca46SMatthew G. Knepley       ctx[1] = d;
4059566063dSJacob Faibussowitsch       PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]));
40612adca46SMatthew G. Knepley       off += nids[b];
40712adca46SMatthew G. Knepley     }
40812adca46SMatthew G. Knepley   }
4093b2202bfSJacob Faibussowitsch   /* Orthonormalize system */
410606c1a1cSJacob Faibussowitsch   for (i = 0; i < m; ++i) {
411b77f2eeeSJacob Faibussowitsch     PetscScalar dots[6];
4125a0e29b9SJacob Faibussowitsch 
4139566063dSJacob Faibussowitsch     PetscCall(VecNormalize(mode[i], NULL));
4149566063dSJacob Faibussowitsch     PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1));
4155a0e29b9SJacob Faibussowitsch     for (j = i + 1; j < m; ++j) {
416b77f2eeeSJacob Faibussowitsch       dots[j] *= -1.0;
4179566063dSJacob Faibussowitsch       PetscCall(VecAXPY(mode[j], dots[j], mode[i]));
4185a0e29b9SJacob Faibussowitsch     }
41912adca46SMatthew G. Knepley   }
4209566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp));
4219566063dSJacob Faibussowitsch   for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i]));
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree2(mode, dots));
4233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42412adca46SMatthew G. Knepley }
42512adca46SMatthew G. Knepley 
426b29cfa1cSToby Isaac /*@
427b29cfa1cSToby Isaac   DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
428b29cfa1cSToby Isaac   are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
429a4e35b19SJacob Faibussowitsch   evaluating the dual space basis of that point.
430b29cfa1cSToby Isaac 
431b29cfa1cSToby Isaac   Input Parameters:
432a1cb98faSBarry Smith + dm     - the `DMPLEX` object
433b29cfa1cSToby Isaac - height - the maximum projection height >= 0
434b29cfa1cSToby Isaac 
435b29cfa1cSToby Isaac   Level: advanced
436b29cfa1cSToby Isaac 
437a4e35b19SJacob Faibussowitsch   Notes:
438a4e35b19SJacob Faibussowitsch   A basis function is associated with the point in its transitively-closed support whose mesh
439a4e35b19SJacob Faibussowitsch   height is highest (w.r.t. DAG height), but not greater than the maximum projection height,
440a4e35b19SJacob Faibussowitsch   which is set with this function.  By default, the maximum projection height is zero, which
441a4e35b19SJacob Faibussowitsch   means that only mesh cells are used to project basis functions.  A height of one, for
442a4e35b19SJacob Faibussowitsch   example, evaluates a cell-interior basis functions using its cells dual space basis, but all
443a4e35b19SJacob Faibussowitsch   other basis functions with the dual space basis of a face.
444a4e35b19SJacob Faibussowitsch 
4451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
446b29cfa1cSToby Isaac @*/
447d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
448d71ae5a4SJacob Faibussowitsch {
449b29cfa1cSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
450b29cfa1cSToby Isaac 
451b29cfa1cSToby Isaac   PetscFunctionBegin;
452b29cfa1cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
453b29cfa1cSToby Isaac   plex->maxProjectionHeight = height;
4543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
455b29cfa1cSToby Isaac }
456b29cfa1cSToby Isaac 
457b29cfa1cSToby Isaac /*@
458b29cfa1cSToby Isaac   DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
459b29cfa1cSToby Isaac   DMPlexProjectXXXLocal() functions.
460b29cfa1cSToby Isaac 
4612fe279fdSBarry Smith   Input Parameter:
462a1cb98faSBarry Smith . dm - the `DMPLEX` object
463b29cfa1cSToby Isaac 
4642fe279fdSBarry Smith   Output Parameter:
465b29cfa1cSToby Isaac . height - the maximum projection height
466b29cfa1cSToby Isaac 
467b29cfa1cSToby Isaac   Level: intermediate
468b29cfa1cSToby Isaac 
4691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
470b29cfa1cSToby Isaac @*/
471d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
472d71ae5a4SJacob Faibussowitsch {
473b29cfa1cSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
474b29cfa1cSToby Isaac 
475b29cfa1cSToby Isaac   PetscFunctionBegin;
476b29cfa1cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
477b29cfa1cSToby Isaac   *height = plex->maxProjectionHeight;
4783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
479b29cfa1cSToby Isaac }
480b29cfa1cSToby Isaac 
481ca3d3a14SMatthew G. Knepley typedef struct {
482ca3d3a14SMatthew G. Knepley   PetscReal    alpha; /* The first Euler angle, and in 2D the only one */
483ca3d3a14SMatthew G. Knepley   PetscReal    beta;  /* The second Euler angle */
484ca3d3a14SMatthew G. Knepley   PetscReal    gamma; /* The third Euler angle */
485ca3d3a14SMatthew G. Knepley   PetscInt     dim;   /* The dimension of R */
486ca3d3a14SMatthew G. Knepley   PetscScalar *R;     /* The rotation matrix, transforming a vector in the local basis to the global basis */
487ca3d3a14SMatthew G. Knepley   PetscScalar *RT;    /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
488ca3d3a14SMatthew G. Knepley } RotCtx;
489ca3d3a14SMatthew G. Knepley 
490ca3d3a14SMatthew G. Knepley /*
491ca3d3a14SMatthew G. Knepley   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
492ca3d3a14SMatthew 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:
493ca3d3a14SMatthew 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.
494ca3d3a14SMatthew 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.
495ca3d3a14SMatthew G. Knepley   $ The XYZ system rotates a third time about the z axis by gamma.
496ca3d3a14SMatthew G. Knepley */
497d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx)
498d71ae5a4SJacob Faibussowitsch {
499ca3d3a14SMatthew G. Knepley   RotCtx   *rc  = (RotCtx *)ctx;
500ca3d3a14SMatthew G. Knepley   PetscInt  dim = rc->dim;
501ca3d3a14SMatthew G. Knepley   PetscReal c1, s1, c2, s2, c3, s3;
502ca3d3a14SMatthew G. Knepley 
503ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
5049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT));
505ca3d3a14SMatthew G. Knepley   switch (dim) {
506ca3d3a14SMatthew G. Knepley   case 2:
5079371c9d4SSatish Balay     c1       = PetscCosReal(rc->alpha);
5089371c9d4SSatish Balay     s1       = PetscSinReal(rc->alpha);
5099371c9d4SSatish Balay     rc->R[0] = c1;
5109371c9d4SSatish Balay     rc->R[1] = s1;
5119371c9d4SSatish Balay     rc->R[2] = -s1;
5129371c9d4SSatish Balay     rc->R[3] = c1;
5139566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim)));
514b458e8f1SJose E. Roman     DMPlex_Transpose2D_Internal(rc->RT);
515ca3d3a14SMatthew G. Knepley     break;
516ca3d3a14SMatthew G. Knepley   case 3:
5179371c9d4SSatish Balay     c1       = PetscCosReal(rc->alpha);
5189371c9d4SSatish Balay     s1       = PetscSinReal(rc->alpha);
5199371c9d4SSatish Balay     c2       = PetscCosReal(rc->beta);
5209371c9d4SSatish Balay     s2       = PetscSinReal(rc->beta);
5219371c9d4SSatish Balay     c3       = PetscCosReal(rc->gamma);
5229371c9d4SSatish Balay     s3       = PetscSinReal(rc->gamma);
5239371c9d4SSatish Balay     rc->R[0] = c1 * c3 - c2 * s1 * s3;
5249371c9d4SSatish Balay     rc->R[1] = c3 * s1 + c1 * c2 * s3;
5259371c9d4SSatish Balay     rc->R[2] = s2 * s3;
5269371c9d4SSatish Balay     rc->R[3] = -c1 * s3 - c2 * c3 * s1;
5279371c9d4SSatish Balay     rc->R[4] = c1 * c2 * c3 - s1 * s3;
5289371c9d4SSatish Balay     rc->R[5] = c3 * s2;
5299371c9d4SSatish Balay     rc->R[6] = s1 * s2;
5309371c9d4SSatish Balay     rc->R[7] = -c1 * s2;
5319371c9d4SSatish Balay     rc->R[8] = c2;
5329566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim)));
533b458e8f1SJose E. Roman     DMPlex_Transpose3D_Internal(rc->RT);
534ca3d3a14SMatthew G. Knepley     break;
535d71ae5a4SJacob Faibussowitsch   default:
536d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
537ca3d3a14SMatthew G. Knepley   }
5383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
539ca3d3a14SMatthew G. Knepley }
540ca3d3a14SMatthew G. Knepley 
541d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx)
542d71ae5a4SJacob Faibussowitsch {
543ca3d3a14SMatthew G. Knepley   RotCtx *rc = (RotCtx *)ctx;
544ca3d3a14SMatthew G. Knepley 
545ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
5469566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rc->R, rc->RT));
5479566063dSJacob Faibussowitsch   PetscCall(PetscFree(rc));
5483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
549ca3d3a14SMatthew G. Knepley }
550ca3d3a14SMatthew G. Knepley 
551d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx)
552d71ae5a4SJacob Faibussowitsch {
553ca3d3a14SMatthew G. Knepley   RotCtx *rc = (RotCtx *)ctx;
554ca3d3a14SMatthew G. Knepley 
555ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
5564f572ea9SToby Isaac   PetscAssertPointer(ctx, 5);
5579371c9d4SSatish Balay   if (l2g) {
5589371c9d4SSatish Balay     *A = rc->R;
5599371c9d4SSatish Balay   } else {
5609371c9d4SSatish Balay     *A = rc->RT;
5619371c9d4SSatish Balay   }
5623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
563ca3d3a14SMatthew G. Knepley }
564ca3d3a14SMatthew G. Knepley 
565d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx)
566d71ae5a4SJacob Faibussowitsch {
567ec277c0fSMatthew G. Knepley   PetscFunctionBegin;
568ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
569ab6a9622SMatthew G. Knepley   switch (dim) {
5709371c9d4SSatish Balay   case 2: {
57127104ee2SJacob Faibussowitsch     PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0};
572ab6a9622SMatthew G. Knepley 
5739566063dSJacob Faibussowitsch     PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx));
5749371c9d4SSatish Balay     z[0] = PetscRealPart(zt[0]);
5759371c9d4SSatish Balay     z[1] = PetscRealPart(zt[1]);
5769371c9d4SSatish Balay   } break;
5779371c9d4SSatish Balay   case 3: {
57827104ee2SJacob Faibussowitsch     PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0};
579ab6a9622SMatthew G. Knepley 
5809566063dSJacob Faibussowitsch     PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx));
5819371c9d4SSatish Balay     z[0] = PetscRealPart(zt[0]);
5829371c9d4SSatish Balay     z[1] = PetscRealPart(zt[1]);
5839371c9d4SSatish Balay     z[2] = PetscRealPart(zt[2]);
5849371c9d4SSatish Balay   } break;
585ab6a9622SMatthew G. Knepley   }
586ab6a9622SMatthew G. Knepley #else
5879566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx));
588ab6a9622SMatthew G. Knepley #endif
5893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
590ab6a9622SMatthew G. Knepley }
591ab6a9622SMatthew G. Knepley 
592d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx)
593d71ae5a4SJacob Faibussowitsch {
594ca3d3a14SMatthew G. Knepley   const PetscScalar *A;
595ca3d3a14SMatthew G. Knepley 
596ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
5979566063dSJacob Faibussowitsch   PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx));
598ca3d3a14SMatthew G. Knepley   switch (dim) {
599d71ae5a4SJacob Faibussowitsch   case 2:
600d71ae5a4SJacob Faibussowitsch     DMPlex_Mult2D_Internal(A, 1, y, z);
601d71ae5a4SJacob Faibussowitsch     break;
602d71ae5a4SJacob Faibussowitsch   case 3:
603d71ae5a4SJacob Faibussowitsch     DMPlex_Mult3D_Internal(A, 1, y, z);
604d71ae5a4SJacob Faibussowitsch     break;
605ca3d3a14SMatthew G. Knepley   }
6063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
607ca3d3a14SMatthew G. Knepley }
608ca3d3a14SMatthew G. Knepley 
609d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
610d71ae5a4SJacob Faibussowitsch {
611ca3d3a14SMatthew G. Knepley   PetscSection       ts;
612ca3d3a14SMatthew G. Knepley   const PetscScalar *ta, *tva;
613ca3d3a14SMatthew G. Knepley   PetscInt           dof;
614ca3d3a14SMatthew G. Knepley 
615ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
6169566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
6179566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
6189566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
6199566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva));
620ca3d3a14SMatthew G. Knepley   if (l2g) {
621ca3d3a14SMatthew G. Knepley     switch (dof) {
622d71ae5a4SJacob Faibussowitsch     case 4:
623d71ae5a4SJacob Faibussowitsch       DMPlex_Mult2D_Internal(tva, 1, a, a);
624d71ae5a4SJacob Faibussowitsch       break;
625d71ae5a4SJacob Faibussowitsch     case 9:
626d71ae5a4SJacob Faibussowitsch       DMPlex_Mult3D_Internal(tva, 1, a, a);
627d71ae5a4SJacob Faibussowitsch       break;
628ca3d3a14SMatthew G. Knepley     }
629ca3d3a14SMatthew G. Knepley   } else {
630ca3d3a14SMatthew G. Knepley     switch (dof) {
631d71ae5a4SJacob Faibussowitsch     case 4:
632d71ae5a4SJacob Faibussowitsch       DMPlex_MultTranspose2D_Internal(tva, 1, a, a);
633d71ae5a4SJacob Faibussowitsch       break;
634d71ae5a4SJacob Faibussowitsch     case 9:
635d71ae5a4SJacob Faibussowitsch       DMPlex_MultTranspose3D_Internal(tva, 1, a, a);
636d71ae5a4SJacob Faibussowitsch       break;
637ca3d3a14SMatthew G. Knepley     }
638ca3d3a14SMatthew G. Knepley   }
6399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
6403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
641ca3d3a14SMatthew G. Knepley }
642ca3d3a14SMatthew G. Knepley 
643d71ae5a4SJacob 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)
644d71ae5a4SJacob Faibussowitsch {
645ca3d3a14SMatthew G. Knepley   PetscSection       s, ts;
646ca3d3a14SMatthew G. Knepley   const PetscScalar *ta, *tvaf, *tvag;
647ca3d3a14SMatthew G. Knepley   PetscInt           fdof, gdof, fpdof, gpdof;
648ca3d3a14SMatthew G. Knepley 
649ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
6509566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
6519566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
6529566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof));
6539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof));
6549566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof));
6559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof));
6569566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
6579566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf));
6589566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag));
659ca3d3a14SMatthew G. Knepley   if (l2g) {
660ca3d3a14SMatthew G. Knepley     switch (fdof) {
661d71ae5a4SJacob Faibussowitsch     case 4:
662d71ae5a4SJacob Faibussowitsch       DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);
663d71ae5a4SJacob Faibussowitsch       break;
664d71ae5a4SJacob Faibussowitsch     case 9:
665d71ae5a4SJacob Faibussowitsch       DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);
666d71ae5a4SJacob Faibussowitsch       break;
667ca3d3a14SMatthew G. Knepley     }
668ca3d3a14SMatthew G. Knepley     switch (gdof) {
669d71ae5a4SJacob Faibussowitsch     case 4:
670d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);
671d71ae5a4SJacob Faibussowitsch       break;
672d71ae5a4SJacob Faibussowitsch     case 9:
673d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);
674d71ae5a4SJacob Faibussowitsch       break;
675ca3d3a14SMatthew G. Knepley     }
676ca3d3a14SMatthew G. Knepley   } else {
677ca3d3a14SMatthew G. Knepley     switch (fdof) {
678d71ae5a4SJacob Faibussowitsch     case 4:
679d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);
680d71ae5a4SJacob Faibussowitsch       break;
681d71ae5a4SJacob Faibussowitsch     case 9:
682d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);
683d71ae5a4SJacob Faibussowitsch       break;
684ca3d3a14SMatthew G. Knepley     }
685ca3d3a14SMatthew G. Knepley     switch (gdof) {
686d71ae5a4SJacob Faibussowitsch     case 4:
687d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);
688d71ae5a4SJacob Faibussowitsch       break;
689d71ae5a4SJacob Faibussowitsch     case 9:
690d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);
691d71ae5a4SJacob Faibussowitsch       break;
692ca3d3a14SMatthew G. Knepley     }
693ca3d3a14SMatthew G. Knepley   }
6949566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
6953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
696ca3d3a14SMatthew G. Knepley }
697ca3d3a14SMatthew G. Knepley 
698d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
699d71ae5a4SJacob Faibussowitsch {
700ca3d3a14SMatthew G. Knepley   PetscSection    s;
701ca3d3a14SMatthew G. Knepley   PetscSection    clSection;
702ca3d3a14SMatthew G. Knepley   IS              clPoints;
703ca3d3a14SMatthew G. Knepley   const PetscInt *clp;
704ca3d3a14SMatthew G. Knepley   PetscInt       *points = NULL;
705ca3d3a14SMatthew G. Knepley   PetscInt        Nf, f, Np, cp, dof, d = 0;
706ca3d3a14SMatthew G. Knepley 
707ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
7089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
7099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
71007218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp));
711ca3d3a14SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
712ca3d3a14SMatthew G. Knepley     for (cp = 0; cp < Np * 2; cp += 2) {
7139566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof));
714ca3d3a14SMatthew G. Knepley       if (!dof) continue;
7159566063dSJacob Faibussowitsch       if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]));
716ca3d3a14SMatthew G. Knepley       d += dof;
717ca3d3a14SMatthew G. Knepley     }
718ca3d3a14SMatthew G. Knepley   }
7199566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
7203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
721ca3d3a14SMatthew G. Knepley }
722ca3d3a14SMatthew G. Knepley 
723d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
724d71ae5a4SJacob Faibussowitsch {
725ca3d3a14SMatthew G. Knepley   PetscSection    s;
726ca3d3a14SMatthew G. Knepley   PetscSection    clSection;
727ca3d3a14SMatthew G. Knepley   IS              clPoints;
728ca3d3a14SMatthew G. Knepley   const PetscInt *clp;
729ca3d3a14SMatthew G. Knepley   PetscInt       *points = NULL;
7308bdb3c71SMatthew G. Knepley   PetscInt        Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
731ca3d3a14SMatthew G. Knepley 
732ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
7339566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
7349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
73507218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp));
736ca3d3a14SMatthew G. Knepley   for (f = 0, r = 0; f < Nf; ++f) {
737ca3d3a14SMatthew G. Knepley     for (cpf = 0; cpf < Np * 2; cpf += 2) {
7389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof));
739ca3d3a14SMatthew G. Knepley       for (g = 0, c = 0; g < Nf; ++g) {
740ca3d3a14SMatthew G. Knepley         for (cpg = 0; cpg < Np * 2; cpg += 2) {
7419566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof));
7429566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c]));
743ca3d3a14SMatthew G. Knepley           c += gdof;
744ca3d3a14SMatthew G. Knepley         }
745ca3d3a14SMatthew G. Knepley       }
74663a3b9bcSJacob Faibussowitsch       PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda);
747ca3d3a14SMatthew G. Knepley       r += fdof;
748ca3d3a14SMatthew G. Knepley     }
749ca3d3a14SMatthew G. Knepley   }
75063a3b9bcSJacob Faibussowitsch   PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda);
7519566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
7523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
753ca3d3a14SMatthew G. Knepley }
754ca3d3a14SMatthew G. Knepley 
755d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
756d71ae5a4SJacob Faibussowitsch {
757ca3d3a14SMatthew G. Knepley   DM                 tdm;
758ca3d3a14SMatthew G. Knepley   Vec                tv;
759ca3d3a14SMatthew G. Knepley   PetscSection       ts, s;
760ca3d3a14SMatthew G. Knepley   const PetscScalar *ta;
761ca3d3a14SMatthew G. Knepley   PetscScalar       *a, *va;
762ca3d3a14SMatthew G. Knepley   PetscInt           pStart, pEnd, p, Nf, f;
763ca3d3a14SMatthew G. Knepley 
764ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
7659566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
7669566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
7679566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
7689566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
7699566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
7709566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
7719566063dSJacob Faibussowitsch   PetscCall(VecGetArray(lv, &a));
7729566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
773ca3d3a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
774ca3d3a14SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
7759566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va));
7769566063dSJacob Faibussowitsch       PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va));
777ca3d3a14SMatthew G. Knepley     }
778ca3d3a14SMatthew G. Knepley   }
7799566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(lv, &a));
7809566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
7813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
782ca3d3a14SMatthew G. Knepley }
783ca3d3a14SMatthew G. Knepley 
784ca3d3a14SMatthew G. Knepley /*@
785ca3d3a14SMatthew G. Knepley   DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis
786ca3d3a14SMatthew G. Knepley 
787ca3d3a14SMatthew G. Knepley   Input Parameters:
788a1cb98faSBarry Smith + dm - The `DM`
789ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis
790ca3d3a14SMatthew G. Knepley 
7912fe279fdSBarry Smith   Output Parameter:
792ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis
793ca3d3a14SMatthew G. Knepley 
794ca3d3a14SMatthew G. Knepley   Level: developer
795ca3d3a14SMatthew G. Knepley 
796a1cb98faSBarry Smith   Note:
797a1cb98faSBarry 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.
798a1cb98faSBarry Smith 
7991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
800ca3d3a14SMatthew G. Knepley @*/
801d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
802d71ae5a4SJacob Faibussowitsch {
803ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
804ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
805ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(lv, VEC_CLASSID, 2);
8069566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE));
8073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
808ca3d3a14SMatthew G. Knepley }
809ca3d3a14SMatthew G. Knepley 
810ca3d3a14SMatthew G. Knepley /*@
811ca3d3a14SMatthew G. Knepley   DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis
812ca3d3a14SMatthew G. Knepley 
813ca3d3a14SMatthew G. Knepley   Input Parameters:
814a1cb98faSBarry Smith + dm - The `DM`
815ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis
816ca3d3a14SMatthew G. Knepley 
8172fe279fdSBarry Smith   Output Parameter:
818ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis
819ca3d3a14SMatthew G. Knepley 
820ca3d3a14SMatthew G. Knepley   Level: developer
821ca3d3a14SMatthew G. Knepley 
822a1cb98faSBarry Smith   Note:
823a1cb98faSBarry 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.
824a1cb98faSBarry Smith 
8251cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
826ca3d3a14SMatthew G. Knepley @*/
827d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
828d71ae5a4SJacob Faibussowitsch {
829ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
830ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
831ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(lv, VEC_CLASSID, 2);
8329566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE));
8333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
834ca3d3a14SMatthew G. Knepley }
835ca3d3a14SMatthew G. Knepley 
836ca3d3a14SMatthew G. Knepley /*@
837ca3d3a14SMatthew G. Knepley   DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions
838ca3d3a14SMatthew G. Knepley   and global solutions, to a local basis, appropriate for discretization integrals and assembly.
839ca3d3a14SMatthew G. Knepley 
840ca3d3a14SMatthew G. Knepley   Input Parameters:
841a1cb98faSBarry Smith + dm    - The `DM`
842ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one
843ca3d3a14SMatthew G. Knepley . beta  - The second Euler angle
844f0fc11ceSJed Brown - gamma - The third Euler angle
845ca3d3a14SMatthew G. Knepley 
846ca3d3a14SMatthew G. Knepley   Level: developer
847ca3d3a14SMatthew G. Knepley 
848a1cb98faSBarry Smith   Note:
849a1cb98faSBarry Smith   Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
850a1cb98faSBarry 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
851a1cb98faSBarry Smith .vb
852a1cb98faSBarry 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.
853a1cb98faSBarry 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.
854a1cb98faSBarry Smith    The XYZ system rotates a third time about the z axis by gamma.
855a1cb98faSBarry Smith .ve
856a1cb98faSBarry Smith 
8571cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`
858ca3d3a14SMatthew G. Knepley @*/
859d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
860d71ae5a4SJacob Faibussowitsch {
861ca3d3a14SMatthew G. Knepley   RotCtx  *rc;
862ca3d3a14SMatthew G. Knepley   PetscInt cdim;
863ca3d3a14SMatthew G. Knepley 
864362febeeSStefano Zampini   PetscFunctionBegin;
8659566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
8669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &rc));
867ca3d3a14SMatthew G. Knepley   dm->transformCtx       = rc;
868ca3d3a14SMatthew G. Knepley   dm->transformSetUp     = DMPlexBasisTransformSetUp_Rotation_Internal;
869ca3d3a14SMatthew G. Knepley   dm->transformDestroy   = DMPlexBasisTransformDestroy_Rotation_Internal;
870ca3d3a14SMatthew G. Knepley   dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
871ca3d3a14SMatthew G. Knepley   rc->dim                = cdim;
872ca3d3a14SMatthew G. Knepley   rc->alpha              = alpha;
873ca3d3a14SMatthew G. Knepley   rc->beta               = beta;
874ca3d3a14SMatthew G. Knepley   rc->gamma              = gamma;
8759566063dSJacob Faibussowitsch   PetscCall((*dm->transformSetUp)(dm, dm->transformCtx));
8769566063dSJacob Faibussowitsch   PetscCall(DMConstructBasisTransform_Internal(dm));
8773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
878ca3d3a14SMatthew G. Knepley }
879ca3d3a14SMatthew G. Knepley 
880b278463cSMatthew G. Knepley /*@C
881ece3a9fcSMatthew G. Knepley   DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates
882b278463cSMatthew G. Knepley 
883b278463cSMatthew G. Knepley   Input Parameters:
884a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
885b278463cSMatthew G. Knepley . time   - The time
886b278463cSMatthew G. Knepley . field  - The field to constrain
8871c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
88820f4b53cSBarry Smith . comps  - An array of constrained component numbers, or `NULL` for all components
889a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
890a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
891b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
892b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
893b278463cSMatthew G. Knepley - ctx    - An optional user context for bcFunc
894b278463cSMatthew G. Knepley 
895b278463cSMatthew G. Knepley   Output Parameter:
896b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values
897b278463cSMatthew G. Knepley 
898b278463cSMatthew G. Knepley   Level: developer
899b278463cSMatthew G. Knepley 
9001cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
901b278463cSMatthew G. Knepley @*/
902d71ae5a4SJacob 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)
903d71ae5a4SJacob Faibussowitsch {
9040163fd50SMatthew G. Knepley   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
90555f2e967SMatthew G. Knepley   void   **ctxs;
906d7ddef95SMatthew G. Knepley   PetscInt numFields;
907d7ddef95SMatthew G. Knepley 
908d7ddef95SMatthew G. Knepley   PetscFunctionBegin;
9099566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
9109566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
911d7ddef95SMatthew G. Knepley   funcs[field] = func;
912d7ddef95SMatthew G. Knepley   ctxs[field]  = ctx;
9139566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX));
9149566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
9153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
916d7ddef95SMatthew G. Knepley }
917d7ddef95SMatthew G. Knepley 
918b278463cSMatthew G. Knepley /*@C
919ece3a9fcSMatthew G. Knepley   DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data
920b278463cSMatthew G. Knepley 
921b278463cSMatthew G. Knepley   Input Parameters:
922a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
923b278463cSMatthew G. Knepley . time   - The time
924b278463cSMatthew G. Knepley . locU   - A local vector with the input solution values
925b278463cSMatthew G. Knepley . field  - The field to constrain
9261c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
92720f4b53cSBarry Smith . comps  - An array of constrained component numbers, or `NULL` for all components
928a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
929a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
930b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
931b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
932b278463cSMatthew G. Knepley - ctx    - An optional user context for bcFunc
933b278463cSMatthew G. Knepley 
934b278463cSMatthew G. Knepley   Output Parameter:
935b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values
936b278463cSMatthew G. Knepley 
937b278463cSMatthew G. Knepley   Level: developer
938b278463cSMatthew G. Knepley 
9391cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
940b278463cSMatthew G. Knepley @*/
941d71ae5a4SJacob 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)
942d71ae5a4SJacob Faibussowitsch {
9439371c9d4SSatish 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[]);
944c60e475cSMatthew G. Knepley   void   **ctxs;
945c60e475cSMatthew G. Knepley   PetscInt numFields;
946c60e475cSMatthew G. Knepley 
947c60e475cSMatthew G. Knepley   PetscFunctionBegin;
9489566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
9499566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
950c60e475cSMatthew G. Knepley   funcs[field] = func;
951c60e475cSMatthew G. Knepley   ctxs[field]  = ctx;
9529566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX));
9539566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
9543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
955c60e475cSMatthew G. Knepley }
956c60e475cSMatthew G. Knepley 
957b278463cSMatthew G. Knepley /*@C
958d5b43468SJose E. Roman   DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data
959ece3a9fcSMatthew G. Knepley 
96020f4b53cSBarry Smith   Collective
961ece3a9fcSMatthew G. Knepley 
962ece3a9fcSMatthew G. Knepley   Input Parameters:
963a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
964ece3a9fcSMatthew G. Knepley . time   - The time
965ece3a9fcSMatthew G. Knepley . locU   - A local vector with the input solution values
966ece3a9fcSMatthew G. Knepley . field  - The field to constrain
967ece3a9fcSMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
96820f4b53cSBarry Smith . comps  - An array of constrained component numbers, or `NULL` for all components
969a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
970a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
971ece3a9fcSMatthew G. Knepley . ids    - An array of ids for constrained points
97220f4b53cSBarry Smith . func   - A pointwise function giving boundary values, the calling sequence is given in `DMProjectBdFieldLabelLocal()`
97320f4b53cSBarry Smith - ctx    - An optional user context for `func`
974ece3a9fcSMatthew G. Knepley 
975ece3a9fcSMatthew G. Knepley   Output Parameter:
976ece3a9fcSMatthew G. Knepley . locX - A local vector to receive the boundary values
977ece3a9fcSMatthew G. Knepley 
978ece3a9fcSMatthew G. Knepley   Level: developer
979ece3a9fcSMatthew G. Knepley 
9801cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
981ece3a9fcSMatthew G. Knepley @*/
982d71ae5a4SJacob 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)
983d71ae5a4SJacob Faibussowitsch {
9849371c9d4SSatish 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[]);
985ece3a9fcSMatthew G. Knepley   void   **ctxs;
986ece3a9fcSMatthew G. Knepley   PetscInt numFields;
987ece3a9fcSMatthew G. Knepley 
988ece3a9fcSMatthew G. Knepley   PetscFunctionBegin;
9899566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
9909566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
991ece3a9fcSMatthew G. Knepley   funcs[field] = func;
992ece3a9fcSMatthew G. Knepley   ctxs[field]  = ctx;
9939566063dSJacob Faibussowitsch   PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX));
9949566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
9953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
996ece3a9fcSMatthew G. Knepley }
997ece3a9fcSMatthew G. Knepley 
998ece3a9fcSMatthew G. Knepley /*@C
999b278463cSMatthew G. Knepley   DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector
1000b278463cSMatthew G. Knepley 
1001b278463cSMatthew G. Knepley   Input Parameters:
1002a1cb98faSBarry Smith + dm           - The `DM`, with a `PetscDS` that matches the problem being constrained
1003b278463cSMatthew G. Knepley . time         - The time
1004b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information
1005b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information
1006b278463cSMatthew G. Knepley . Grad         - A vector with the FVM cell gradient information
1007b278463cSMatthew G. Knepley . field        - The field to constrain
10081c531cf8SMatthew G. Knepley . Nc           - The number of constrained field components, or 0 for all components
100920f4b53cSBarry Smith . comps        - An array of constrained component numbers, or `NULL` for all components
1010a1cb98faSBarry Smith . label        - The `DMLabel` defining constrained points
1011a1cb98faSBarry Smith . numids       - The number of `DMLabel` ids for constrained points
1012b278463cSMatthew G. Knepley . ids          - An array of ids for constrained points
1013b278463cSMatthew G. Knepley . func         - A pointwise function giving boundary values
1014b278463cSMatthew G. Knepley - ctx          - An optional user context for bcFunc
1015b278463cSMatthew G. Knepley 
1016b278463cSMatthew G. Knepley   Output Parameter:
1017b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values
1018b278463cSMatthew G. Knepley 
1019b278463cSMatthew G. Knepley   Level: developer
1020b278463cSMatthew G. Knepley 
1021a1cb98faSBarry Smith   Note:
1022a1cb98faSBarry Smith   This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()`
1023a1cb98faSBarry Smith 
10241cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
1025b278463cSMatthew G. Knepley @*/
1026d71ae5a4SJacob 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)
1027d71ae5a4SJacob Faibussowitsch {
102861f58d28SMatthew G. Knepley   PetscDS            prob;
1029da97024aSMatthew G. Knepley   PetscSF            sf;
1030d7ddef95SMatthew G. Knepley   DM                 dmFace, dmCell, dmGrad;
103120369375SToby Isaac   const PetscScalar *facegeom, *cellgeom = NULL, *grad;
1032da97024aSMatthew G. Knepley   const PetscInt    *leaves;
1033d7ddef95SMatthew G. Knepley   PetscScalar       *x, *fx;
1034520b3818SMatthew G. Knepley   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
10353ba16761SJacob Faibussowitsch   PetscErrorCode     ierru = PETSC_SUCCESS;
1036d7ddef95SMatthew G. Knepley 
1037d7ddef95SMatthew G. Knepley   PetscFunctionBegin;
10389566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
10399566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
1040da97024aSMatthew G. Knepley   nleaves = PetscMax(0, nleaves);
10419566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
10429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
10439566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
10449566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
10459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
104620369375SToby Isaac   if (cellGeometry) {
10479566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeometry, &dmCell));
10489566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
104920369375SToby Isaac   }
1050d7ddef95SMatthew G. Knepley   if (Grad) {
1051c0a6632aSMatthew G. Knepley     PetscFV fv;
1052c0a6632aSMatthew G. Knepley 
10539566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv));
10549566063dSJacob Faibussowitsch     PetscCall(VecGetDM(Grad, &dmGrad));
10559566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(Grad, &grad));
10569566063dSJacob Faibussowitsch     PetscCall(PetscFVGetNumComponents(fv, &pdim));
10579566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx));
1058d7ddef95SMatthew G. Knepley   }
10599566063dSJacob Faibussowitsch   PetscCall(VecGetArray(locX, &x));
1060d7ddef95SMatthew G. Knepley   for (i = 0; i < numids; ++i) {
1061d7ddef95SMatthew G. Knepley     IS              faceIS;
1062d7ddef95SMatthew G. Knepley     const PetscInt *faces;
1063d7ddef95SMatthew G. Knepley     PetscInt        numFaces, f;
1064d7ddef95SMatthew G. Knepley 
10659566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS));
1066d7ddef95SMatthew G. Knepley     if (!faceIS) continue; /* No points with that id on this process */
10679566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(faceIS, &numFaces));
10689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(faceIS, &faces));
1069d7ddef95SMatthew G. Knepley     for (f = 0; f < numFaces; ++f) {
1070d7ddef95SMatthew G. Knepley       const PetscInt   face = faces[f], *cells;
1071640bce14SSatish Balay       PetscFVFaceGeom *fg;
1072d7ddef95SMatthew G. Knepley 
1073d7ddef95SMatthew G. Knepley       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
10749566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc));
1075da97024aSMatthew G. Knepley       if (loc >= 0) continue;
10769566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
10779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, face, &cells));
1078d7ddef95SMatthew G. Knepley       if (Grad) {
1079640bce14SSatish Balay         PetscFVCellGeom *cg;
1080640bce14SSatish Balay         PetscScalar     *cx, *cgrad;
1081d7ddef95SMatthew G. Knepley         PetscScalar     *xG;
1082d7ddef95SMatthew G. Knepley         PetscReal        dx[3];
1083d7ddef95SMatthew G. Knepley         PetscInt         d;
1084d7ddef95SMatthew G. Knepley 
10859566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg));
10869566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx));
10879566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad));
10889566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG));
1089d7ddef95SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
1090d7ddef95SMatthew G. Knepley         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx);
10919566063dSJacob Faibussowitsch         PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx));
1092d7ddef95SMatthew G. Knepley       } else {
1093640bce14SSatish Balay         PetscScalar *xI;
1094d7ddef95SMatthew G. Knepley         PetscScalar *xG;
1095d7ddef95SMatthew G. Knepley 
10969566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI));
10979566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG));
1098e735a8a9SMatthew G. Knepley         ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
1099e735a8a9SMatthew G. Knepley         if (ierru) {
11009566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(faceIS, &faces));
11019566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&faceIS));
1102e735a8a9SMatthew G. Knepley           goto cleanup;
1103e735a8a9SMatthew G. Knepley         }
1104d7ddef95SMatthew G. Knepley       }
1105d7ddef95SMatthew G. Knepley     }
11069566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(faceIS, &faces));
11079566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&faceIS));
1108d7ddef95SMatthew G. Knepley   }
1109e735a8a9SMatthew G. Knepley cleanup:
11109566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(locX, &x));
1111d7ddef95SMatthew G. Knepley   if (Grad) {
11129566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx));
11139566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(Grad, &grad));
1114d7ddef95SMatthew G. Knepley   }
11159566063dSJacob Faibussowitsch   if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
11169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
11179566063dSJacob Faibussowitsch   PetscCall(ierru);
11183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1119d7ddef95SMatthew G. Knepley }
1120d7ddef95SMatthew G. Knepley 
1121d71ae5a4SJacob Faibussowitsch static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx)
1122d71ae5a4SJacob Faibussowitsch {
11230c364540SMatthew G. Knepley   PetscInt c;
11240c364540SMatthew G. Knepley   for (c = 0; c < Nc; ++c) u[c] = 0.0;
11253ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
11260c364540SMatthew G. Knepley }
11270c364540SMatthew G. Knepley 
1128d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1129d71ae5a4SJacob Faibussowitsch {
11300c364540SMatthew G. Knepley   PetscObject isZero;
1131e5e52638SMatthew G. Knepley   PetscDS     prob;
1132d7ddef95SMatthew G. Knepley   PetscInt    numBd, b;
113355f2e967SMatthew G. Knepley 
113455f2e967SMatthew G. Knepley   PetscFunctionBegin;
11359566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
11369566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
11379566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero));
113855f2e967SMatthew G. Knepley   for (b = 0; b < numBd; ++b) {
113945480ffeSMatthew G. Knepley     PetscWeakForm           wf;
1140f971fd6bSMatthew G. Knepley     DMBoundaryConditionType type;
114145480ffeSMatthew G. Knepley     const char             *name;
1142d7ddef95SMatthew G. Knepley     DMLabel                 label;
11431c531cf8SMatthew G. Knepley     PetscInt                field, Nc;
11441c531cf8SMatthew G. Knepley     const PetscInt         *comps;
1145d7ddef95SMatthew G. Knepley     PetscObject             obj;
1146d7ddef95SMatthew G. Knepley     PetscClassId            id;
114745480ffeSMatthew G. Knepley     void (*bvfunc)(void);
1148d7ddef95SMatthew G. Knepley     PetscInt        numids;
1149d7ddef95SMatthew G. Knepley     const PetscInt *ids;
115055f2e967SMatthew G. Knepley     void           *ctx;
115155f2e967SMatthew G. Knepley 
11529566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
1153f971fd6bSMatthew G. Knepley     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
11549566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
11559566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
1156d7ddef95SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
1157c60e475cSMatthew G. Knepley       switch (type) {
1158c60e475cSMatthew G. Knepley         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
11599371c9d4SSatish Balay       case DM_BC_ESSENTIAL: {
116045480ffeSMatthew G. Knepley         PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc;
116145480ffeSMatthew G. Knepley 
116245480ffeSMatthew G. Knepley         if (isZero) func = zero;
11639566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
11649566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX));
11659566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
11669371c9d4SSatish Balay       } break;
11679371c9d4SSatish Balay       case DM_BC_ESSENTIAL_FIELD: {
116845480ffeSMatthew G. Knepley         PetscPointFunc func = (PetscPointFunc)bvfunc;
116945480ffeSMatthew G. Knepley 
11709566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
11719566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX));
11729566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
11739371c9d4SSatish Balay       } break;
1174d71ae5a4SJacob Faibussowitsch       default:
1175d71ae5a4SJacob Faibussowitsch         break;
1176c60e475cSMatthew G. Knepley       }
1177d7ddef95SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
117845480ffeSMatthew G. Knepley       {
117945480ffeSMatthew G. Knepley         PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc;
118045480ffeSMatthew G. Knepley 
118143ea7facSMatthew G. Knepley         if (!faceGeomFVM) continue;
11829566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX));
118345480ffeSMatthew G. Knepley       }
118463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
118555f2e967SMatthew G. Knepley   }
11863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
118755f2e967SMatthew G. Knepley }
118855f2e967SMatthew G. Knepley 
1189d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1190d71ae5a4SJacob Faibussowitsch {
119156cf3b9cSMatthew G. Knepley   PetscObject isZero;
119256cf3b9cSMatthew G. Knepley   PetscDS     prob;
119356cf3b9cSMatthew G. Knepley   PetscInt    numBd, b;
119456cf3b9cSMatthew G. Knepley 
119556cf3b9cSMatthew G. Knepley   PetscFunctionBegin;
11963ba16761SJacob Faibussowitsch   if (!locX) PetscFunctionReturn(PETSC_SUCCESS);
11979566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
11989566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
11999566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero));
120056cf3b9cSMatthew G. Knepley   for (b = 0; b < numBd; ++b) {
120145480ffeSMatthew G. Knepley     PetscWeakForm           wf;
120256cf3b9cSMatthew G. Knepley     DMBoundaryConditionType type;
120345480ffeSMatthew G. Knepley     const char             *name;
120456cf3b9cSMatthew G. Knepley     DMLabel                 label;
120556cf3b9cSMatthew G. Knepley     PetscInt                field, Nc;
120656cf3b9cSMatthew G. Knepley     const PetscInt         *comps;
120756cf3b9cSMatthew G. Knepley     PetscObject             obj;
120856cf3b9cSMatthew G. Knepley     PetscClassId            id;
120956cf3b9cSMatthew G. Knepley     PetscInt                numids;
121056cf3b9cSMatthew G. Knepley     const PetscInt         *ids;
121145480ffeSMatthew G. Knepley     void (*bvfunc)(void);
121256cf3b9cSMatthew G. Knepley     void *ctx;
121356cf3b9cSMatthew G. Knepley 
12149566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx));
121556cf3b9cSMatthew G. Knepley     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
12169566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
12179566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
121856cf3b9cSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
121956cf3b9cSMatthew G. Knepley       switch (type) {
122056cf3b9cSMatthew G. Knepley         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
12219371c9d4SSatish Balay       case DM_BC_ESSENTIAL: {
122245480ffeSMatthew G. Knepley         PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc;
122345480ffeSMatthew G. Knepley 
122445480ffeSMatthew G. Knepley         if (isZero) func_t = zero;
12259566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
12269566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX));
12279566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
12289371c9d4SSatish Balay       } break;
12299371c9d4SSatish Balay       case DM_BC_ESSENTIAL_FIELD: {
123045480ffeSMatthew G. Knepley         PetscPointFunc func_t = (PetscPointFunc)bvfunc;
123145480ffeSMatthew G. Knepley 
12329566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
12339566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX));
12349566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
12359371c9d4SSatish Balay       } break;
1236d71ae5a4SJacob Faibussowitsch       default:
1237d71ae5a4SJacob Faibussowitsch         break;
123856cf3b9cSMatthew G. Knepley       }
123963a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
124056cf3b9cSMatthew G. Knepley   }
12413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
124256cf3b9cSMatthew G. Knepley }
124356cf3b9cSMatthew G. Knepley 
1244f1d73a7aSMatthew G. Knepley /*@
1245f1d73a7aSMatthew G. Knepley   DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector
1246f1d73a7aSMatthew G. Knepley 
1247ed808b8fSJed Brown   Not Collective
1248ed808b8fSJed Brown 
1249f1d73a7aSMatthew G. Knepley   Input Parameters:
1250a1cb98faSBarry Smith + dm              - The `DM`
1251f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1252f1d73a7aSMatthew G. Knepley . time            - The time
1253f1d73a7aSMatthew G. Knepley . faceGeomFVM     - Face geometry data for FV discretizations
1254f1d73a7aSMatthew G. Knepley . cellGeomFVM     - Cell geometry data for FV discretizations
1255f1d73a7aSMatthew G. Knepley - gradFVM         - Gradient reconstruction data for FV discretizations
1256f1d73a7aSMatthew G. Knepley 
12572fe279fdSBarry Smith   Output Parameter:
1258f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values
1259f1d73a7aSMatthew G. Knepley 
1260ed808b8fSJed Brown   Level: intermediate
1261f1d73a7aSMatthew G. Knepley 
12621cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()`
1263f1d73a7aSMatthew G. Knepley @*/
1264d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1265d71ae5a4SJacob Faibussowitsch {
1266f1d73a7aSMatthew G. Knepley   PetscFunctionBegin;
1267f1d73a7aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1268064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
1269ad540459SPierre Jolivet   if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5);
1270ad540459SPierre Jolivet   if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6);
1271ad540459SPierre Jolivet   if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7);
1272cac4c232SBarry Smith   PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM));
12733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1274f1d73a7aSMatthew G. Knepley }
1275f1d73a7aSMatthew G. Knepley 
127656cf3b9cSMatthew G. Knepley /*@
1277a5b23f4aSJose E. Roman   DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector
127856cf3b9cSMatthew G. Knepley 
127956cf3b9cSMatthew G. Knepley   Input Parameters:
1280a1cb98faSBarry Smith + dm              - The `DM`
128156cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
128256cf3b9cSMatthew G. Knepley . time            - The time
128356cf3b9cSMatthew G. Knepley . faceGeomFVM     - Face geometry data for FV discretizations
128456cf3b9cSMatthew G. Knepley . cellGeomFVM     - Cell geometry data for FV discretizations
128556cf3b9cSMatthew G. Knepley - gradFVM         - Gradient reconstruction data for FV discretizations
128656cf3b9cSMatthew G. Knepley 
12872fe279fdSBarry Smith   Output Parameter:
128856cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values
128956cf3b9cSMatthew G. Knepley 
129056cf3b9cSMatthew G. Knepley   Level: developer
129156cf3b9cSMatthew G. Knepley 
12921cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`
129356cf3b9cSMatthew G. Knepley @*/
1294d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1295d71ae5a4SJacob Faibussowitsch {
129656cf3b9cSMatthew G. Knepley   PetscFunctionBegin;
129756cf3b9cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1298ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3);
1299ad540459SPierre Jolivet   if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5);
1300ad540459SPierre Jolivet   if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6);
1301ad540459SPierre Jolivet   if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7);
1302cac4c232SBarry Smith   PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM));
13033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
130456cf3b9cSMatthew G. Knepley }
130556cf3b9cSMatthew G. Knepley 
1306d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1307d71ae5a4SJacob Faibussowitsch {
1308574a98acSMatthew G. Knepley   Vec localX;
1309574a98acSMatthew G. Knepley 
1310574a98acSMatthew G. Knepley   PetscFunctionBegin;
13119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
13129566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL));
13139566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
13149566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
13159566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff));
13169566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
13173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1318574a98acSMatthew G. Knepley }
1319574a98acSMatthew G. Knepley 
1320574a98acSMatthew G. Knepley /*@C
132160225df5SJacob Faibussowitsch   DMPlexComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
1322574a98acSMatthew G. Knepley 
132320f4b53cSBarry Smith   Collective
1324c0f8e1fdSMatthew G. Knepley 
1325574a98acSMatthew G. Knepley   Input Parameters:
1326a1cb98faSBarry Smith + dm     - The `DM`
1327574a98acSMatthew G. Knepley . time   - The time
1328574a98acSMatthew G. Knepley . funcs  - The functions to evaluate for each field component
132920f4b53cSBarry Smith . ctxs   - Optional array of contexts to pass to each function, or `NULL`.
1330574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector
1331574a98acSMatthew G. Knepley 
1332574a98acSMatthew G. Knepley   Output Parameter:
1333574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2
1334574a98acSMatthew G. Knepley 
1335574a98acSMatthew G. Knepley   Level: developer
1336574a98acSMatthew G. Knepley 
13371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1338574a98acSMatthew G. Knepley @*/
1339d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
1340d71ae5a4SJacob Faibussowitsch {
13410f09c10fSMatthew G. Knepley   const PetscInt   debug = ((DM_Plex *)dm->data)->printL2;
1342ca3d3a14SMatthew G. Knepley   DM               tdm;
1343ca3d3a14SMatthew G. Knepley   Vec              tv;
1344cb1e1211SMatthew G Knepley   PetscSection     section;
1345c5bbbd5bSMatthew G. Knepley   PetscQuadrature  quad;
13464bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
134715496722SMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
13484bee2e38SMatthew G. Knepley   PetscReal       *coords, *gcoords;
1349cb1e1211SMatthew G Knepley   PetscReal        localDiff = 0.0;
13507318780aSToby Isaac   const PetscReal *quadWeights;
1351412e9a14SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset;
1352ca3d3a14SMatthew G. Knepley   PetscBool        transform;
1353cb1e1211SMatthew G Knepley 
1354cb1e1211SMatthew G Knepley   PetscFunctionBegin;
13559566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
13572a4e142eSMatthew G. Knepley   fegeom.dimEmbed = coordDim;
13589566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
13599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
13609566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
13619566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
13629566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
1363eae3dc7dSJacob Faibussowitsch   PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
1364cb1e1211SMatthew G Knepley   for (field = 0; field < numFields; ++field) {
136515496722SMatthew G. Knepley     PetscObject  obj;
136615496722SMatthew G. Knepley     PetscClassId id;
1367c5bbbd5bSMatthew G. Knepley     PetscInt     Nc;
1368c5bbbd5bSMatthew G. Knepley 
13699566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
13709566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
137115496722SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
137215496722SMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
137315496722SMatthew G. Knepley 
13749566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
13759566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
137615496722SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
137715496722SMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
137815496722SMatthew G. Knepley 
13799566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
13809566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
138163a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1382c5bbbd5bSMatthew G. Knepley     numComponents += Nc;
1383cb1e1211SMatthew G Knepley   }
13849566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
138563a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
1386c9cb6370SYANG Zongze   PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
13879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
13889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
1389cb1e1211SMatthew G Knepley   for (c = cStart; c < cEnd; ++c) {
1390a1e44745SMatthew G. Knepley     PetscScalar *x        = NULL;
1391cb1e1211SMatthew G Knepley     PetscReal    elemDiff = 0.0;
13929c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1393cb1e1211SMatthew G Knepley 
13949566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
1395e8e188d2SZach Atkins     PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x));
1396cb1e1211SMatthew G Knepley 
139715496722SMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
139815496722SMatthew G. Knepley       PetscObject  obj;
139915496722SMatthew G. Knepley       PetscClassId id;
1400c110b1eeSGeoffrey Irving       void *const  ctx = ctxs ? ctxs[field] : NULL;
140115496722SMatthew G. Knepley       PetscInt     Nb, Nc, q, fc;
1402cb1e1211SMatthew G Knepley 
14039566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, &obj));
14049566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
14059371c9d4SSatish Balay       if (id == PETSCFE_CLASSID) {
14069371c9d4SSatish Balay         PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
14079371c9d4SSatish Balay         PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
14089371c9d4SSatish Balay       } else if (id == PETSCFV_CLASSID) {
14099371c9d4SSatish Balay         PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
14109371c9d4SSatish Balay         Nb = 1;
14119371c9d4SSatish Balay       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1412cb1e1211SMatthew G Knepley       if (debug) {
1413cb1e1211SMatthew G Knepley         char title[1024];
141463a3b9bcSJacob Faibussowitsch         PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field));
14159566063dSJacob Faibussowitsch         PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset]));
1416cb1e1211SMatthew G Knepley       }
14177318780aSToby Isaac       for (q = 0; q < Nq; ++q) {
14182a4e142eSMatthew G. Knepley         PetscFEGeom    qgeom;
1419d0609cedSBarry Smith         PetscErrorCode ierr;
14202a4e142eSMatthew G. Knepley 
14212a4e142eSMatthew G. Knepley         qgeom.dimEmbed = fegeom.dimEmbed;
14222a4e142eSMatthew G. Knepley         qgeom.J        = &fegeom.J[q * coordDim * coordDim];
14232a4e142eSMatthew G. Knepley         qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
14242a4e142eSMatthew G. Knepley         qgeom.detJ     = &fegeom.detJ[q];
142563a3b9bcSJacob 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);
1426d3a7d86cSMatthew G. Knepley         if (transform) {
1427d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * Nq];
14289566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx));
1429d3a7d86cSMatthew G. Knepley         } else {
1430d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * q];
1431d3a7d86cSMatthew G. Knepley         }
14329566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(funcVal, Nc));
1433ca3d3a14SMatthew G. Knepley         ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx);
1434e735a8a9SMatthew G. Knepley         if (ierr) {
14359566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
14369566063dSJacob Faibussowitsch           PetscCall(DMRestoreLocalVector(dm, &localX));
14379566063dSJacob Faibussowitsch           PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1438e735a8a9SMatthew G. Knepley         }
14399566063dSJacob Faibussowitsch         if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
14409566063dSJacob Faibussowitsch         if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant));
14419566063dSJacob Faibussowitsch         else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant));
14422df84da0SMatthew G. Knepley         else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
144315496722SMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
1444beaa55a6SMatthew G. Knepley           const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
14459371c9d4SSatish Balay           if (debug)
14469371c9d4SSatish 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.),
14479371c9d4SSatish Balay                                   (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc])));
14484bee2e38SMatthew G. Knepley           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1449cb1e1211SMatthew G Knepley         }
1450cb1e1211SMatthew G Knepley       }
14519c3cf19fSMatthew G. Knepley       fieldOffset += Nb;
1452beaa55a6SMatthew G. Knepley       qc += Nc;
1453cb1e1211SMatthew G Knepley     }
14549566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
14559566063dSJacob Faibussowitsch     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff));
1456cb1e1211SMatthew G Knepley     localDiff += elemDiff;
1457cb1e1211SMatthew G Knepley   }
14589566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
14591c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
1460cb1e1211SMatthew G Knepley   *diff = PetscSqrtReal(*diff);
14613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1462cb1e1211SMatthew G Knepley }
1463cb1e1211SMatthew G Knepley 
1464d71ae5a4SJacob 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)
1465d71ae5a4SJacob Faibussowitsch {
14660f09c10fSMatthew G. Knepley   const PetscInt   debug = ((DM_Plex *)dm->data)->printL2;
1467ca3d3a14SMatthew G. Knepley   DM               tdm;
1468cb1e1211SMatthew G Knepley   PetscSection     section;
146940e14135SMatthew G. Knepley   PetscQuadrature  quad;
1470ca3d3a14SMatthew G. Knepley   Vec              localX, tv;
14719c3cf19fSMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
14722a4e142eSMatthew G. Knepley   const PetscReal *quadWeights;
14734bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
14744bee2e38SMatthew G. Knepley   PetscReal       *coords, *gcoords;
147540e14135SMatthew G. Knepley   PetscReal        localDiff = 0.0;
1476485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset;
1477ca3d3a14SMatthew G. Knepley   PetscBool        transform;
1478cb1e1211SMatthew G Knepley 
1479cb1e1211SMatthew G Knepley   PetscFunctionBegin;
14809566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14819566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
14824bee2e38SMatthew G. Knepley   fegeom.dimEmbed = coordDim;
14839566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
14849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
14859566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
14869566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
14879566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
14889566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
14899566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
14909566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
1491652b88e8SMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
14920f2d7e86SMatthew G. Knepley     PetscFE  fe;
149340e14135SMatthew G. Knepley     PetscInt Nc;
1494652b88e8SMatthew G. Knepley 
14959566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe));
14969566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &quad));
14979566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents(fe, &Nc));
149840e14135SMatthew G. Knepley     numComponents += Nc;
1499652b88e8SMatthew G. Knepley   }
15009566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
150163a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
15029566063dSJacob Faibussowitsch   /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */
1503c9cb6370SYANG Zongze   PetscCall(PetscMalloc6(numComponents, &funcVal, coordDim * (Nq + 1), &coords, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ, numComponents * coordDim, &interpolant, Nq, &fegeom.detJ));
15049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
150540e14135SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
150640e14135SMatthew G. Knepley     PetscScalar *x        = NULL;
150740e14135SMatthew G. Knepley     PetscReal    elemDiff = 0.0;
15089c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1509652b88e8SMatthew G. Knepley 
15109566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
1511e8e188d2SZach Atkins     PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x));
151240e14135SMatthew G. Knepley 
15139c3cf19fSMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
15140f2d7e86SMatthew G. Knepley       PetscFE     fe;
151551259fa3SMatthew G. Knepley       void *const ctx = ctxs ? ctxs[field] : NULL;
15169c3cf19fSMatthew G. Knepley       PetscInt    Nb, Nc, q, fc;
151740e14135SMatthew G. Knepley 
15189566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe));
15199566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
15209566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
152140e14135SMatthew G. Knepley       if (debug) {
152240e14135SMatthew G. Knepley         char title[1024];
15239566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field));
15249566063dSJacob Faibussowitsch         PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset]));
1525652b88e8SMatthew G. Knepley       }
15269c3cf19fSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
15272a4e142eSMatthew G. Knepley         PetscFEGeom    qgeom;
1528d0609cedSBarry Smith         PetscErrorCode ierr;
15292a4e142eSMatthew G. Knepley 
15302a4e142eSMatthew G. Knepley         qgeom.dimEmbed = fegeom.dimEmbed;
15312a4e142eSMatthew G. Knepley         qgeom.J        = &fegeom.J[q * coordDim * coordDim];
15322a4e142eSMatthew G. Knepley         qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
15332a4e142eSMatthew G. Knepley         qgeom.detJ     = &fegeom.detJ[q];
15342df84da0SMatthew 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);
1535d3a7d86cSMatthew G. Knepley         if (transform) {
1536d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * Nq];
15379566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx));
1538d3a7d86cSMatthew G. Knepley         } else {
1539d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * q];
1540d3a7d86cSMatthew G. Knepley         }
15419566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(funcVal, Nc));
15424bee2e38SMatthew G. Knepley         ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx);
1543e735a8a9SMatthew G. Knepley         if (ierr) {
15449566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
15459566063dSJacob Faibussowitsch           PetscCall(DMRestoreLocalVector(dm, &localX));
15469566063dSJacob Faibussowitsch           PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ));
1547e735a8a9SMatthew G. Knepley         }
15489566063dSJacob Faibussowitsch         if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
15499566063dSJacob Faibussowitsch         PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant));
15504bee2e38SMatthew G. Knepley         /* Overwrite with the dot product if the normal is given */
15514bee2e38SMatthew G. Knepley         if (n) {
15524bee2e38SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
15534bee2e38SMatthew G. Knepley             PetscScalar sum = 0.0;
15544bee2e38SMatthew G. Knepley             PetscInt    d;
15554bee2e38SMatthew G. Knepley             for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d];
15564bee2e38SMatthew G. Knepley             interpolant[fc] = sum;
15574bee2e38SMatthew G. Knepley           }
15584bee2e38SMatthew G. Knepley         }
15599c3cf19fSMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
1560beaa55a6SMatthew G. Knepley           const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
156163a3b9bcSJacob 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])));
15624bee2e38SMatthew G. Knepley           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
156340e14135SMatthew G. Knepley         }
156440e14135SMatthew G. Knepley       }
15659c3cf19fSMatthew G. Knepley       fieldOffset += Nb;
15669c3cf19fSMatthew G. Knepley       qc += Nc;
156740e14135SMatthew G. Knepley     }
15689566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
156963a3b9bcSJacob Faibussowitsch     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff));
157040e14135SMatthew G. Knepley     localDiff += elemDiff;
157140e14135SMatthew G. Knepley   }
15729566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ));
15739566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
15741c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
157540e14135SMatthew G. Knepley   *diff = PetscSqrtReal(*diff);
15763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1577cb1e1211SMatthew G Knepley }
1578cb1e1211SMatthew G Knepley 
1579d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1580d71ae5a4SJacob Faibussowitsch {
15810f09c10fSMatthew G. Knepley   const PetscInt debug = ((DM_Plex *)dm->data)->printL2;
1582ca3d3a14SMatthew G. Knepley   DM             tdm;
1583083401c6SMatthew G. Knepley   DMLabel        depthLabel;
158473d901b8SMatthew G. Knepley   PetscSection   section;
1585ca3d3a14SMatthew G. Knepley   Vec            localX, tv;
158673d901b8SMatthew G. Knepley   PetscReal     *localDiff;
1587083401c6SMatthew G. Knepley   PetscInt       dim, depth, dE, Nf, f, Nds, s;
1588ca3d3a14SMatthew G. Knepley   PetscBool      transform;
158973d901b8SMatthew G. Knepley 
159073d901b8SMatthew G. Knepley   PetscFunctionBegin;
15919566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
15929566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
15939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
15949566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
15959566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
15969566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
15979566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
15989566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
15999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
16009566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(depthLabel, &depth));
1601083401c6SMatthew G. Knepley 
16029566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
16039566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
16049566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
16059566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX));
16069566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
16079566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Nf, &localDiff));
1608083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1609083401c6SMatthew G. Knepley     PetscDS          ds;
1610083401c6SMatthew G. Knepley     DMLabel          label;
1611083401c6SMatthew G. Knepley     IS               fieldIS, pointIS;
1612083401c6SMatthew G. Knepley     const PetscInt  *fields, *points = NULL;
1613083401c6SMatthew G. Knepley     PetscQuadrature  quad;
1614083401c6SMatthew G. Knepley     const PetscReal *quadPoints, *quadWeights;
1615083401c6SMatthew G. Knepley     PetscFEGeom      fegeom;
1616083401c6SMatthew G. Knepley     PetscReal       *coords, *gcoords;
1617083401c6SMatthew G. Knepley     PetscScalar     *funcVal, *interpolant;
16185fedec97SMatthew G. Knepley     PetscBool        isCohesive;
1619083401c6SMatthew G. Knepley     PetscInt         qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf;
162073d901b8SMatthew G. Knepley 
162107218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
16229566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(fieldIS, &fields));
16239566063dSJacob Faibussowitsch     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
16249566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(ds, &dsNf));
16259566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalComponents(ds, &totNc));
16269566063dSJacob Faibussowitsch     PetscCall(PetscDSGetQuadrature(ds, &quad));
16279566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
162863a3b9bcSJacob Faibussowitsch     PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc);
16299566063dSJacob Faibussowitsch     PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ));
1630083401c6SMatthew G. Knepley     if (!label) {
16319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1632083401c6SMatthew G. Knepley     } else {
16339566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
16349566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pointIS, &cEnd));
16359566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pointIS, &points));
1636083401c6SMatthew G. Knepley     }
163773d901b8SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1638083401c6SMatthew G. Knepley       const PetscInt  cell = points ? points[c] : c;
163973d901b8SMatthew G. Knepley       PetscScalar    *x    = NULL;
16405fedec97SMatthew G. Knepley       const PetscInt *cone;
16415fedec97SMatthew G. Knepley       PetscInt        qc = 0, fOff = 0, dep;
164273d901b8SMatthew G. Knepley 
16439566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, cell, &dep));
1644083401c6SMatthew G. Knepley       if (dep != depth - 1) continue;
16455fedec97SMatthew G. Knepley       if (isCohesive) {
16469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cell, &cone));
16479566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
164896959cd1SMatthew G. Knepley       } else {
16499566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
165096959cd1SMatthew G. Knepley       }
1651e8e188d2SZach Atkins       PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x));
16525fedec97SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
165315496722SMatthew G. Knepley         PetscObject  obj;
165415496722SMatthew G. Knepley         PetscClassId id;
1655083401c6SMatthew G. Knepley         void *const  ctx = ctxs ? ctxs[fields[f]] : NULL;
165615496722SMatthew G. Knepley         PetscInt     Nb, Nc, q, fc;
165715496722SMatthew G. Knepley         PetscReal    elemDiff = 0.0;
16585fedec97SMatthew G. Knepley         PetscBool    cohesive;
165915496722SMatthew G. Knepley 
16609566063dSJacob Faibussowitsch         PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
16619566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
16629566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
16639371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
16649371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
16659371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
16669371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
16679371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
16689371c9d4SSatish Balay           Nb = 1;
16699371c9d4SSatish Balay         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
1670c82db6dbSMatthew G. Knepley         if (isCohesive && !cohesive) {
1671c82db6dbSMatthew G. Knepley           fOff += Nb * 2;
1672c82db6dbSMatthew G. Knepley           qc += Nc;
1673c82db6dbSMatthew G. Knepley           continue;
1674c82db6dbSMatthew G. Knepley         }
167573d901b8SMatthew G. Knepley         if (debug) {
167673d901b8SMatthew G. Knepley           char title[1024];
167763a3b9bcSJacob Faibussowitsch           PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f]));
16789566063dSJacob Faibussowitsch           PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff]));
167973d901b8SMatthew G. Knepley         }
16807318780aSToby Isaac         for (q = 0; q < Nq; ++q) {
16812a4e142eSMatthew G. Knepley           PetscFEGeom    qgeom;
1682d0609cedSBarry Smith           PetscErrorCode ierr;
16832a4e142eSMatthew G. Knepley 
16842a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
1685083401c6SMatthew G. Knepley           qgeom.J        = &fegeom.J[q * dE * dE];
1686083401c6SMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * dE * dE];
16872a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
168863a3b9bcSJacob 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);
1689d3a7d86cSMatthew G. Knepley           if (transform) {
1690083401c6SMatthew G. Knepley             gcoords = &coords[dE * Nq];
16919566063dSJacob Faibussowitsch             PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx));
1692d3a7d86cSMatthew G. Knepley           } else {
1693083401c6SMatthew G. Knepley             gcoords = &coords[dE * q];
1694d3a7d86cSMatthew G. Knepley           }
16952df84da0SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.;
1696083401c6SMatthew G. Knepley           ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx);
1697e735a8a9SMatthew G. Knepley           if (ierr) {
16989566063dSJacob Faibussowitsch             PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x));
16999566063dSJacob Faibussowitsch             PetscCall(DMRestoreLocalVector(dm, &localX));
17009566063dSJacob Faibussowitsch             PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1701e735a8a9SMatthew G. Knepley           }
17029566063dSJacob Faibussowitsch           if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
170396959cd1SMatthew G. Knepley           /* Call once for each face, except for lagrange field */
17049566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant));
17059566063dSJacob Faibussowitsch           else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant));
170663a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
170715496722SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
1708beaa55a6SMatthew G. Knepley             const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
17099371c9d4SSatish Balay             if (debug)
17109371c9d4SSatish 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.),
17119371c9d4SSatish Balay                                     (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q])));
17124bee2e38SMatthew G. Knepley             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
171373d901b8SMatthew G. Knepley           }
171473d901b8SMatthew G. Knepley         }
1715083401c6SMatthew G. Knepley         fOff += Nb;
17169c3cf19fSMatthew G. Knepley         qc += Nc;
1717083401c6SMatthew G. Knepley         localDiff[fields[f]] += elemDiff;
171863a3b9bcSJacob 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]]));
171973d901b8SMatthew G. Knepley       }
17209566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x));
1721083401c6SMatthew G. Knepley     }
1722083401c6SMatthew G. Knepley     if (label) {
17239566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pointIS, &points));
17249566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1725083401c6SMatthew G. Knepley     }
17269566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(fieldIS, &fields));
17279566063dSJacob Faibussowitsch     PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
172873d901b8SMatthew G. Knepley   }
17299566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
17301c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
17319566063dSJacob Faibussowitsch   PetscCall(PetscFree(localDiff));
1732083401c6SMatthew G. Knepley   for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]);
17333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
173473d901b8SMatthew G. Knepley }
173573d901b8SMatthew G. Knepley 
1736e729f68cSMatthew G. Knepley /*@C
1737e729f68cSMatthew 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.
1738e729f68cSMatthew G. Knepley 
173920f4b53cSBarry Smith   Collective
1740c0f8e1fdSMatthew G. Knepley 
1741e729f68cSMatthew G. Knepley   Input Parameters:
1742a1cb98faSBarry Smith + dm    - The `DM`
17430163fd50SMatthew G. Knepley . time  - The time
174420f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation
174520f4b53cSBarry Smith . ctxs  - Optional array of contexts to pass to each function, or `NULL`.
1746e729f68cSMatthew G. Knepley - X     - The coefficient vector u_h
1747e729f68cSMatthew G. Knepley 
1748e729f68cSMatthew G. Knepley   Output Parameter:
174920f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell
1750e729f68cSMatthew G. Knepley 
1751e729f68cSMatthew G. Knepley   Level: developer
1752e729f68cSMatthew G. Knepley 
17531cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1754e729f68cSMatthew G. Knepley @*/
1755d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1756d71ae5a4SJacob Faibussowitsch {
1757e729f68cSMatthew G. Knepley   PetscSection     section;
1758e729f68cSMatthew G. Knepley   PetscQuadrature  quad;
1759e729f68cSMatthew G. Knepley   Vec              localX;
17604bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
1761e729f68cSMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
17624bee2e38SMatthew G. Knepley   PetscReal       *coords;
1763e729f68cSMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
1764485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset;
1765e729f68cSMatthew G. Knepley 
1766e729f68cSMatthew G. Knepley   PetscFunctionBegin;
17679566063dSJacob Faibussowitsch   PetscCall(VecSet(D, 0.0));
17689566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17699566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
17709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
17719566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
17729566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
17739566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX));
17749566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
17759566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
1776e729f68cSMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
1777e729f68cSMatthew G. Knepley     PetscObject  obj;
1778e729f68cSMatthew G. Knepley     PetscClassId id;
1779e729f68cSMatthew G. Knepley     PetscInt     Nc;
1780e729f68cSMatthew G. Knepley 
17819566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
17829566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
1783e729f68cSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
1784e729f68cSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
1785e729f68cSMatthew G. Knepley 
17869566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
17879566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
1788e729f68cSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
1789e729f68cSMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
1790e729f68cSMatthew G. Knepley 
17919566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
17929566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
179363a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1794e729f68cSMatthew G. Knepley     numComponents += Nc;
1795e729f68cSMatthew G. Knepley   }
17969566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
179763a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
17989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
17999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1800e729f68cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1801e729f68cSMatthew G. Knepley     PetscScalar *x        = NULL;
18026f288a59SMatthew G. Knepley     PetscScalar  elemDiff = 0.0;
18039c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1804e729f68cSMatthew G. Knepley 
18059566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
1806e8e188d2SZach Atkins     PetscCall(DMPlexVecGetOrientedClosure_Internal(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x));
1807e729f68cSMatthew G. Knepley 
1808e729f68cSMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1809e729f68cSMatthew G. Knepley       PetscObject  obj;
1810e729f68cSMatthew G. Knepley       PetscClassId id;
1811e729f68cSMatthew G. Knepley       void *const  ctx = ctxs ? ctxs[field] : NULL;
1812e729f68cSMatthew G. Knepley       PetscInt     Nb, Nc, q, fc;
1813e729f68cSMatthew G. Knepley 
18149566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, &obj));
18159566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
18169371c9d4SSatish Balay       if (id == PETSCFE_CLASSID) {
18179371c9d4SSatish Balay         PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
18189371c9d4SSatish Balay         PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
18199371c9d4SSatish Balay       } else if (id == PETSCFV_CLASSID) {
18209371c9d4SSatish Balay         PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
18219371c9d4SSatish Balay         Nb = 1;
18229371c9d4SSatish Balay       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
182323f34ed2SToby Isaac       if (funcs[field]) {
18247318780aSToby Isaac         for (q = 0; q < Nq; ++q) {
18252a4e142eSMatthew G. Knepley           PetscFEGeom qgeom;
18262a4e142eSMatthew G. Knepley 
18272a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
18282a4e142eSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * coordDim * coordDim];
18292a4e142eSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
18302a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
183163a3b9bcSJacob 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);
18329566063dSJacob Faibussowitsch           PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx));
1833c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument)
1834e735a8a9SMatthew G. Knepley           if (ierr) {
18359566063dSJacob Faibussowitsch             PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
18369566063dSJacob Faibussowitsch             PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
18379566063dSJacob Faibussowitsch             PetscCall(DMRestoreLocalVector(dm, &localX));
1838e735a8a9SMatthew G. Knepley           }
1839c3e24edfSBarry Smith #endif
18409566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant));
18419566063dSJacob Faibussowitsch           else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant));
184263a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1843e729f68cSMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
1844beaa55a6SMatthew G. Knepley             const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
18454bee2e38SMatthew G. Knepley             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1846e729f68cSMatthew G. Knepley           }
1847e729f68cSMatthew G. Knepley         }
184823f34ed2SToby Isaac       }
1849beaa55a6SMatthew G. Knepley       fieldOffset += Nb;
18509c3cf19fSMatthew G. Knepley       qc += Nc;
1851e729f68cSMatthew G. Knepley     }
18529566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
18539566063dSJacob Faibussowitsch     PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES));
1854e729f68cSMatthew G. Knepley   }
18559566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
18569566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
18579566063dSJacob Faibussowitsch   PetscCall(VecSqrtAbs(D));
18583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1859e729f68cSMatthew G. Knepley }
1860e729f68cSMatthew G. Knepley 
18615f0b18bfSMatthew G. Knepley /*@
186220f4b53cSBarry Smith   DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1
18635f0b18bfSMatthew G. Knepley 
186420f4b53cSBarry Smith   Collective
18655f0b18bfSMatthew G. Knepley 
18665f0b18bfSMatthew G. Knepley   Input Parameters:
1867a1cb98faSBarry Smith + dm   - The `DM`
18685f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h
18695f0b18bfSMatthew G. Knepley 
18705f0b18bfSMatthew G. Knepley   Output Parameter:
1871a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function
18725f0b18bfSMatthew G. Knepley 
18735f0b18bfSMatthew G. Knepley   Level: developer
18745f0b18bfSMatthew G. Knepley 
1875a1cb98faSBarry Smith   Note:
1876a1cb98faSBarry 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
1877a1cb98faSBarry Smith 
18781cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
18795f0b18bfSMatthew G. Knepley @*/
1880d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC)
1881d71ae5a4SJacob Faibussowitsch {
18825f0b18bfSMatthew G. Knepley   PetscInt         debug = ((DM_Plex *)dm->data)->printFEM;
18835f0b18bfSMatthew G. Knepley   DM               dmc;
18845f0b18bfSMatthew G. Knepley   PetscQuadrature  quad;
18855f0b18bfSMatthew G. Knepley   PetscScalar     *interpolant, *valsum;
18865f0b18bfSMatthew G. Knepley   PetscFEGeom      fegeom;
18875f0b18bfSMatthew G. Knepley   PetscReal       *coords;
18885f0b18bfSMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
18895f0b18bfSMatthew G. Knepley   PetscInt         dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v;
18905f0b18bfSMatthew G. Knepley 
18915f0b18bfSMatthew G. Knepley   PetscFunctionBegin;
18929566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite));
18939566063dSJacob Faibussowitsch   PetscCall(VecGetDM(locC, &dmc));
18949566063dSJacob Faibussowitsch   PetscCall(VecSet(locC, 0.0));
18959566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
18969566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
18975f0b18bfSMatthew G. Knepley   fegeom.dimEmbed = cdim;
18989566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
18995f0b18bfSMatthew G. Knepley   PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
19005f0b18bfSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
19015f0b18bfSMatthew G. Knepley     PetscObject  obj;
19025f0b18bfSMatthew G. Knepley     PetscClassId id;
19035f0b18bfSMatthew G. Knepley     PetscInt     fNc;
19045f0b18bfSMatthew G. Knepley 
19059566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, f, NULL, &obj));
19069566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
19075f0b18bfSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
19085f0b18bfSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
19095f0b18bfSMatthew G. Knepley 
19109566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
19119566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &fNc));
19125f0b18bfSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
19135f0b18bfSMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
19145f0b18bfSMatthew G. Knepley 
19159566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
19169566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &fNc));
191763a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
19185f0b18bfSMatthew G. Knepley     Nc += fNc;
19195f0b18bfSMatthew G. Knepley   }
19209566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
192163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc);
19229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ));
19239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
19249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
19255f0b18bfSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
19265f0b18bfSMatthew G. Knepley     PetscScalar volsum = 0.0;
19275f0b18bfSMatthew G. Knepley     PetscInt   *star   = NULL;
19285f0b18bfSMatthew G. Knepley     PetscInt    starSize, st, fc;
19295f0b18bfSMatthew G. Knepley 
19309566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(valsum, Nc));
19319566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
19325f0b18bfSMatthew G. Knepley     for (st = 0; st < starSize * 2; st += 2) {
19335f0b18bfSMatthew G. Knepley       const PetscInt cell = star[st];
19345f0b18bfSMatthew G. Knepley       PetscScalar   *val  = &valsum[Nc];
19355f0b18bfSMatthew G. Knepley       PetscScalar   *x    = NULL;
19365f0b18bfSMatthew G. Knepley       PetscReal      vol  = 0.0;
19375f0b18bfSMatthew G. Knepley       PetscInt       foff = 0;
19385f0b18bfSMatthew G. Knepley 
19395f0b18bfSMatthew G. Knepley       if ((cell < cStart) || (cell >= cEnd)) continue;
19409566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
19419566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x));
19425f0b18bfSMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
19435f0b18bfSMatthew G. Knepley         PetscObject  obj;
19445f0b18bfSMatthew G. Knepley         PetscClassId id;
19455f0b18bfSMatthew G. Knepley         PetscInt     Nb, fNc, q;
19465f0b18bfSMatthew G. Knepley 
19479566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(val, Nc));
19489566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, f, NULL, &obj));
19499566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
19509371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
19519371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc));
19529371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
19539371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
19549371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc));
19559371c9d4SSatish Balay           Nb = 1;
19569371c9d4SSatish Balay         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
19575f0b18bfSMatthew G. Knepley         for (q = 0; q < Nq; ++q) {
19585f0b18bfSMatthew G. Knepley           const PetscReal wt = quadWeights[q] * fegeom.detJ[q];
19595f0b18bfSMatthew G. Knepley           PetscFEGeom     qgeom;
19605f0b18bfSMatthew G. Knepley 
19615f0b18bfSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
19625f0b18bfSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * cdim * cdim];
19635f0b18bfSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * cdim * cdim];
19645f0b18bfSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
196563a3b9bcSJacob 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);
19669566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant));
196763a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
19685f0b18bfSMatthew G. Knepley           for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt;
19695f0b18bfSMatthew G. Knepley           vol += wt;
19705f0b18bfSMatthew G. Knepley         }
19715f0b18bfSMatthew G. Knepley         foff += Nb;
19725f0b18bfSMatthew G. Knepley       }
19739566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x));
19745f0b18bfSMatthew G. Knepley       for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc];
19755f0b18bfSMatthew G. Knepley       volsum += vol;
19765f0b18bfSMatthew G. Knepley       if (debug) {
19779566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell));
19785f0b18bfSMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
19799566063dSJacob Faibussowitsch           if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
19809566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc])));
19815f0b18bfSMatthew G. Knepley         }
19829566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
19835f0b18bfSMatthew G. Knepley       }
19845f0b18bfSMatthew G. Knepley     }
19855f0b18bfSMatthew G. Knepley     for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum;
19869566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
19879566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES));
19885f0b18bfSMatthew G. Knepley   }
19899566063dSJacob Faibussowitsch   PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
19903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19915f0b18bfSMatthew G. Knepley }
19925f0b18bfSMatthew G. Knepley 
19935f0b18bfSMatthew G. Knepley /*@
199420f4b53cSBarry Smith   DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1
19951555c271SMatthew G. Knepley 
199620f4b53cSBarry Smith   Collective
1997c0f8e1fdSMatthew G. Knepley 
19981555c271SMatthew G. Knepley   Input Parameters:
1999a1cb98faSBarry Smith + dm   - The `DM`
20005f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h
20011555c271SMatthew G. Knepley 
20021555c271SMatthew G. Knepley   Output Parameter:
2003a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient
20041555c271SMatthew G. Knepley 
20051555c271SMatthew G. Knepley   Level: developer
20061555c271SMatthew G. Knepley 
2007a1cb98faSBarry Smith   Note:
2008a1cb98faSBarry 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
2009a1cb98faSBarry Smith 
20101cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
20111555c271SMatthew G. Knepley @*/
2012d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
2013d71ae5a4SJacob Faibussowitsch {
2014db1066baSMatthew G. Knepley   DM_Plex         *mesh  = (DM_Plex *)dm->data;
2015db1066baSMatthew G. Knepley   PetscInt         debug = mesh->printFEM;
20161555c271SMatthew G. Knepley   DM               dmC;
20171555c271SMatthew G. Knepley   PetscQuadrature  quad;
20181555c271SMatthew G. Knepley   PetscScalar     *interpolant, *gradsum;
20194bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
20204bee2e38SMatthew G. Knepley   PetscReal       *coords;
20211555c271SMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
2022485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
20231555c271SMatthew G. Knepley 
20241555c271SMatthew G. Knepley   PetscFunctionBegin;
20259566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite));
20269566063dSJacob Faibussowitsch   PetscCall(VecGetDM(locC, &dmC));
20279566063dSJacob Faibussowitsch   PetscCall(VecSet(locC, 0.0));
20289566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
20299566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
20304bee2e38SMatthew G. Knepley   fegeom.dimEmbed = coordDim;
20319566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
20325f80ce2aSJacob Faibussowitsch   PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
20331555c271SMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
20341555c271SMatthew G. Knepley     PetscObject  obj;
20351555c271SMatthew G. Knepley     PetscClassId id;
20361555c271SMatthew G. Knepley     PetscInt     Nc;
20371555c271SMatthew G. Knepley 
20389566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
20399566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
20401555c271SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
20411555c271SMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
20421555c271SMatthew G. Knepley 
20439566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
20449566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
20451555c271SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
20461555c271SMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
20471555c271SMatthew G. Knepley 
20489566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
20499566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
205063a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
20511555c271SMatthew G. Knepley     numComponents += Nc;
20521555c271SMatthew G. Knepley   }
20539566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
205463a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
20559566063dSJacob 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));
20569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
20579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
20581555c271SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
20591555c271SMatthew G. Knepley     PetscScalar volsum = 0.0;
20601555c271SMatthew G. Knepley     PetscInt   *star   = NULL;
20611555c271SMatthew G. Knepley     PetscInt    starSize, st, d, fc;
20621555c271SMatthew G. Knepley 
20639566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gradsum, coordDim * numComponents));
20649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
20651555c271SMatthew G. Knepley     for (st = 0; st < starSize * 2; st += 2) {
20661555c271SMatthew G. Knepley       const PetscInt cell = star[st];
20671555c271SMatthew G. Knepley       PetscScalar   *grad = &gradsum[coordDim * numComponents];
20681555c271SMatthew G. Knepley       PetscScalar   *x    = NULL;
20691555c271SMatthew G. Knepley       PetscReal      vol  = 0.0;
20701555c271SMatthew G. Knepley 
20711555c271SMatthew G. Knepley       if ((cell < cStart) || (cell >= cEnd)) continue;
20729566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
20739566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x));
20741555c271SMatthew G. Knepley       for (field = 0, fieldOffset = 0; field < numFields; ++field) {
20751555c271SMatthew G. Knepley         PetscObject  obj;
20761555c271SMatthew G. Knepley         PetscClassId id;
20771555c271SMatthew G. Knepley         PetscInt     Nb, Nc, q, qc = 0;
20781555c271SMatthew G. Knepley 
20799566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(grad, coordDim * numComponents));
20809566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, field, NULL, &obj));
20819566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
20829371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
20839371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
20849371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
20859371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
20869371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
20879371c9d4SSatish Balay           Nb = 1;
20889371c9d4SSatish Balay         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
20891555c271SMatthew G. Knepley         for (q = 0; q < Nq; ++q) {
20902a4e142eSMatthew G. Knepley           PetscFEGeom qgeom;
20912a4e142eSMatthew G. Knepley 
20922a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
20932a4e142eSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * coordDim * coordDim];
20942a4e142eSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
20952a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
209663a3b9bcSJacob 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);
20979566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant));
209863a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
20991555c271SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
210053d2db2dSJoe Wallwork             const PetscReal wt = quadWeights[q * qNc + qc];
21011555c271SMatthew G. Knepley 
21024bee2e38SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q];
21031555c271SMatthew G. Knepley           }
21044bee2e38SMatthew G. Knepley           vol += quadWeights[q * qNc] * fegeom.detJ[q];
21051555c271SMatthew G. Knepley         }
21061555c271SMatthew G. Knepley         fieldOffset += Nb;
21071555c271SMatthew G. Knepley         qc += Nc;
21081555c271SMatthew G. Knepley       }
21099566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x));
2110f8527842SMatthew G. Knepley       for (fc = 0; fc < numComponents; ++fc) {
2111ad540459SPierre Jolivet         for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d];
2112f8527842SMatthew G. Knepley       }
2113f8527842SMatthew G. Knepley       volsum += vol;
2114db1066baSMatthew G. Knepley       if (debug) {
21159566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell));
21161555c271SMatthew G. Knepley         for (fc = 0; fc < numComponents; ++fc) {
21171555c271SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) {
21189566063dSJacob Faibussowitsch             if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
21199566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d])));
21201555c271SMatthew G. Knepley           }
21211555c271SMatthew G. Knepley         }
21229566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
2123db1066baSMatthew G. Knepley       }
21241555c271SMatthew G. Knepley     }
21251555c271SMatthew G. Knepley     for (fc = 0; fc < numComponents; ++fc) {
21261555c271SMatthew G. Knepley       for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum;
21271555c271SMatthew G. Knepley     }
21289566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
21299566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES));
21301555c271SMatthew G. Knepley   }
21319566063dSJacob Faibussowitsch   PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
21323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21331555c271SMatthew G. Knepley }
21341555c271SMatthew G. Knepley 
2135d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user)
2136d71ae5a4SJacob Faibussowitsch {
2137338f77d5SMatthew G. Knepley   DM           dmAux = NULL;
213861aaff12SToby Isaac   PetscDS      prob, probAux = NULL;
213973d901b8SMatthew G. Knepley   PetscSection section, sectionAux;
2140338f77d5SMatthew G. Knepley   Vec          locX, locA;
2141c330f8ffSToby Isaac   PetscInt     dim, numCells = cEnd - cStart, c, f;
2142c330f8ffSToby Isaac   PetscBool    useFVM = PETSC_FALSE;
2143338f77d5SMatthew G. Knepley   /* DS */
2144338f77d5SMatthew G. Knepley   PetscInt           Nf, totDim, *uOff, *uOff_x, numConstants;
2145338f77d5SMatthew G. Knepley   PetscInt           NfAux, totDimAux, *aOff;
2146338f77d5SMatthew G. Knepley   PetscScalar       *u, *a;
2147338f77d5SMatthew G. Knepley   const PetscScalar *constants;
2148338f77d5SMatthew G. Knepley   /* Geometry */
2149c330f8ffSToby Isaac   PetscFEGeom       *cgeomFEM;
2150338f77d5SMatthew G. Knepley   DM                 dmGrad;
2151c330f8ffSToby Isaac   PetscQuadrature    affineQuad      = NULL;
2152338f77d5SMatthew G. Knepley   Vec                cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
2153b5a3613cSMatthew G. Knepley   PetscFVCellGeom   *cgeomFVM;
2154338f77d5SMatthew G. Knepley   const PetscScalar *lgrad;
2155b7260050SToby Isaac   PetscInt           maxDegree;
2156c330f8ffSToby Isaac   DMField            coordField;
2157c330f8ffSToby Isaac   IS                 cellIS;
215873d901b8SMatthew G. Knepley 
215973d901b8SMatthew G. Knepley   PetscFunctionBegin;
21609566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
21619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
21629566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
21639566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
2164338f77d5SMatthew G. Knepley   /* Determine which discretizations we have */
2165b5a3613cSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
2166b5a3613cSMatthew G. Knepley     PetscObject  obj;
2167b5a3613cSMatthew G. Knepley     PetscClassId id;
2168b5a3613cSMatthew G. Knepley 
21699566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
21709566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
2171338f77d5SMatthew G. Knepley     if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
2172338f77d5SMatthew G. Knepley   }
2173338f77d5SMatthew G. Knepley   /* Get local solution with boundary values */
21749566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &locX));
21759566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
21769566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
21779566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
2178338f77d5SMatthew G. Knepley   /* Read DS information */
21799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
21809566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(prob, &uOff));
21819566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x));
21829566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS));
21839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(prob, &numConstants, &constants));
2184338f77d5SMatthew G. Knepley   /* Read Auxiliary DS information */
21859566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
21869a2a23afSMatthew G. Knepley   if (locA) {
21879566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
21889566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
21899566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(probAux, &NfAux));
21909566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
21919566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
21929566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(probAux, &aOff));
2193338f77d5SMatthew G. Knepley   }
2194338f77d5SMatthew G. Knepley   /* Allocate data  arrays */
21959566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells * totDim, &u));
21969566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
2197338f77d5SMatthew G. Knepley   /* Read out geometry */
21989566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
21999566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
2200b7260050SToby Isaac   if (maxDegree <= 1) {
22019566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
220248a46eb9SPierre Jolivet     if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM));
2203b5a3613cSMatthew G. Knepley   }
2204b5a3613cSMatthew G. Knepley   if (useFVM) {
2205338f77d5SMatthew G. Knepley     PetscFV   fv = NULL;
2206b5a3613cSMatthew G. Knepley     Vec       grad;
2207b5a3613cSMatthew G. Knepley     PetscInt  fStart, fEnd;
2208b5a3613cSMatthew G. Knepley     PetscBool compGrad;
2209b5a3613cSMatthew G. Knepley 
2210338f77d5SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
2211338f77d5SMatthew G. Knepley       PetscObject  obj;
2212338f77d5SMatthew G. Knepley       PetscClassId id;
2213338f77d5SMatthew G. Knepley 
22149566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
22159566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
22169371c9d4SSatish Balay       if (id == PETSCFV_CLASSID) {
22179371c9d4SSatish Balay         fv = (PetscFV)obj;
22189371c9d4SSatish Balay         break;
22199371c9d4SSatish Balay       }
2220338f77d5SMatthew G. Knepley     }
22219566063dSJacob Faibussowitsch     PetscCall(PetscFVGetComputeGradients(fv, &compGrad));
22229566063dSJacob Faibussowitsch     PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE));
22239566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM));
22249566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad));
22259566063dSJacob Faibussowitsch     PetscCall(PetscFVSetComputeGradients(fv, compGrad));
22269566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
2227b5a3613cSMatthew G. Knepley     /* Reconstruct and limit cell gradients */
22289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
22299566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmGrad, &grad));
22309566063dSJacob Faibussowitsch     PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad));
2231b5a3613cSMatthew G. Knepley     /* Communicate gradient values */
22329566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmGrad, &locGrad));
22339566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad));
22349566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad));
22359566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
2236b5a3613cSMatthew G. Knepley     /* Handle non-essential (e.g. outflow) boundary values */
22379566063dSJacob Faibussowitsch     PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad));
22389566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &lgrad));
2239b5a3613cSMatthew G. Knepley   }
2240338f77d5SMatthew G. Knepley   /* Read out data from inputs */
224173d901b8SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
224273d901b8SMatthew G. Knepley     PetscScalar *x = NULL;
224373d901b8SMatthew G. Knepley     PetscInt     i;
224473d901b8SMatthew G. Knepley 
22459566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x));
22460f2d7e86SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
22479566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x));
224873d901b8SMatthew G. Knepley     if (dmAux) {
22499566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x));
22500f2d7e86SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
22519566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x));
225273d901b8SMatthew G. Knepley     }
225373d901b8SMatthew G. Knepley   }
2254338f77d5SMatthew G. Knepley   /* Do integration for each field */
225573d901b8SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
2256c1f031eeSMatthew G. Knepley     PetscObject  obj;
2257c1f031eeSMatthew G. Knepley     PetscClassId id;
2258c1f031eeSMatthew G. Knepley     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
225973d901b8SMatthew G. Knepley 
22609566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
22619566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
2262c1f031eeSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
2263c1f031eeSMatthew G. Knepley       PetscFE         fe = (PetscFE)obj;
2264c1f031eeSMatthew G. Knepley       PetscQuadrature q;
2265c330f8ffSToby Isaac       PetscFEGeom    *chunkGeom = NULL;
2266c1f031eeSMatthew G. Knepley       PetscInt        Nq, Nb;
2267c1f031eeSMatthew G. Knepley 
22689566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
22699566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &q));
22709566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
22719566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
2272c1f031eeSMatthew G. Knepley       blockSize = Nb * Nq;
227373d901b8SMatthew G. Knepley       batchSize = numBlocks * blockSize;
22749566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
227573d901b8SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
227673d901b8SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
227773d901b8SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
227873d901b8SMatthew G. Knepley       offset    = numCells - Nr;
227948a46eb9SPierre Jolivet       if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM));
22809566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
22819566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral));
22829566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom));
22839566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf]));
22849566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom));
228548a46eb9SPierre Jolivet       if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM));
2286c1f031eeSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
2287c1f031eeSMatthew G. Knepley       PetscInt       foff;
2288420e96edSMatthew G. Knepley       PetscPointFunc obj_func;
2289b69edc29SMatthew G. Knepley       PetscScalar    lint;
2290c1f031eeSMatthew G. Knepley 
22919566063dSJacob Faibussowitsch       PetscCall(PetscDSGetObjective(prob, f, &obj_func));
22929566063dSJacob Faibussowitsch       PetscCall(PetscDSGetFieldOffset(prob, f, &foff));
2293c1f031eeSMatthew G. Knepley       if (obj_func) {
2294c1f031eeSMatthew G. Knepley         for (c = 0; c < numCells; ++c) {
2295b5a3613cSMatthew G. Knepley           PetscScalar *u_x;
2296b5a3613cSMatthew G. Knepley 
22979566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x));
2298338f77d5SMatthew 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);
2299338f77d5SMatthew G. Knepley           cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume;
230073d901b8SMatthew G. Knepley         }
2301c1f031eeSMatthew G. Knepley       }
230263a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
2303c1f031eeSMatthew G. Knepley   }
2304338f77d5SMatthew G. Knepley   /* Cleanup data arrays */
2305b5a3613cSMatthew G. Knepley   if (useFVM) {
23069566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(locGrad, &lgrad));
23079566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
23089566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
23099566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&faceGeometryFVM));
23109566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellGeometryFVM));
23119566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmGrad));
2312b5a3613cSMatthew G. Knepley   }
23139566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscFree(a));
23149566063dSJacob Faibussowitsch   PetscCall(PetscFree(u));
2315338f77d5SMatthew G. Knepley   /* Cleanup */
231648a46eb9SPierre Jolivet   if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM));
23179566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&affineQuad));
23189566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
23199566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &locX));
23203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2321338f77d5SMatthew G. Knepley }
2322338f77d5SMatthew G. Knepley 
2323338f77d5SMatthew G. Knepley /*@
2324338f77d5SMatthew G. Knepley   DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user
2325338f77d5SMatthew G. Knepley 
2326338f77d5SMatthew G. Knepley   Input Parameters:
2327338f77d5SMatthew G. Knepley + dm   - The mesh
2328338f77d5SMatthew G. Knepley . X    - Global input vector
2329338f77d5SMatthew G. Knepley - user - The user context
2330338f77d5SMatthew G. Knepley 
2331338f77d5SMatthew G. Knepley   Output Parameter:
2332338f77d5SMatthew G. Knepley . integral - Integral for each field
2333338f77d5SMatthew G. Knepley 
2334338f77d5SMatthew G. Knepley   Level: developer
2335338f77d5SMatthew G. Knepley 
23361cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2337338f77d5SMatthew G. Knepley @*/
2338d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user)
2339d71ae5a4SJacob Faibussowitsch {
2340338f77d5SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dm->data;
2341b8feb594SMatthew G. Knepley   PetscScalar *cintegral, *lintegral;
2342412e9a14SMatthew G. Knepley   PetscInt     Nf, f, cellHeight, cStart, cEnd, cell;
2343338f77d5SMatthew G. Knepley 
2344338f77d5SMatthew G. Knepley   PetscFunctionBegin;
2345338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2346338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
23474f572ea9SToby Isaac   PetscAssertPointer(integral, 3);
23489566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
23499566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
23509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
23519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2352338f77d5SMatthew G. Knepley   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
23539566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral));
23549566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user));
2355338f77d5SMatthew G. Knepley   /* Sum up values */
2356338f77d5SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
2357338f77d5SMatthew G. Knepley     const PetscInt c = cell - cStart;
2358338f77d5SMatthew G. Knepley 
23599566063dSJacob Faibussowitsch     if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]));
2360b8feb594SMatthew G. Knepley     for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f];
2361338f77d5SMatthew G. Knepley   }
23621c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
236373d901b8SMatthew G. Knepley   if (mesh->printFEM) {
23649566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:"));
23659566063dSJacob Faibussowitsch     for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f])));
23669566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n"));
236773d901b8SMatthew G. Knepley   }
23689566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lintegral, cintegral));
23699566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
23703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2371338f77d5SMatthew G. Knepley }
2372338f77d5SMatthew G. Knepley 
2373338f77d5SMatthew G. Knepley /*@
2374338f77d5SMatthew G. Knepley   DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user
2375338f77d5SMatthew G. Knepley 
2376338f77d5SMatthew G. Knepley   Input Parameters:
2377338f77d5SMatthew G. Knepley + dm   - The mesh
2378338f77d5SMatthew G. Knepley . X    - Global input vector
2379338f77d5SMatthew G. Knepley - user - The user context
2380338f77d5SMatthew G. Knepley 
2381338f77d5SMatthew G. Knepley   Output Parameter:
238260225df5SJacob Faibussowitsch . F - Cellwise integrals for each field
2383338f77d5SMatthew G. Knepley 
2384338f77d5SMatthew G. Knepley   Level: developer
2385338f77d5SMatthew G. Knepley 
23861cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2387338f77d5SMatthew G. Knepley @*/
2388d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user)
2389d71ae5a4SJacob Faibussowitsch {
2390338f77d5SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dm->data;
2391338f77d5SMatthew G. Knepley   DM           dmF;
2392338f77d5SMatthew G. Knepley   PetscSection sectionF;
2393338f77d5SMatthew G. Knepley   PetscScalar *cintegral, *af;
2394412e9a14SMatthew G. Knepley   PetscInt     Nf, f, cellHeight, cStart, cEnd, cell;
2395338f77d5SMatthew G. Knepley 
2396338f77d5SMatthew G. Knepley   PetscFunctionBegin;
2397338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2398338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2399338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
24009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
24019566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
24029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
24039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2404338f77d5SMatthew G. Knepley   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
24059566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral));
24069566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user));
2407338f77d5SMatthew G. Knepley   /* Put values in F*/
24089566063dSJacob Faibussowitsch   PetscCall(VecGetDM(F, &dmF));
24099566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmF, &sectionF));
24109566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &af));
2411338f77d5SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
2412338f77d5SMatthew G. Knepley     const PetscInt c = cell - cStart;
2413338f77d5SMatthew G. Knepley     PetscInt       dof, off;
2414338f77d5SMatthew G. Knepley 
24159566063dSJacob Faibussowitsch     if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]));
24169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(sectionF, cell, &dof));
24179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(sectionF, cell, &off));
241863a3b9bcSJacob Faibussowitsch     PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf);
2419338f77d5SMatthew G. Knepley     for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f];
2420338f77d5SMatthew G. Knepley   }
24219566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &af));
24229566063dSJacob Faibussowitsch   PetscCall(PetscFree(cintegral));
24239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
24243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
242573d901b8SMatthew G. Knepley }
242673d901b8SMatthew G. Knepley 
2427d71ae5a4SJacob 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)
2428d71ae5a4SJacob Faibussowitsch {
24299b6f715bSMatthew G. Knepley   DM                 plex = NULL, plexA = NULL;
2430a6e0b375SMatthew G. Knepley   DMEnclosureType    encAux;
24319b6f715bSMatthew G. Knepley   PetscDS            prob, probAux       = NULL;
24329b6f715bSMatthew G. Knepley   PetscSection       section, sectionAux = NULL;
24339b6f715bSMatthew G. Knepley   Vec                locA = NULL;
24349b6f715bSMatthew G. Knepley   DMField            coordField;
24359b6f715bSMatthew G. Knepley   PetscInt           Nf, totDim, *uOff, *uOff_x;
24369b6f715bSMatthew G. Knepley   PetscInt           NfAux = 0, totDimAux = 0, *aOff = NULL;
24379b6f715bSMatthew G. Knepley   PetscScalar       *u, *a = NULL;
243864c72086SMatthew G. Knepley   const PetscScalar *constants;
24399b6f715bSMatthew G. Knepley   PetscInt           numConstants, f;
244064c72086SMatthew G. Knepley 
244164c72086SMatthew G. Knepley   PetscFunctionBegin;
24429566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
24439566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
24449566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
24459566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
24469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
244764c72086SMatthew G. Knepley   /* Determine which discretizations we have */
24489b6f715bSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
244964c72086SMatthew G. Knepley     PetscObject  obj;
245064c72086SMatthew G. Knepley     PetscClassId id;
245164c72086SMatthew G. Knepley 
24529566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
24539566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
245463a3b9bcSJacob Faibussowitsch     PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f);
245564c72086SMatthew G. Knepley   }
245664c72086SMatthew G. Knepley   /* Read DS information */
24579566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
24589566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(prob, &uOff));
24599566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x));
24609566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(prob, &numConstants, &constants));
246164c72086SMatthew G. Knepley   /* Read Auxiliary DS information */
24629566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
24639b6f715bSMatthew G. Knepley   if (locA) {
24649b6f715bSMatthew G. Knepley     DM dmAux;
24659b6f715bSMatthew G. Knepley 
24669566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
24679566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
24689566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
24699566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
24709566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(probAux, &NfAux));
24719566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
24729566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
24739566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(probAux, &aOff));
247464c72086SMatthew G. Knepley   }
24759b6f715bSMatthew G. Knepley   /* Integrate over points */
24769b6f715bSMatthew G. Knepley   {
24779b6f715bSMatthew G. Knepley     PetscFEGeom    *fgeom, *chunkGeom = NULL;
2478b7260050SToby Isaac     PetscInt        maxDegree;
24799b6f715bSMatthew G. Knepley     PetscQuadrature qGeom = NULL;
24809b6f715bSMatthew G. Knepley     const PetscInt *points;
24819b6f715bSMatthew G. Knepley     PetscInt        numFaces, face, Nq, field;
24829b6f715bSMatthew G. Knepley     PetscInt        numChunks, chunkSize, chunk, Nr, offset;
248364c72086SMatthew G. Knepley 
24849566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
24859566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
24869566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a));
24879566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
248864c72086SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
248964c72086SMatthew G. Knepley       PetscFE fe;
249064c72086SMatthew G. Knepley 
24919566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe));
24929566063dSJacob Faibussowitsch       if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
24939b6f715bSMatthew G. Knepley       if (!qGeom) {
24949566063dSJacob Faibussowitsch         PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
24959566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)qGeom));
24969b6f715bSMatthew G. Knepley       }
24979566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
24989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
24999b6f715bSMatthew G. Knepley       for (face = 0; face < numFaces; ++face) {
2500f15274beSMatthew Knepley         const PetscInt point = points[face], *support;
25019b6f715bSMatthew G. Knepley         PetscScalar   *x     = NULL;
2502f15274beSMatthew Knepley         PetscInt       i;
25039b6f715bSMatthew G. Knepley 
25049566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, point, &support));
25059566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
25069b6f715bSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
25079566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
25089b6f715bSMatthew G. Knepley         if (locA) {
25099b6f715bSMatthew G. Knepley           PetscInt subp;
25109566063dSJacob Faibussowitsch           PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
25119566063dSJacob Faibussowitsch           PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
25129b6f715bSMatthew G. Knepley           for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i];
25139566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
25149b6f715bSMatthew G. Knepley         }
25159b6f715bSMatthew G. Knepley       }
25169b6f715bSMatthew G. Knepley       /* Get blocking */
25179b6f715bSMatthew G. Knepley       {
25189b6f715bSMatthew G. Knepley         PetscQuadrature q;
25199b6f715bSMatthew G. Knepley         PetscInt        numBatches, batchSize, numBlocks, blockSize;
25209b6f715bSMatthew G. Knepley         PetscInt        Nq, Nb;
25219b6f715bSMatthew G. Knepley 
25229566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
25239566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &q));
25249566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
25259566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
252664c72086SMatthew G. Knepley         blockSize = Nb * Nq;
252764c72086SMatthew G. Knepley         batchSize = numBlocks * blockSize;
25289b6f715bSMatthew G. Knepley         chunkSize = numBatches * batchSize;
25299566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
25309b6f715bSMatthew G. Knepley         numChunks = numFaces / chunkSize;
25319b6f715bSMatthew G. Knepley         Nr        = numFaces % chunkSize;
253264c72086SMatthew G. Knepley         offset    = numFaces - Nr;
253364c72086SMatthew G. Knepley       }
25349b6f715bSMatthew G. Knepley       /* Do integration for each field */
25359b6f715bSMatthew G. Knepley       for (chunk = 0; chunk < numChunks; ++chunk) {
25369566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom));
25379566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral));
25389566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom));
253964c72086SMatthew G. Knepley       }
25409566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
25419566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf]));
25429566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
254364c72086SMatthew G. Knepley       /* Cleanup data arrays */
25449566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
25459566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&qGeom));
25469566063dSJacob Faibussowitsch       PetscCall(PetscFree2(u, a));
25479566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pointIS, &points));
254864c72086SMatthew G. Knepley     }
254964c72086SMatthew G. Knepley   }
25509566063dSJacob Faibussowitsch   if (plex) PetscCall(DMDestroy(&plex));
25519566063dSJacob Faibussowitsch   if (plexA) PetscCall(DMDestroy(&plexA));
25523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25539b6f715bSMatthew G. Knepley }
25549b6f715bSMatthew G. Knepley 
255560225df5SJacob Faibussowitsch /*@C
25569b6f715bSMatthew G. Knepley   DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
25579b6f715bSMatthew G. Knepley 
25589b6f715bSMatthew G. Knepley   Input Parameters:
25599b6f715bSMatthew G. Knepley + dm      - The mesh
25609b6f715bSMatthew G. Knepley . X       - Global input vector
2561a1cb98faSBarry Smith . label   - The boundary `DMLabel`
2562a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values
2563a1cb98faSBarry Smith . vals    - The label values to use, or NULL for all values
256467b8a455SSatish Balay . func    - The function to integrate along the boundary
25659b6f715bSMatthew G. Knepley - user    - The user context
25669b6f715bSMatthew G. Knepley 
25679b6f715bSMatthew G. Knepley   Output Parameter:
25689b6f715bSMatthew G. Knepley . integral - Integral for each field
25699b6f715bSMatthew G. Knepley 
25709b6f715bSMatthew G. Knepley   Level: developer
25719b6f715bSMatthew G. Knepley 
25721cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()`
25739b6f715bSMatthew G. Knepley @*/
2574d71ae5a4SJacob 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)
2575d71ae5a4SJacob Faibussowitsch {
25769b6f715bSMatthew G. Knepley   Vec          locX;
25779b6f715bSMatthew G. Knepley   PetscSection section;
25789b6f715bSMatthew G. Knepley   DMLabel      depthLabel;
25799b6f715bSMatthew G. Knepley   IS           facetIS;
25809b6f715bSMatthew G. Knepley   PetscInt     dim, Nf, f, v;
25819b6f715bSMatthew G. Knepley 
25829b6f715bSMatthew G. Knepley   PetscFunctionBegin;
25839b6f715bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
25849b6f715bSMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2585292bffcbSToby Isaac   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
25864f572ea9SToby Isaac   if (vals) PetscAssertPointer(vals, 5);
25874f572ea9SToby Isaac   PetscAssertPointer(integral, 7);
25889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
25899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
25909566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
25919566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
25929566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
25939566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
25949b6f715bSMatthew G. Knepley   /* Get local solution with boundary values */
25959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &locX));
25969566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
25979566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
25989566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
25999b6f715bSMatthew G. Knepley   /* Loop over label values */
26009566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(integral, Nf));
26019b6f715bSMatthew G. Knepley   for (v = 0; v < numVals; ++v) {
26029b6f715bSMatthew G. Knepley     IS           pointIS;
26039b6f715bSMatthew G. Knepley     PetscInt     numFaces, face;
26049b6f715bSMatthew G. Knepley     PetscScalar *fintegral;
26059b6f715bSMatthew G. Knepley 
26069566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS));
26079b6f715bSMatthew G. Knepley     if (!pointIS) continue; /* No points with that id on this process */
26089b6f715bSMatthew G. Knepley     {
26099b6f715bSMatthew G. Knepley       IS isectIS;
26109b6f715bSMatthew G. Knepley 
26119b6f715bSMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
26129566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
26139566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
26149b6f715bSMatthew G. Knepley       pointIS = isectIS;
26159b6f715bSMatthew G. Knepley     }
26169566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
26179566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numFaces * Nf, &fintegral));
26189566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user));
26199b6f715bSMatthew G. Knepley     /* Sum point contributions into integral */
26209371c9d4SSatish Balay     for (f = 0; f < Nf; ++f)
26219371c9d4SSatish Balay       for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f];
26229566063dSJacob Faibussowitsch     PetscCall(PetscFree(fintegral));
26239566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
26249b6f715bSMatthew G. Knepley   }
26259566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &locX));
26269566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
26279566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
26283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
262964c72086SMatthew G. Knepley }
263064c72086SMatthew G. Knepley 
2631d69c5d34SMatthew G. Knepley /*@
2632a1cb98faSBarry Smith   DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`.
2633d69c5d34SMatthew G. Knepley 
2634d69c5d34SMatthew G. Knepley   Input Parameters:
2635cf51de39SMatthew G. Knepley + dmc       - The coarse mesh
2636cf51de39SMatthew G. Knepley . dmf       - The fine mesh
2637cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology
2638d69c5d34SMatthew G. Knepley - user      - The user context
2639d69c5d34SMatthew G. Knepley 
2640d69c5d34SMatthew G. Knepley   Output Parameter:
2641934789fcSMatthew G. Knepley . In - The interpolation matrix
2642d69c5d34SMatthew G. Knepley 
2643d69c5d34SMatthew G. Knepley   Level: developer
2644d69c5d34SMatthew G. Knepley 
26451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()`
2646d69c5d34SMatthew G. Knepley @*/
2647d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user)
2648d71ae5a4SJacob Faibussowitsch {
2649d69c5d34SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmc->data;
2650d69c5d34SMatthew G. Knepley   const char  *name = "Interpolator";
2651d69c5d34SMatthew G. Knepley   PetscFE     *feRef;
265297c42addSMatthew G. Knepley   PetscFV     *fvRef;
2653d69c5d34SMatthew G. Knepley   PetscSection fsection, fglobalSection;
2654d69c5d34SMatthew G. Knepley   PetscSection csection, cglobalSection;
2655d69c5d34SMatthew G. Knepley   PetscScalar *elemMat;
2656485ad865SMatthew G. Knepley   PetscInt     dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
26572ea9c922SToby Isaac   PetscInt     cTotDim = 0, rTotDim = 0;
2658d69c5d34SMatthew G. Knepley 
2659d69c5d34SMatthew G. Knepley   PetscFunctionBegin;
26609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
26619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmf, &dim));
26629566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
26639566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &fglobalSection));
26649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
26659566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
26669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &Nf));
26679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd));
26689566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef));
2669d69c5d34SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
26702ea9c922SToby Isaac     PetscObject  obj, objc;
26712ea9c922SToby Isaac     PetscClassId id, idc;
26722ea9c922SToby Isaac     PetscInt     rNb = 0, Nc = 0, cNb = 0;
2673d69c5d34SMatthew G. Knepley 
26749566063dSJacob Faibussowitsch     PetscCall(DMGetField(dmf, f, NULL, &obj));
26759566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
267697c42addSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
267797c42addSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
267897c42addSMatthew G. Knepley 
2679cf51de39SMatthew G. Knepley       if (isRefined) {
26809566063dSJacob Faibussowitsch         PetscCall(PetscFERefine(fe, &feRef[f]));
2681cf51de39SMatthew G. Knepley       } else {
26829566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)fe));
2683cf51de39SMatthew G. Knepley         feRef[f] = fe;
2684cf51de39SMatthew G. Knepley       }
26859566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feRef[f], &rNb));
26869566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
268797c42addSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
268897c42addSMatthew G. Knepley       PetscFV        fv = (PetscFV)obj;
268997c42addSMatthew G. Knepley       PetscDualSpace Q;
269097c42addSMatthew G. Knepley 
2691cf51de39SMatthew G. Knepley       if (isRefined) {
26929566063dSJacob Faibussowitsch         PetscCall(PetscFVRefine(fv, &fvRef[f]));
2693cf51de39SMatthew G. Knepley       } else {
26949566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)fv));
2695cf51de39SMatthew G. Knepley         fvRef[f] = fv;
2696cf51de39SMatthew G. Knepley       }
26979566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[f], &Q));
26989566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &rNb));
26999566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &Q));
27009566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
270197c42addSMatthew G. Knepley     }
27029566063dSJacob Faibussowitsch     PetscCall(DMGetField(dmc, f, NULL, &objc));
27039566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(objc, &idc));
27042ea9c922SToby Isaac     if (idc == PETSCFE_CLASSID) {
27052ea9c922SToby Isaac       PetscFE fe = (PetscFE)objc;
27062ea9c922SToby Isaac 
27079566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &cNb));
27082ea9c922SToby Isaac     } else if (id == PETSCFV_CLASSID) {
27092ea9c922SToby Isaac       PetscFV        fv = (PetscFV)obj;
27102ea9c922SToby Isaac       PetscDualSpace Q;
27112ea9c922SToby Isaac 
27129566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &Q));
27139566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &cNb));
2714d69c5d34SMatthew G. Knepley     }
27152ea9c922SToby Isaac     rTotDim += rNb;
27162ea9c922SToby Isaac     cTotDim += cNb;
27172ea9c922SToby Isaac   }
27189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat));
27199566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim));
2720d69c5d34SMatthew G. Knepley   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
2721d69c5d34SMatthew G. Knepley     PetscDualSpace   Qref;
2722d69c5d34SMatthew G. Knepley     PetscQuadrature  f;
2723d69c5d34SMatthew G. Knepley     const PetscReal *qpoints, *qweights;
2724d69c5d34SMatthew G. Knepley     PetscReal       *points;
2725d69c5d34SMatthew G. Knepley     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;
2726d69c5d34SMatthew G. Knepley 
2727d69c5d34SMatthew G. Knepley     /* Compose points from all dual basis functionals */
272897c42addSMatthew G. Knepley     if (feRef[fieldI]) {
27299566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref));
27309566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc));
273197c42addSMatthew G. Knepley     } else {
27329566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref));
27339566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc));
273497c42addSMatthew G. Knepley     }
27359566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim));
2736d69c5d34SMatthew G. Knepley     for (i = 0; i < fpdim; ++i) {
27379566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
27389566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL));
2739d69c5d34SMatthew G. Knepley       npoints += Np;
2740d69c5d34SMatthew G. Knepley     }
27419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(npoints * dim, &points));
2742d69c5d34SMatthew G. Knepley     for (i = 0, k = 0; i < fpdim; ++i) {
27439566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
27449566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL));
27459371c9d4SSatish Balay       for (p = 0; p < Np; ++p, ++k)
27469371c9d4SSatish Balay         for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d];
2747d69c5d34SMatthew G. Knepley     }
2748d69c5d34SMatthew G. Knepley 
2749d69c5d34SMatthew G. Knepley     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
275097c42addSMatthew G. Knepley       PetscObject  obj;
275197c42addSMatthew G. Knepley       PetscClassId id;
27529c3cf19fSMatthew G. Knepley       PetscInt     NcJ = 0, cpdim = 0, j, qNc;
2753d69c5d34SMatthew G. Knepley 
27549566063dSJacob Faibussowitsch       PetscCall(DMGetField(dmc, fieldJ, NULL, &obj));
27559566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
275697c42addSMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
275797c42addSMatthew G. Knepley         PetscFE         fe = (PetscFE)obj;
2758ef0bb6c7SMatthew G. Knepley         PetscTabulation T  = NULL;
2759d69c5d34SMatthew G. Knepley 
2760d69c5d34SMatthew G. Knepley         /* Evaluate basis at points */
27619566063dSJacob Faibussowitsch         PetscCall(PetscFEGetNumComponents(fe, &NcJ));
27629566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &cpdim));
2763ffe73a53SMatthew G. Knepley         /* For now, fields only interpolate themselves */
2764ffe73a53SMatthew G. Knepley         if (fieldI == fieldJ) {
276563a3b9bcSJacob 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);
27669566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T));
2767d69c5d34SMatthew G. Knepley           for (i = 0, k = 0; i < fpdim; ++i) {
27689566063dSJacob Faibussowitsch             PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
27699566063dSJacob Faibussowitsch             PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights));
277063a3b9bcSJacob 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);
2771d69c5d34SMatthew G. Knepley             for (p = 0; p < Np; ++p, ++k) {
277236a6d9c0SMatthew G. Knepley               for (j = 0; j < cpdim; ++j) {
2773d172c84bSMatthew G. Knepley                 /*
2774d172c84bSMatthew G. Knepley                    cTotDim:            Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
2775d172c84bSMatthew G. Knepley                    offsetI, offsetJ:   Offsets into the larger element interpolation matrix for different fields
2776d172c84bSMatthew G. Knepley                    fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
2777d172c84bSMatthew G. Knepley                    qNC, Nc, Ncj, c:    Number of components in this field
2778d172c84bSMatthew G. Knepley                    Np, p:              Number of quad points in the fine grid functional i
2779d172c84bSMatthew G. Knepley                    k:                  i*Np + p, overall point number for the interpolation
2780d172c84bSMatthew G. Knepley                 */
2781ef0bb6c7SMatthew 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];
278236a6d9c0SMatthew G. Knepley               }
2783d69c5d34SMatthew G. Knepley             }
2784d69c5d34SMatthew G. Knepley           }
27859566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&T));
2786ffe73a53SMatthew G. Knepley         }
278797c42addSMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
278897c42addSMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
278997c42addSMatthew G. Knepley 
279097c42addSMatthew G. Knepley         /* Evaluate constant function at points */
27919566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &NcJ));
279297c42addSMatthew G. Knepley         cpdim = 1;
279397c42addSMatthew G. Knepley         /* For now, fields only interpolate themselves */
279497c42addSMatthew G. Knepley         if (fieldI == fieldJ) {
279563a3b9bcSJacob 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);
279697c42addSMatthew G. Knepley           for (i = 0, k = 0; i < fpdim; ++i) {
27979566063dSJacob Faibussowitsch             PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
27989566063dSJacob Faibussowitsch             PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights));
279963a3b9bcSJacob 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);
280097c42addSMatthew G. Knepley             for (p = 0; p < Np; ++p, ++k) {
280197c42addSMatthew G. Knepley               for (j = 0; j < cpdim; ++j) {
2802458eb97cSMatthew G. Knepley                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c];
280397c42addSMatthew G. Knepley               }
280497c42addSMatthew G. Knepley             }
280597c42addSMatthew G. Knepley           }
280697c42addSMatthew G. Knepley         }
280797c42addSMatthew G. Knepley       }
2808d172c84bSMatthew G. Knepley       offsetJ += cpdim;
2809d69c5d34SMatthew G. Knepley     }
2810d172c84bSMatthew G. Knepley     offsetI += fpdim;
28119566063dSJacob Faibussowitsch     PetscCall(PetscFree(points));
2812d69c5d34SMatthew G. Knepley   }
28139566063dSJacob Faibussowitsch   if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat));
28147f5b169aSMatthew G. Knepley   /* Preallocate matrix */
28157f5b169aSMatthew G. Knepley   {
2816c094ef40SMatthew G. Knepley     Mat          preallocator;
2817c094ef40SMatthew G. Knepley     PetscScalar *vals;
2818c094ef40SMatthew G. Knepley     PetscInt    *cellCIndices, *cellFIndices;
2819c094ef40SMatthew G. Knepley     PetscInt     locRows, locCols, cell;
28207f5b169aSMatthew G. Knepley 
28219566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(In, &locRows, &locCols));
28229566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator));
28239566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
28249566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE));
28259566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
28269566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices));
28277f5b169aSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
2828cf51de39SMatthew G. Knepley       if (isRefined) {
28299566063dSJacob Faibussowitsch         PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices));
28309566063dSJacob Faibussowitsch         PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES));
2831cf51de39SMatthew G. Knepley       } else {
2832e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES));
2833cf51de39SMatthew G. Knepley       }
28347f5b169aSMatthew G. Knepley     }
28359566063dSJacob Faibussowitsch     PetscCall(PetscFree3(vals, cellCIndices, cellFIndices));
28369566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
28379566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
28389566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In));
28399566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
28407f5b169aSMatthew G. Knepley   }
28417f5b169aSMatthew G. Knepley   /* Fill matrix */
28429566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(In));
2843d69c5d34SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
2844cf51de39SMatthew G. Knepley     if (isRefined) {
28459566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES));
2846cf51de39SMatthew G. Knepley     } else {
2847e8e188d2SZach Atkins       PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES));
2848cf51de39SMatthew G. Knepley     }
2849d69c5d34SMatthew G. Knepley   }
28509566063dSJacob Faibussowitsch   for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f]));
28519566063dSJacob Faibussowitsch   PetscCall(PetscFree2(feRef, fvRef));
28529566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
28539566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY));
28549566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY));
28559318fe57SMatthew G. Knepley   if (mesh->printFEM > 1) {
28569566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name));
28572ce66baaSPierre Jolivet     PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE));
28589566063dSJacob Faibussowitsch     PetscCall(MatView(In, NULL));
2859d69c5d34SMatthew G. Knepley   }
28609566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
28613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2862d69c5d34SMatthew G. Knepley }
28636c73c22cSMatthew G. Knepley 
2864d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user)
2865d71ae5a4SJacob Faibussowitsch {
2866bd041c0cSMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness");
2867bd041c0cSMatthew G. Knepley }
2868bd041c0cSMatthew G. Knepley 
286968132eb9SMatthew G. Knepley /*@
2870a1cb98faSBarry Smith   DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`.
287168132eb9SMatthew G. Knepley 
287268132eb9SMatthew G. Knepley   Input Parameters:
287368132eb9SMatthew G. Knepley + dmf  - The fine mesh
287468132eb9SMatthew G. Knepley . dmc  - The coarse mesh
287568132eb9SMatthew G. Knepley - user - The user context
287668132eb9SMatthew G. Knepley 
287768132eb9SMatthew G. Knepley   Output Parameter:
287868132eb9SMatthew G. Knepley . In - The interpolation matrix
287968132eb9SMatthew G. Knepley 
288068132eb9SMatthew G. Knepley   Level: developer
288168132eb9SMatthew G. Knepley 
28821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()`
288368132eb9SMatthew G. Knepley @*/
2884d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user)
2885d71ae5a4SJacob Faibussowitsch {
288664e98e1dSMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmf->data;
288764e98e1dSMatthew G. Knepley   const char  *name = "Interpolator";
28884ef9d792SMatthew G. Knepley   PetscDS      prob;
2889a0806964SMatthew G. Knepley   Mat          interp;
2890a0806964SMatthew G. Knepley   PetscSection fsection, globalFSection;
2891a0806964SMatthew G. Knepley   PetscSection csection, globalCSection;
2892a0806964SMatthew G. Knepley   PetscInt     locRows, locCols;
28934ef9d792SMatthew G. Knepley   PetscReal   *x, *v0, *J, *invJ, detJ;
28944ef9d792SMatthew G. Knepley   PetscReal   *v0c, *Jc, *invJc, detJc;
28954ef9d792SMatthew G. Knepley   PetscScalar *elemMat;
2896a0806964SMatthew G. Knepley   PetscInt     dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s;
28974ef9d792SMatthew G. Knepley 
28984ef9d792SMatthew G. Knepley   PetscFunctionBegin;
28999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
29009566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmc, &dim));
29019566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
29029566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL));
29039566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
29049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
29059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc));
29069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
29079566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
29089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
29099566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &globalCSection));
2910a0806964SMatthew G. Knepley   PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd));
29119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
29129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(totDim, &elemMat));
29134ef9d792SMatthew G. Knepley 
2914a0806964SMatthew G. Knepley   PetscCall(MatGetLocalSize(In, &locRows, &locCols));
2915a0806964SMatthew G. Knepley   PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp));
2916a0806964SMatthew G. Knepley   PetscCall(MatSetType(interp, MATPREALLOCATOR));
2917a0806964SMatthew G. Knepley   PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE));
2918a0806964SMatthew G. Knepley   PetscCall(MatSetUp(interp));
2919a0806964SMatthew G. Knepley   for (s = 0; s < 2; ++s) {
29204ef9d792SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
29214ef9d792SMatthew G. Knepley       PetscObject      obj;
29224ef9d792SMatthew G. Knepley       PetscClassId     id;
2923c0d7054bSMatthew G. Knepley       PetscDualSpace   Q = NULL;
2924ef0bb6c7SMatthew G. Knepley       PetscTabulation  T = NULL;
29254ef9d792SMatthew G. Knepley       PetscQuadrature  f;
29264ef9d792SMatthew G. Knepley       const PetscReal *qpoints, *qweights;
2927d0f6233fSMatthew G. Knepley       PetscInt         Nc, qNc, Np, fpdim, off, i, d;
29284ef9d792SMatthew G. Knepley 
2929d0f6233fSMatthew G. Knepley       PetscCall(PetscDSGetFieldOffset(prob, field, &off));
29309566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, &obj));
29319566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
29324ef9d792SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
29334ef9d792SMatthew G. Knepley         PetscFE fe = (PetscFE)obj;
29344ef9d792SMatthew G. Knepley 
29359566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &Q));
29369566063dSJacob Faibussowitsch         PetscCall(PetscFEGetNumComponents(fe, &Nc));
2937a0806964SMatthew G. Knepley         if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T));
29384ef9d792SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
29394ef9d792SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
29404ef9d792SMatthew G. Knepley 
29419566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace(fv, &Q));
29424ef9d792SMatthew G. Knepley         Nc = 1;
294363a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
29449566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &fpdim));
29454ef9d792SMatthew G. Knepley       /* For each fine grid cell */
29464ef9d792SMatthew G. Knepley       for (cell = cStart; cell < cEnd; ++cell) {
29474ef9d792SMatthew G. Knepley         PetscInt *findices, *cindices;
29484ef9d792SMatthew G. Knepley         PetscInt  numFIndices, numCIndices;
29494ef9d792SMatthew G. Knepley 
29509566063dSJacob Faibussowitsch         PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
29519566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
2952d0f6233fSMatthew 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);
29534ef9d792SMatthew G. Knepley         for (i = 0; i < fpdim; ++i) {
29544ef9d792SMatthew G. Knepley           Vec                pointVec;
29554ef9d792SMatthew G. Knepley           PetscScalar       *pV;
295612111d7cSToby Isaac           PetscSF            coarseCellSF = NULL;
29573a93e3b7SToby Isaac           const PetscSFNode *coarseCells;
2958d0f6233fSMatthew G. Knepley           PetscInt           numCoarseCells, cpdim, row = findices[i + off], q, c, j;
29594ef9d792SMatthew G. Knepley 
29604ef9d792SMatthew G. Knepley           /* Get points from the dual basis functional quadrature */
29619566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(Q, i, &f));
29629566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights));
296363a3b9bcSJacob 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);
29649566063dSJacob Faibussowitsch           PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec));
29659566063dSJacob Faibussowitsch           PetscCall(VecSetBlockSize(pointVec, dim));
29669566063dSJacob Faibussowitsch           PetscCall(VecGetArray(pointVec, &pV));
29674ef9d792SMatthew G. Knepley           for (q = 0; q < Np; ++q) {
2968c330f8ffSToby Isaac             const PetscReal xi0[3] = {-1., -1., -1.};
2969c330f8ffSToby Isaac 
29704ef9d792SMatthew G. Knepley             /* Transform point to real space */
2971c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
29724ef9d792SMatthew G. Knepley             for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
29734ef9d792SMatthew G. Knepley           }
29749566063dSJacob Faibussowitsch           PetscCall(VecRestoreArray(pointVec, &pV));
29754ef9d792SMatthew G. Knepley           /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
29761555c271SMatthew G. Knepley           /* OPT: Read this out from preallocation information */
29779566063dSJacob Faibussowitsch           PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
29784ef9d792SMatthew G. Knepley           /* Update preallocation info */
29799566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
29805f80ce2aSJacob Faibussowitsch           PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
29819566063dSJacob Faibussowitsch           PetscCall(VecGetArray(pointVec, &pV));
29824ef9d792SMatthew G. Knepley           for (ccell = 0; ccell < numCoarseCells; ++ccell) {
2983826eb36dSMatthew G. Knepley             PetscReal       pVReal[3];
2984c330f8ffSToby Isaac             const PetscReal xi0[3] = {-1., -1., -1.};
2985826eb36dSMatthew G. Knepley 
29869566063dSJacob Faibussowitsch             PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
2987a0806964SMatthew G. Knepley             if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim));
2988a0806964SMatthew G. Knepley             else cpdim = 1;
2989a0806964SMatthew G. Knepley 
2990a0806964SMatthew G. Knepley             if (s) {
29914ef9d792SMatthew G. Knepley               /* Transform points from real space to coarse reference space */
29929566063dSJacob Faibussowitsch               PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc));
2993e2d86523SMatthew G. Knepley               for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
2994c330f8ffSToby Isaac               CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
29954ef9d792SMatthew G. Knepley 
29964ef9d792SMatthew G. Knepley               if (id == PETSCFE_CLASSID) {
29974ef9d792SMatthew G. Knepley                 /* Evaluate coarse basis on contained point */
2998a0806964SMatthew G. Knepley                 PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T));
29999566063dSJacob Faibussowitsch                 PetscCall(PetscArrayzero(elemMat, cpdim));
30004ef9d792SMatthew G. Knepley                 /* Get elemMat entries by multiplying by weight */
30014ef9d792SMatthew G. Knepley                 for (j = 0; j < cpdim; ++j) {
3002ef0bb6c7SMatthew G. Knepley                   for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c];
30034ef9d792SMatthew G. Knepley                 }
30044ef9d792SMatthew G. Knepley               } else {
30054ef9d792SMatthew G. Knepley                 for (j = 0; j < cpdim; ++j) {
30069c3cf19fSMatthew G. Knepley                   for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c];
30074ef9d792SMatthew G. Knepley                 }
30084ef9d792SMatthew G. Knepley               }
30099566063dSJacob Faibussowitsch               if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
3010a0806964SMatthew G. Knepley             }
3011a0806964SMatthew G. Knepley             /* Update interpolator */
3012d0f6233fSMatthew G. Knepley             PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim);
3013a0806964SMatthew G. Knepley             PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES));
30149566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
30154ef9d792SMatthew G. Knepley           }
30169566063dSJacob Faibussowitsch           PetscCall(VecRestoreArray(pointVec, &pV));
30179566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseCellSF));
30189566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&pointVec));
30194ef9d792SMatthew G. Knepley         }
30209566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
30214ef9d792SMatthew G. Knepley       }
3022a0806964SMatthew G. Knepley       if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T));
3023a0806964SMatthew G. Knepley     }
3024a0806964SMatthew G. Knepley     if (!s) {
3025a0806964SMatthew G. Knepley       PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY));
3026a0806964SMatthew G. Knepley       PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY));
3027a0806964SMatthew G. Knepley       PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In));
3028a0806964SMatthew G. Knepley       PetscCall(MatDestroy(&interp));
3029a0806964SMatthew G. Knepley       interp = In;
3030a0806964SMatthew G. Knepley     }
30314ef9d792SMatthew G. Knepley   }
30329566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
30339566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0c, Jc, invJc));
30349566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
30359566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY));
30369566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY));
30379566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
30383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30394ef9d792SMatthew G. Knepley }
30404ef9d792SMatthew G. Knepley 
304146fa42a0SMatthew G. Knepley /*@
3042a1cb98faSBarry Smith   DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`.
3043bd041c0cSMatthew G. Knepley 
3044bd041c0cSMatthew G. Knepley   Input Parameters:
3045bd041c0cSMatthew G. Knepley + dmf  - The fine mesh
3046bd041c0cSMatthew G. Knepley . dmc  - The coarse mesh
3047bd041c0cSMatthew G. Knepley - user - The user context
3048bd041c0cSMatthew G. Knepley 
3049bd041c0cSMatthew G. Knepley   Output Parameter:
3050bd041c0cSMatthew G. Knepley . mass - The mass matrix
3051bd041c0cSMatthew G. Knepley 
3052bd041c0cSMatthew G. Knepley   Level: developer
3053bd041c0cSMatthew G. Knepley 
30541cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()`
3055bd041c0cSMatthew G. Knepley @*/
3056d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user)
3057d71ae5a4SJacob Faibussowitsch {
3058bd041c0cSMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmf->data;
3059bd041c0cSMatthew G. Knepley   const char  *name = "Mass Matrix";
3060bd041c0cSMatthew G. Knepley   PetscDS      prob;
3061bd041c0cSMatthew G. Knepley   PetscSection fsection, csection, globalFSection, globalCSection;
3062e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
3063bd041c0cSMatthew G. Knepley   PetscLayout  rLayout;
3064bd041c0cSMatthew G. Knepley   PetscInt    *dnz, *onz;
3065bd041c0cSMatthew G. Knepley   PetscInt     locRows, rStart, rEnd;
3066bd041c0cSMatthew G. Knepley   PetscReal   *x, *v0, *J, *invJ, detJ;
3067bd041c0cSMatthew G. Knepley   PetscReal   *v0c, *Jc, *invJc, detJc;
3068bd041c0cSMatthew G. Knepley   PetscScalar *elemMat;
3069bd041c0cSMatthew G. Knepley   PetscInt     dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
3070bd041c0cSMatthew G. Knepley 
3071bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
30729566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmc, &dim));
30739566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
30749566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL));
30759566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
30769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
30779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc));
30789566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
30799566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
30809566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
30819566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &globalCSection));
30829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
30839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
30849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(totDim, &elemMat));
3085bd041c0cSMatthew G. Knepley 
30869566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, NULL));
30879566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout));
30889566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
30899566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
30909566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
30919566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd));
30929566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
30939566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
30949566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
3095bd041c0cSMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3096bd041c0cSMatthew G. Knepley     PetscObject      obj;
3097bd041c0cSMatthew G. Knepley     PetscClassId     id;
3098bd041c0cSMatthew G. Knepley     PetscQuadrature  quad;
3099bd041c0cSMatthew G. Knepley     const PetscReal *qpoints;
3100bd041c0cSMatthew G. Knepley     PetscInt         Nq, Nc, i, d;
3101bd041c0cSMatthew G. Knepley 
31029566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
31039566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
31049566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad));
31059566063dSJacob Faibussowitsch     else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad));
31069566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL));
3107bd041c0cSMatthew G. Knepley     /* For each fine grid cell */
3108bd041c0cSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3109bd041c0cSMatthew G. Knepley       Vec                pointVec;
3110bd041c0cSMatthew G. Knepley       PetscScalar       *pV;
3111bd041c0cSMatthew G. Knepley       PetscSF            coarseCellSF = NULL;
3112bd041c0cSMatthew G. Knepley       const PetscSFNode *coarseCells;
3113bd041c0cSMatthew G. Knepley       PetscInt           numCoarseCells, q, c;
3114bd041c0cSMatthew G. Knepley       PetscInt          *findices, *cindices;
3115bd041c0cSMatthew G. Knepley       PetscInt           numFIndices, numCIndices;
3116bd041c0cSMatthew G. Knepley 
31179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
31189566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3119bd041c0cSMatthew G. Knepley       /* Get points from the quadrature */
31209566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec));
31219566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(pointVec, dim));
31229566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3123bd041c0cSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
3124c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3125c330f8ffSToby Isaac 
3126bd041c0cSMatthew G. Knepley         /* Transform point to real space */
3127c330f8ffSToby Isaac         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3128bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3129bd041c0cSMatthew G. Knepley       }
31309566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
3131bd041c0cSMatthew G. Knepley       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
31329566063dSJacob Faibussowitsch       PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
31339566063dSJacob Faibussowitsch       PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view"));
3134bd041c0cSMatthew G. Knepley       /* Update preallocation info */
31359566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
31365f80ce2aSJacob Faibussowitsch       PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
3137bd041c0cSMatthew G. Knepley       {
3138e8f14785SLisandro Dalcin         PetscHashIJKey key;
3139e8f14785SLisandro Dalcin         PetscBool      missing;
3140bd041c0cSMatthew G. Knepley 
3141bd041c0cSMatthew G. Knepley         for (i = 0; i < numFIndices; ++i) {
3142e8f14785SLisandro Dalcin           key.i = findices[i];
3143e8f14785SLisandro Dalcin           if (key.i >= 0) {
3144bd041c0cSMatthew G. Knepley             /* Get indices for coarse elements */
3145bd041c0cSMatthew G. Knepley             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
31469566063dSJacob Faibussowitsch               PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3147bd041c0cSMatthew G. Knepley               for (c = 0; c < numCIndices; ++c) {
3148e8f14785SLisandro Dalcin                 key.j = cindices[c];
3149e8f14785SLisandro Dalcin                 if (key.j < 0) continue;
31509566063dSJacob Faibussowitsch                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
3151bd041c0cSMatthew G. Knepley                 if (missing) {
3152e8f14785SLisandro Dalcin                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart];
3153e8f14785SLisandro Dalcin                   else ++onz[key.i - rStart];
3154bd041c0cSMatthew G. Knepley                 }
3155bd041c0cSMatthew G. Knepley               }
31569566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3157bd041c0cSMatthew G. Knepley             }
3158bd041c0cSMatthew G. Knepley           }
3159bd041c0cSMatthew G. Knepley         }
3160bd041c0cSMatthew G. Knepley       }
31619566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coarseCellSF));
31629566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&pointVec));
31639566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3164bd041c0cSMatthew G. Knepley     }
3165bd041c0cSMatthew G. Knepley   }
31669566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
31679566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
31689566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
31699566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
3170bd041c0cSMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3171bd041c0cSMatthew G. Knepley     PetscObject      obj;
3172bd041c0cSMatthew G. Knepley     PetscClassId     id;
3173ef0bb6c7SMatthew G. Knepley     PetscTabulation  T, Tfine;
3174bd041c0cSMatthew G. Knepley     PetscQuadrature  quad;
3175bd041c0cSMatthew G. Knepley     const PetscReal *qpoints, *qweights;
3176bd041c0cSMatthew G. Knepley     PetscInt         Nq, Nc, i, d;
3177bd041c0cSMatthew G. Knepley 
31789566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
31799566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
3180ef0bb6c7SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
31819566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad));
31829566063dSJacob Faibussowitsch       PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine));
31839566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T));
3184ef0bb6c7SMatthew G. Knepley     } else {
31859566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad));
3186ef0bb6c7SMatthew G. Knepley     }
31879566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights));
3188bd041c0cSMatthew G. Knepley     /* For each fine grid cell */
3189bd041c0cSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3190bd041c0cSMatthew G. Knepley       Vec                pointVec;
3191bd041c0cSMatthew G. Knepley       PetscScalar       *pV;
3192bd041c0cSMatthew G. Knepley       PetscSF            coarseCellSF = NULL;
3193bd041c0cSMatthew G. Knepley       const PetscSFNode *coarseCells;
3194bd041c0cSMatthew G. Knepley       PetscInt           numCoarseCells, cpdim, q, c, j;
3195bd041c0cSMatthew G. Knepley       PetscInt          *findices, *cindices;
3196bd041c0cSMatthew G. Knepley       PetscInt           numFIndices, numCIndices;
3197bd041c0cSMatthew G. Knepley 
31989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
31999566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3200bd041c0cSMatthew G. Knepley       /* Get points from the quadrature */
32019566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec));
32029566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(pointVec, dim));
32039566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3204bd041c0cSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
3205c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3206c330f8ffSToby Isaac 
3207bd041c0cSMatthew G. Knepley         /* Transform point to real space */
3208c330f8ffSToby Isaac         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3209bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3210bd041c0cSMatthew G. Knepley       }
32119566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
3212bd041c0cSMatthew G. Knepley       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
32139566063dSJacob Faibussowitsch       PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
3214bd041c0cSMatthew G. Knepley       /* Update matrix */
32159566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
32165f80ce2aSJacob Faibussowitsch       PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
32179566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3218bd041c0cSMatthew G. Knepley       for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3219bd041c0cSMatthew G. Knepley         PetscReal       pVReal[3];
3220c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3221c330f8ffSToby Isaac 
32229566063dSJacob Faibussowitsch         PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3223bd041c0cSMatthew G. Knepley         /* Transform points from real space to coarse reference space */
32249566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc));
3225bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
3226c330f8ffSToby Isaac         CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
3227bd041c0cSMatthew G. Knepley 
3228bd041c0cSMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
3229bd041c0cSMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
3230bd041c0cSMatthew G. Knepley 
3231bd041c0cSMatthew G. Knepley           /* Evaluate coarse basis on contained point */
32329566063dSJacob Faibussowitsch           PetscCall(PetscFEGetDimension(fe, &cpdim));
32339566063dSJacob Faibussowitsch           PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T));
3234bd041c0cSMatthew G. Knepley           /* Get elemMat entries by multiplying by weight */
3235bd041c0cSMatthew G. Knepley           for (i = 0; i < numFIndices; ++i) {
32369566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(elemMat, cpdim));
3237bd041c0cSMatthew G. Knepley             for (j = 0; j < cpdim; ++j) {
3238ef0bb6c7SMatthew 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;
3239bd041c0cSMatthew G. Knepley             }
3240bd041c0cSMatthew G. Knepley             /* Update interpolator */
32419566063dSJacob Faibussowitsch             if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
324263a3b9bcSJacob Faibussowitsch             PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim);
32439566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES));
3244bd041c0cSMatthew G. Knepley           }
3245bd041c0cSMatthew G. Knepley         } else {
3246bd041c0cSMatthew G. Knepley           cpdim = 1;
3247bd041c0cSMatthew G. Knepley           for (i = 0; i < numFIndices; ++i) {
32489566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(elemMat, cpdim));
3249bd041c0cSMatthew G. Knepley             for (j = 0; j < cpdim; ++j) {
3250bd041c0cSMatthew G. Knepley               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ;
3251bd041c0cSMatthew G. Knepley             }
3252bd041c0cSMatthew G. Knepley             /* Update interpolator */
32539566063dSJacob Faibussowitsch             if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
325463a3b9bcSJacob 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));
325563a3b9bcSJacob Faibussowitsch             PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim);
32569566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES));
3257bd041c0cSMatthew G. Knepley           }
3258bd041c0cSMatthew G. Knepley         }
32599566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3260bd041c0cSMatthew G. Knepley       }
32619566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
32629566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coarseCellSF));
32639566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&pointVec));
32649566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3265bd041c0cSMatthew G. Knepley     }
32669566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T));
3267bd041c0cSMatthew G. Knepley   }
32689566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
32699566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0c, Jc, invJc));
32709566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
32719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
32729566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
32733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3274bd041c0cSMatthew G. Knepley }
3275bd041c0cSMatthew G. Knepley 
3276bd041c0cSMatthew G. Knepley /*@
327746fa42a0SMatthew G. Knepley   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
327846fa42a0SMatthew G. Knepley 
327946fa42a0SMatthew G. Knepley   Input Parameters:
328046fa42a0SMatthew G. Knepley + dmc  - The coarse mesh
328160225df5SJacob Faibussowitsch . dmf  - The fine mesh
328246fa42a0SMatthew G. Knepley - user - The user context
328346fa42a0SMatthew G. Knepley 
328446fa42a0SMatthew G. Knepley   Output Parameter:
328546fa42a0SMatthew G. Knepley . sc - The mapping
328646fa42a0SMatthew G. Knepley 
328746fa42a0SMatthew G. Knepley   Level: developer
328846fa42a0SMatthew G. Knepley 
32891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()`
329046fa42a0SMatthew G. Knepley @*/
3291d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user)
3292d71ae5a4SJacob Faibussowitsch {
3293e9d4ef1bSMatthew G. Knepley   PetscDS      prob;
32947c927364SMatthew G. Knepley   PetscFE     *feRef;
329597c42addSMatthew G. Knepley   PetscFV     *fvRef;
32967c927364SMatthew G. Knepley   Vec          fv, cv;
32977c927364SMatthew G. Knepley   IS           fis, cis;
32987c927364SMatthew G. Knepley   PetscSection fsection, fglobalSection, csection, cglobalSection;
32997c927364SMatthew G. Knepley   PetscInt    *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3300485ad865SMatthew G. Knepley   PetscInt     cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
33016f3d3cbcSMatthew G. Knepley   PetscBool   *needAvg;
33027c927364SMatthew G. Knepley 
33037c927364SMatthew G. Knepley   PetscFunctionBegin;
33049566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0));
33059566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmf, &dim));
33069566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
33079566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &fglobalSection));
33089566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
33099566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
33109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &Nf));
33119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd));
33129566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
33139566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg));
33147c927364SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
331597c42addSMatthew G. Knepley     PetscObject  obj;
331697c42addSMatthew G. Knepley     PetscClassId id;
3317aa7890ccSMatthew G. Knepley     PetscInt     fNb = 0, Nc = 0;
33187c927364SMatthew G. Knepley 
33199566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
33209566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
332197c42addSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
332297c42addSMatthew G. Knepley       PetscFE    fe = (PetscFE)obj;
33236f3d3cbcSMatthew G. Knepley       PetscSpace sp;
33249b2fc754SMatthew G. Knepley       PetscInt   maxDegree;
332597c42addSMatthew G. Knepley 
33269566063dSJacob Faibussowitsch       PetscCall(PetscFERefine(fe, &feRef[f]));
33279566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feRef[f], &fNb));
33289566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
33299566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &sp));
33309566063dSJacob Faibussowitsch       PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree));
33319b2fc754SMatthew G. Knepley       if (!maxDegree) needAvg[f] = PETSC_TRUE;
333297c42addSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
333397c42addSMatthew G. Knepley       PetscFV        fv = (PetscFV)obj;
333497c42addSMatthew G. Knepley       PetscDualSpace Q;
333597c42addSMatthew G. Knepley 
33369566063dSJacob Faibussowitsch       PetscCall(PetscFVRefine(fv, &fvRef[f]));
33379566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[f], &Q));
33389566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &fNb));
33399566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
33406f3d3cbcSMatthew G. Knepley       needAvg[f] = PETSC_TRUE;
334197c42addSMatthew G. Knepley     }
3342d172c84bSMatthew G. Knepley     fTotDim += fNb;
33437c927364SMatthew G. Knepley   }
33449566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &cTotDim));
33459566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cTotDim, &cmap));
33467c927364SMatthew G. Knepley   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
33477c927364SMatthew G. Knepley     PetscFE        feC;
334897c42addSMatthew G. Knepley     PetscFV        fvC;
33497c927364SMatthew G. Knepley     PetscDualSpace QF, QC;
3350d172c84bSMatthew G. Knepley     PetscInt       order = -1, NcF, NcC, fpdim, cpdim;
33517c927364SMatthew G. Knepley 
335297c42addSMatthew G. Knepley     if (feRef[field]) {
33539566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC));
33549566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feC, &NcC));
33559566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feRef[field], &NcF));
33569566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feRef[field], &QF));
33579566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetOrder(QF, &order));
33589566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QF, &fpdim));
33599566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feC, &QC));
33609566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QC, &cpdim));
336197c42addSMatthew G. Knepley     } else {
33629566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC));
33639566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvC, &NcC));
33649566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF));
33659566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[field], &QF));
33669566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QF, &fpdim));
33679566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvC, &QC));
33689566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QC, &cpdim));
336997c42addSMatthew G. Knepley     }
337063a3b9bcSJacob 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);
33717c927364SMatthew G. Knepley     for (c = 0; c < cpdim; ++c) {
33727c927364SMatthew G. Knepley       PetscQuadrature  cfunc;
3373d172c84bSMatthew G. Knepley       const PetscReal *cqpoints, *cqweights;
3374d172c84bSMatthew G. Knepley       PetscInt         NqcC, NpC;
337597c42addSMatthew G. Knepley       PetscBool        found = PETSC_FALSE;
33767c927364SMatthew G. Knepley 
33779566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc));
33789566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights));
337963a3b9bcSJacob 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);
33801dca8a05SBarry Smith       PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
33817c927364SMatthew G. Knepley       for (f = 0; f < fpdim; ++f) {
33827c927364SMatthew G. Knepley         PetscQuadrature  ffunc;
3383d172c84bSMatthew G. Knepley         const PetscReal *fqpoints, *fqweights;
33847c927364SMatthew G. Knepley         PetscReal        sum = 0.0;
3385d172c84bSMatthew G. Knepley         PetscInt         NqcF, NpF;
33867c927364SMatthew G. Knepley 
33879566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc));
33889566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights));
338963a3b9bcSJacob 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);
33907c927364SMatthew G. Knepley         if (NpC != NpF) continue;
33917c927364SMatthew G. Knepley         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
33927c927364SMatthew G. Knepley         if (sum > 1.0e-9) continue;
3393d172c84bSMatthew G. Knepley         for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]);
3394d172c84bSMatthew G. Knepley         if (sum < 1.0e-9) continue;
3395d172c84bSMatthew G. Knepley         cmap[offsetC + c] = offsetF + f;
339697c42addSMatthew G. Knepley         found             = PETSC_TRUE;
33977c927364SMatthew G. Knepley         break;
33987c927364SMatthew G. Knepley       }
339997c42addSMatthew G. Knepley       if (!found) {
340097c42addSMatthew G. Knepley         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3401d172c84bSMatthew G. Knepley         if (fvRef[field] || (feRef[field] && order == 0)) {
3402d172c84bSMatthew G. Knepley           cmap[offsetC + c] = offsetF + 0;
340397c42addSMatthew G. Knepley         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
340497c42addSMatthew G. Knepley       }
34057c927364SMatthew G. Knepley     }
3406d172c84bSMatthew G. Knepley     offsetC += cpdim;
3407d172c84bSMatthew G. Knepley     offsetF += fpdim;
34087c927364SMatthew G. Knepley   }
34099371c9d4SSatish Balay   for (f = 0; f < Nf; ++f) {
34109371c9d4SSatish Balay     PetscCall(PetscFEDestroy(&feRef[f]));
34119371c9d4SSatish Balay     PetscCall(PetscFVDestroy(&fvRef[f]));
34129371c9d4SSatish Balay   }
34139566063dSJacob Faibussowitsch   PetscCall(PetscFree3(feRef, fvRef, needAvg));
34147c927364SMatthew G. Knepley 
34159566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmf, &fv));
34169566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmc, &cv));
34179566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(cv, &startC, &endC));
34189566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m));
34199566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices));
34209566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &cindices));
34219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &findices));
34227c927364SMatthew G. Knepley   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
34237c927364SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
34249566063dSJacob Faibussowitsch     PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices));
34257c927364SMatthew G. Knepley     for (d = 0; d < cTotDim; ++d) {
34260bd915a7SMatthew G. Knepley       if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
3427d2457c26SMatthew G. Knepley       PetscCheck(!(findices[cellCIndices[d] - startC] >= 0) || !(findices[cellCIndices[d] - startC] != cellFIndices[cmap[d]]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell %" PetscInt_FMT " Coarse dof %" PetscInt_FMT " maps to both %" PetscInt_FMT " and %" PetscInt_FMT, c, cindices[cellCIndices[d] - startC], findices[cellCIndices[d] - startC], cellFIndices[cmap[d]]);
34287c927364SMatthew G. Knepley       cindices[cellCIndices[d] - startC] = cellCIndices[d];
34297c927364SMatthew G. Knepley       findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]];
34307c927364SMatthew G. Knepley     }
34317c927364SMatthew G. Knepley   }
34329566063dSJacob Faibussowitsch   PetscCall(PetscFree(cmap));
34339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(cellCIndices, cellFIndices));
34347c927364SMatthew G. Knepley 
34359566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis));
34369566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis));
34379566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(cv, cis, fv, fis, sc));
34389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
34399566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
34409566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmf, &fv));
34419566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmc, &cv));
34429566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0));
34433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3444cb1e1211SMatthew G Knepley }
3445a1cf66bbSMatthew G. Knepley 
34462f856554SMatthew G. Knepley /*@C
34472f856554SMatthew G. Knepley   DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
34482f856554SMatthew G. Knepley 
34492f856554SMatthew G. Knepley   Input Parameters:
3450a1cb98faSBarry Smith + dm     - The `DM`
34512f856554SMatthew G. Knepley . cellIS - The cells to include
34522f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
34532f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL
34542f856554SMatthew G. Knepley - locA   - A local vector with auxiliary fields, or NULL
34552f856554SMatthew G. Knepley 
34562f856554SMatthew G. Knepley   Output Parameters:
34572f856554SMatthew G. Knepley + u   - The field coefficients
34582f856554SMatthew G. Knepley . u_t - The fields derivative coefficients
34592f856554SMatthew G. Knepley - a   - The auxiliary field coefficients
34602f856554SMatthew G. Knepley 
34612f856554SMatthew G. Knepley   Level: developer
34622f856554SMatthew G. Knepley 
34631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
34642f856554SMatthew G. Knepley @*/
3465d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3466d71ae5a4SJacob Faibussowitsch {
34672f856554SMatthew G. Knepley   DM              plex, plexA = NULL;
3468a6e0b375SMatthew G. Knepley   DMEnclosureType encAux;
34692f856554SMatthew G. Knepley   PetscSection    section, sectionAux;
34702f856554SMatthew G. Knepley   PetscDS         prob;
34712f856554SMatthew G. Knepley   const PetscInt *cells;
34722f856554SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, totDim, totDimAux, c;
34732f856554SMatthew G. Knepley 
34742f856554SMatthew G. Knepley   PetscFunctionBegin;
34752f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3476064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
3477ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4);
3478ad540459SPierre Jolivet   if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5);
34794f572ea9SToby Isaac   PetscAssertPointer(u, 6);
34804f572ea9SToby Isaac   PetscAssertPointer(u_t, 7);
34814f572ea9SToby Isaac   PetscAssertPointer(a, 8);
34829566063dSJacob Faibussowitsch   PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE));
34839566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
34849566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
348507218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL));
34869566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
34872f856554SMatthew G. Knepley   if (locA) {
34882f856554SMatthew G. Knepley     DM      dmAux;
34892f856554SMatthew G. Knepley     PetscDS probAux;
34902f856554SMatthew G. Knepley 
34919566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
34929566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
34939566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE));
34949566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
34959566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
34969566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
34972f856554SMatthew G. Knepley   }
34982f856554SMatthew G. Knepley   numCells = cEnd - cStart;
34999566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u));
35009371c9d4SSatish Balay   if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t));
3501ad540459SPierre Jolivet   else *u_t = NULL;
35029371c9d4SSatish Balay   if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a));
3503ad540459SPierre Jolivet   else *a = NULL;
35042f856554SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
35052f856554SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
35062f856554SMatthew G. Knepley     const PetscInt cind = c - cStart;
35072f856554SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
35082f856554SMatthew G. Knepley     PetscInt       i;
35092f856554SMatthew G. Knepley 
35109566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x));
35112f856554SMatthew G. Knepley     for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i];
35129566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x));
35132f856554SMatthew G. Knepley     if (locX_t) {
35149566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t));
35152f856554SMatthew G. Knepley       for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i];
35169566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t));
35172f856554SMatthew G. Knepley     }
35182f856554SMatthew G. Knepley     if (locA) {
35192f856554SMatthew G. Knepley       PetscInt subcell;
35209566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell));
35219566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x));
35222f856554SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i];
35239566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x));
35242f856554SMatthew G. Knepley     }
35252f856554SMatthew G. Knepley   }
35269566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
35279566063dSJacob Faibussowitsch   if (locA) PetscCall(DMDestroy(&plexA));
35289566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
35293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35302f856554SMatthew G. Knepley }
35312f856554SMatthew G. Knepley 
35322f856554SMatthew G. Knepley /*@C
35332f856554SMatthew G. Knepley   DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
35342f856554SMatthew G. Knepley 
35352f856554SMatthew G. Knepley   Input Parameters:
3536a1cb98faSBarry Smith + dm     - The `DM`
35372f856554SMatthew G. Knepley . cellIS - The cells to include
35382f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
35392f856554SMatthew G. Knepley . locX_t - A local vector with solution field time derivatives, or NULL
35402f856554SMatthew G. Knepley - locA   - A local vector with auxiliary fields, or NULL
35412f856554SMatthew G. Knepley 
35422f856554SMatthew G. Knepley   Output Parameters:
35432f856554SMatthew G. Knepley + u   - The field coefficients
35442f856554SMatthew G. Knepley . u_t - The fields derivative coefficients
35452f856554SMatthew G. Knepley - a   - The auxiliary field coefficients
35462f856554SMatthew G. Knepley 
35472f856554SMatthew G. Knepley   Level: developer
35482f856554SMatthew G. Knepley 
35491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
35502f856554SMatthew G. Knepley @*/
3551d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3552d71ae5a4SJacob Faibussowitsch {
35532f856554SMatthew G. Knepley   PetscFunctionBegin;
35549566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u));
35559566063dSJacob Faibussowitsch   if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t));
35569566063dSJacob Faibussowitsch   if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a));
35573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35582f856554SMatthew G. Knepley }
35592f856554SMatthew G. Knepley 
3560a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3561d71ae5a4SJacob Faibussowitsch {
356207218a29SMatthew G. Knepley   DM              plex, plexA = NULL;
356307218a29SMatthew G. Knepley   DMEnclosureType encAux;
356407218a29SMatthew G. Knepley   PetscSection    section, sectionAux;
356507218a29SMatthew G. Knepley   PetscDS         ds, dsIn;
35666528b96dSMatthew G. Knepley   const PetscInt *cells;
356707218a29SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f;
35686528b96dSMatthew G. Knepley 
35696528b96dSMatthew G. Knepley   PetscFunctionBegin;
357007218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
357107218a29SMatthew G. Knepley   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2);
357207218a29SMatthew G. Knepley   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
357307218a29SMatthew G. Knepley   if (locX_t) { PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); }
357407218a29SMatthew G. Knepley   if (locA) { PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); }
35754f572ea9SToby Isaac   PetscAssertPointer(u, 6);
35764f572ea9SToby Isaac   PetscAssertPointer(u_t, 7);
35774f572ea9SToby Isaac   PetscAssertPointer(a, 8);
357807218a29SMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
357907218a29SMatthew G. Knepley   numCells = cEnd - cStart;
358007218a29SMatthew G. Knepley   PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE));
358107218a29SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &section));
358207218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn));
358307218a29SMatthew G. Knepley   PetscCall(PetscDSGetNumFields(dsIn, &Nf));
358407218a29SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(dsIn, &totDim));
358507218a29SMatthew G. Knepley   if (locA) {
358607218a29SMatthew G. Knepley     DM      dmAux;
358707218a29SMatthew G. Knepley     PetscDS probAux;
358807218a29SMatthew G. Knepley 
358907218a29SMatthew G. Knepley     PetscCall(VecGetDM(locA, &dmAux));
359007218a29SMatthew G. Knepley     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
359107218a29SMatthew G. Knepley     PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE));
359207218a29SMatthew G. Knepley     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
359307218a29SMatthew G. Knepley     PetscCall(DMGetDS(dmAux, &probAux));
359407218a29SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
359507218a29SMatthew G. Knepley   }
359607218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u));
359707218a29SMatthew G. Knepley   if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t));
359807218a29SMatthew G. Knepley   else {
359907218a29SMatthew G. Knepley     *u_t = NULL;
360007218a29SMatthew G. Knepley   }
360107218a29SMatthew G. Knepley   if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a));
360207218a29SMatthew G. Knepley   else {
360307218a29SMatthew G. Knepley     *a = NULL;
360407218a29SMatthew G. Knepley   }
360507218a29SMatthew G. Knepley   // Loop over cohesive cells
360607218a29SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
360707218a29SMatthew G. Knepley     const PetscInt  cell = cells ? cells[c] : c;
360807218a29SMatthew G. Knepley     const PetscInt  cind = c - cStart;
360974a0c561SMatthew G. Knepley     PetscScalar    *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL;
361074a0c561SMatthew G. Knepley     PetscScalar    *ul = &(*u)[cind * totDim], *ul_t = u_t ? &(*u_t)[cind * totDim] : NULL;
361107218a29SMatthew G. Knepley     const PetscInt *cone, *ornt;
361207218a29SMatthew G. Knepley     PetscInt        Nx = 0, Nxf, s;
361307218a29SMatthew G. Knepley 
361407218a29SMatthew G. Knepley     PetscCall(DMPlexGetCone(dm, cell, &cone));
361507218a29SMatthew G. Knepley     PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
361607218a29SMatthew G. Knepley     // Put in cohesive unknowns
361707218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf));
361874a0c561SMatthew G. Knepley     if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t));
361907218a29SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
362007218a29SMatthew G. Knepley       PetscInt  fdofIn, foff, foffIn;
362107218a29SMatthew G. Knepley       PetscBool cohesive;
362207218a29SMatthew G. Knepley 
362307218a29SMatthew G. Knepley       PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive));
362407218a29SMatthew G. Knepley       if (!cohesive) continue;
362507218a29SMatthew G. Knepley       PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn));
362607218a29SMatthew G. Knepley       PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff));
362707218a29SMatthew G. Knepley       PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn));
362807218a29SMatthew G. Knepley       for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i];
362974a0c561SMatthew G. Knepley       if (locX_t)
363074a0c561SMatthew G. Knepley         for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i];
363107218a29SMatthew G. Knepley       Nx += fdofIn;
363207218a29SMatthew G. Knepley     }
363307218a29SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf));
363474a0c561SMatthew G. Knepley     if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t));
363507218a29SMatthew G. Knepley     // Loop over sides of surface
363607218a29SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
363707218a29SMatthew G. Knepley       const PetscInt *support;
363807218a29SMatthew G. Knepley       const PetscInt  face = cone[s];
363907218a29SMatthew G. Knepley       PetscInt        ssize, ncell, Nxc;
364007218a29SMatthew G. Knepley 
364107218a29SMatthew G. Knepley       // I don't think I need the face to have 0 orientation in the hybrid cell
364207218a29SMatthew G. Knepley       //PetscCheck(!ornt[s], PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %" PetscInt_FMT " in hybrid cell %" PetscInt_FMT " has orientation %" PetscInt_FMT " != 0", face, cell, ornt[s]);
364307218a29SMatthew G. Knepley       PetscCall(DMPlexGetSupport(dm, face, &support));
364407218a29SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, face, &ssize));
364507218a29SMatthew G. Knepley       if (support[0] == cell) ncell = support[1];
364607218a29SMatthew G. Knepley       else if (support[1] == cell) ncell = support[0];
364707218a29SMatthew G. Knepley       else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", face, cell);
364807218a29SMatthew G. Knepley       // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields
364907218a29SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc));
365074a0c561SMatthew G. Knepley       if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t));
365107218a29SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
365207218a29SMatthew G. Knepley         PetscInt  fdofIn, foffIn;
365307218a29SMatthew G. Knepley         PetscBool cohesive;
365407218a29SMatthew G. Knepley 
365507218a29SMatthew G. Knepley         PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive));
365607218a29SMatthew G. Knepley         if (cohesive) continue;
365707218a29SMatthew G. Knepley         PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn));
365807218a29SMatthew G. Knepley         PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn));
365907218a29SMatthew G. Knepley         for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foffIn + i];
366074a0c561SMatthew G. Knepley         if (locX_t)
366174a0c561SMatthew G. Knepley           for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foffIn + i];
366207218a29SMatthew G. Knepley         Nx += fdofIn;
366307218a29SMatthew G. Knepley       }
366407218a29SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc));
366574a0c561SMatthew G. Knepley       if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t));
366607218a29SMatthew G. Knepley     }
366707218a29SMatthew G. Knepley     PetscCheck(Nx == totDim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Closure size %" PetscInt_FMT " for cell %" PetscInt_FMT " does not match DS size %" PetscInt_FMT, Nx, cell, totDim);
366807218a29SMatthew G. Knepley 
366907218a29SMatthew G. Knepley     if (locA) {
367007218a29SMatthew G. Knepley       PetscScalar *al = &(*a)[cind * totDimAux];
367107218a29SMatthew G. Knepley       PetscInt     subcell;
367207218a29SMatthew G. Knepley 
367307218a29SMatthew G. Knepley       PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell));
367407218a29SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x));
367507218a29SMatthew G. Knepley       PetscCheck(Nx == totDimAux, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Closure size %" PetscInt_FMT " for subcell %" PetscInt_FMT "does not match DS size %" PetscInt_FMT, Nx, subcell, totDimAux);
367607218a29SMatthew G. Knepley       for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i];
367707218a29SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x));
367807218a29SMatthew G. Knepley     }
367907218a29SMatthew G. Knepley   }
368007218a29SMatthew G. Knepley   PetscCall(DMDestroy(&plex));
368107218a29SMatthew G. Knepley   PetscCall(DMDestroy(&plexA));
368207218a29SMatthew G. Knepley   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
368307218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
368407218a29SMatthew G. Knepley }
368507218a29SMatthew G. Knepley 
368607218a29SMatthew G. Knepley /*
36873e2b0218SMatthew G. Knepley   DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface
368807218a29SMatthew G. Knepley 
368907218a29SMatthew G. Knepley   Input Parameters:
369007218a29SMatthew G. Knepley + dm      - The full domain DM
369107218a29SMatthew G. Knepley . dmX     - An array of DM for the field, say an auxiliary DM, indexed by s
369207218a29SMatthew G. Knepley . dsX     - An array of PetscDS for the field, indexed by s
369307218a29SMatthew G. Knepley . cellIS  - The interface cells for which we want values
369407218a29SMatthew G. Knepley . locX    - An array of local vectors with the field values, indexed by s
369507218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face
369607218a29SMatthew G. Knepley 
369707218a29SMatthew G. Knepley   Output Parameter:
369807218a29SMatthew G. Knepley . x       - An array of field values, indexed by s
369907218a29SMatthew G. Knepley 
370007218a29SMatthew G. Knepley   Note:
370176fbde31SPierre Jolivet   The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`.
370207218a29SMatthew G. Knepley 
370307218a29SMatthew G. Knepley   Level: advanced
370407218a29SMatthew G. Knepley 
370576fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()`
370607218a29SMatthew G. Knepley */
370707218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[])
370807218a29SMatthew G. Knepley {
370907218a29SMatthew G. Knepley   DM              plexX[2];
371007218a29SMatthew G. Knepley   DMEnclosureType encX[2];
371107218a29SMatthew G. Knepley   PetscSection    sectionX[2];
371207218a29SMatthew G. Knepley   const PetscInt *cells;
371307218a29SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, c, s, totDimX[2];
371407218a29SMatthew G. Knepley 
371507218a29SMatthew G. Knepley   PetscFunctionBegin;
37164f572ea9SToby Isaac   PetscAssertPointer(locX, 5);
371707218a29SMatthew G. Knepley   if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS);
37184f572ea9SToby Isaac   PetscAssertPointer(dmX, 2);
37194f572ea9SToby Isaac   PetscAssertPointer(dsX, 3);
372007218a29SMatthew G. Knepley   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4);
37214f572ea9SToby Isaac   PetscAssertPointer(x, 7);
37229566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
37236528b96dSMatthew G. Knepley   numCells = cEnd - cStart;
3724148442b3SMatthew G. Knepley   for (s = 0; s < 2; ++s) {
372507218a29SMatthew G. Knepley     PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2);
372607218a29SMatthew G. Knepley     PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3);
372707218a29SMatthew G. Knepley     PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5);
372807218a29SMatthew G. Knepley     PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE));
372907218a29SMatthew G. Knepley     PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s]));
373007218a29SMatthew G. Knepley     PetscCall(DMGetLocalSection(dmX[s], &sectionX[s]));
373107218a29SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s]));
373207218a29SMatthew G. Knepley     PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s]));
373304c51a94SMatthew G. Knepley   }
3734148442b3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
37356528b96dSMatthew G. Knepley     const PetscInt  cell = cells ? cells[c] : c;
37366528b96dSMatthew G. Knepley     const PetscInt  cind = c - cStart;
37376528b96dSMatthew G. Knepley     const PetscInt *cone, *ornt;
37386528b96dSMatthew G. Knepley 
37399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, cell, &cone));
37409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
374107218a29SMatthew G. Knepley     //PetscCheck(!ornt[0], PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %" PetscInt_FMT " in hybrid cell %" PetscInt_FMT " has orientation %" PetscInt_FMT " != 0", cone[0], cell, ornt[0]);
3742148442b3SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
374307218a29SMatthew G. Knepley       const PetscInt tdX     = totDimX[s];
374407218a29SMatthew G. Knepley       PetscScalar   *closure = NULL, *xl = &x[s][cind * tdX];
374507218a29SMatthew G. Knepley       PetscInt       face = cone[s], point = face, subpoint, Nx, i;
374607218a29SMatthew G. Knepley 
374707218a29SMatthew G. Knepley       if (useCell) {
37485fedec97SMatthew G. Knepley         const PetscInt *support;
374907218a29SMatthew G. Knepley         PetscInt        ssize;
37506528b96dSMatthew G. Knepley 
375107218a29SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, face, &support));
375207218a29SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, face, &ssize));
375307218a29SMatthew 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", face, cell, ssize);
375407218a29SMatthew G. Knepley         if (support[0] == cell) point = support[1];
375507218a29SMatthew G. Knepley         else if (support[1] == cell) point = support[0];
375607218a29SMatthew G. Knepley         else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", face, cell);
375707218a29SMatthew G. Knepley       }
375807218a29SMatthew G. Knepley       PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint));
3759e8e188d2SZach Atkins       PetscCall(DMPlexVecGetOrientedClosure_Internal(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure));
376007218a29SMatthew G. Knepley       PetscCheck(Nx == tdX, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Closure size %" PetscInt_FMT " for subpoint %" PetscInt_FMT " does not match DS size %" PetscInt_FMT, Nx, subpoint, tdX);
376107218a29SMatthew G. Knepley       for (i = 0; i < Nx; ++i) xl[i] = closure[i];
376207218a29SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure));
37636528b96dSMatthew G. Knepley     }
37646528b96dSMatthew G. Knepley   }
376507218a29SMatthew G. Knepley   for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s]));
37669566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
37673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37686528b96dSMatthew G. Knepley }
37696528b96dSMatthew G. Knepley 
377007218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[])
3771d71ae5a4SJacob Faibussowitsch {
37726528b96dSMatthew G. Knepley   PetscFunctionBegin;
377307218a29SMatthew G. Knepley   if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS);
377407218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0]));
377507218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1]));
37763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37776528b96dSMatthew G. Knepley }
37786528b96dSMatthew G. Knepley 
37792f856554SMatthew G. Knepley /*@C
37802f856554SMatthew G. Knepley   DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
37812f856554SMatthew G. Knepley 
37822f856554SMatthew G. Knepley   Input Parameters:
3783a1cb98faSBarry Smith + dm           - The `DM`
37842f856554SMatthew G. Knepley . fStart       - The first face to include
37852f856554SMatthew G. Knepley . fEnd         - The first face to exclude
37862f856554SMatthew G. Knepley . locX         - A local vector with the solution fields
37872f856554SMatthew G. Knepley . locX_t       - A local vector with solution field time derivatives, or NULL
37882f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
37892f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry
379060225df5SJacob Faibussowitsch - locGrad      - A local vector with field gradients, or NULL
37912f856554SMatthew G. Knepley 
37922f856554SMatthew G. Knepley   Output Parameters:
37932f856554SMatthew G. Knepley + Nface - The number of faces with field values
37942f856554SMatthew G. Knepley . uL    - The field values at the left side of the face
37952f856554SMatthew G. Knepley - uR    - The field values at the right side of the face
37962f856554SMatthew G. Knepley 
37972f856554SMatthew G. Knepley   Level: developer
37982f856554SMatthew G. Knepley 
37991cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
38002f856554SMatthew G. Knepley @*/
3801d71ae5a4SJacob 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)
3802d71ae5a4SJacob Faibussowitsch {
38032f856554SMatthew G. Knepley   DM                 dmFace, dmCell, dmGrad = NULL;
38042f856554SMatthew G. Knepley   PetscSection       section;
38052f856554SMatthew G. Knepley   PetscDS            prob;
38062f856554SMatthew G. Knepley   DMLabel            ghostLabel;
38072f856554SMatthew G. Knepley   const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
38082f856554SMatthew G. Knepley   PetscBool         *isFE;
38092f856554SMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
38102f856554SMatthew G. Knepley 
38112f856554SMatthew G. Knepley   PetscFunctionBegin;
38122f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
38132f856554SMatthew G. Knepley   PetscValidHeaderSpecific(locX, VEC_CLASSID, 4);
3814ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);
38152f856554SMatthew G. Knepley   PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6);
38162f856554SMatthew G. Knepley   PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7);
3817ad540459SPierre Jolivet   if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);
38184f572ea9SToby Isaac   PetscAssertPointer(uL, 10);
38194f572ea9SToby Isaac   PetscAssertPointer(uR, 11);
38209566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
38219566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
38229566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
38239566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
38249566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(prob, &Nc));
38259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(Nf, &isFE));
38262f856554SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
38272f856554SMatthew G. Knepley     PetscObject  obj;
38282f856554SMatthew G. Knepley     PetscClassId id;
38292f856554SMatthew G. Knepley 
38309566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
38319566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
38329371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
38339371c9d4SSatish Balay       isFE[f] = PETSC_TRUE;
38349371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
38359371c9d4SSatish Balay       isFE[f] = PETSC_FALSE;
38369371c9d4SSatish Balay     } else {
38379371c9d4SSatish Balay       isFE[f] = PETSC_FALSE;
38389371c9d4SSatish Balay     }
38392f856554SMatthew G. Knepley   }
38409566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
38419566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(locX, &x));
38429566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
38439566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
38449566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
38459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
38462f856554SMatthew G. Knepley   if (locGrad) {
38479566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locGrad, &dmGrad));
38489566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &lgrad));
38492f856554SMatthew G. Knepley   }
38509566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL));
38519566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR));
38522f856554SMatthew G. Knepley   /* Right now just eat the extra work for FE (could make a cell loop) */
38532f856554SMatthew G. Knepley   for (face = fStart, iface = 0; face < fEnd; ++face) {
38542f856554SMatthew G. Knepley     const PetscInt  *cells;
38552f856554SMatthew G. Knepley     PetscFVFaceGeom *fg;
38562f856554SMatthew G. Knepley     PetscFVCellGeom *cgL, *cgR;
38572f856554SMatthew G. Knepley     PetscScalar     *xL, *xR, *gL, *gR;
38582f856554SMatthew G. Knepley     PetscScalar     *uLl = *uL, *uRl = *uR;
38592f856554SMatthew G. Knepley     PetscInt         ghost, nsupp, nchild;
38602f856554SMatthew G. Knepley 
38619566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
38629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
38639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
38642f856554SMatthew G. Knepley     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
38659566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
38669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, face, &cells));
38679566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL));
38689566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR));
38692f856554SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
38702f856554SMatthew G. Knepley       PetscInt off;
38712f856554SMatthew G. Knepley 
38729566063dSJacob Faibussowitsch       PetscCall(PetscDSGetComponentOffset(prob, f, &off));
38732f856554SMatthew G. Knepley       if (isFE[f]) {
38742f856554SMatthew G. Knepley         const PetscInt *cone;
38752f856554SMatthew G. Knepley         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
38762f856554SMatthew G. Knepley 
38772f856554SMatthew G. Knepley         xL = xR = NULL;
38789566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldComponents(section, f, &comp));
38799566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL));
38809566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR));
38819566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cells[0], &cone));
38829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL));
38839371c9d4SSatish Balay         for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL)
38849371c9d4SSatish Balay           if (cone[faceLocL] == face) break;
38859566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cells[1], &cone));
38869566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR));
38879371c9d4SSatish Balay         for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR)
38889371c9d4SSatish Balay           if (cone[faceLocR] == face) break;
38891dca8a05SBarry 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]);
38902f856554SMatthew G. Knepley         /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
38912f856554SMatthew G. Knepley         /* TODO: this is a hack that might not be right for nonconforming */
38922f856554SMatthew G. Knepley         if (faceLocL < coneSizeL) {
38939566063dSJacob Faibussowitsch           PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off]));
38949566063dSJacob Faibussowitsch           if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]));
38952f856554SMatthew G. Knepley           else {
38969371c9d4SSatish Balay             for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d];
38979371c9d4SSatish Balay           }
38989371c9d4SSatish Balay         } else {
38999566063dSJacob Faibussowitsch           PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]));
39009566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldComponents(section, f, &comp));
39012f856554SMatthew G. Knepley           for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d];
39022f856554SMatthew G. Knepley         }
39039566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL));
39049566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR));
39052f856554SMatthew G. Knepley       } else {
39062f856554SMatthew G. Knepley         PetscFV  fv;
39072f856554SMatthew G. Knepley         PetscInt numComp, c;
39082f856554SMatthew G. Knepley 
39099566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv));
39109566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numComp));
39119566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL));
39129566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR));
39132f856554SMatthew G. Knepley         if (dmGrad) {
39142f856554SMatthew G. Knepley           PetscReal dxL[3], dxR[3];
39152f856554SMatthew G. Knepley 
39169566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL));
39179566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR));
39182f856554SMatthew G. Knepley           DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
39192f856554SMatthew G. Knepley           DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
39202f856554SMatthew G. Knepley           for (c = 0; c < numComp; ++c) {
39212f856554SMatthew G. Knepley             uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL);
39222f856554SMatthew G. Knepley             uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR);
39232f856554SMatthew G. Knepley           }
39242f856554SMatthew G. Knepley         } else {
39252f856554SMatthew G. Knepley           for (c = 0; c < numComp; ++c) {
39262f856554SMatthew G. Knepley             uLl[iface * Nc + off + c] = xL[c];
39272f856554SMatthew G. Knepley             uRl[iface * Nc + off + c] = xR[c];
39282f856554SMatthew G. Knepley           }
39292f856554SMatthew G. Knepley         }
39302f856554SMatthew G. Knepley       }
39312f856554SMatthew G. Knepley     }
39322f856554SMatthew G. Knepley     ++iface;
39332f856554SMatthew G. Knepley   }
39342f856554SMatthew G. Knepley   *Nface = iface;
39359566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(locX, &x));
39369566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
39379566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
393848a46eb9SPierre Jolivet   if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad));
39399566063dSJacob Faibussowitsch   PetscCall(PetscFree(isFE));
39403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39412f856554SMatthew G. Knepley }
39422f856554SMatthew G. Knepley 
39432f856554SMatthew G. Knepley /*@C
39442f856554SMatthew G. Knepley   DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
39452f856554SMatthew G. Knepley 
39462f856554SMatthew G. Knepley   Input Parameters:
3947a1cb98faSBarry Smith + dm           - The `DM`
39482f856554SMatthew G. Knepley . fStart       - The first face to include
39492f856554SMatthew G. Knepley . fEnd         - The first face to exclude
39502f856554SMatthew G. Knepley . locX         - A local vector with the solution fields
39512f856554SMatthew G. Knepley . locX_t       - A local vector with solution field time derivatives, or NULL
39522f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
39532f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry
395460225df5SJacob Faibussowitsch - locGrad      - A local vector with field gradients, or NULL
39552f856554SMatthew G. Knepley 
39562f856554SMatthew G. Knepley   Output Parameters:
39572f856554SMatthew G. Knepley + Nface - The number of faces with field values
39582f856554SMatthew G. Knepley . uL    - The field values at the left side of the face
39592f856554SMatthew G. Knepley - uR    - The field values at the right side of the face
39602f856554SMatthew G. Knepley 
39612f856554SMatthew G. Knepley   Level: developer
39622f856554SMatthew G. Knepley 
39631cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
39642f856554SMatthew G. Knepley @*/
3965d71ae5a4SJacob 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)
3966d71ae5a4SJacob Faibussowitsch {
39672f856554SMatthew G. Knepley   PetscFunctionBegin;
39689566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL));
39699566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR));
39703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39712f856554SMatthew G. Knepley }
39722f856554SMatthew G. Knepley 
39732f856554SMatthew G. Knepley /*@C
39742f856554SMatthew G. Knepley   DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
39752f856554SMatthew G. Knepley 
39762f856554SMatthew G. Knepley   Input Parameters:
3977a1cb98faSBarry Smith + dm           - The `DM`
39782f856554SMatthew G. Knepley . fStart       - The first face to include
39792f856554SMatthew G. Knepley . fEnd         - The first face to exclude
39802f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
39812f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry
39822f856554SMatthew G. Knepley 
39832f856554SMatthew G. Knepley   Output Parameters:
39842f856554SMatthew G. Knepley + Nface - The number of faces with field values
39852f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal
39862f856554SMatthew G. Knepley - vol   - The cell volume
39872f856554SMatthew G. Knepley 
39882f856554SMatthew G. Knepley   Level: developer
39892f856554SMatthew G. Knepley 
39901cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
39912f856554SMatthew G. Knepley @*/
3992d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
3993d71ae5a4SJacob Faibussowitsch {
39942f856554SMatthew G. Knepley   DM                 dmFace, dmCell;
39952f856554SMatthew G. Knepley   DMLabel            ghostLabel;
39962f856554SMatthew G. Knepley   const PetscScalar *facegeom, *cellgeom;
39972f856554SMatthew G. Knepley   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
39982f856554SMatthew G. Knepley 
39992f856554SMatthew G. Knepley   PetscFunctionBegin;
40002f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40012f856554SMatthew G. Knepley   PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4);
40022f856554SMatthew G. Knepley   PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5);
40034f572ea9SToby Isaac   PetscAssertPointer(fgeom, 7);
40044f572ea9SToby Isaac   PetscAssertPointer(vol, 8);
40059566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
40069566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
40079566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
40089566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
40099566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
40109566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
40119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFaces, fgeom));
40129566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol));
40132f856554SMatthew G. Knepley   for (face = fStart, iface = 0; face < fEnd; ++face) {
40142f856554SMatthew G. Knepley     const PetscInt  *cells;
40152f856554SMatthew G. Knepley     PetscFVFaceGeom *fg;
40162f856554SMatthew G. Knepley     PetscFVCellGeom *cgL, *cgR;
40172f856554SMatthew G. Knepley     PetscFVFaceGeom *fgeoml = *fgeom;
40182f856554SMatthew G. Knepley     PetscReal       *voll   = *vol;
40192f856554SMatthew G. Knepley     PetscInt         ghost, d, nchild, nsupp;
40202f856554SMatthew G. Knepley 
40219566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
40229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
40239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
40242f856554SMatthew G. Knepley     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
40259566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
40269566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, face, &cells));
40279566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL));
40289566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR));
40292f856554SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
40302f856554SMatthew G. Knepley       fgeoml[iface].centroid[d] = fg->centroid[d];
40312f856554SMatthew G. Knepley       fgeoml[iface].normal[d]   = fg->normal[d];
40322f856554SMatthew G. Knepley     }
40332f856554SMatthew G. Knepley     voll[iface * 2 + 0] = cgL->volume;
40342f856554SMatthew G. Knepley     voll[iface * 2 + 1] = cgR->volume;
40352f856554SMatthew G. Knepley     ++iface;
40362f856554SMatthew G. Knepley   }
40372f856554SMatthew G. Knepley   *Nface = iface;
40389566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
40399566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
40403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40412f856554SMatthew G. Knepley }
40422f856554SMatthew G. Knepley 
40432f856554SMatthew G. Knepley /*@C
40442f856554SMatthew G. Knepley   DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
40452f856554SMatthew G. Knepley 
40462f856554SMatthew G. Knepley   Input Parameters:
4047a1cb98faSBarry Smith + dm           - The `DM`
40482f856554SMatthew G. Knepley . fStart       - The first face to include
40492f856554SMatthew G. Knepley . fEnd         - The first face to exclude
40502f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
40512f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry
40522f856554SMatthew G. Knepley 
40532f856554SMatthew G. Knepley   Output Parameters:
40542f856554SMatthew G. Knepley + Nface - The number of faces with field values
40552f856554SMatthew G. Knepley . fgeom - The extract the face centroid and normal
40562f856554SMatthew G. Knepley - vol   - The cell volume
40572f856554SMatthew G. Knepley 
40582f856554SMatthew G. Knepley   Level: developer
40592f856554SMatthew G. Knepley 
40601cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
40612f856554SMatthew G. Knepley @*/
4062d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol)
4063d71ae5a4SJacob Faibussowitsch {
40642f856554SMatthew G. Knepley   PetscFunctionBegin;
40659566063dSJacob Faibussowitsch   PetscCall(PetscFree(*fgeom));
40669566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol));
40673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40682f856554SMatthew G. Knepley }
40692f856554SMatthew G. Knepley 
4070d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
4071d71ae5a4SJacob Faibussowitsch {
4072a1cf66bbSMatthew G. Knepley   char           composeStr[33] = {0};
4073a1cf66bbSMatthew G. Knepley   PetscObjectId  id;
4074a1cf66bbSMatthew G. Knepley   PetscContainer container;
4075a1cf66bbSMatthew G. Knepley 
4076a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
40779566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetId((PetscObject)quad, &id));
407863a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id));
40799566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container));
4080a1cf66bbSMatthew G. Knepley   if (container) {
40819566063dSJacob Faibussowitsch     PetscCall(PetscContainerGetPointer(container, (void **)geom));
4082a1cf66bbSMatthew G. Knepley   } else {
40839566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom));
40849566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
40859566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(container, (void *)*geom));
40869566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom));
40879566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container));
40889566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&container));
4089a1cf66bbSMatthew G. Knepley   }
40903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4091a1cf66bbSMatthew G. Knepley }
4092a1cf66bbSMatthew G. Knepley 
4093d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
4094d71ae5a4SJacob Faibussowitsch {
4095a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
4096a1cf66bbSMatthew G. Knepley   *geom = NULL;
40973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4098a1cf66bbSMatthew G. Knepley }
4099a1cf66bbSMatthew G. Knepley 
4100d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user)
4101d71ae5a4SJacob Faibussowitsch {
410292d50984SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
410392d50984SMatthew G. Knepley   const char     *name       = "Residual";
410492d50984SMatthew G. Knepley   DM              dmAux      = NULL;
410592d50984SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
410692d50984SMatthew G. Knepley   PetscDS         prob       = NULL;
410792d50984SMatthew G. Knepley   PetscDS         probAux    = NULL;
410892d50984SMatthew G. Knepley   PetscBool       useFEM     = PETSC_FALSE;
410992d50984SMatthew G. Knepley   PetscBool       isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
411092d50984SMatthew G. Knepley   DMField         coordField = NULL;
4111c0006e53SPatrick Farrell   Vec             locA;
4112c0006e53SPatrick Farrell   PetscScalar    *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
411392d50984SMatthew G. Knepley   IS              chunkIS;
411492d50984SMatthew G. Knepley   const PetscInt *cells;
411592d50984SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
4116364207b6SKarl Rupp   PetscInt        Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
411792d50984SMatthew G. Knepley   PetscInt        maxDegree = PETSC_MAX_INT;
411806ad1575SMatthew G. Knepley   PetscFormKey    key;
411992d50984SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
412092d50984SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
412192d50984SMatthew G. Knepley 
412292d50984SMatthew G. Knepley   PetscFunctionBegin;
41239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
412492d50984SMatthew G. Knepley   /* FEM+FVM */
412592d50984SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
41269566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
41279566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
41289566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
41299566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
41309566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
413192d50984SMatthew G. Knepley   if (locA) {
41329566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
41339566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
41349566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
413592d50984SMatthew G. Knepley   }
413692d50984SMatthew G. Knepley   /* 2: Get geometric data */
413792d50984SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
413892d50984SMatthew G. Knepley     PetscObject  obj;
413992d50984SMatthew G. Knepley     PetscClassId id;
414092d50984SMatthew G. Knepley     PetscBool    fimp;
414192d50984SMatthew G. Knepley 
41429566063dSJacob Faibussowitsch     PetscCall(PetscDSGetImplicit(prob, f, &fimp));
414392d50984SMatthew G. Knepley     if (isImplicit != fimp) continue;
41449566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
41459566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
4146ad540459SPierre Jolivet     if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
41475f80ce2aSJacob Faibussowitsch     PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented");
414892d50984SMatthew G. Knepley   }
414992d50984SMatthew G. Knepley   if (useFEM) {
41509566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
41519566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
415292d50984SMatthew G. Knepley     if (maxDegree <= 1) {
41539566063dSJacob Faibussowitsch       PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
415448a46eb9SPierre Jolivet       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
415592d50984SMatthew G. Knepley     } else {
41569566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
415792d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
415892d50984SMatthew G. Knepley         PetscObject  obj;
415992d50984SMatthew G. Knepley         PetscClassId id;
416092d50984SMatthew G. Knepley         PetscBool    fimp;
416192d50984SMatthew G. Knepley 
41629566063dSJacob Faibussowitsch         PetscCall(PetscDSGetImplicit(prob, f, &fimp));
416392d50984SMatthew G. Knepley         if (isImplicit != fimp) continue;
41649566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, &obj));
41659566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
416692d50984SMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
416792d50984SMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
416892d50984SMatthew G. Knepley 
41699566063dSJacob Faibussowitsch           PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
41709566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)quads[f]));
41719566063dSJacob Faibussowitsch           PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
417292d50984SMatthew G. Knepley         }
417392d50984SMatthew G. Knepley       }
417492d50984SMatthew G. Knepley     }
417592d50984SMatthew G. Knepley   }
417692d50984SMatthew G. Knepley   /* Loop over chunks */
41779566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
41789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
41799566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS));
418092d50984SMatthew G. Knepley   numCells      = cEnd - cStart;
418192d50984SMatthew G. Knepley   numChunks     = 1;
418292d50984SMatthew G. Knepley   cellChunkSize = numCells / numChunks;
418392d50984SMatthew G. Knepley   numChunks     = PetscMin(1, numCells);
41846528b96dSMatthew G. Knepley   key.label     = NULL;
41856528b96dSMatthew G. Knepley   key.value     = 0;
418606ad1575SMatthew G. Knepley   key.part      = 0;
418792d50984SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
4188c0006e53SPatrick Farrell     PetscScalar     *elemVec, *fluxL = NULL, *fluxR = NULL;
4189c0006e53SPatrick Farrell     PetscReal       *vol   = NULL;
4190c0006e53SPatrick Farrell     PetscFVFaceGeom *fgeom = NULL;
419192d50984SMatthew G. Knepley     PetscInt         cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
4192c0006e53SPatrick Farrell     PetscInt         numFaces = 0;
419392d50984SMatthew G. Knepley 
419492d50984SMatthew G. Knepley     /* Extract field coefficients */
419592d50984SMatthew G. Knepley     if (useFEM) {
41969566063dSJacob Faibussowitsch       PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells));
41979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
41989566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
41999566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemVec, numCells * totDim));
420092d50984SMatthew G. Knepley     }
420192d50984SMatthew 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 */
420292d50984SMatthew G. Knepley     /* Loop over fields */
420392d50984SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
420492d50984SMatthew G. Knepley       PetscObject  obj;
420592d50984SMatthew G. Knepley       PetscClassId id;
420692d50984SMatthew G. Knepley       PetscBool    fimp;
420792d50984SMatthew G. Knepley       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
420892d50984SMatthew G. Knepley 
42096528b96dSMatthew G. Knepley       key.field = f;
42109566063dSJacob Faibussowitsch       PetscCall(PetscDSGetImplicit(prob, f, &fimp));
421192d50984SMatthew G. Knepley       if (isImplicit != fimp) continue;
42129566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
42139566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
421492d50984SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
421592d50984SMatthew G. Knepley         PetscFE         fe        = (PetscFE)obj;
421692d50984SMatthew G. Knepley         PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
421792d50984SMatthew G. Knepley         PetscFEGeom    *chunkGeom = NULL;
421892d50984SMatthew G. Knepley         PetscQuadrature quad      = affineQuad ? affineQuad : quads[f];
421992d50984SMatthew G. Knepley         PetscInt        Nq, Nb;
422092d50984SMatthew G. Knepley 
42219566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
42229566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
42239566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
422492d50984SMatthew G. Knepley         blockSize = Nb;
422592d50984SMatthew G. Knepley         batchSize = numBlocks * blockSize;
42269566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
422792d50984SMatthew G. Knepley         numChunks = numCells / (numBatches * batchSize);
422892d50984SMatthew G. Knepley         Ne        = numChunks * numBatches * batchSize;
422992d50984SMatthew G. Knepley         Nr        = numCells % (numBatches * batchSize);
423092d50984SMatthew G. Knepley         offset    = numCells - Nr;
423192d50984SMatthew G. Knepley         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
423292d50984SMatthew 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) */
42339566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
42349566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec));
42359566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom));
42369566063dSJacob 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]));
42379566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom));
423892d50984SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
423992d50984SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
424092d50984SMatthew G. Knepley 
424192d50984SMatthew G. Knepley         Ne = numFaces;
424292d50984SMatthew G. Knepley         /* Riemann solve over faces (need fields at face centroids) */
424392d50984SMatthew G. Knepley         /*   We need to evaluate FE fields at those coordinates */
42449566063dSJacob Faibussowitsch         PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR));
424563a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
424692d50984SMatthew G. Knepley     }
424792d50984SMatthew G. Knepley     /* Loop over domain */
424892d50984SMatthew G. Knepley     if (useFEM) {
424992d50984SMatthew G. Knepley       /* Add elemVec to locX */
425092d50984SMatthew G. Knepley       for (c = cS; c < cE; ++c) {
425192d50984SMatthew G. Knepley         const PetscInt cell = cells ? cells[c] : c;
425292d50984SMatthew G. Knepley         const PetscInt cind = c - cStart;
425392d50984SMatthew G. Knepley 
42549566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
425592d50984SMatthew G. Knepley         if (ghostLabel) {
425692d50984SMatthew G. Knepley           PetscInt ghostVal;
425792d50984SMatthew G. Knepley 
42589566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
425992d50984SMatthew G. Knepley           if (ghostVal > 0) continue;
426092d50984SMatthew G. Knepley         }
42619566063dSJacob Faibussowitsch         PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
426292d50984SMatthew G. Knepley       }
426392d50984SMatthew G. Knepley     }
426492d50984SMatthew G. Knepley     /* Handle time derivative */
426592d50984SMatthew G. Knepley     if (locX_t) {
426692d50984SMatthew G. Knepley       PetscScalar *x_t, *fa;
426792d50984SMatthew G. Knepley 
42689566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
42699566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locX_t, &x_t));
427092d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
427192d50984SMatthew G. Knepley         PetscFV      fv;
427292d50984SMatthew G. Knepley         PetscObject  obj;
427392d50984SMatthew G. Knepley         PetscClassId id;
427492d50984SMatthew G. Knepley         PetscInt     pdim, d;
427592d50984SMatthew G. Knepley 
42769566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, &obj));
42779566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
427892d50984SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
427992d50984SMatthew G. Knepley         fv = (PetscFV)obj;
42809566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
428192d50984SMatthew G. Knepley         for (c = cS; c < cE; ++c) {
428292d50984SMatthew G. Knepley           const PetscInt cell = cells ? cells[c] : c;
428392d50984SMatthew G. Knepley           PetscScalar   *u_t, *r;
428492d50984SMatthew G. Knepley 
428592d50984SMatthew G. Knepley           if (ghostLabel) {
428692d50984SMatthew G. Knepley             PetscInt ghostVal;
428792d50984SMatthew G. Knepley 
42889566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
428992d50984SMatthew G. Knepley             if (ghostVal > 0) continue;
429092d50984SMatthew G. Knepley           }
42919566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t));
42929566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r));
429392d50984SMatthew G. Knepley           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
429492d50984SMatthew G. Knepley         }
429592d50984SMatthew G. Knepley       }
42969566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locX_t, &x_t));
42979566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
429892d50984SMatthew G. Knepley     }
429992d50984SMatthew G. Knepley     if (useFEM) {
43009566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
43019566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
430292d50984SMatthew G. Knepley     }
430392d50984SMatthew G. Knepley   }
43049566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISDestroy(&chunkIS));
43059566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
430692d50984SMatthew G. Knepley   /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */
430792d50984SMatthew G. Knepley   if (useFEM) {
430892d50984SMatthew G. Knepley     if (maxDegree <= 1) {
43099566063dSJacob Faibussowitsch       PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
43109566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&affineQuad));
431192d50984SMatthew G. Knepley     } else {
431292d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
43139566063dSJacob Faibussowitsch         PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
43149566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureDestroy(&quads[f]));
431592d50984SMatthew G. Knepley       }
43169566063dSJacob Faibussowitsch       PetscCall(PetscFree2(quads, geoms));
431792d50984SMatthew G. Knepley     }
431892d50984SMatthew G. Knepley   }
43199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
43203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
432192d50984SMatthew G. Knepley }
432292d50984SMatthew G. Knepley 
4323a1cf66bbSMatthew G. Knepley /*
4324a1cf66bbSMatthew 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
4325a1cf66bbSMatthew G. Knepley 
4326a1cf66bbSMatthew G. Knepley   X   - The local solution vector
4327a5b23f4aSJose E. Roman   X_t - The local solution time derivative vector, or NULL
4328a1cf66bbSMatthew G. Knepley */
4329d71ae5a4SJacob 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)
4330d71ae5a4SJacob Faibussowitsch {
4331a1cf66bbSMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
4332a1cf66bbSMatthew G. Knepley   const char     *name = "Jacobian", *nameP = "JacobianPre";
4333a1cf66bbSMatthew G. Knepley   DM              dmAux = NULL;
4334a1cf66bbSMatthew G. Knepley   PetscDS         prob, probAux = NULL;
4335a1cf66bbSMatthew G. Knepley   PetscSection    sectionAux = NULL;
4336a1cf66bbSMatthew G. Knepley   Vec             A;
4337a1cf66bbSMatthew G. Knepley   DMField         coordField;
4338a1cf66bbSMatthew G. Knepley   PetscFEGeom    *cgeomFEM;
4339a1cf66bbSMatthew G. Knepley   PetscQuadrature qGeom = NULL;
4340a1cf66bbSMatthew G. Knepley   Mat             J = Jac, JP = JacP;
4341a1cf66bbSMatthew G. Knepley   PetscScalar    *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
4342e432b41dSStefano Zampini   PetscBool       hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE;
4343a1cf66bbSMatthew G. Knepley   const PetscInt *cells;
434406ad1575SMatthew G. Knepley   PetscFormKey    key;
43459b2fc754SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
4346a1cf66bbSMatthew G. Knepley 
4347a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
43489566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
43499566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
43509566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
43519566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
43529566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A));
43539a2a23afSMatthew G. Knepley   if (A) {
43549566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
43559566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
43569566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
4357a1cf66bbSMatthew G. Knepley   }
4358a1cf66bbSMatthew G. Knepley   /* Get flags */
43599566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
43609566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE));
4361a1cf66bbSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
4362a1cf66bbSMatthew G. Knepley     PetscObject  disc;
4363a1cf66bbSMatthew G. Knepley     PetscClassId id;
43649566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc));
43659566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
43669371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
43679371c9d4SSatish Balay       isFE[fieldI] = PETSC_TRUE;
43689371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
43699371c9d4SSatish Balay       hasFV        = PETSC_TRUE;
43709371c9d4SSatish Balay       isFE[fieldI] = PETSC_FALSE;
43719371c9d4SSatish Balay     }
4372a1cf66bbSMatthew G. Knepley   }
43739566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(prob, &hasJac));
43749566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
43759566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
4376a1cf66bbSMatthew G. Knepley   assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
4377a1cf66bbSMatthew G. Knepley   hasDyn      = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
43789566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */
43799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
43809566063dSJacob Faibussowitsch   if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
4381a1cf66bbSMatthew G. Knepley   /* Compute batch sizes */
4382a1cf66bbSMatthew G. Knepley   if (isFE[0]) {
4383a1cf66bbSMatthew G. Knepley     PetscFE         fe;
4384a1cf66bbSMatthew G. Knepley     PetscQuadrature q;
4385a1cf66bbSMatthew G. Knepley     PetscInt        numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
4386a1cf66bbSMatthew G. Knepley 
43879566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe));
43889566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &q));
43899566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL));
43909566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
43919566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
4392a1cf66bbSMatthew G. Knepley     blockSize = Nb * numQuadPoints;
4393a1cf66bbSMatthew G. Knepley     batchSize = numBlocks * blockSize;
4394a1cf66bbSMatthew G. Knepley     chunkSize = numBatches * batchSize;
4395a1cf66bbSMatthew G. Knepley     numChunks = numCells / chunkSize + numCells % chunkSize;
43969566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
4397a1cf66bbSMatthew G. Knepley   } else {
4398a1cf66bbSMatthew G. Knepley     chunkSize = numCells;
4399a1cf66bbSMatthew G. Knepley     numChunks = 1;
4400a1cf66bbSMatthew G. Knepley   }
4401a1cf66bbSMatthew G. Knepley   /* Get work space */
4402a1cf66bbSMatthew 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;
44039566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work));
44049566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(work, wsz));
4405a1cf66bbSMatthew G. Knepley   off      = 0;
4406a1cf66bbSMatthew G. Knepley   u        = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4407a1cf66bbSMatthew G. Knepley   u_t      = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4408a1cf66bbSMatthew G. Knepley   a        = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL;
4409a1cf66bbSMatthew G. Knepley   elemMat  = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4410a1cf66bbSMatthew G. Knepley   elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4411a1cf66bbSMatthew G. Knepley   elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
441263a3b9bcSJacob Faibussowitsch   PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz);
4413a1cf66bbSMatthew G. Knepley   /* Setup geometry */
44149566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
44159566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
44169566063dSJacob Faibussowitsch   if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
4417a1cf66bbSMatthew G. Knepley   if (!qGeom) {
4418a1cf66bbSMatthew G. Knepley     PetscFE fe;
4419a1cf66bbSMatthew G. Knepley 
44209566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe));
44219566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &qGeom));
44229566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)qGeom));
4423a1cf66bbSMatthew G. Knepley   }
44249566063dSJacob Faibussowitsch   PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
4425a1cf66bbSMatthew G. Knepley   /* Compute volume integrals */
44269566063dSJacob Faibussowitsch   if (assembleJac) PetscCall(MatZeroEntries(J));
44279566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(JP));
44286528b96dSMatthew G. Knepley   key.label = NULL;
44296528b96dSMatthew G. Knepley   key.value = 0;
443006ad1575SMatthew G. Knepley   key.part  = 0;
4431a1cf66bbSMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4432a1cf66bbSMatthew G. Knepley     const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
4433a1cf66bbSMatthew G. Knepley     PetscInt       c;
4434a1cf66bbSMatthew G. Knepley 
4435a1cf66bbSMatthew G. Knepley     /* Extract values */
4436a1cf66bbSMatthew G. Knepley     for (c = 0; c < Ncell; ++c) {
4437a1cf66bbSMatthew G. Knepley       const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4438a1cf66bbSMatthew G. Knepley       PetscScalar   *x = NULL, *x_t = NULL;
4439a1cf66bbSMatthew G. Knepley       PetscInt       i;
4440a1cf66bbSMatthew G. Knepley 
4441a1cf66bbSMatthew G. Knepley       if (X) {
44429566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x));
4443a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
44449566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x));
4445a1cf66bbSMatthew G. Knepley       }
4446a1cf66bbSMatthew G. Knepley       if (X_t) {
44479566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t));
4448a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i];
44499566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t));
4450a1cf66bbSMatthew G. Knepley       }
4451a1cf66bbSMatthew G. Knepley       if (dmAux) {
44529566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x));
4453a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
44549566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x));
4455a1cf66bbSMatthew G. Knepley       }
4456a1cf66bbSMatthew G. Knepley     }
4457a1cf66bbSMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
4458a1cf66bbSMatthew G. Knepley       PetscFE fe;
44599566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
4460a1cf66bbSMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
44616528b96dSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
44629566063dSJacob Faibussowitsch         if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat));
44639566063dSJacob Faibussowitsch         if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP));
44649566063dSJacob Faibussowitsch         if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD));
4465a1cf66bbSMatthew G. Knepley       }
4466a1cf66bbSMatthew G. Knepley       /* For finite volume, add the identity */
4467a1cf66bbSMatthew G. Knepley       if (!isFE[fieldI]) {
4468a1cf66bbSMatthew G. Knepley         PetscFV  fv;
4469a1cf66bbSMatthew G. Knepley         PetscInt eOffset = 0, Nc, fc, foff;
4470a1cf66bbSMatthew G. Knepley 
44719566063dSJacob Faibussowitsch         PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff));
44729566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv));
44739566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &Nc));
4474a1cf66bbSMatthew G. Knepley         for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) {
4475a1cf66bbSMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
4476a1cf66bbSMatthew G. Knepley             const PetscInt i = foff + fc;
4477ad540459SPierre Jolivet             if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
4478ad540459SPierre Jolivet             if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0;
4479a1cf66bbSMatthew G. Knepley           }
4480a1cf66bbSMatthew G. Knepley         }
4481a1cf66bbSMatthew G. Knepley       }
4482a1cf66bbSMatthew G. Knepley     }
4483a1cf66bbSMatthew G. Knepley     /*   Add contribution from X_t */
44849371c9d4SSatish Balay     if (hasDyn) {
44859371c9d4SSatish Balay       for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
44869371c9d4SSatish Balay     }
4487a1cf66bbSMatthew G. Knepley     /* Insert values into matrix */
4488a1cf66bbSMatthew G. Knepley     for (c = 0; c < Ncell; ++c) {
4489a1cf66bbSMatthew G. Knepley       const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4490a1cf66bbSMatthew G. Knepley       if (mesh->printFEM > 1) {
44919566063dSJacob Faibussowitsch         if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim]));
44929566063dSJacob Faibussowitsch         if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim]));
4493a1cf66bbSMatthew G. Knepley       }
4494e8e188d2SZach Atkins       if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES));
4495e8e188d2SZach Atkins       PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES));
4496a1cf66bbSMatthew G. Knepley     }
4497a1cf66bbSMatthew G. Knepley   }
4498a1cf66bbSMatthew G. Knepley   /* Cleanup */
44999566063dSJacob Faibussowitsch   PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
45009566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&qGeom));
45019566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
45029566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE));
45039566063dSJacob 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));
4504a1cf66bbSMatthew G. Knepley   /* Compute boundary integrals */
45059566063dSJacob Faibussowitsch   /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */
4506a1cf66bbSMatthew G. Knepley   /* Assemble matrix */
45079371c9d4SSatish Balay   if (assembleJac) {
45089371c9d4SSatish Balay     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
45099371c9d4SSatish Balay     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
45109371c9d4SSatish Balay   }
45119371c9d4SSatish Balay   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
45129371c9d4SSatish Balay   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
45139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
45143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4515a1cf66bbSMatthew G. Knepley }
45163e9753d6SMatthew G. Knepley 
45173e9753d6SMatthew G. Knepley /******** FEM Assembly Function ********/
45183e9753d6SMatthew G. Knepley 
4519d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4520d71ae5a4SJacob Faibussowitsch {
45213e9753d6SMatthew G. Knepley   PetscBool isPlex;
45223e9753d6SMatthew G. Knepley 
45233e9753d6SMatthew G. Knepley   PetscFunctionBegin;
45249566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
45253e9753d6SMatthew G. Knepley   if (isPlex) {
45263e9753d6SMatthew G. Knepley     *plex = dm;
45279566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
45283e9753d6SMatthew G. Knepley   } else {
45299566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
45303e9753d6SMatthew G. Knepley     if (!*plex) {
45319566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
45329566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
45331baa6e33SBarry Smith       if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex));
45343e9753d6SMatthew G. Knepley     } else {
45359566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)*plex));
45363e9753d6SMatthew G. Knepley     }
45373e9753d6SMatthew G. Knepley   }
45383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45393e9753d6SMatthew G. Knepley }
45403e9753d6SMatthew G. Knepley 
45413e9753d6SMatthew G. Knepley /*@
45423e9753d6SMatthew G. Knepley   DMPlexGetGeometryFVM - Return precomputed geometric data
45433e9753d6SMatthew G. Knepley 
454420f4b53cSBarry Smith   Collective
45453e9753d6SMatthew G. Knepley 
45463e9753d6SMatthew G. Knepley   Input Parameter:
4547a1cb98faSBarry Smith . dm - The `DM`
45483e9753d6SMatthew G. Knepley 
45493e9753d6SMatthew G. Knepley   Output Parameters:
45503e9753d6SMatthew G. Knepley + facegeom  - The values precomputed from face geometry
45513e9753d6SMatthew G. Knepley . cellgeom  - The values precomputed from cell geometry
45523e9753d6SMatthew G. Knepley - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell
45533e9753d6SMatthew G. Knepley 
45543e9753d6SMatthew G. Knepley   Level: developer
45553e9753d6SMatthew G. Knepley 
45561cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()`
45573e9753d6SMatthew G. Knepley @*/
4558d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius)
4559d71ae5a4SJacob Faibussowitsch {
45603e9753d6SMatthew G. Knepley   DM plex;
45613e9753d6SMatthew G. Knepley 
45623e9753d6SMatthew G. Knepley   PetscFunctionBegin;
45633e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
45649566063dSJacob Faibussowitsch   PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE));
45659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL));
45669566063dSJacob Faibussowitsch   if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius));
45679566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
45683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45693e9753d6SMatthew G. Knepley }
45703e9753d6SMatthew G. Knepley 
45713e9753d6SMatthew G. Knepley /*@
45723e9753d6SMatthew G. Knepley   DMPlexGetGradientDM - Return gradient data layout
45733e9753d6SMatthew G. Knepley 
457420f4b53cSBarry Smith   Collective
45753e9753d6SMatthew G. Knepley 
45763e9753d6SMatthew G. Knepley   Input Parameters:
4577a1cb98faSBarry Smith + dm - The `DM`
457820f4b53cSBarry Smith - fv - The `PetscFV`
45793e9753d6SMatthew G. Knepley 
45803e9753d6SMatthew G. Knepley   Output Parameter:
45813e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values
45823e9753d6SMatthew G. Knepley 
45833e9753d6SMatthew G. Knepley   Level: developer
45843e9753d6SMatthew G. Knepley 
45851cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()`
45863e9753d6SMatthew G. Knepley @*/
4587d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4588d71ae5a4SJacob Faibussowitsch {
45893e9753d6SMatthew G. Knepley   DM        plex;
45903e9753d6SMatthew G. Knepley   PetscBool computeGradients;
45913e9753d6SMatthew G. Knepley 
45923e9753d6SMatthew G. Knepley   PetscFunctionBegin;
45933e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
45943e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
45954f572ea9SToby Isaac   PetscAssertPointer(dmGrad, 3);
45969566063dSJacob Faibussowitsch   PetscCall(PetscFVGetComputeGradients(fv, &computeGradients));
45979371c9d4SSatish Balay   if (!computeGradients) {
45989371c9d4SSatish Balay     *dmGrad = NULL;
45993ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
46009371c9d4SSatish Balay   }
46019566063dSJacob Faibussowitsch   PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE));
46029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad));
46039566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
46043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46053e9753d6SMatthew G. Knepley }
46063e9753d6SMatthew G. Knepley 
4607d71ae5a4SJacob 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)
4608d71ae5a4SJacob Faibussowitsch {
46093e9753d6SMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
46103e9753d6SMatthew G. Knepley   DM              plex = NULL, plexA = NULL;
46113e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
46123e9753d6SMatthew G. Knepley   PetscDS         prob, probAux       = NULL;
46133e9753d6SMatthew G. Knepley   PetscSection    section, sectionAux = NULL;
46143e9753d6SMatthew G. Knepley   Vec             locA = NULL;
46153e9753d6SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
46163e9753d6SMatthew G. Knepley   PetscInt        totDim, totDimAux = 0;
46173e9753d6SMatthew G. Knepley 
46183e9753d6SMatthew G. Knepley   PetscFunctionBegin;
46199566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
46209566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
46219566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
46229566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
46239566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA));
46243e9753d6SMatthew G. Knepley   if (locA) {
46253e9753d6SMatthew G. Knepley     DM dmAux;
46263e9753d6SMatthew G. Knepley 
46279566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
46289566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
46299566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
46309566063dSJacob Faibussowitsch     PetscCall(DMGetDS(plexA, &probAux));
46319566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
46329566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexA, &sectionAux));
46333e9753d6SMatthew G. Knepley   }
46340c290148SMatthew G. Knepley   {
46353e9753d6SMatthew G. Knepley     PetscFEGeom    *fgeom;
46363e9753d6SMatthew G. Knepley     PetscInt        maxDegree;
46373e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
46383e9753d6SMatthew G. Knepley     IS              pointIS;
46393e9753d6SMatthew G. Knepley     const PetscInt *points;
46403e9753d6SMatthew G. Knepley     PetscInt        numFaces, face, Nq;
46413e9753d6SMatthew G. Knepley 
46429566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
46430c290148SMatthew G. Knepley     if (!pointIS) goto end; /* No points with that id on this process */
46443e9753d6SMatthew G. Knepley     {
46453e9753d6SMatthew G. Knepley       IS isectIS;
46463e9753d6SMatthew G. Knepley 
46473e9753d6SMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
46489566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
46499566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
46503e9753d6SMatthew G. Knepley       pointIS = isectIS;
46513e9753d6SMatthew G. Knepley     }
46529566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
46539566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
46549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a));
46559566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
465648a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
46573e9753d6SMatthew G. Knepley     if (!qGeom) {
46583e9753d6SMatthew G. Knepley       PetscFE fe;
46593e9753d6SMatthew G. Knepley 
46609566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe));
46619566063dSJacob Faibussowitsch       PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
46629566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
46633e9753d6SMatthew G. Knepley     }
46649566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
46659566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
46663e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
4667f15274beSMatthew Knepley       const PetscInt point = points[face], *support;
46683e9753d6SMatthew G. Knepley       PetscScalar   *x     = NULL;
4669f15274beSMatthew Knepley       PetscInt       i;
46703e9753d6SMatthew G. Knepley 
46719566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, point, &support));
46729566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
46733e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
46749566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
46753e9753d6SMatthew G. Knepley       if (locX_t) {
46769566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x));
46773e9753d6SMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
46789566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x));
46793e9753d6SMatthew G. Knepley       }
46803e9753d6SMatthew G. Knepley       if (locA) {
46813e9753d6SMatthew G. Knepley         PetscInt subp;
46823e9753d6SMatthew G. Knepley 
46839566063dSJacob Faibussowitsch         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
46849566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
46853e9753d6SMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
46869566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
46873e9753d6SMatthew G. Knepley       }
46883e9753d6SMatthew G. Knepley     }
46899566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(elemVec, numFaces * totDim));
46903e9753d6SMatthew G. Knepley     {
46913e9753d6SMatthew G. Knepley       PetscFE      fe;
46923e9753d6SMatthew G. Knepley       PetscInt     Nb;
46933e9753d6SMatthew G. Knepley       PetscFEGeom *chunkGeom = NULL;
46943e9753d6SMatthew G. Knepley       /* Conforming batches */
46953e9753d6SMatthew G. Knepley       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
46963e9753d6SMatthew G. Knepley       /* Remainder */
46973e9753d6SMatthew G. Knepley       PetscInt Nr, offset;
46983e9753d6SMatthew G. Knepley 
46999566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe));
47009566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
47019566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
47023e9753d6SMatthew G. Knepley       /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
47033e9753d6SMatthew G. Knepley       blockSize = Nb;
47043e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
47059566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
47063e9753d6SMatthew G. Knepley       numChunks = numFaces / (numBatches * batchSize);
47073e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
47083e9753d6SMatthew G. Knepley       Nr        = numFaces % (numBatches * batchSize);
47093e9753d6SMatthew G. Knepley       offset    = numFaces - Nr;
47109566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom));
47119566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec));
47129566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom));
47139566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
47149566063dSJacob 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]));
47159566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
47163e9753d6SMatthew G. Knepley     }
47173e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
47183e9753d6SMatthew G. Knepley       const PetscInt point = points[face], *support;
47193e9753d6SMatthew G. Knepley 
47209566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim]));
47219566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(plex, point, &support));
47229566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES));
47233e9753d6SMatthew G. Knepley     }
47249566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
47259566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
47269566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
47279566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
47289566063dSJacob Faibussowitsch     PetscCall(PetscFree4(u, u_t, elemVec, a));
47293e9753d6SMatthew G. Knepley   }
47300c290148SMatthew G. Knepley end:
47319566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
47329566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plexA));
47333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47343e9753d6SMatthew G. Knepley }
47353e9753d6SMatthew G. Knepley 
4736d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF)
4737d71ae5a4SJacob Faibussowitsch {
47383e9753d6SMatthew G. Knepley   DMField  coordField;
47393e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
47403e9753d6SMatthew G. Knepley   IS       facetIS;
47413e9753d6SMatthew G. Knepley   PetscInt dim;
47423e9753d6SMatthew G. Knepley 
47433e9753d6SMatthew G. Knepley   PetscFunctionBegin;
47449566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
47459566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
47469566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
47479566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
47489566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS));
47499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
47503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47513e9753d6SMatthew G. Knepley }
47523e9753d6SMatthew G. Knepley 
4753a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4754d71ae5a4SJacob Faibussowitsch {
47553e9753d6SMatthew G. Knepley   PetscDS  prob;
47563e9753d6SMatthew G. Knepley   PetscInt numBd, bd;
47573e9753d6SMatthew G. Knepley   DMField  coordField = NULL;
47583e9753d6SMatthew G. Knepley   IS       facetIS    = NULL;
47593e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
47603e9753d6SMatthew G. Knepley   PetscInt dim;
47613e9753d6SMatthew G. Knepley 
47623e9753d6SMatthew G. Knepley   PetscFunctionBegin;
47639566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
47649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
47659566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
47669566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
47679566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
47683e9753d6SMatthew G. Knepley   for (bd = 0; bd < numBd; ++bd) {
476945480ffeSMatthew G. Knepley     PetscWeakForm           wf;
47703e9753d6SMatthew G. Knepley     DMBoundaryConditionType type;
47713e9753d6SMatthew G. Knepley     DMLabel                 label;
47723e9753d6SMatthew G. Knepley     const PetscInt         *values;
47730c290148SMatthew G. Knepley     PetscInt                field, numValues, v;
47743e9753d6SMatthew G. Knepley     PetscObject             obj;
47753e9753d6SMatthew G. Knepley     PetscClassId            id;
47760c290148SMatthew G. Knepley     PetscFormKey            key;
47773e9753d6SMatthew G. Knepley 
47789566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL));
47793d3e5d66SMatthew G. Knepley     if (type & DM_BC_ESSENTIAL) continue;
47809566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
47819566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
47823d3e5d66SMatthew G. Knepley     if (id != PETSCFE_CLASSID) continue;
47833e9753d6SMatthew G. Knepley     if (!facetIS) {
47843e9753d6SMatthew G. Knepley       DMLabel  depthLabel;
47853e9753d6SMatthew G. Knepley       PetscInt dim;
47863e9753d6SMatthew G. Knepley 
47879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
47889566063dSJacob Faibussowitsch       PetscCall(DMGetDimension(dm, &dim));
47899566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
47903e9753d6SMatthew G. Knepley     }
47919566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
47920c290148SMatthew G. Knepley     for (v = 0; v < numValues; ++v) {
47930c290148SMatthew G. Knepley       key.label = label;
47940c290148SMatthew G. Knepley       key.value = values[v];
47950c290148SMatthew G. Knepley       key.field = field;
47960c290148SMatthew G. Knepley       key.part  = 0;
47979566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS));
47980c290148SMatthew G. Knepley     }
47993e9753d6SMatthew G. Knepley   }
48009566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
48013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48023e9753d6SMatthew G. Knepley }
48033e9753d6SMatthew G. Knepley 
4804d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
4805d71ae5a4SJacob Faibussowitsch {
48063e9753d6SMatthew G. Knepley   DM_Plex         *mesh       = (DM_Plex *)dm->data;
48073e9753d6SMatthew G. Knepley   const char      *name       = "Residual";
48083e9753d6SMatthew G. Knepley   DM               dmAux      = NULL;
48093e9753d6SMatthew G. Knepley   DM               dmGrad     = NULL;
48103e9753d6SMatthew G. Knepley   DMLabel          ghostLabel = NULL;
48116528b96dSMatthew G. Knepley   PetscDS          ds         = NULL;
48126528b96dSMatthew G. Knepley   PetscDS          dsAux      = NULL;
48133e9753d6SMatthew G. Knepley   PetscSection     section    = NULL;
48143e9753d6SMatthew G. Knepley   PetscBool        useFEM     = PETSC_FALSE;
48153e9753d6SMatthew G. Knepley   PetscBool        useFVM     = PETSC_FALSE;
48163e9753d6SMatthew G. Knepley   PetscBool        isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
48173e9753d6SMatthew G. Knepley   PetscFV          fvm        = NULL;
48183e9753d6SMatthew G. Knepley   PetscFVCellGeom *cgeomFVM   = NULL;
48193e9753d6SMatthew G. Knepley   PetscFVFaceGeom *fgeomFVM   = NULL;
48203e9753d6SMatthew G. Knepley   DMField          coordField = NULL;
48213e9753d6SMatthew G. Knepley   Vec              locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL;
48223e9753d6SMatthew G. Knepley   PetscScalar     *u = NULL, *u_t, *a, *uL, *uR;
48233e9753d6SMatthew G. Knepley   IS               chunkIS;
48243e9753d6SMatthew G. Knepley   const PetscInt  *cells;
48253e9753d6SMatthew G. Knepley   PetscInt         cStart, cEnd, numCells;
48263e9753d6SMatthew G. Knepley   PetscInt         Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
48273e9753d6SMatthew G. Knepley   PetscInt         maxDegree  = PETSC_MAX_INT;
48283e9753d6SMatthew G. Knepley   PetscQuadrature  affineQuad = NULL, *quads = NULL;
48293e9753d6SMatthew G. Knepley   PetscFEGeom     *affineGeom = NULL, **geoms = NULL;
48303e9753d6SMatthew G. Knepley 
48313e9753d6SMatthew G. Knepley   PetscFunctionBegin;
48323ba16761SJacob Faibussowitsch   if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS);
4833437e83fbSMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
48343ba16761SJacob Faibussowitsch   if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS);
48359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
48363e9753d6SMatthew G. Knepley   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
48373e9753d6SMatthew G. Knepley   /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
48383e9753d6SMatthew G. Knepley   /* FEM+FVM */
48399566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
48403e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
48419566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
48429566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
484307218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL));
48449566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
48459566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
48469566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA));
48473e9753d6SMatthew G. Knepley   if (locA) {
48483e9753d6SMatthew G. Knepley     PetscInt subcell;
48499566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
48501059d808SMatthew G. Knepley     PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell));
485107218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL));
48529566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
48533e9753d6SMatthew G. Knepley   }
48543e9753d6SMatthew G. Knepley   /* 2: Get geometric data */
48553e9753d6SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
48563e9753d6SMatthew G. Knepley     PetscObject  obj;
48573e9753d6SMatthew G. Knepley     PetscClassId id;
48583e9753d6SMatthew G. Knepley     PetscBool    fimp;
48593e9753d6SMatthew G. Knepley 
48609566063dSJacob Faibussowitsch     PetscCall(PetscDSGetImplicit(ds, f, &fimp));
48613e9753d6SMatthew G. Knepley     if (isImplicit != fimp) continue;
48629566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
48639566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
4864ad540459SPierre Jolivet     if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
48659371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) {
48669371c9d4SSatish Balay       useFVM = PETSC_TRUE;
48679371c9d4SSatish Balay       fvm    = (PetscFV)obj;
48689371c9d4SSatish Balay     }
48693e9753d6SMatthew G. Knepley   }
48703e9753d6SMatthew G. Knepley   if (useFEM) {
48719566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
48729566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
48733e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
48749566063dSJacob Faibussowitsch       PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
487548a46eb9SPierre Jolivet       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
48763e9753d6SMatthew G. Knepley     } else {
48779566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
48783e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
48793e9753d6SMatthew G. Knepley         PetscObject  obj;
48803e9753d6SMatthew G. Knepley         PetscClassId id;
48813e9753d6SMatthew G. Knepley         PetscBool    fimp;
48823e9753d6SMatthew G. Knepley 
48839566063dSJacob Faibussowitsch         PetscCall(PetscDSGetImplicit(ds, f, &fimp));
48843e9753d6SMatthew G. Knepley         if (isImplicit != fimp) continue;
48859566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
48869566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
48873e9753d6SMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
48883e9753d6SMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
48893e9753d6SMatthew G. Knepley 
48909566063dSJacob Faibussowitsch           PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
48919566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)quads[f]));
48929566063dSJacob Faibussowitsch           PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
48933e9753d6SMatthew G. Knepley         }
48943e9753d6SMatthew G. Knepley       }
48953e9753d6SMatthew G. Knepley     }
48963e9753d6SMatthew G. Knepley   }
48973e9753d6SMatthew G. Knepley   if (useFVM) {
48989566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL));
48999566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM));
49009566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
49013e9753d6SMatthew G. Knepley     /* Reconstruct and limit cell gradients */
49029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad));
49033e9753d6SMatthew G. Knepley     if (dmGrad) {
49049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
49059566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(dmGrad, &grad));
49069566063dSJacob Faibussowitsch       PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad));
49073e9753d6SMatthew G. Knepley       /* Communicate gradient values */
49089566063dSJacob Faibussowitsch       PetscCall(DMGetLocalVector(dmGrad, &locGrad));
49099566063dSJacob Faibussowitsch       PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad));
49109566063dSJacob Faibussowitsch       PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad));
49119566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
49123e9753d6SMatthew G. Knepley     }
49133e9753d6SMatthew G. Knepley     /* Handle non-essential (e.g. outflow) boundary values */
49149566063dSJacob Faibussowitsch     PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad));
49153e9753d6SMatthew G. Knepley   }
49163e9753d6SMatthew G. Knepley   /* Loop over chunks */
49179566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS));
49183e9753d6SMatthew G. Knepley   numCells      = cEnd - cStart;
49193e9753d6SMatthew G. Knepley   numChunks     = 1;
49203e9753d6SMatthew G. Knepley   cellChunkSize = numCells / numChunks;
49213e9753d6SMatthew G. Knepley   faceChunkSize = (fEnd - fStart) / numChunks;
49223e9753d6SMatthew G. Knepley   numChunks     = PetscMin(1, numCells);
49233e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
49243e9753d6SMatthew G. Knepley     PetscScalar     *elemVec, *fluxL, *fluxR;
49253e9753d6SMatthew G. Knepley     PetscReal       *vol;
49263e9753d6SMatthew G. Knepley     PetscFVFaceGeom *fgeom;
49273e9753d6SMatthew G. Knepley     PetscInt         cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
49283e9753d6SMatthew G. Knepley     PetscInt         fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face;
49293e9753d6SMatthew G. Knepley 
49303e9753d6SMatthew G. Knepley     /* Extract field coefficients */
49313e9753d6SMatthew G. Knepley     if (useFEM) {
49329566063dSJacob Faibussowitsch       PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells));
49339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
49349566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
49359566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemVec, numCells * totDim));
49363e9753d6SMatthew G. Knepley     }
49373e9753d6SMatthew G. Knepley     if (useFVM) {
49389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR));
49399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol));
49409566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL));
49419566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR));
49429566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(fluxL, numFaces * totDim));
49439566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(fluxR, numFaces * totDim));
49443e9753d6SMatthew G. Knepley     }
49453e9753d6SMatthew 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 */
49463e9753d6SMatthew G. Knepley     /* Loop over fields */
49473e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
49483e9753d6SMatthew G. Knepley       PetscObject  obj;
49493e9753d6SMatthew G. Knepley       PetscClassId id;
49503e9753d6SMatthew G. Knepley       PetscBool    fimp;
49513e9753d6SMatthew G. Knepley       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
49523e9753d6SMatthew G. Knepley 
49536528b96dSMatthew G. Knepley       key.field = f;
49549566063dSJacob Faibussowitsch       PetscCall(PetscDSGetImplicit(ds, f, &fimp));
49553e9753d6SMatthew G. Knepley       if (isImplicit != fimp) continue;
49569566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &obj));
49579566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
49583e9753d6SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
49593e9753d6SMatthew G. Knepley         PetscFE         fe        = (PetscFE)obj;
49603e9753d6SMatthew G. Knepley         PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
49613e9753d6SMatthew G. Knepley         PetscFEGeom    *chunkGeom = NULL;
49623e9753d6SMatthew G. Knepley         PetscQuadrature quad      = affineQuad ? affineQuad : quads[f];
49633e9753d6SMatthew G. Knepley         PetscInt        Nq, Nb;
49643e9753d6SMatthew G. Knepley 
49659566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
49669566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
49679566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
49683e9753d6SMatthew G. Knepley         blockSize = Nb;
49693e9753d6SMatthew G. Knepley         batchSize = numBlocks * blockSize;
49709566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
49713e9753d6SMatthew G. Knepley         numChunks = numCells / (numBatches * batchSize);
49723e9753d6SMatthew G. Knepley         Ne        = numChunks * numBatches * batchSize;
49733e9753d6SMatthew G. Knepley         Nr        = numCells % (numBatches * batchSize);
49743e9753d6SMatthew G. Knepley         offset    = numCells - Nr;
49753e9753d6SMatthew G. Knepley         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
49763e9753d6SMatthew 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) */
49779566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
49789566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec));
49799566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom));
4980072f5ffdSStefano Zampini         PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim]));
49819566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom));
49823e9753d6SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
49833e9753d6SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
49843e9753d6SMatthew G. Knepley 
49853e9753d6SMatthew G. Knepley         Ne = numFaces;
49863e9753d6SMatthew G. Knepley         /* Riemann solve over faces (need fields at face centroids) */
49873e9753d6SMatthew G. Knepley         /*   We need to evaluate FE fields at those coordinates */
49889566063dSJacob Faibussowitsch         PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR));
498963a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
49903e9753d6SMatthew G. Knepley     }
49913e9753d6SMatthew G. Knepley     /* Loop over domain */
49923e9753d6SMatthew G. Knepley     if (useFEM) {
49933e9753d6SMatthew G. Knepley       /* Add elemVec to locX */
49943e9753d6SMatthew G. Knepley       for (c = cS; c < cE; ++c) {
49953e9753d6SMatthew G. Knepley         const PetscInt cell = cells ? cells[c] : c;
49963e9753d6SMatthew G. Knepley         const PetscInt cind = c - cStart;
49973e9753d6SMatthew G. Knepley 
49989566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
49993e9753d6SMatthew G. Knepley         if (ghostLabel) {
50003e9753d6SMatthew G. Knepley           PetscInt ghostVal;
50013e9753d6SMatthew G. Knepley 
50029566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
50033e9753d6SMatthew G. Knepley           if (ghostVal > 0) continue;
50043e9753d6SMatthew G. Knepley         }
50059566063dSJacob Faibussowitsch         PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
50063e9753d6SMatthew G. Knepley       }
50073e9753d6SMatthew G. Knepley     }
50083e9753d6SMatthew G. Knepley     if (useFVM) {
50093e9753d6SMatthew G. Knepley       PetscScalar *fa;
50103e9753d6SMatthew G. Knepley       PetscInt     iface;
50113e9753d6SMatthew G. Knepley 
50129566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
50133e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
50143e9753d6SMatthew G. Knepley         PetscFV      fv;
50153e9753d6SMatthew G. Knepley         PetscObject  obj;
50163e9753d6SMatthew G. Knepley         PetscClassId id;
50173e9753d6SMatthew G. Knepley         PetscInt     foff, pdim;
50183e9753d6SMatthew G. Knepley 
50199566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
50209566063dSJacob Faibussowitsch         PetscCall(PetscDSGetFieldOffset(ds, f, &foff));
50219566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
50223e9753d6SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
50233e9753d6SMatthew G. Knepley         fv = (PetscFV)obj;
50249566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
50253e9753d6SMatthew G. Knepley         /* Accumulate fluxes to cells */
50263e9753d6SMatthew G. Knepley         for (face = fS, iface = 0; face < fE; ++face) {
50273e9753d6SMatthew G. Knepley           const PetscInt *scells;
50283e9753d6SMatthew G. Knepley           PetscScalar    *fL = NULL, *fR = NULL;
50293e9753d6SMatthew G. Knepley           PetscInt        ghost, d, nsupp, nchild;
50303e9753d6SMatthew G. Knepley 
50319566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
50329566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
50339566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
50343e9753d6SMatthew G. Knepley           if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
50359566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupport(dm, face, &scells));
50369566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost));
50379566063dSJacob Faibussowitsch           if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL));
50389566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost));
50399566063dSJacob Faibussowitsch           if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR));
50403e9753d6SMatthew G. Knepley           for (d = 0; d < pdim; ++d) {
50413e9753d6SMatthew G. Knepley             if (fL) fL[d] -= fluxL[iface * totDim + foff + d];
50423e9753d6SMatthew G. Knepley             if (fR) fR[d] += fluxR[iface * totDim + foff + d];
50433e9753d6SMatthew G. Knepley           }
50443e9753d6SMatthew G. Knepley           ++iface;
50453e9753d6SMatthew G. Knepley         }
50463e9753d6SMatthew G. Knepley       }
50479566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
50483e9753d6SMatthew G. Knepley     }
50493e9753d6SMatthew G. Knepley     /* Handle time derivative */
50503e9753d6SMatthew G. Knepley     if (locX_t) {
50513e9753d6SMatthew G. Knepley       PetscScalar *x_t, *fa;
50523e9753d6SMatthew G. Knepley 
50539566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
50549566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locX_t, &x_t));
50553e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
50563e9753d6SMatthew G. Knepley         PetscFV      fv;
50573e9753d6SMatthew G. Knepley         PetscObject  obj;
50583e9753d6SMatthew G. Knepley         PetscClassId id;
50593e9753d6SMatthew G. Knepley         PetscInt     pdim, d;
50603e9753d6SMatthew G. Knepley 
50619566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
50629566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
50633e9753d6SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
50643e9753d6SMatthew G. Knepley         fv = (PetscFV)obj;
50659566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
50663e9753d6SMatthew G. Knepley         for (c = cS; c < cE; ++c) {
50673e9753d6SMatthew G. Knepley           const PetscInt cell = cells ? cells[c] : c;
50683e9753d6SMatthew G. Knepley           PetscScalar   *u_t, *r;
50693e9753d6SMatthew G. Knepley 
50703e9753d6SMatthew G. Knepley           if (ghostLabel) {
50713e9753d6SMatthew G. Knepley             PetscInt ghostVal;
50723e9753d6SMatthew G. Knepley 
50739566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
50743e9753d6SMatthew G. Knepley             if (ghostVal > 0) continue;
50753e9753d6SMatthew G. Knepley           }
50769566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t));
50779566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r));
50783e9753d6SMatthew G. Knepley           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
50793e9753d6SMatthew G. Knepley         }
50803e9753d6SMatthew G. Knepley       }
50819566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locX_t, &x_t));
50829566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
50833e9753d6SMatthew G. Knepley     }
50843e9753d6SMatthew G. Knepley     if (useFEM) {
50859566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
50869566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
50873e9753d6SMatthew G. Knepley     }
50883e9753d6SMatthew G. Knepley     if (useFVM) {
50899566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR));
50909566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol));
50919566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL));
50929566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR));
50939566063dSJacob Faibussowitsch       if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
50943e9753d6SMatthew G. Knepley     }
50953e9753d6SMatthew G. Knepley   }
50969566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISDestroy(&chunkIS));
50979566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
50983e9753d6SMatthew G. Knepley 
50993e9753d6SMatthew G. Knepley   if (useFEM) {
51009566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user));
51013e9753d6SMatthew G. Knepley 
51023e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
51039566063dSJacob Faibussowitsch       PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
51049566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&affineQuad));
51053e9753d6SMatthew G. Knepley     } else {
51063e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
51079566063dSJacob Faibussowitsch         PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
51089566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureDestroy(&quads[f]));
51093e9753d6SMatthew G. Knepley       }
51109566063dSJacob Faibussowitsch       PetscCall(PetscFree2(quads, geoms));
51113e9753d6SMatthew G. Knepley     }
51123e9753d6SMatthew G. Knepley   }
51133e9753d6SMatthew G. Knepley 
51143e9753d6SMatthew G. Knepley   /* FEM */
51153e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
51163e9753d6SMatthew G. Knepley   /* 2: Get geometric data */
51173e9753d6SMatthew G. Knepley   /* 3: Handle boundary values */
51183e9753d6SMatthew G. Knepley   /* 4: Loop over domain */
51193e9753d6SMatthew G. Knepley   /*   Extract coefficients */
51203e9753d6SMatthew G. Knepley   /* Loop over fields */
51213e9753d6SMatthew G. Knepley   /*   Set tiling for FE*/
51223e9753d6SMatthew G. Knepley   /*   Integrate FE residual to get elemVec */
51233e9753d6SMatthew G. Knepley   /*     Loop over subdomain */
51243e9753d6SMatthew G. Knepley   /*       Loop over quad points */
51253e9753d6SMatthew G. Knepley   /*         Transform coords to real space */
51263e9753d6SMatthew G. Knepley   /*         Evaluate field and aux fields at point */
51273e9753d6SMatthew G. Knepley   /*         Evaluate residual at point */
51283e9753d6SMatthew G. Knepley   /*         Transform residual to real space */
51293e9753d6SMatthew G. Knepley   /*       Add residual to elemVec */
51303e9753d6SMatthew G. Knepley   /* Loop over domain */
51313e9753d6SMatthew G. Knepley   /*   Add elemVec to locX */
51323e9753d6SMatthew G. Knepley 
51333e9753d6SMatthew G. Knepley   /* FVM */
51343e9753d6SMatthew G. Knepley   /* Get geometric data */
51353e9753d6SMatthew G. Knepley   /* If using gradients */
51363e9753d6SMatthew G. Knepley   /*   Compute gradient data */
51373e9753d6SMatthew G. Knepley   /*   Loop over domain faces */
51383e9753d6SMatthew G. Knepley   /*     Count computational faces */
51393e9753d6SMatthew G. Knepley   /*     Reconstruct cell gradient */
51403e9753d6SMatthew G. Knepley   /*   Loop over domain cells */
51413e9753d6SMatthew G. Knepley   /*     Limit cell gradients */
51423e9753d6SMatthew G. Knepley   /* Handle boundary values */
51433e9753d6SMatthew G. Knepley   /* Loop over domain faces */
51443e9753d6SMatthew G. Knepley   /*   Read out field, centroid, normal, volume for each side of face */
51453e9753d6SMatthew G. Knepley   /* Riemann solve over faces */
51463e9753d6SMatthew G. Knepley   /* Loop over domain faces */
51473e9753d6SMatthew G. Knepley   /*   Accumulate fluxes to cells */
51483e9753d6SMatthew G. Knepley   /* TODO Change printFEM to printDisc here */
51493e9753d6SMatthew G. Knepley   if (mesh->printFEM) {
51503e9753d6SMatthew G. Knepley     Vec          locFbc;
51513e9753d6SMatthew G. Knepley     PetscInt     pStart, pEnd, p, maxDof;
51523e9753d6SMatthew G. Knepley     PetscScalar *zeroes;
51533e9753d6SMatthew G. Knepley 
51549566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(locF, &locFbc));
51559566063dSJacob Faibussowitsch     PetscCall(VecCopy(locF, locFbc));
51569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
51579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(section, &maxDof));
51589566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxDof, &zeroes));
515948a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES));
51609566063dSJacob Faibussowitsch     PetscCall(PetscFree(zeroes));
51619566063dSJacob Faibussowitsch     PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc));
51629566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locFbc));
51633e9753d6SMatthew G. Knepley   }
51649566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
51653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51663e9753d6SMatthew G. Knepley }
51673e9753d6SMatthew G. Knepley 
51686528b96dSMatthew G. Knepley /*
51696528b96dSMatthew G. Knepley   1) Allow multiple kernels for BdResidual for hybrid DS
51706528b96dSMatthew G. Knepley 
51716528b96dSMatthew G. Knepley   DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux
51726528b96dSMatthew G. Knepley 
51736528b96dSMatthew G. Knepley   DONE 3) Change DMGetCellFields() to get different aux data a[] for each side
51746528b96dSMatthew G. Knepley      - I think I just need to replace a[] with the closure from each face
51756528b96dSMatthew G. Knepley 
51766528b96dSMatthew G. Knepley   4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before
51776528b96dSMatthew G. Knepley */
5178d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user)
5179d71ae5a4SJacob Faibussowitsch {
51803e9753d6SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
51813e9753d6SMatthew G. Knepley   const char     *name       = "Hybrid Residual";
518204c51a94SMatthew G. Knepley   DM              dmAux[3]   = {NULL, NULL, NULL};
51833e9753d6SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
51846528b96dSMatthew G. Knepley   PetscDS         ds         = NULL;
518507218a29SMatthew G. Knepley   PetscDS         dsIn       = NULL;
51866528b96dSMatthew G. Knepley   PetscDS         dsAux[3]   = {NULL, NULL, NULL};
518704c51a94SMatthew G. Knepley   Vec             locA[3]    = {NULL, NULL, NULL};
518807218a29SMatthew G. Knepley   DM              dmScale[3] = {NULL, NULL, NULL};
518907218a29SMatthew G. Knepley   PetscDS         dsScale[3] = {NULL, NULL, NULL};
519007218a29SMatthew G. Knepley   Vec             locS[3]    = {NULL, NULL, NULL};
51913e9753d6SMatthew G. Knepley   PetscSection    section    = NULL;
51923e9753d6SMatthew G. Knepley   DMField         coordField = NULL;
519307218a29SMatthew G. Knepley   PetscScalar    *a[3]       = {NULL, NULL, NULL};
519407218a29SMatthew G. Knepley   PetscScalar    *s[3]       = {NULL, NULL, NULL};
5195b2ab40e6SMatthew G. Knepley   PetscScalar    *u          = NULL, *u_t;
519607218a29SMatthew G. Knepley   PetscScalar    *elemVecNeg, *elemVecPos, *elemVecCoh;
51973e9753d6SMatthew G. Knepley   IS              chunkIS;
51983e9753d6SMatthew G. Knepley   const PetscInt *cells;
51993e9753d6SMatthew G. Knepley   PetscInt       *faces;
52003e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
52013e2b0218SMatthew G. Knepley   PetscInt        Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk;
52023e9753d6SMatthew G. Knepley   PetscInt        maxDegree  = PETSC_MAX_INT;
52033e9753d6SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
52043e9753d6SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
52053e9753d6SMatthew G. Knepley 
52063e9753d6SMatthew G. Knepley   PetscFunctionBegin;
52073ba16761SJacob Faibussowitsch   if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS);
5208437e83fbSMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
5209437e83fbSMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
52103ba16761SJacob Faibussowitsch   if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS);
52115fedec97SMatthew G. Knepley   if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
52125fedec97SMatthew G. Knepley     const char *name;
52139566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name));
521463a3b9bcSJacob 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);
52155fedec97SMatthew G. Knepley   }
52169566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
52173e9753d6SMatthew G. Knepley   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
52183e9753d6SMatthew G. Knepley   /* FEM */
52193e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
52209566063dSJacob Faibussowitsch   PetscCall(DMGetSection(dm, &section));
52219566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
522207218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn));
52239566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
52249566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
522507218a29SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn));
52269566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]));
522704c51a94SMatthew G. Knepley   if (locA[2]) {
52281059d808SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
52291059d808SMatthew G. Knepley 
52309566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA[2], &dmAux[2]));
523107218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL));
52329566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]));
52336528b96dSMatthew G. Knepley     {
52346528b96dSMatthew G. Knepley       const PetscInt *cone;
52356528b96dSMatthew G. Knepley       PetscInt        c;
52366528b96dSMatthew G. Knepley 
52371059d808SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
52386528b96dSMatthew G. Knepley       for (c = 0; c < 2; ++c) {
52396528b96dSMatthew G. Knepley         const PetscInt *support;
52406528b96dSMatthew G. Knepley         PetscInt        ssize, s;
52416528b96dSMatthew G. Knepley 
52429566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
52439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
52441059d808SMatthew 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);
52451059d808SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
52461059d808SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
52471059d808SMatthew 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);
52489566063dSJacob Faibussowitsch         PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]));
5249c75bfeddSPierre 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);
52509566063dSJacob Faibussowitsch         if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c]));
5251ad540459SPierre Jolivet         else dmAux[c] = dmAux[2];
525207218a29SMatthew G. Knepley         PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL));
52539566063dSJacob Faibussowitsch         PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]));
52546528b96dSMatthew G. Knepley       }
52556528b96dSMatthew G. Knepley     }
52563e9753d6SMatthew G. Knepley   }
525707218a29SMatthew G. Knepley   /* Handle mass matrix scaling
525807218a29SMatthew G. Knepley        The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */
525907218a29SMatthew G. Knepley   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2]));
526007218a29SMatthew G. Knepley   if (locS[2]) {
52613e2b0218SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
526207218a29SMatthew G. Knepley     PetscInt       Nb, Nbs;
526307218a29SMatthew G. Knepley 
526407218a29SMatthew G. Knepley     PetscCall(VecGetDM(locS[2], &dmScale[2]));
52653e2b0218SMatthew G. Knepley     PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL));
52663e2b0218SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2]));
526707218a29SMatthew G. Knepley     // BRAD: This is not set correctly
526807218a29SMatthew G. Knepley     key[2].field = 2;
526907218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb));
527007218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs));
527107218a29SMatthew G. Knepley     PetscCheck(Nb == Nbs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field %" PetscInt_FMT " of size %" PetscInt_FMT " cannot be scaled by field of size %" PetscInt_FMT, key[2].field, Nb, Nbs);
52723e2b0218SMatthew G. Knepley     {
52733e2b0218SMatthew G. Knepley       const PetscInt *cone;
52743e2b0218SMatthew G. Knepley       PetscInt        c;
52753e2b0218SMatthew G. Knepley 
52763e2b0218SMatthew G. Knepley       locS[1] = locS[0] = locS[2];
52773e2b0218SMatthew G. Knepley       dmScale[1] = dmScale[0] = dmScale[2];
52783e2b0218SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
52793e2b0218SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
52803e2b0218SMatthew G. Knepley         const PetscInt *support;
52813e2b0218SMatthew G. Knepley         PetscInt        ssize, s;
52823e2b0218SMatthew G. Knepley 
52833e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
52843e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
52853e2b0218SMatthew 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);
52863e2b0218SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
52873e2b0218SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
52883e2b0218SMatthew 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);
52893e2b0218SMatthew G. Knepley         PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL));
52903e2b0218SMatthew G. Knepley         PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c]));
52913e2b0218SMatthew G. Knepley       }
52923e2b0218SMatthew G. Knepley     }
529307218a29SMatthew G. Knepley   }
52943e9753d6SMatthew G. Knepley   /* 2: Setup geometric data */
52959566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
52969566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
52973e9753d6SMatthew G. Knepley   if (maxDegree > 1) {
52989566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
52993e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
53003e9753d6SMatthew G. Knepley       PetscFE fe;
53013e9753d6SMatthew G. Knepley 
53029566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
53033e9753d6SMatthew G. Knepley       if (fe) {
53049566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
53059566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)quads[f]));
53063e9753d6SMatthew G. Knepley       }
53073e9753d6SMatthew G. Knepley     }
53083e9753d6SMatthew G. Knepley   }
53093e9753d6SMatthew G. Knepley   /* Loop over chunks */
53103e9753d6SMatthew G. Knepley   cellChunkSize = numCells;
53113e9753d6SMatthew G. Knepley   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
531207218a29SMatthew G. Knepley   PetscCall(PetscCalloc1(2 * cellChunkSize, &faces));
531307218a29SMatthew G. Knepley   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS));
53143e9753d6SMatthew G. Knepley   /* Extract field coefficients */
53153e9753d6SMatthew G. Knepley   /* NOTE This needs the end cap faces to have identical orientations */
531607218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
531707218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
53183e2b0218SMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s));
531907218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg));
532007218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos));
532107218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh));
53223e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
53233e9753d6SMatthew G. Knepley     PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
53243e9753d6SMatthew G. Knepley 
532507218a29SMatthew G. Knepley     PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim));
532607218a29SMatthew G. Knepley     PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim));
532707218a29SMatthew G. Knepley     PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim));
53283e9753d6SMatthew G. Knepley     /* Get faces */
53293e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
53303e9753d6SMatthew G. Knepley       const PetscInt  cell = cells ? cells[c] : c;
53313e9753d6SMatthew G. Knepley       const PetscInt *cone;
53329566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cell, &cone));
533307218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 0] = cone[0];
533407218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 1] = cone[1];
53353e9753d6SMatthew G. Knepley     }
533607218a29SMatthew G. Knepley     PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER));
53373e9753d6SMatthew G. Knepley     /* Get geometric data */
53383e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
53399566063dSJacob Faibussowitsch       if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad));
53409566063dSJacob Faibussowitsch       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom));
53413e9753d6SMatthew G. Knepley     } else {
53423e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
53439566063dSJacob Faibussowitsch         if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]));
53443e9753d6SMatthew G. Knepley       }
53453e9753d6SMatthew G. Knepley     }
53463e9753d6SMatthew G. Knepley     /* Loop over fields */
53473e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
53483e9753d6SMatthew G. Knepley       PetscFE         fe;
53493e9753d6SMatthew G. Knepley       PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
5350148442b3SMatthew G. Knepley       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
53513e9753d6SMatthew G. Knepley       PetscQuadrature quad = affineQuad ? affineQuad : quads[f];
53523e9753d6SMatthew G. Knepley       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
53535fedec97SMatthew G. Knepley       PetscBool       isCohesiveField;
53543e9753d6SMatthew G. Knepley 
53559566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
53563e9753d6SMatthew G. Knepley       if (!fe) continue;
53579566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
53589566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
53599566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
53603e9753d6SMatthew G. Knepley       blockSize = Nb;
53613e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
53629566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
53633e9753d6SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
53643e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
53653e9753d6SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
53663e9753d6SMatthew G. Knepley       offset    = numCells - Nr;
536707218a29SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom));
536807218a29SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom));
53699566063dSJacob Faibussowitsch       PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
53705fedec97SMatthew G. Knepley       chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE;
53716528b96dSMatthew G. Knepley       key[0].field                                = f;
53726528b96dSMatthew G. Knepley       key[1].field                                = f;
53735fedec97SMatthew G. Knepley       key[2].field                                = f;
537407218a29SMatthew G. Knepley       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVecNeg));
537507218a29SMatthew G. Knepley       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVecNeg[offset * totDim]));
537607218a29SMatthew G. Knepley       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVecPos));
537707218a29SMatthew G. Knepley       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVecPos[offset * totDim]));
537807218a29SMatthew G. Knepley       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVecCoh));
537907218a29SMatthew G. Knepley       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVecCoh[offset * totDim]));
53809566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom));
53819566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom));
53823e9753d6SMatthew G. Knepley     }
53833e9753d6SMatthew G. Knepley     /* Add elemVec to locX */
53843e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
53853e9753d6SMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
53863e9753d6SMatthew G. Knepley       const PetscInt cind = c - cStart;
538707218a29SMatthew G. Knepley       PetscInt       i;
53883e9753d6SMatthew G. Knepley 
538907218a29SMatthew G. Knepley       /* Scale element values */
539007218a29SMatthew G. Knepley       if (locS[0]) {
53913e2b0218SMatthew G. Knepley         PetscInt  Nb, off = cind * totDim, soff = cind * totDimScale[0];
539207218a29SMatthew G. Knepley         PetscBool cohesive;
539307218a29SMatthew G. Knepley 
539407218a29SMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
539507218a29SMatthew G. Knepley           PetscCall(PetscDSGetFieldSize(ds, f, &Nb));
539607218a29SMatthew G. Knepley           PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
539707218a29SMatthew G. Knepley           if (f == key[2].field) {
539807218a29SMatthew G. Knepley             PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields");
539907218a29SMatthew G. Knepley             // No cohesive scaling field is currently input
540007218a29SMatthew G. Knepley             for (i = 0; i < Nb; ++i) elemVecCoh[off + i] += s[0][soff + i] * elemVecNeg[off + i] + s[1][soff + i] * elemVecPos[off + i];
540107218a29SMatthew G. Knepley             off += Nb;
540207218a29SMatthew G. Knepley           } else {
540307218a29SMatthew G. Knepley             const PetscInt N = cohesive ? Nb : Nb * 2;
540407218a29SMatthew G. Knepley 
540507218a29SMatthew G. Knepley             for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i];
540607218a29SMatthew G. Knepley             off += N;
540707218a29SMatthew G. Knepley           }
540807218a29SMatthew G. Knepley         }
540907218a29SMatthew G. Knepley       } else {
541007218a29SMatthew G. Knepley         for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i];
541107218a29SMatthew G. Knepley       }
541207218a29SMatthew G. Knepley       if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim]));
54133e9753d6SMatthew G. Knepley       if (ghostLabel) {
54143e9753d6SMatthew G. Knepley         PetscInt ghostVal;
54153e9753d6SMatthew G. Knepley 
54169566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
54173e9753d6SMatthew G. Knepley         if (ghostVal > 0) continue;
54183e9753d6SMatthew G. Knepley       }
541907218a29SMatthew G. Knepley       PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES));
54203e9753d6SMatthew G. Knepley     }
54213e9753d6SMatthew G. Knepley   }
54229566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
542307218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
54243e2b0218SMatthew G. Knepley   PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s));
542507218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg));
542607218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos));
542707218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh));
54289566063dSJacob Faibussowitsch   PetscCall(PetscFree(faces));
54299566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&chunkIS));
54309566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
54313e9753d6SMatthew G. Knepley   if (maxDegree <= 1) {
54329566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
54339566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&affineQuad));
54343e9753d6SMatthew G. Knepley   } else {
54353e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
54369566063dSJacob Faibussowitsch       if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
54379566063dSJacob Faibussowitsch       if (quads) PetscCall(PetscQuadratureDestroy(&quads[f]));
54383e9753d6SMatthew G. Knepley     }
54399566063dSJacob Faibussowitsch     PetscCall(PetscFree2(quads, geoms));
54403e9753d6SMatthew G. Knepley   }
544185cc2951SMatthew G. Knepley   if (mesh->printFEM) {
544285cc2951SMatthew G. Knepley     Vec          locFbc;
544385cc2951SMatthew G. Knepley     PetscInt     pStart, pEnd, p, maxDof;
544485cc2951SMatthew G. Knepley     PetscScalar *zeroes;
544585cc2951SMatthew G. Knepley 
544685cc2951SMatthew G. Knepley     PetscCall(VecDuplicate(locF, &locFbc));
544785cc2951SMatthew G. Knepley     PetscCall(VecCopy(locF, locFbc));
544885cc2951SMatthew G. Knepley     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
544985cc2951SMatthew G. Knepley     PetscCall(PetscSectionGetMaxDof(section, &maxDof));
545085cc2951SMatthew G. Knepley     PetscCall(PetscCalloc1(maxDof, &zeroes));
545185cc2951SMatthew G. Knepley     for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES));
545285cc2951SMatthew G. Knepley     PetscCall(PetscFree(zeroes));
545385cc2951SMatthew G. Knepley     PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc));
545485cc2951SMatthew G. Knepley     PetscCall(VecDestroy(&locFbc));
545585cc2951SMatthew G. Knepley   }
54569566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
54573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54583e9753d6SMatthew G. Knepley }
54593e9753d6SMatthew G. Knepley 
5460a4e35b19SJacob Faibussowitsch static 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)
5461d71ae5a4SJacob Faibussowitsch {
54623e9753d6SMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
54633e9753d6SMatthew G. Knepley   DM              plex = NULL, plexA = NULL, tdm;
54643e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
54653e9753d6SMatthew G. Knepley   PetscDS         prob, probAux       = NULL;
54663e9753d6SMatthew G. Knepley   PetscSection    section, sectionAux = NULL;
5467e432b41dSStefano Zampini   PetscSection    globalSection;
54683e9753d6SMatthew G. Knepley   Vec             locA = NULL, tv;
54693e9753d6SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL;
54703e9753d6SMatthew G. Knepley   PetscInt        v;
54713e9753d6SMatthew G. Knepley   PetscInt        Nf, totDim, totDimAux = 0;
5472e432b41dSStefano Zampini   PetscBool       transform;
54733e9753d6SMatthew G. Knepley 
54743e9753d6SMatthew G. Knepley   PetscFunctionBegin;
54759566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
54769566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
54779566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
54789566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
54799566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
54809566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
54819566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
54829566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
54839566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA));
54843e9753d6SMatthew G. Knepley   if (locA) {
54853e9753d6SMatthew G. Knepley     DM dmAux;
54863e9753d6SMatthew G. Knepley 
54879566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
54889566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
54899566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
54909566063dSJacob Faibussowitsch     PetscCall(DMGetDS(plexA, &probAux));
54919566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
54929566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexA, &sectionAux));
54933e9753d6SMatthew G. Knepley   }
54943e9753d6SMatthew G. Knepley 
54959566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
54963e9753d6SMatthew G. Knepley   for (v = 0; v < numValues; ++v) {
54973e9753d6SMatthew G. Knepley     PetscFEGeom    *fgeom;
54983e9753d6SMatthew G. Knepley     PetscInt        maxDegree;
54993e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
55003e9753d6SMatthew G. Knepley     IS              pointIS;
55013e9753d6SMatthew G. Knepley     const PetscInt *points;
550206ad1575SMatthew G. Knepley     PetscFormKey    key;
55033e9753d6SMatthew G. Knepley     PetscInt        numFaces, face, Nq;
55043e9753d6SMatthew G. Knepley 
550545480ffeSMatthew G. Knepley     key.label = label;
550645480ffeSMatthew G. Knepley     key.value = values[v];
550706ad1575SMatthew G. Knepley     key.part  = 0;
55089566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
55093e9753d6SMatthew G. Knepley     if (!pointIS) continue; /* No points with that id on this process */
55103e9753d6SMatthew G. Knepley     {
55113e9753d6SMatthew G. Knepley       IS isectIS;
55123e9753d6SMatthew G. Knepley 
55133e9753d6SMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
55149566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
55159566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
55163e9753d6SMatthew G. Knepley       pointIS = isectIS;
55173e9753d6SMatthew G. Knepley     }
55189566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
55199566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
55209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a));
55219566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
552248a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
55233e9753d6SMatthew G. Knepley     if (!qGeom) {
55243e9753d6SMatthew G. Knepley       PetscFE fe;
55253e9753d6SMatthew G. Knepley 
55269566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
55279566063dSJacob Faibussowitsch       PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
55289566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
55293e9753d6SMatthew G. Knepley     }
55309566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
55319566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
55323e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
5533f15274beSMatthew Knepley       const PetscInt point = points[face], *support;
55343e9753d6SMatthew G. Knepley       PetscScalar   *x     = NULL;
5535f15274beSMatthew Knepley       PetscInt       i;
55363e9753d6SMatthew G. Knepley 
55379566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, point, &support));
55389566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
55393e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
55409566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
55413e9753d6SMatthew G. Knepley       if (locX_t) {
55429566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x));
55433e9753d6SMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
55449566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x));
55453e9753d6SMatthew G. Knepley       }
55463e9753d6SMatthew G. Knepley       if (locA) {
55473e9753d6SMatthew G. Knepley         PetscInt subp;
55489566063dSJacob Faibussowitsch         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
55499566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
55503e9753d6SMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
55519566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
55523e9753d6SMatthew G. Knepley       }
55533e9753d6SMatthew G. Knepley     }
55549566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim));
55553e9753d6SMatthew G. Knepley     {
55563e9753d6SMatthew G. Knepley       PetscFE  fe;
55573e9753d6SMatthew G. Knepley       PetscInt Nb;
55583e9753d6SMatthew G. Knepley       /* Conforming batches */
55593e9753d6SMatthew G. Knepley       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
55603e9753d6SMatthew G. Knepley       /* Remainder */
55613e9753d6SMatthew G. Knepley       PetscFEGeom *chunkGeom = NULL;
55623e9753d6SMatthew G. Knepley       PetscInt     fieldJ, Nr, offset;
55633e9753d6SMatthew G. Knepley 
55649566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
55659566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
55669566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
55673e9753d6SMatthew G. Knepley       blockSize = Nb;
55683e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
55699566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
55703e9753d6SMatthew G. Knepley       numChunks = numFaces / (numBatches * batchSize);
55713e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
55723e9753d6SMatthew G. Knepley       Nr        = numFaces % (numBatches * batchSize);
55733e9753d6SMatthew G. Knepley       offset    = numFaces - Nr;
55749566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom));
55753e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
557645480ffeSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
55779566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
55783e9753d6SMatthew G. Knepley       }
55799566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
55803e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
558145480ffeSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
55829566063dSJacob 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]));
55833e9753d6SMatthew G. Knepley       }
55849566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
55853e9753d6SMatthew G. Knepley     }
55863e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
55873e9753d6SMatthew G. Knepley       const PetscInt point = points[face], *support;
55883e9753d6SMatthew G. Knepley 
55893e9753d6SMatthew G. Knepley       /* Transform to global basis before insertion in Jacobian */
55909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(plex, point, &support));
55919566063dSJacob Faibussowitsch       if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim]));
55929566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim]));
5593e8e188d2SZach Atkins       PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES));
55943e9753d6SMatthew G. Knepley     }
55959566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
55969566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
55979566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
55989566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
55999566063dSJacob Faibussowitsch     PetscCall(PetscFree4(u, u_t, elemMat, a));
56003e9753d6SMatthew G. Knepley   }
56019566063dSJacob Faibussowitsch   if (plex) PetscCall(DMDestroy(&plex));
56029566063dSJacob Faibussowitsch   if (plexA) PetscCall(DMDestroy(&plexA));
56033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56043e9753d6SMatthew G. Knepley }
56053e9753d6SMatthew G. Knepley 
5606d71ae5a4SJacob 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)
5607d71ae5a4SJacob Faibussowitsch {
56083e9753d6SMatthew G. Knepley   DMField  coordField;
56093e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
56103e9753d6SMatthew G. Knepley   IS       facetIS;
56113e9753d6SMatthew G. Knepley   PetscInt dim;
56123e9753d6SMatthew G. Knepley 
56133e9753d6SMatthew G. Knepley   PetscFunctionBegin;
56149566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
56159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
56169566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
56179566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
56189566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS));
56199566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
56203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56213e9753d6SMatthew G. Knepley }
56223e9753d6SMatthew G. Knepley 
5623a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user)
5624d71ae5a4SJacob Faibussowitsch {
56253e9753d6SMatthew G. Knepley   PetscDS  prob;
56263e9753d6SMatthew G. Knepley   PetscInt dim, numBd, bd;
56273e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
56283e9753d6SMatthew G. Knepley   DMField  coordField = NULL;
56293e9753d6SMatthew G. Knepley   IS       facetIS;
56303e9753d6SMatthew G. Knepley 
56313e9753d6SMatthew G. Knepley   PetscFunctionBegin;
56329566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
56339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
56349566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
56359566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
56369566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
56379566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
56383e9753d6SMatthew G. Knepley   for (bd = 0; bd < numBd; ++bd) {
563945480ffeSMatthew G. Knepley     PetscWeakForm           wf;
56403e9753d6SMatthew G. Knepley     DMBoundaryConditionType type;
56413e9753d6SMatthew G. Knepley     DMLabel                 label;
56423e9753d6SMatthew G. Knepley     const PetscInt         *values;
56433e9753d6SMatthew G. Knepley     PetscInt                fieldI, numValues;
56443e9753d6SMatthew G. Knepley     PetscObject             obj;
56453e9753d6SMatthew G. Knepley     PetscClassId            id;
56463e9753d6SMatthew G. Knepley 
56479566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL));
56483d3e5d66SMatthew G. Knepley     if (type & DM_BC_ESSENTIAL) continue;
56499566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj));
56509566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
56513d3e5d66SMatthew G. Knepley     if (id != PETSCFE_CLASSID) continue;
56529566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS));
56533e9753d6SMatthew G. Knepley   }
56549566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
56553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56563e9753d6SMatthew G. Knepley }
56573e9753d6SMatthew G. Knepley 
5658d71ae5a4SJacob 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)
5659d71ae5a4SJacob Faibussowitsch {
56603e9753d6SMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
56613e9753d6SMatthew G. Knepley   const char     *name  = "Jacobian";
56629a2a23afSMatthew G. Knepley   DM              dmAux = NULL, plex, tdm;
56633e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
56643e9753d6SMatthew G. Knepley   Vec             A, tv;
56653e9753d6SMatthew G. Knepley   DMField         coordField;
56663e9753d6SMatthew G. Knepley   PetscDS         prob, probAux = NULL;
5667e432b41dSStefano Zampini   PetscSection    section, globalSection, sectionAux;
56683e9753d6SMatthew G. Knepley   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
56693e9753d6SMatthew G. Knepley   const PetscInt *cells;
56703e9753d6SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ;
567128351e22SJed Brown   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
5672e04ae0b4SMatthew G. Knepley   PetscBool       hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform;
56733e9753d6SMatthew G. Knepley 
56743e9753d6SMatthew G. Knepley   PetscFunctionBegin;
5675af18b51aSmarkadams4   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
5676e04ae0b4SMatthew G. Knepley   if (!cellIS) goto end;
56779566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
5678437e83fbSMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
5679437e83fbSMatthew G. Knepley   if (cStart >= cEnd) goto end;
56809566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
56819566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
56829566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
56839566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
56849566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
568507218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL));
56869566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
56879566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
56889566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(prob, &hasJac));
56899566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
56903e9753d6SMatthew G. Knepley   /* user passed in the same matrix, avoid double contributions and
56913e9753d6SMatthew G. Knepley      only assemble the Jacobian */
56923e9753d6SMatthew G. Knepley   if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
56939566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
56943e9753d6SMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
56959566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A));
56969a2a23afSMatthew G. Knepley   if (A) {
56979566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
56989566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
56999566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plex));
57009566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plex, &sectionAux));
57019566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
57029566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
57033e9753d6SMatthew G. Knepley   }
57049566063dSJacob 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));
57059566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
57069566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
57073e9753d6SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
57083e9753d6SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
57093e9753d6SMatthew G. Knepley     const PetscInt cind = c - cStart;
57103e9753d6SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
57113e9753d6SMatthew G. Knepley     PetscInt       i;
57123e9753d6SMatthew G. Knepley 
57139566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x));
57143e9753d6SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
57159566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x));
57163e9753d6SMatthew G. Knepley     if (X_t) {
57179566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t));
57183e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
57199566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t));
57203e9753d6SMatthew G. Knepley     }
57213e9753d6SMatthew G. Knepley     if (dmAux) {
57223e9753d6SMatthew G. Knepley       PetscInt subcell;
57239566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell));
57249566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x));
57253e9753d6SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
57269566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x));
57273e9753d6SMatthew G. Knepley     }
57283e9753d6SMatthew G. Knepley   }
57299566063dSJacob Faibussowitsch   if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim));
57309566063dSJacob Faibussowitsch   if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim));
57319566063dSJacob Faibussowitsch   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim));
57323e9753d6SMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
57333e9753d6SMatthew G. Knepley     PetscClassId    id;
57343e9753d6SMatthew G. Knepley     PetscFE         fe;
57353e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
57363e9753d6SMatthew G. Knepley     PetscInt        Nb;
57373e9753d6SMatthew G. Knepley     /* Conforming batches */
57383e9753d6SMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
57393e9753d6SMatthew G. Knepley     /* Remainder */
57403e9753d6SMatthew G. Knepley     PetscInt     Nr, offset, Nq;
57413e9753d6SMatthew G. Knepley     PetscInt     maxDegree;
57423e9753d6SMatthew G. Knepley     PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
57433e9753d6SMatthew G. Knepley 
57449566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
57459566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
57469371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) {
57479371c9d4SSatish Balay       hasFV = PETSC_TRUE;
57489371c9d4SSatish Balay       continue;
57499371c9d4SSatish Balay     }
57509566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
57519566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
57529566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
575348a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
57543e9753d6SMatthew G. Knepley     if (!qGeom) {
57559566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
57569566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
57573e9753d6SMatthew G. Knepley     }
57589566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
57599566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
57603e9753d6SMatthew G. Knepley     blockSize = Nb;
57613e9753d6SMatthew G. Knepley     batchSize = numBlocks * blockSize;
57629566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
57633e9753d6SMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
57643e9753d6SMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
57653e9753d6SMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
57663e9753d6SMatthew G. Knepley     offset    = numCells - Nr;
57679566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
57689566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
57693e9753d6SMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
57706528b96dSMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
57713e9753d6SMatthew G. Knepley       if (hasJac) {
57729566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
5773072f5ffdSStefano Zampini         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim]));
57743e9753d6SMatthew G. Knepley       }
57753e9753d6SMatthew G. Knepley       if (hasPrec) {
57769566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP));
5777072f5ffdSStefano Zampini         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatP[offset * totDim * totDim]));
57783e9753d6SMatthew G. Knepley       }
57793e9753d6SMatthew G. Knepley       if (hasDyn) {
57809566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD));
5781072f5ffdSStefano Zampini         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMatD[offset * totDim * totDim]));
57823e9753d6SMatthew G. Knepley       }
57833e9753d6SMatthew G. Knepley     }
57849566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
57859566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
57869566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
57879566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
57883e9753d6SMatthew G. Knepley   }
57893e9753d6SMatthew G. Knepley   /*   Add contribution from X_t */
57909371c9d4SSatish Balay   if (hasDyn) {
57919371c9d4SSatish Balay     for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
57929371c9d4SSatish Balay   }
57933e9753d6SMatthew G. Knepley   if (hasFV) {
57943e9753d6SMatthew G. Knepley     PetscClassId id;
57953e9753d6SMatthew G. Knepley     PetscFV      fv;
57963e9753d6SMatthew G. Knepley     PetscInt     offsetI, NcI, NbI = 1, fc, f;
57973e9753d6SMatthew G. Knepley 
57983e9753d6SMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
57999566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv));
58009566063dSJacob Faibussowitsch       PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI));
58019566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId((PetscObject)fv, &id));
58023e9753d6SMatthew G. Knepley       if (id != PETSCFV_CLASSID) continue;
58033e9753d6SMatthew G. Knepley       /* Put in the identity */
58049566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &NcI));
58053e9753d6SMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
58063e9753d6SMatthew G. Knepley         const PetscInt cind    = c - cStart;
58073e9753d6SMatthew G. Knepley         const PetscInt eOffset = cind * totDim * totDim;
58083e9753d6SMatthew G. Knepley         for (fc = 0; fc < NcI; ++fc) {
58093e9753d6SMatthew G. Knepley           for (f = 0; f < NbI; ++f) {
58103e9753d6SMatthew G. Knepley             const PetscInt i = offsetI + f * NcI + fc;
58113e9753d6SMatthew G. Knepley             if (hasPrec) {
5812ad540459SPierre Jolivet               if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
58133e9753d6SMatthew G. Knepley               elemMatP[eOffset + i * totDim + i] = 1.0;
58149371c9d4SSatish Balay             } else {
58159371c9d4SSatish Balay               elemMat[eOffset + i * totDim + i] = 1.0;
58169371c9d4SSatish Balay             }
58173e9753d6SMatthew G. Knepley           }
58183e9753d6SMatthew G. Knepley         }
58193e9753d6SMatthew G. Knepley       }
58203e9753d6SMatthew G. Knepley     }
58213e9753d6SMatthew G. Knepley     /* No allocated space for FV stuff, so ignore the zero entries */
58229566063dSJacob Faibussowitsch     PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
58233e9753d6SMatthew G. Knepley   }
58243e9753d6SMatthew G. Knepley   /* Insert values into matrix */
58253e9753d6SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
58263e9753d6SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
58273e9753d6SMatthew G. Knepley     const PetscInt cind = c - cStart;
58283e9753d6SMatthew G. Knepley 
58293e9753d6SMatthew G. Knepley     /* Transform to global basis before insertion in Jacobian */
58309566063dSJacob Faibussowitsch     if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim]));
58313e9753d6SMatthew G. Knepley     if (hasPrec) {
58323e9753d6SMatthew G. Knepley       if (hasJac) {
58339566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
5834e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
58353e9753d6SMatthew G. Knepley       }
58369566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim]));
58379566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES));
58383e9753d6SMatthew G. Knepley     } else {
58393e9753d6SMatthew G. Knepley       if (hasJac) {
58409566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
5841e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
58423e9753d6SMatthew G. Knepley       }
58433e9753d6SMatthew G. Knepley     }
58443e9753d6SMatthew G. Knepley   }
58459566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
58469566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
58479566063dSJacob Faibussowitsch   PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD));
58483e9753d6SMatthew G. Knepley   if (dmAux) {
58499566063dSJacob Faibussowitsch     PetscCall(PetscFree(a));
58509566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&plex));
58513e9753d6SMatthew G. Knepley   }
58523e9753d6SMatthew G. Knepley   /* Compute boundary integrals */
58539566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user));
58543e9753d6SMatthew G. Knepley   /* Assemble matrix */
58559371c9d4SSatish Balay end : {
5856e04ae0b4SMatthew G. Knepley   PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp;
5857e04ae0b4SMatthew G. Knepley 
5858712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
58593e9753d6SMatthew G. Knepley   if (hasJac && hasPrec) {
58609566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
58619566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
58623e9753d6SMatthew G. Knepley   }
5863e04ae0b4SMatthew G. Knepley }
58649566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
58659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
58669566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
58673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58683e9753d6SMatthew G. Knepley }
58693e9753d6SMatthew G. Knepley 
5870d71ae5a4SJacob 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)
5871d71ae5a4SJacob Faibussowitsch {
58723e9753d6SMatthew G. Knepley   DM_Plex        *mesh          = (DM_Plex *)dm->data;
58733e9753d6SMatthew G. Knepley   const char     *name          = "Hybrid Jacobian";
5874148442b3SMatthew G. Knepley   DM              dmAux[3]      = {NULL, NULL, NULL};
5875148442b3SMatthew G. Knepley   DMLabel         ghostLabel    = NULL;
58763e9753d6SMatthew G. Knepley   DM              plex          = NULL;
58773e9753d6SMatthew G. Knepley   DM              plexA         = NULL;
5878148442b3SMatthew G. Knepley   PetscDS         ds            = NULL;
587907218a29SMatthew G. Knepley   PetscDS         dsIn          = NULL;
5880148442b3SMatthew G. Knepley   PetscDS         dsAux[3]      = {NULL, NULL, NULL};
5881148442b3SMatthew G. Knepley   Vec             locA[3]       = {NULL, NULL, NULL};
588207218a29SMatthew G. Knepley   DM              dmScale[3]    = {NULL, NULL, NULL};
588307218a29SMatthew G. Knepley   PetscDS         dsScale[3]    = {NULL, NULL, NULL};
588407218a29SMatthew G. Knepley   Vec             locS[3]       = {NULL, NULL, NULL};
58853e9753d6SMatthew G. Knepley   PetscSection    section       = NULL;
5886148442b3SMatthew G. Knepley   PetscSection    sectionAux[3] = {NULL, NULL, NULL};
58873e9753d6SMatthew G. Knepley   DMField         coordField    = NULL;
588807218a29SMatthew G. Knepley   PetscScalar    *a[3]          = {NULL, NULL, NULL};
588907218a29SMatthew G. Knepley   PetscScalar    *s[3]          = {NULL, NULL, NULL};
589007218a29SMatthew G. Knepley   PetscScalar    *u             = NULL, *u_t;
589107218a29SMatthew G. Knepley   PetscScalar    *elemMatNeg, *elemMatPos, *elemMatCoh;
589207218a29SMatthew G. Knepley   PetscScalar    *elemMatNegP, *elemMatPosP, *elemMatCohP;
5893e432b41dSStefano Zampini   PetscSection    globalSection;
58943e9753d6SMatthew G. Knepley   IS              chunkIS;
58953e9753d6SMatthew G. Knepley   const PetscInt *cells;
58963e9753d6SMatthew G. Knepley   PetscInt       *faces;
58973e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
58983e2b0218SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk;
58993e9753d6SMatthew G. Knepley   PetscInt        maxDegree  = PETSC_MAX_INT;
59003e9753d6SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
59013e9753d6SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
5902e432b41dSStefano Zampini   PetscBool       hasBdJac, hasBdPrec;
59033e9753d6SMatthew G. Knepley 
59043e9753d6SMatthew G. Knepley   PetscFunctionBegin;
59053ba16761SJacob Faibussowitsch   if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS);
5906437e83fbSMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
5907437e83fbSMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
59083ba16761SJacob Faibussowitsch   if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS);
59095fedec97SMatthew G. Knepley   if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
59105fedec97SMatthew G. Knepley     const char *name;
59119566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name));
591263a3b9bcSJacob 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);
59135fedec97SMatthew G. Knepley   }
59149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
59159566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
59169566063dSJacob Faibussowitsch   PetscCall(DMGetSection(dm, &section));
59179566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
59189566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
591907218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn));
59209566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
59219566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
592207218a29SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn));
59239566063dSJacob Faibussowitsch   PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac));
59249566063dSJacob Faibussowitsch   PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec));
59259566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]));
5926148442b3SMatthew G. Knepley   if (locA[2]) {
59271059d808SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
59281059d808SMatthew G. Knepley 
59299566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA[2], &dmAux[2]));
59309566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA));
59319566063dSJacob Faibussowitsch     PetscCall(DMGetSection(dmAux[2], &sectionAux[2]));
593207218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL));
59339566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]));
5934148442b3SMatthew G. Knepley     {
5935148442b3SMatthew G. Knepley       const PetscInt *cone;
5936148442b3SMatthew G. Knepley       PetscInt        c;
5937148442b3SMatthew G. Knepley 
59381059d808SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
5939148442b3SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
5940148442b3SMatthew G. Knepley         const PetscInt *support;
5941148442b3SMatthew G. Knepley         PetscInt        ssize, s;
5942148442b3SMatthew G. Knepley 
59439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
59449566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
59451059d808SMatthew 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);
59461059d808SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
59471059d808SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
59481059d808SMatthew 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);
59499566063dSJacob Faibussowitsch         PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]));
59509566063dSJacob Faibussowitsch         if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c]));
5951ad540459SPierre Jolivet         else dmAux[c] = dmAux[2];
595207218a29SMatthew G. Knepley         PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL));
59539566063dSJacob Faibussowitsch         PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]));
5954148442b3SMatthew G. Knepley       }
5955148442b3SMatthew G. Knepley     }
59563e9753d6SMatthew G. Knepley   }
595707218a29SMatthew G. Knepley   /* Handle mass matrix scaling
595807218a29SMatthew G. Knepley        The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */
595907218a29SMatthew G. Knepley   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2]));
596007218a29SMatthew G. Knepley   if (locS[2]) {
59613e2b0218SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
596207218a29SMatthew G. Knepley     PetscInt       Nb, Nbs;
596307218a29SMatthew G. Knepley 
596407218a29SMatthew G. Knepley     PetscCall(VecGetDM(locS[2], &dmScale[2]));
596507218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL));
59663e2b0218SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2]));
596707218a29SMatthew G. Knepley     // BRAD: This is not set correctly
596807218a29SMatthew G. Knepley     key[2].field = 2;
596907218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb));
597007218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs));
597107218a29SMatthew G. Knepley     PetscCheck(Nb == Nbs, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field %" PetscInt_FMT " of size %" PetscInt_FMT " cannot be scaled by field of size %" PetscInt_FMT, key[2].field, Nb, Nbs);
59723e2b0218SMatthew G. Knepley     {
59733e2b0218SMatthew G. Knepley       const PetscInt *cone;
59743e2b0218SMatthew G. Knepley       PetscInt        c;
59753e2b0218SMatthew G. Knepley 
59763e2b0218SMatthew G. Knepley       locS[1] = locS[0] = locS[2];
59773e2b0218SMatthew G. Knepley       dmScale[1] = dmScale[0] = dmScale[2];
59783e2b0218SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
59793e2b0218SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
59803e2b0218SMatthew G. Knepley         const PetscInt *support;
59813e2b0218SMatthew G. Knepley         PetscInt        ssize, s;
59823e2b0218SMatthew G. Knepley 
59833e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
59843e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
59853e2b0218SMatthew 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);
59863e2b0218SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
59873e2b0218SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
59883e2b0218SMatthew 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);
59893e2b0218SMatthew G. Knepley         PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL));
59903e2b0218SMatthew G. Knepley         PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c]));
59913e2b0218SMatthew G. Knepley       }
59923e2b0218SMatthew G. Knepley     }
599307218a29SMatthew G. Knepley   }
599407218a29SMatthew G. Knepley   /* 2: Setup geometric data */
59959566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
59969566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
59973e9753d6SMatthew G. Knepley   if (maxDegree > 1) {
59983e9753d6SMatthew G. Knepley     PetscInt f;
59999566063dSJacob Faibussowitsch     PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
60003e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
60013e9753d6SMatthew G. Knepley       PetscFE fe;
60023e9753d6SMatthew G. Knepley 
60039566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
60043e9753d6SMatthew G. Knepley       if (fe) {
60059566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
60069566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)quads[f]));
60073e9753d6SMatthew G. Knepley       }
60083e9753d6SMatthew G. Knepley     }
60093e9753d6SMatthew G. Knepley   }
601007218a29SMatthew G. Knepley   /* Loop over chunks */
60113e9753d6SMatthew G. Knepley   cellChunkSize = numCells;
60123e9753d6SMatthew G. Knepley   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
601307218a29SMatthew G. Knepley   PetscCall(PetscCalloc1(2 * cellChunkSize, &faces));
6014a4158a15SMatthew G. Knepley   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS));
601507218a29SMatthew G. Knepley   /* Extract field coefficients */
601607218a29SMatthew G. Knepley   /* NOTE This needs the end cap faces to have identical orientations */
601707218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
601807218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
60198bf0a22dSMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s));
602007218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg));
602107218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos));
602207218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh));
602307218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP));
602407218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP));
602507218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP));
60263e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
60273e9753d6SMatthew G. Knepley     PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
60283e9753d6SMatthew G. Knepley 
602907218a29SMatthew G. Knepley     if (hasBdJac) {
603007218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim));
603107218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim));
603207218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim));
603307218a29SMatthew G. Knepley     }
603407218a29SMatthew G. Knepley     if (hasBdPrec) {
603507218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim));
603607218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim));
603707218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim));
603807218a29SMatthew G. Knepley     }
60393e9753d6SMatthew G. Knepley     /* Get faces */
60403e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
60413e9753d6SMatthew G. Knepley       const PetscInt  cell = cells ? cells[c] : c;
60423e9753d6SMatthew G. Knepley       const PetscInt *cone;
60439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(plex, cell, &cone));
604407218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 0] = cone[0];
604507218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 1] = cone[1];
60463e9753d6SMatthew G. Knepley     }
604707218a29SMatthew G. Knepley     PetscCall(ISGeneralSetIndices(chunkIS, 2 * cellChunkSize, faces, PETSC_USE_POINTER));
60483e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
60499566063dSJacob Faibussowitsch       if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad));
60509566063dSJacob Faibussowitsch       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom));
60513e9753d6SMatthew G. Knepley     } else {
60523e9753d6SMatthew G. Knepley       PetscInt f;
60533e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
60549566063dSJacob Faibussowitsch         if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]));
60553e9753d6SMatthew G. Knepley       }
60563e9753d6SMatthew G. Knepley     }
60573e9753d6SMatthew G. Knepley 
60583e9753d6SMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
60593e9753d6SMatthew G. Knepley       PetscFE         feI;
60603e9753d6SMatthew G. Knepley       PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[fieldI];
60613e9753d6SMatthew G. Knepley       PetscFEGeom    *chunkGeom = NULL, *remGeom = NULL;
60623e9753d6SMatthew G. Knepley       PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI];
60633e9753d6SMatthew G. Knepley       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
60645fedec97SMatthew G. Knepley       PetscBool       isCohesiveField;
60653e9753d6SMatthew G. Knepley 
60669566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
60673e9753d6SMatthew G. Knepley       if (!feI) continue;
60689566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches));
60699566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
60709566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feI, &Nb));
60713e9753d6SMatthew G. Knepley       blockSize = Nb;
60723e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
60739566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches));
60743e9753d6SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
60753e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
60763e9753d6SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
60773e9753d6SMatthew G. Knepley       offset    = numCells - Nr;
607807218a29SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(geom, 0, offset * 2, &chunkGeom));
607907218a29SMatthew G. Knepley       PetscCall(PetscFEGeomGetChunk(geom, offset * 2, numCells * 2, &remGeom));
60809566063dSJacob Faibussowitsch       PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField));
60813e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
60823e9753d6SMatthew G. Knepley         PetscFE feJ;
60833e9753d6SMatthew G. Knepley 
60849566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
60853e9753d6SMatthew G. Knepley         if (!feJ) continue;
6086148442b3SMatthew G. Knepley         key[0].field = fieldI * Nf + fieldJ;
6087148442b3SMatthew G. Knepley         key[1].field = fieldI * Nf + fieldJ;
60885fedec97SMatthew G. Knepley         key[2].field = fieldI * Nf + fieldJ;
6089148442b3SMatthew G. Knepley         if (hasBdJac) {
609007218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg));
609107218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNeg[offset * totDim * totDim]));
609207218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos));
609307218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPos[offset * totDim * totDim]));
6094148442b3SMatthew G. Knepley         }
6095148442b3SMatthew G. Knepley         if (hasBdPrec) {
609607218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNegP));
609707218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim]));
609807218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPosP));
609907218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim]));
6100148442b3SMatthew G. Knepley         }
61015fedec97SMatthew G. Knepley         if (hasBdJac) {
610207218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh));
610307218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCoh[offset * totDim * totDim]));
6104148442b3SMatthew G. Knepley         }
61055fedec97SMatthew G. Knepley         if (hasBdPrec) {
610607218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCohP));
610707218a29SMatthew G. Knepley           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDimIn], u_t ? &u_t[offset * totDimIn] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim]));
61083e9753d6SMatthew G. Knepley         }
61093e9753d6SMatthew G. Knepley       }
61109566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom));
61119566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom));
61123e9753d6SMatthew G. Knepley     }
61133e9753d6SMatthew G. Knepley     /* Insert values into matrix */
61143e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
61153e9753d6SMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
611607218a29SMatthew G. Knepley       const PetscInt cind = c - cS, coff = cind * totDim * totDim;
611707218a29SMatthew G. Knepley       PetscInt       i, j;
61183e9753d6SMatthew G. Knepley 
611907218a29SMatthew G. Knepley       /* Scale element values */
612007218a29SMatthew G. Knepley       if (locS[0]) {
61213e2b0218SMatthew G. Knepley         PetscInt  Nb, soff = cind * totDimScale[0], off = 0;
612207218a29SMatthew G. Knepley         PetscBool cohesive;
612307218a29SMatthew G. Knepley 
612407218a29SMatthew G. Knepley         for (fieldI = 0; fieldI < Nf; ++fieldI) {
612507218a29SMatthew G. Knepley           PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb));
612607218a29SMatthew G. Knepley           PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive));
612707218a29SMatthew G. Knepley 
612807218a29SMatthew G. Knepley           if (fieldI == key[2].field) {
612907218a29SMatthew G. Knepley             PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields");
61308bf0a22dSMatthew G. Knepley             for (i = 0; i < Nb; ++i) {
613107218a29SMatthew G. Knepley               for (j = 0; j < totDim; ++j) elemMatCoh[coff + (off + i) * totDim + j] += s[0][soff + i] * elemMatNeg[coff + (off + i) * totDim + j] + s[1][soff + i] * elemMatPos[coff + (off + i) * totDim + j];
61328bf0a22dSMatthew G. Knepley               if (hasBdPrec)
61338bf0a22dSMatthew G. Knepley                 for (j = 0; j < totDim; ++j) elemMatCohP[coff + (off + i) * totDim + j] += s[0][soff + i] * elemMatNegP[coff + (off + i) * totDim + j] + s[1][soff + i] * elemMatPosP[coff + (off + i) * totDim + j];
61348bf0a22dSMatthew G. Knepley             }
613507218a29SMatthew G. Knepley             off += Nb;
613607218a29SMatthew G. Knepley           } else {
613707218a29SMatthew G. Knepley             const PetscInt N = cohesive ? Nb : Nb * 2;
613807218a29SMatthew G. Knepley 
61398bf0a22dSMatthew G. Knepley             for (i = 0; i < N; ++i) {
614007218a29SMatthew G. Knepley               for (j = 0; j < totDim; ++j) elemMatCoh[coff + (off + i) * totDim + j] += elemMatNeg[coff + (off + i) * totDim + j] + elemMatPos[coff + (off + i) * totDim + j];
61418bf0a22dSMatthew G. Knepley               if (hasBdPrec)
61428bf0a22dSMatthew G. Knepley                 for (j = 0; j < totDim; ++j) elemMatCohP[coff + (off + i) * totDim + j] += elemMatNegP[coff + (off + i) * totDim + j] + elemMatPosP[coff + (off + i) * totDim + j];
61438bf0a22dSMatthew G. Knepley             }
614407218a29SMatthew G. Knepley             off += N;
614507218a29SMatthew G. Knepley           }
614607218a29SMatthew G. Knepley         }
614707218a29SMatthew G. Knepley       } else {
614807218a29SMatthew G. Knepley         for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i];
61498bf0a22dSMatthew G. Knepley         if (hasBdPrec)
61508bf0a22dSMatthew G. Knepley           for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i];
615107218a29SMatthew G. Knepley       }
61523e9753d6SMatthew G. Knepley       if (hasBdPrec) {
61533e9753d6SMatthew G. Knepley         if (hasBdJac) {
615407218a29SMatthew G. Knepley           if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim]));
6155e8e188d2SZach Atkins           PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES));
61563e9753d6SMatthew G. Knepley         }
615707218a29SMatthew G. Knepley         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim]));
615807218a29SMatthew G. Knepley         PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES));
61593e9753d6SMatthew G. Knepley       } else if (hasBdJac) {
616007218a29SMatthew G. Knepley         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim]));
6161e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES));
61623e9753d6SMatthew G. Knepley       }
61633e9753d6SMatthew G. Knepley     }
61643e9753d6SMatthew G. Knepley   }
61659566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
616607218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
616707218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg));
616807218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos));
616907218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh));
617007218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP));
617107218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP));
617207218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP));
61739566063dSJacob Faibussowitsch   PetscCall(PetscFree(faces));
61749566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&chunkIS));
61759566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
61763e9753d6SMatthew G. Knepley   if (maxDegree <= 1) {
61779566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
61789566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&affineQuad));
61793e9753d6SMatthew G. Knepley   } else {
61803e9753d6SMatthew G. Knepley     PetscInt f;
61813e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
61829566063dSJacob Faibussowitsch       if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
61839566063dSJacob Faibussowitsch       if (quads) PetscCall(PetscQuadratureDestroy(&quads[f]));
61843e9753d6SMatthew G. Knepley     }
61859566063dSJacob Faibussowitsch     PetscCall(PetscFree2(quads, geoms));
61863e9753d6SMatthew G. Knepley   }
61879566063dSJacob Faibussowitsch   if (dmAux[2]) PetscCall(DMDestroy(&plexA));
61889566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
61899566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
61903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61913e9753d6SMatthew G. Knepley }
61928e3a2eefSMatthew G. Knepley 
61938e3a2eefSMatthew G. Knepley /*
61948e3a2eefSMatthew 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.
61958e3a2eefSMatthew G. Knepley 
61968e3a2eefSMatthew G. Knepley   Input Parameters:
61978e3a2eefSMatthew G. Knepley + dm     - The mesh
6198baca6076SPierre Jolivet . key    - The PetscWeakFormKey indicating where integration should happen
619906ad1575SMatthew G. Knepley . cellIS - The cells to integrate over
62008e3a2eefSMatthew G. Knepley . t      - The time
6201145b44c9SPierre Jolivet . X_tShift - The multiplier for the Jacobian with respect to X_t
62028e3a2eefSMatthew G. Knepley . X      - Local solution vector
62038e3a2eefSMatthew G. Knepley . X_t    - Time-derivative of the local solution vector
62048e3a2eefSMatthew G. Knepley . Y      - Local input vector
620506ad1575SMatthew G. Knepley - user   - the user context
62068e3a2eefSMatthew G. Knepley 
62078e3a2eefSMatthew G. Knepley   Output Parameter:
62088e3a2eefSMatthew G. Knepley . Z - Local output vector
62098e3a2eefSMatthew G. Knepley 
62108e3a2eefSMatthew G. Knepley   Note:
62118e3a2eefSMatthew G. Knepley   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
62128e3a2eefSMatthew G. Knepley   like a GPU, or vectorize on a multicore machine.
62138e3a2eefSMatthew G. Knepley */
6214d71ae5a4SJacob 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)
6215d71ae5a4SJacob Faibussowitsch {
62168e3a2eefSMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
62178e3a2eefSMatthew G. Knepley   const char     *name  = "Jacobian";
62188e3a2eefSMatthew G. Knepley   DM              dmAux = NULL, plex, plexAux = NULL;
62198e3a2eefSMatthew G. Knepley   DMEnclosureType encAux;
62208e3a2eefSMatthew G. Knepley   Vec             A;
62218e3a2eefSMatthew G. Knepley   DMField         coordField;
62228e3a2eefSMatthew G. Knepley   PetscDS         prob, probAux = NULL;
62238e3a2eefSMatthew G. Knepley   PetscQuadrature quad;
62248e3a2eefSMatthew G. Knepley   PetscSection    section, globalSection, sectionAux;
62258e3a2eefSMatthew G. Knepley   PetscScalar    *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z;
62268e3a2eefSMatthew G. Knepley   const PetscInt *cells;
62278e3a2eefSMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ;
62288e3a2eefSMatthew G. Knepley   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
62298e3a2eefSMatthew G. Knepley   PetscBool       hasDyn;
62308e3a2eefSMatthew G. Knepley 
62318e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
623221d77094SMatthew G. Knepley   if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS);
62339566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
62349566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
62359566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
62369566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
62379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
62389566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
623907218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL));
62409566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
62419566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
62429566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
62438e3a2eefSMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
62449566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A));
62458e3a2eefSMatthew G. Knepley   if (A) {
62469566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
62479566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
62489566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexAux));
62499566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexAux, &sectionAux));
62509566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
62519566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
62528e3a2eefSMatthew G. Knepley   }
62539566063dSJacob Faibussowitsch   PetscCall(VecSet(Z, 0.0));
62549566063dSJacob 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));
62559566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
62569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
62578e3a2eefSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
62588e3a2eefSMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
62598e3a2eefSMatthew G. Knepley     const PetscInt cind = c - cStart;
62608e3a2eefSMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
62618e3a2eefSMatthew G. Knepley     PetscInt       i;
62628e3a2eefSMatthew G. Knepley 
62639566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x));
62648e3a2eefSMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
62659566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x));
62668e3a2eefSMatthew G. Knepley     if (X_t) {
62679566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t));
62688e3a2eefSMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
62699566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t));
62708e3a2eefSMatthew G. Knepley     }
62718e3a2eefSMatthew G. Knepley     if (dmAux) {
62728e3a2eefSMatthew G. Knepley       PetscInt subcell;
62739566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell));
62749566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x));
62758e3a2eefSMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
62769566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x));
62778e3a2eefSMatthew G. Knepley     }
62789566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x));
62798e3a2eefSMatthew G. Knepley     for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i];
62809566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x));
62818e3a2eefSMatthew G. Knepley   }
62829566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim));
62839566063dSJacob Faibussowitsch   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim));
62848e3a2eefSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
62858e3a2eefSMatthew G. Knepley     PetscFE  fe;
62868e3a2eefSMatthew G. Knepley     PetscInt Nb;
62878e3a2eefSMatthew G. Knepley     /* Conforming batches */
62888e3a2eefSMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
62898e3a2eefSMatthew G. Knepley     /* Remainder */
62908e3a2eefSMatthew G. Knepley     PetscInt        Nr, offset, Nq;
62918e3a2eefSMatthew G. Knepley     PetscQuadrature qGeom = NULL;
62928e3a2eefSMatthew G. Knepley     PetscInt        maxDegree;
62938e3a2eefSMatthew G. Knepley     PetscFEGeom    *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
62948e3a2eefSMatthew G. Knepley 
62959566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
62969566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &quad));
62979566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
62989566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
62999566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
63009566063dSJacob Faibussowitsch     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
63018e3a2eefSMatthew G. Knepley     if (!qGeom) {
63029566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
63039566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
63048e3a2eefSMatthew G. Knepley     }
63059566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
63069566063dSJacob Faibussowitsch     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
63078e3a2eefSMatthew G. Knepley     blockSize = Nb;
63088e3a2eefSMatthew G. Knepley     batchSize = numBlocks * blockSize;
63099566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
63108e3a2eefSMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
63118e3a2eefSMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
63128e3a2eefSMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
63138e3a2eefSMatthew G. Knepley     offset    = numCells - Nr;
63149566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
63159566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
63168e3a2eefSMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
63178e3a2eefSMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
63189566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
63199566063dSJacob 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]));
63208e3a2eefSMatthew G. Knepley       if (hasDyn) {
63219566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD));
63229566063dSJacob 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]));
63238e3a2eefSMatthew G. Knepley       }
63248e3a2eefSMatthew G. Knepley     }
63259566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
63269566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
63279566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
63289566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
63298e3a2eefSMatthew G. Knepley   }
63308e3a2eefSMatthew G. Knepley   if (hasDyn) {
63318e3a2eefSMatthew G. Knepley     for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
63328e3a2eefSMatthew G. Knepley   }
63338e3a2eefSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
63348e3a2eefSMatthew G. Knepley     const PetscInt     cell = cells ? cells[c] : c;
63358e3a2eefSMatthew G. Knepley     const PetscInt     cind = c - cStart;
63368e3a2eefSMatthew G. Knepley     const PetscBLASInt M = totDim, one = 1;
63378e3a2eefSMatthew G. Knepley     const PetscScalar  a = 1.0, b = 0.0;
63388e3a2eefSMatthew G. Knepley 
6339792fecdfSBarry Smith     PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one));
63408e3a2eefSMatthew G. Knepley     if (mesh->printFEM > 1) {
63419566063dSJacob Faibussowitsch       PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
63429566063dSJacob Faibussowitsch       PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim]));
63439566063dSJacob Faibussowitsch       PetscCall(DMPrintCellVector(c, "Z", totDim, z));
63448e3a2eefSMatthew G. Knepley     }
63459566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES));
63468e3a2eefSMatthew G. Knepley   }
63479566063dSJacob Faibussowitsch   PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z));
63488e3a2eefSMatthew G. Knepley   if (mesh->printFEM) {
63499566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n"));
63509566063dSJacob Faibussowitsch     PetscCall(VecView(Z, NULL));
63518e3a2eefSMatthew G. Knepley   }
63521059d808SMatthew G. Knepley   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
63539566063dSJacob Faibussowitsch   PetscCall(PetscFree(a));
63549566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plexAux));
63559566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
63569566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
63573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63588e3a2eefSMatthew G. Knepley }
6359