xref: /petsc/src/dm/impls/plex/plexfem.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
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 
DMPlexConvertPlex(DM dm,DM * plex,PetscBool copy)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));
33cbf8eb3cSStefano Zampini     } else {
34cbf8eb3cSStefano Zampini       PetscCall(PetscObjectReference((PetscObject)*plex));
35cbf8eb3cSStefano Zampini     }
362f856554SMatthew G. Knepley     if (copy) {
372f856554SMatthew G. Knepley       DMSubDomainHookLink link;
389a2a23afSMatthew G. Knepley 
39bb4b53efSMatthew G. Knepley       PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, *plex));
409566063dSJacob Faibussowitsch       PetscCall(DMCopyAuxiliaryVec(dm, *plex));
419a2a23afSMatthew G. Knepley       /* Run the subdomain hook (this will copy the DMSNES/DMTS) */
422f856554SMatthew G. Knepley       for (link = dm->subdomainhook; link; link = link->next) {
439566063dSJacob Faibussowitsch         if (link->ddhook) PetscCall((*link->ddhook)(dm, *plex, link->ctx));
442f856554SMatthew G. Knepley       }
452f856554SMatthew G. Knepley     }
462f856554SMatthew G. Knepley   }
473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
482f856554SMatthew G. Knepley }
492f856554SMatthew G. Knepley 
PetscContainerCtxDestroy_PetscFEGeom(PetscCtxRt ctx)50*2a8381b2SBarry Smith static PetscErrorCode PetscContainerCtxDestroy_PetscFEGeom(PetscCtxRt ctx)
51d71ae5a4SJacob Faibussowitsch {
52*2a8381b2SBarry Smith   PetscFEGeom *geom = *(PetscFEGeom **)ctx;
539b6f715bSMatthew G. Knepley 
549b6f715bSMatthew G. Knepley   PetscFunctionBegin;
559566063dSJacob Faibussowitsch   PetscCall(PetscFEGeomDestroy(&geom));
563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
579b6f715bSMatthew G. Knepley }
589b6f715bSMatthew G. Knepley 
DMPlexGetFEGeom(DMField coordField,IS pointIS,PetscQuadrature quad,PetscFEGeomMode mode,PetscFEGeom ** geom)59ac9d17c7SMatthew G. Knepley static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscFEGeomMode mode, PetscFEGeom **geom)
60d71ae5a4SJacob Faibussowitsch {
619b6f715bSMatthew G. Knepley   char           composeStr[33] = {0};
629b6f715bSMatthew G. Knepley   PetscObjectId  id;
639b6f715bSMatthew G. Knepley   PetscContainer container;
649b6f715bSMatthew G. Knepley 
659b6f715bSMatthew G. Knepley   PetscFunctionBegin;
669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetId((PetscObject)quad, &id));
6763a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id));
689566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container));
699b6f715bSMatthew G. Knepley   if (container) {
70*2a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(container, geom));
719b6f715bSMatthew G. Knepley   } else {
72ac9d17c7SMatthew G. Knepley     PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, mode, geom));
739566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
749566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(container, (void *)*geom));
7549abdd8aSBarry Smith     PetscCall(PetscContainerSetCtxDestroy(container, PetscContainerCtxDestroy_PetscFEGeom));
769566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container));
779566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&container));
789b6f715bSMatthew G. Knepley   }
793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
809b6f715bSMatthew G. Knepley }
819b6f715bSMatthew G. Knepley 
DMPlexRestoreFEGeom(DMField coordField,IS pointIS,PetscQuadrature quad,PetscFEGeomMode mode,PetscFEGeom ** geom)82ac9d17c7SMatthew G. Knepley static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscFEGeomMode mode, PetscFEGeom **geom)
83d71ae5a4SJacob Faibussowitsch {
849b6f715bSMatthew G. Knepley   PetscFunctionBegin;
859b6f715bSMatthew G. Knepley   *geom = NULL;
863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
879b6f715bSMatthew G. Knepley }
889b6f715bSMatthew G. Knepley 
8946fa42a0SMatthew G. Knepley /*@
9046fa42a0SMatthew G. Knepley   DMPlexGetScale - Get the scale for the specified fundamental unit
9146fa42a0SMatthew G. Knepley 
9220f4b53cSBarry Smith   Not Collective
9346fa42a0SMatthew G. Knepley 
944165533cSJose E. Roman   Input Parameters:
95a1cb98faSBarry Smith + dm   - the `DM`
9646fa42a0SMatthew G. Knepley - unit - The SI unit
9746fa42a0SMatthew G. Knepley 
984165533cSJose E. Roman   Output Parameter:
9946fa42a0SMatthew G. Knepley . scale - The value used to scale all quantities with this unit
10046fa42a0SMatthew G. Knepley 
10146fa42a0SMatthew G. Knepley   Level: advanced
10246fa42a0SMatthew G. Knepley 
1031cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit`
10446fa42a0SMatthew G. Knepley @*/
DMPlexGetScale(DM dm,PetscUnit unit,PetscReal * scale)105d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
106d71ae5a4SJacob Faibussowitsch {
107cb1e1211SMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
108cb1e1211SMatthew G Knepley 
109cb1e1211SMatthew G Knepley   PetscFunctionBegin;
110cb1e1211SMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1114f572ea9SToby Isaac   PetscAssertPointer(scale, 3);
112cb1e1211SMatthew G Knepley   *scale = mesh->scale[unit];
1133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
114cb1e1211SMatthew G Knepley }
115cb1e1211SMatthew G Knepley 
11646fa42a0SMatthew G. Knepley /*@
11746fa42a0SMatthew G. Knepley   DMPlexSetScale - Set the scale for the specified fundamental unit
11846fa42a0SMatthew G. Knepley 
11920f4b53cSBarry Smith   Not Collective
12046fa42a0SMatthew G. Knepley 
1214165533cSJose E. Roman   Input Parameters:
122a1cb98faSBarry Smith + dm    - the `DM`
12346fa42a0SMatthew G. Knepley . unit  - The SI unit
12446fa42a0SMatthew G. Knepley - scale - The value used to scale all quantities with this unit
12546fa42a0SMatthew G. Knepley 
12646fa42a0SMatthew G. Knepley   Level: advanced
12746fa42a0SMatthew G. Knepley 
1281cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit`
12946fa42a0SMatthew G. Knepley @*/
DMPlexSetScale(DM dm,PetscUnit unit,PetscReal scale)130d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
131d71ae5a4SJacob Faibussowitsch {
132cb1e1211SMatthew G Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
133cb1e1211SMatthew G Knepley 
134cb1e1211SMatthew G Knepley   PetscFunctionBegin;
135cb1e1211SMatthew G Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
136cb1e1211SMatthew G Knepley   mesh->scale[unit] = scale;
1373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
138cb1e1211SMatthew G Knepley }
139cb1e1211SMatthew G Knepley 
DMPlexGetUseCeed_Plex(DM dm,PetscBool * useCeed)140d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed_Plex(DM dm, PetscBool *useCeed)
141d2b2dc1eSMatthew G. Knepley {
142d2b2dc1eSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
143d2b2dc1eSMatthew G. Knepley 
144d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
145d2b2dc1eSMatthew G. Knepley   *useCeed = mesh->useCeed;
146d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
147d2b2dc1eSMatthew G. Knepley }
DMPlexSetUseCeed_Plex(DM dm,PetscBool useCeed)148d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed_Plex(DM dm, PetscBool useCeed)
149d2b2dc1eSMatthew G. Knepley {
150d2b2dc1eSMatthew G. Knepley   DM_Plex *mesh = (DM_Plex *)dm->data;
151d2b2dc1eSMatthew G. Knepley 
152d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
153d2b2dc1eSMatthew G. Knepley   mesh->useCeed = useCeed;
154d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
155d2b2dc1eSMatthew G. Knepley }
156d2b2dc1eSMatthew G. Knepley 
157d2b2dc1eSMatthew G. Knepley /*@
158d2b2dc1eSMatthew G. Knepley   DMPlexGetUseCeed - Get flag for using the LibCEED backend
159d2b2dc1eSMatthew G. Knepley 
160d2b2dc1eSMatthew G. Knepley   Not collective
161d2b2dc1eSMatthew G. Knepley 
162d2b2dc1eSMatthew G. Knepley   Input Parameter:
163d2b2dc1eSMatthew G. Knepley . dm - The `DM`
164d2b2dc1eSMatthew G. Knepley 
165d2b2dc1eSMatthew G. Knepley   Output Parameter:
166d2b2dc1eSMatthew G. Knepley . useCeed - The flag
167d2b2dc1eSMatthew G. Knepley 
168d2b2dc1eSMatthew G. Knepley   Level: intermediate
169d2b2dc1eSMatthew G. Knepley 
170d2b2dc1eSMatthew G. Knepley .seealso: `DMPlexSetUseCeed()`
171d2b2dc1eSMatthew G. Knepley @*/
DMPlexGetUseCeed(DM dm,PetscBool * useCeed)172d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexGetUseCeed(DM dm, PetscBool *useCeed)
173d2b2dc1eSMatthew G. Knepley {
174d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
175d2b2dc1eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
176d2b2dc1eSMatthew G. Knepley   PetscAssertPointer(useCeed, 2);
177d2b2dc1eSMatthew G. Knepley   *useCeed = PETSC_FALSE;
178d2b2dc1eSMatthew G. Knepley   PetscTryMethod(dm, "DMPlexGetUseCeed_C", (DM, PetscBool *), (dm, useCeed));
179d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
180d2b2dc1eSMatthew G. Knepley }
181d2b2dc1eSMatthew G. Knepley 
182d2b2dc1eSMatthew G. Knepley /*@
183d2b2dc1eSMatthew G. Knepley   DMPlexSetUseCeed - Set flag for using the LibCEED backend
184d2b2dc1eSMatthew G. Knepley 
185d2b2dc1eSMatthew G. Knepley   Not collective
186d2b2dc1eSMatthew G. Knepley 
187d2b2dc1eSMatthew G. Knepley   Input Parameters:
188d2b2dc1eSMatthew G. Knepley + dm      - The `DM`
189d2b2dc1eSMatthew G. Knepley - useCeed - The flag
190d2b2dc1eSMatthew G. Knepley 
191d2b2dc1eSMatthew G. Knepley   Level: intermediate
192d2b2dc1eSMatthew G. Knepley 
193fe8e7dddSPierre Jolivet .seealso: `DMPlexGetUseCeed()`
194d2b2dc1eSMatthew G. Knepley @*/
DMPlexSetUseCeed(DM dm,PetscBool useCeed)195d2b2dc1eSMatthew G. Knepley PetscErrorCode DMPlexSetUseCeed(DM dm, PetscBool useCeed)
196d2b2dc1eSMatthew G. Knepley {
197d2b2dc1eSMatthew G. Knepley   PetscFunctionBegin;
198d2b2dc1eSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
199d2b2dc1eSMatthew G. Knepley   PetscValidLogicalCollectiveBool(dm, useCeed, 2);
200d2b2dc1eSMatthew G. Knepley   PetscUseMethod(dm, "DMPlexSetUseCeed_C", (DM, PetscBool), (dm, useCeed));
201d2b2dc1eSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
202d2b2dc1eSMatthew G. Knepley }
203d2b2dc1eSMatthew G. Knepley 
204e8e188d2SZach Atkins /*@
205e8e188d2SZach Atkins   DMPlexGetUseMatClosurePermutation - Get flag for using a closure permutation for matrix insertion
206e8e188d2SZach Atkins 
207e8e188d2SZach Atkins   Not collective
208e8e188d2SZach Atkins 
209e8e188d2SZach Atkins   Input Parameter:
210e8e188d2SZach Atkins . dm - The `DM`
211e8e188d2SZach Atkins 
212e8e188d2SZach Atkins   Output Parameter:
213e8e188d2SZach Atkins . useClPerm - The flag
214e8e188d2SZach Atkins 
215e8e188d2SZach Atkins   Level: intermediate
216e8e188d2SZach Atkins 
217e8e188d2SZach Atkins .seealso: `DMPlexSetUseMatClosurePermutation()`
218e8e188d2SZach Atkins @*/
DMPlexGetUseMatClosurePermutation(DM dm,PetscBool * useClPerm)219e8e188d2SZach Atkins PetscErrorCode DMPlexGetUseMatClosurePermutation(DM dm, PetscBool *useClPerm)
220e8e188d2SZach Atkins {
221e8e188d2SZach Atkins   DM_Plex *mesh = (DM_Plex *)dm->data;
222e8e188d2SZach Atkins 
223e8e188d2SZach Atkins   PetscFunctionBegin;
224e8e188d2SZach Atkins   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
225e8e188d2SZach Atkins   PetscAssertPointer(useClPerm, 2);
226e8e188d2SZach Atkins   *useClPerm = mesh->useMatClPerm;
227e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
228e8e188d2SZach Atkins }
229e8e188d2SZach Atkins 
230e8e188d2SZach Atkins /*@
231e8e188d2SZach Atkins   DMPlexSetUseMatClosurePermutation - Set flag for using a closure permutation for matrix insertion
232e8e188d2SZach Atkins 
233e8e188d2SZach Atkins   Not collective
234e8e188d2SZach Atkins 
235e8e188d2SZach Atkins   Input Parameters:
236e8e188d2SZach Atkins + dm        - The `DM`
237e8e188d2SZach Atkins - useClPerm - The flag
238e8e188d2SZach Atkins 
239e8e188d2SZach Atkins   Level: intermediate
240e8e188d2SZach Atkins 
241e8e188d2SZach Atkins .seealso: `DMPlexGetUseMatClosurePermutation()`
242e8e188d2SZach Atkins @*/
DMPlexSetUseMatClosurePermutation(DM dm,PetscBool useClPerm)243e8e188d2SZach Atkins PetscErrorCode DMPlexSetUseMatClosurePermutation(DM dm, PetscBool useClPerm)
244e8e188d2SZach Atkins {
245e8e188d2SZach Atkins   DM_Plex *mesh = (DM_Plex *)dm->data;
246e8e188d2SZach Atkins 
247e8e188d2SZach Atkins   PetscFunctionBegin;
248e8e188d2SZach Atkins   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
249e8e188d2SZach Atkins   PetscValidLogicalCollectiveBool(dm, useClPerm, 2);
250e8e188d2SZach Atkins   mesh->useMatClPerm = useClPerm;
251e8e188d2SZach Atkins   PetscFunctionReturn(PETSC_SUCCESS);
252e8e188d2SZach Atkins }
253e8e188d2SZach Atkins 
DMPlexProjectRigidBody_Private(PetscInt dim,PetscReal t,const PetscReal X[],PetscInt Nc,PetscScalar * mode,PetscCtx ctx)254*2a8381b2SBarry Smith static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, PetscCtx ctx)
255d71ae5a4SJacob Faibussowitsch {
2569371c9d4SSatish Balay   const PetscInt eps[3][3][3] = {
2579371c9d4SSatish Balay     {{0, 0, 0},  {0, 0, 1},  {0, -1, 0}},
2589371c9d4SSatish Balay     {{0, 0, -1}, {0, 0, 0},  {1, 0, 0} },
2599371c9d4SSatish Balay     {{0, 1, 0},  {-1, 0, 0}, {0, 0, 0} }
2609371c9d4SSatish Balay   };
261026175e5SToby Isaac   PetscInt *ctxInt = (PetscInt *)ctx;
262ad917190SMatthew G. Knepley   PetscInt  dim2   = ctxInt[0];
263026175e5SToby Isaac   PetscInt  d      = ctxInt[1];
264026175e5SToby Isaac   PetscInt  i, j, k = dim > 2 ? d - dim : d;
265026175e5SToby Isaac 
266ad917190SMatthew G. Knepley   PetscFunctionBegin;
26763a3b9bcSJacob Faibussowitsch   PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2);
268026175e5SToby Isaac   for (i = 0; i < dim; i++) mode[i] = 0.;
269026175e5SToby Isaac   if (d < dim) {
27012adca46SMatthew G. Knepley     mode[d] = 1.; /* Translation along axis d */
271ad917190SMatthew G. Knepley   } else {
272026175e5SToby Isaac     for (i = 0; i < dim; i++) {
273ac530a7eSPierre Jolivet       for (j = 0; j < dim; j++) mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */
274026175e5SToby Isaac     }
275026175e5SToby Isaac   }
2763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
277026175e5SToby Isaac }
278026175e5SToby Isaac 
279cc4e42d9SMartin Diehl /*@
28012adca46SMatthew G. Knepley   DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation
281cb1e1211SMatthew G Knepley 
28220f4b53cSBarry Smith   Collective
283cb1e1211SMatthew G Knepley 
2844165533cSJose E. Roman   Input Parameters:
285a1cb98faSBarry Smith + dm    - the `DM`
28656cf3b9cSMatthew G. Knepley - field - The field number for the rigid body space, or 0 for the default
287cb1e1211SMatthew G Knepley 
2884165533cSJose E. Roman   Output Parameter:
289cb1e1211SMatthew G Knepley . sp - the null space
290cb1e1211SMatthew G Knepley 
291cb1e1211SMatthew G Knepley   Level: advanced
292cb1e1211SMatthew G Knepley 
293a1cb98faSBarry Smith   Note:
294a1cb98faSBarry Smith   This is necessary to provide a suitable coarse space for algebraic multigrid
295a1cb98faSBarry Smith 
2961cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG`
297cb1e1211SMatthew G Knepley @*/
DMPlexCreateRigidBody(DM dm,PetscInt field,MatNullSpace * sp)298d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp)
299d71ae5a4SJacob Faibussowitsch {
30056cf3b9cSMatthew G. Knepley   PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *);
301cb1e1211SMatthew G Knepley   MPI_Comm     comm;
302026175e5SToby Isaac   Vec          mode[6];
303026175e5SToby Isaac   PetscSection section, globalSection;
30456cf3b9cSMatthew G. Knepley   PetscInt     dim, dimEmbed, Nf, n, m, mmin, d, i, j;
305db14aad5SMatthew G. Knepley   void       **ctxs;
306cb1e1211SMatthew G Knepley 
307cb1e1211SMatthew G Knepley   PetscFunctionBegin;
3089566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3099566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
3109566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
3119566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
31263a3b9bcSJacob Faibussowitsch   PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf);
31356cf3b9cSMatthew G. Knepley   if (dim == 1 && Nf < 2) {
3149566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp));
3153ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
316cb1e1211SMatthew G Knepley   }
3179566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
3189566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
3199566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n));
320db14aad5SMatthew G. Knepley   PetscCall(PetscCalloc2(Nf, &func, Nf, &ctxs));
321b247467aSMatthew G. Knepley   m = (dim * (dim + 1)) / 2;
3229566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &mode[0]));
3239566063dSJacob Faibussowitsch   PetscCall(VecSetType(mode[0], dm->vectype));
3249566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE));
3259566063dSJacob Faibussowitsch   PetscCall(VecSetUp(mode[0]));
3269566063dSJacob Faibussowitsch   PetscCall(VecGetSize(mode[0], &n));
327b247467aSMatthew G. Knepley   mmin        = PetscMin(m, n);
32856cf3b9cSMatthew G. Knepley   func[field] = DMPlexProjectRigidBody_Private;
3299566063dSJacob Faibussowitsch   for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i]));
330026175e5SToby Isaac   for (d = 0; d < m; d++) {
331330485fdSToby Isaac     PetscInt ctx[2];
332cb1e1211SMatthew G Knepley 
333db14aad5SMatthew G. Knepley     ctxs[field] = (void *)(&ctx[0]);
3349d8fbdeaSMatthew G. Knepley     ctx[0]      = dimEmbed;
335330485fdSToby Isaac     ctx[1]      = d;
336db14aad5SMatthew G. Knepley     PetscCall(DMProjectFunction(dm, 0.0, func, ctxs, INSERT_VALUES, mode[d]));
337cb1e1211SMatthew G Knepley   }
3383b2202bfSJacob Faibussowitsch   /* Orthonormalize system */
339b50a2c0aSJacob Faibussowitsch   for (i = 0; i < mmin; ++i) {
340b77f2eeeSJacob Faibussowitsch     PetscScalar dots[6];
3419c9054dfSZach Atkins     PetscReal   norm;
342b50a2c0aSJacob Faibussowitsch 
3439c9054dfSZach Atkins     PetscCall(VecNormalize(mode[i], &norm));
3449c9054dfSZach Atkins     if (PetscAbsReal(norm) <= PETSC_SQRT_MACHINE_EPSILON) {
3459c9054dfSZach Atkins       PetscCall(VecDestroy(&mode[i]));
3469c9054dfSZach Atkins       if (i < mmin - 1) {
3479c9054dfSZach Atkins         for (j = i; j < mmin - 1; j++) mode[j] = mode[j + 1];
3489c9054dfSZach Atkins         mode[mmin - 1] = NULL;
3499c9054dfSZach Atkins       }
3509c9054dfSZach Atkins       m--;
3519c9054dfSZach Atkins       mmin--;
3529c9054dfSZach Atkins       i--;
3539c9054dfSZach Atkins       continue;
3549c9054dfSZach Atkins     }
3559566063dSJacob Faibussowitsch     PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1));
356b50a2c0aSJacob Faibussowitsch     for (j = i + 1; j < mmin; ++j) {
357b77f2eeeSJacob Faibussowitsch       dots[j] *= -1.0;
3589566063dSJacob Faibussowitsch       PetscCall(VecAXPY(mode[j], dots[j], mode[i]));
359b50a2c0aSJacob Faibussowitsch     }
360cb1e1211SMatthew G Knepley   }
3619566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp));
3629566063dSJacob Faibussowitsch   for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i]));
363db14aad5SMatthew G. Knepley   PetscCall(PetscFree2(func, ctxs));
3643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
365cb1e1211SMatthew G Knepley }
366cb1e1211SMatthew G Knepley 
367cc4e42d9SMartin Diehl /*@
36812adca46SMatthew G. Knepley   DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation
36912adca46SMatthew G. Knepley 
37020f4b53cSBarry Smith   Collective
37112adca46SMatthew G. Knepley 
3724165533cSJose E. Roman   Input Parameters:
373a1cb98faSBarry Smith + dm    - the `DM`
37412adca46SMatthew G. Knepley . nb    - The number of bodies
375a1cb98faSBarry Smith . label - The `DMLabel` marking each domain
37612adca46SMatthew G. Knepley . nids  - The number of ids per body
37712adca46SMatthew G. Knepley - ids   - An array of the label ids in sequence for each domain
37812adca46SMatthew G. Knepley 
3794165533cSJose E. Roman   Output Parameter:
38012adca46SMatthew G. Knepley . sp - the null space
38112adca46SMatthew G. Knepley 
38212adca46SMatthew G. Knepley   Level: advanced
38312adca46SMatthew G. Knepley 
384a1cb98faSBarry Smith   Note:
385a1cb98faSBarry Smith   This is necessary to provide a suitable coarse space for algebraic multigrid
386a1cb98faSBarry Smith 
3871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`
38812adca46SMatthew G. Knepley @*/
DMPlexCreateRigidBodies(DM dm,PetscInt nb,DMLabel label,const PetscInt nids[],const PetscInt ids[],MatNullSpace * sp)389d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp)
390d71ae5a4SJacob Faibussowitsch {
39112adca46SMatthew G. Knepley   MPI_Comm     comm;
39212adca46SMatthew G. Knepley   PetscSection section, globalSection;
39312adca46SMatthew G. Knepley   Vec         *mode;
39412adca46SMatthew G. Knepley   PetscScalar *dots;
39512adca46SMatthew G. Knepley   PetscInt     dim, dimEmbed, n, m, b, d, i, j, off;
39612adca46SMatthew G. Knepley 
39712adca46SMatthew G. Knepley   PetscFunctionBegin;
3989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3999566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
4009566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
4019566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
4029566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
4039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n));
40412adca46SMatthew G. Knepley   m = nb * (dim * (dim + 1)) / 2;
4059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(m, &mode, m, &dots));
4069566063dSJacob Faibussowitsch   PetscCall(VecCreate(comm, &mode[0]));
4079566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE));
4089566063dSJacob Faibussowitsch   PetscCall(VecSetUp(mode[0]));
4099566063dSJacob Faibussowitsch   for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i]));
41012adca46SMatthew G. Knepley   for (b = 0, off = 0; b < nb; ++b) {
41112adca46SMatthew G. Knepley     for (d = 0; d < m / nb; ++d) {
41212adca46SMatthew G. Knepley       PetscInt ctx[2];
41312adca46SMatthew G. Knepley       PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private;
41412adca46SMatthew G. Knepley       void *voidctx                                                                                   = (void *)(&ctx[0]);
41512adca46SMatthew G. Knepley 
41612adca46SMatthew G. Knepley       ctx[0] = dimEmbed;
41712adca46SMatthew G. Knepley       ctx[1] = d;
4189566063dSJacob Faibussowitsch       PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]));
41912adca46SMatthew G. Knepley       off += nids[b];
42012adca46SMatthew G. Knepley     }
42112adca46SMatthew G. Knepley   }
4223b2202bfSJacob Faibussowitsch   /* Orthonormalize system */
423606c1a1cSJacob Faibussowitsch   for (i = 0; i < m; ++i) {
424b77f2eeeSJacob Faibussowitsch     PetscScalar dots[6];
4255a0e29b9SJacob Faibussowitsch 
4269566063dSJacob Faibussowitsch     PetscCall(VecNormalize(mode[i], NULL));
4279566063dSJacob Faibussowitsch     PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1));
4285a0e29b9SJacob Faibussowitsch     for (j = i + 1; j < m; ++j) {
429b77f2eeeSJacob Faibussowitsch       dots[j] *= -1.0;
4309566063dSJacob Faibussowitsch       PetscCall(VecAXPY(mode[j], dots[j], mode[i]));
4315a0e29b9SJacob Faibussowitsch     }
43212adca46SMatthew G. Knepley   }
4339566063dSJacob Faibussowitsch   PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp));
4349566063dSJacob Faibussowitsch   for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i]));
4359566063dSJacob Faibussowitsch   PetscCall(PetscFree2(mode, dots));
4363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43712adca46SMatthew G. Knepley }
43812adca46SMatthew G. Knepley 
439b29cfa1cSToby Isaac /*@
440b29cfa1cSToby Isaac   DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs
441b29cfa1cSToby Isaac   are computed by associating the basis function with one of the mesh points in its transitively-closed support, and
442a4e35b19SJacob Faibussowitsch   evaluating the dual space basis of that point.
443b29cfa1cSToby Isaac 
444b29cfa1cSToby Isaac   Input Parameters:
445a1cb98faSBarry Smith + dm     - the `DMPLEX` object
446b29cfa1cSToby Isaac - height - the maximum projection height >= 0
447b29cfa1cSToby Isaac 
448b29cfa1cSToby Isaac   Level: advanced
449b29cfa1cSToby Isaac 
450a4e35b19SJacob Faibussowitsch   Notes:
451a4e35b19SJacob Faibussowitsch   A basis function is associated with the point in its transitively-closed support whose mesh
452a4e35b19SJacob Faibussowitsch   height is highest (w.r.t. DAG height), but not greater than the maximum projection height,
453a4e35b19SJacob Faibussowitsch   which is set with this function.  By default, the maximum projection height is zero, which
454a4e35b19SJacob Faibussowitsch   means that only mesh cells are used to project basis functions.  A height of one, for
455a4e35b19SJacob Faibussowitsch   example, evaluates a cell-interior basis functions using its cells dual space basis, but all
456a4e35b19SJacob Faibussowitsch   other basis functions with the dual space basis of a face.
457a4e35b19SJacob Faibussowitsch 
4581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
459b29cfa1cSToby Isaac @*/
DMPlexSetMaxProjectionHeight(DM dm,PetscInt height)460d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height)
461d71ae5a4SJacob Faibussowitsch {
462b29cfa1cSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
463b29cfa1cSToby Isaac 
464b29cfa1cSToby Isaac   PetscFunctionBegin;
465b29cfa1cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
466b29cfa1cSToby Isaac   plex->maxProjectionHeight = height;
4673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
468b29cfa1cSToby Isaac }
469b29cfa1cSToby Isaac 
470b29cfa1cSToby Isaac /*@
471b29cfa1cSToby Isaac   DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in
472b29cfa1cSToby Isaac   DMPlexProjectXXXLocal() functions.
473b29cfa1cSToby Isaac 
4742fe279fdSBarry Smith   Input Parameter:
475a1cb98faSBarry Smith . dm - the `DMPLEX` object
476b29cfa1cSToby Isaac 
4772fe279fdSBarry Smith   Output Parameter:
478b29cfa1cSToby Isaac . height - the maximum projection height
479b29cfa1cSToby Isaac 
480b29cfa1cSToby Isaac   Level: intermediate
481b29cfa1cSToby Isaac 
4821cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`
483b29cfa1cSToby Isaac @*/
DMPlexGetMaxProjectionHeight(DM dm,PetscInt * height)484d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height)
485d71ae5a4SJacob Faibussowitsch {
486b29cfa1cSToby Isaac   DM_Plex *plex = (DM_Plex *)dm->data;
487b29cfa1cSToby Isaac 
488b29cfa1cSToby Isaac   PetscFunctionBegin;
489b29cfa1cSToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
490b29cfa1cSToby Isaac   *height = plex->maxProjectionHeight;
4913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
492b29cfa1cSToby Isaac }
493b29cfa1cSToby Isaac 
494ca3d3a14SMatthew G. Knepley typedef struct {
495ca3d3a14SMatthew G. Knepley   PetscReal    alpha; /* The first Euler angle, and in 2D the only one */
496ca3d3a14SMatthew G. Knepley   PetscReal    beta;  /* The second Euler angle */
497ca3d3a14SMatthew G. Knepley   PetscReal    gamma; /* The third Euler angle */
498ca3d3a14SMatthew G. Knepley   PetscInt     dim;   /* The dimension of R */
499ca3d3a14SMatthew G. Knepley   PetscScalar *R;     /* The rotation matrix, transforming a vector in the local basis to the global basis */
500ca3d3a14SMatthew G. Knepley   PetscScalar *RT;    /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */
501ca3d3a14SMatthew G. Knepley } RotCtx;
502ca3d3a14SMatthew G. Knepley 
503ca3d3a14SMatthew G. Knepley /*
504ca3d3a14SMatthew G. Knepley   Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
505ca3d3a14SMatthew 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:
506ca3d3a14SMatthew 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.
507ca3d3a14SMatthew 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.
508ca3d3a14SMatthew G. Knepley   $ The XYZ system rotates a third time about the z axis by gamma.
509ca3d3a14SMatthew G. Knepley */
DMPlexBasisTransformSetUp_Rotation_Internal(DM dm,PetscCtx ctx)510*2a8381b2SBarry Smith static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, PetscCtx ctx)
511d71ae5a4SJacob Faibussowitsch {
512ca3d3a14SMatthew G. Knepley   RotCtx   *rc  = (RotCtx *)ctx;
513ca3d3a14SMatthew G. Knepley   PetscInt  dim = rc->dim;
514ca3d3a14SMatthew G. Knepley   PetscReal c1, s1, c2, s2, c3, s3;
515ca3d3a14SMatthew G. Knepley 
516ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
5179566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT));
518ca3d3a14SMatthew G. Knepley   switch (dim) {
519ca3d3a14SMatthew G. Knepley   case 2:
5209371c9d4SSatish Balay     c1       = PetscCosReal(rc->alpha);
5219371c9d4SSatish Balay     s1       = PetscSinReal(rc->alpha);
5229371c9d4SSatish Balay     rc->R[0] = c1;
5239371c9d4SSatish Balay     rc->R[1] = s1;
5249371c9d4SSatish Balay     rc->R[2] = -s1;
5259371c9d4SSatish Balay     rc->R[3] = c1;
5269566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim)));
527b458e8f1SJose E. Roman     DMPlex_Transpose2D_Internal(rc->RT);
528ca3d3a14SMatthew G. Knepley     break;
529ca3d3a14SMatthew G. Knepley   case 3:
5309371c9d4SSatish Balay     c1       = PetscCosReal(rc->alpha);
5319371c9d4SSatish Balay     s1       = PetscSinReal(rc->alpha);
5329371c9d4SSatish Balay     c2       = PetscCosReal(rc->beta);
5339371c9d4SSatish Balay     s2       = PetscSinReal(rc->beta);
5349371c9d4SSatish Balay     c3       = PetscCosReal(rc->gamma);
5359371c9d4SSatish Balay     s3       = PetscSinReal(rc->gamma);
5369371c9d4SSatish Balay     rc->R[0] = c1 * c3 - c2 * s1 * s3;
5379371c9d4SSatish Balay     rc->R[1] = c3 * s1 + c1 * c2 * s3;
5389371c9d4SSatish Balay     rc->R[2] = s2 * s3;
5399371c9d4SSatish Balay     rc->R[3] = -c1 * s3 - c2 * c3 * s1;
5409371c9d4SSatish Balay     rc->R[4] = c1 * c2 * c3 - s1 * s3;
5419371c9d4SSatish Balay     rc->R[5] = c3 * s2;
5429371c9d4SSatish Balay     rc->R[6] = s1 * s2;
5439371c9d4SSatish Balay     rc->R[7] = -c1 * s2;
5449371c9d4SSatish Balay     rc->R[8] = c2;
5459566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim)));
546b458e8f1SJose E. Roman     DMPlex_Transpose3D_Internal(rc->RT);
547ca3d3a14SMatthew G. Knepley     break;
548d71ae5a4SJacob Faibussowitsch   default:
549d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim);
550ca3d3a14SMatthew G. Knepley   }
5513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
552ca3d3a14SMatthew G. Knepley }
553ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformDestroy_Rotation_Internal(DM dm,PetscCtx ctx)554*2a8381b2SBarry Smith static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, PetscCtx ctx)
555d71ae5a4SJacob Faibussowitsch {
556ca3d3a14SMatthew G. Knepley   RotCtx *rc = (RotCtx *)ctx;
557ca3d3a14SMatthew G. Knepley 
558ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
5599566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rc->R, rc->RT));
5609566063dSJacob Faibussowitsch   PetscCall(PetscFree(rc));
5613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
562ca3d3a14SMatthew G. Knepley }
563ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm,const PetscReal x[],PetscBool l2g,const PetscScalar ** A,PetscCtx ctx)564*2a8381b2SBarry Smith static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, PetscCtx ctx)
565d71ae5a4SJacob Faibussowitsch {
566ca3d3a14SMatthew G. Knepley   RotCtx *rc = (RotCtx *)ctx;
567ca3d3a14SMatthew G. Knepley 
568ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
5694f572ea9SToby Isaac   PetscAssertPointer(ctx, 5);
5709371c9d4SSatish Balay   if (l2g) {
5719371c9d4SSatish Balay     *A = rc->R;
5729371c9d4SSatish Balay   } else {
5739371c9d4SSatish Balay     *A = rc->RT;
5749371c9d4SSatish Balay   }
5753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
576ca3d3a14SMatthew G. Knepley }
577ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformApplyReal_Internal(DM dm,const PetscReal x[],PetscBool l2g,PetscInt dim,const PetscReal * y,PetscReal * z,PetscCtx ctx)578*2a8381b2SBarry Smith PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, PetscCtx ctx)
579d71ae5a4SJacob Faibussowitsch {
580ec277c0fSMatthew G. Knepley   PetscFunctionBegin;
581ab6a9622SMatthew G. Knepley #if defined(PETSC_USE_COMPLEX)
582ab6a9622SMatthew G. Knepley   switch (dim) {
5839371c9d4SSatish Balay   case 2: {
58427104ee2SJacob Faibussowitsch     PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0};
585ab6a9622SMatthew G. Knepley 
5869566063dSJacob Faibussowitsch     PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx));
5879371c9d4SSatish Balay     z[0] = PetscRealPart(zt[0]);
5889371c9d4SSatish Balay     z[1] = PetscRealPart(zt[1]);
5899371c9d4SSatish Balay   } break;
5909371c9d4SSatish Balay   case 3: {
59127104ee2SJacob Faibussowitsch     PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0};
592ab6a9622SMatthew G. Knepley 
5939566063dSJacob Faibussowitsch     PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx));
5949371c9d4SSatish Balay     z[0] = PetscRealPart(zt[0]);
5959371c9d4SSatish Balay     z[1] = PetscRealPart(zt[1]);
5969371c9d4SSatish Balay     z[2] = PetscRealPart(zt[2]);
5979371c9d4SSatish Balay   } break;
598ab6a9622SMatthew G. Knepley   }
599ab6a9622SMatthew G. Knepley #else
6009566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx));
601ab6a9622SMatthew G. Knepley #endif
6023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
603ab6a9622SMatthew G. Knepley }
604ab6a9622SMatthew G. Knepley 
DMPlexBasisTransformApply_Internal(DM dm,const PetscReal x[],PetscBool l2g,PetscInt dim,const PetscScalar * y,PetscScalar * z,PetscCtx ctx)605*2a8381b2SBarry Smith PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, PetscCtx ctx)
606d71ae5a4SJacob Faibussowitsch {
607ca3d3a14SMatthew G. Knepley   const PetscScalar *A;
608ca3d3a14SMatthew G. Knepley 
609ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
6109566063dSJacob Faibussowitsch   PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx));
611ca3d3a14SMatthew G. Knepley   switch (dim) {
612d71ae5a4SJacob Faibussowitsch   case 2:
613d71ae5a4SJacob Faibussowitsch     DMPlex_Mult2D_Internal(A, 1, y, z);
614d71ae5a4SJacob Faibussowitsch     break;
615d71ae5a4SJacob Faibussowitsch   case 3:
616d71ae5a4SJacob Faibussowitsch     DMPlex_Mult3D_Internal(A, 1, y, z);
617d71ae5a4SJacob Faibussowitsch     break;
618ca3d3a14SMatthew G. Knepley   }
6193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
620ca3d3a14SMatthew G. Knepley }
621ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformField_Internal(DM dm,DM tdm,Vec tv,PetscInt p,PetscInt f,PetscBool l2g,PetscScalar * a)622d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a)
623d71ae5a4SJacob Faibussowitsch {
624ca3d3a14SMatthew G. Knepley   PetscSection       ts;
625ca3d3a14SMatthew G. Knepley   const PetscScalar *ta, *tva;
626ca3d3a14SMatthew G. Knepley   PetscInt           dof;
627ca3d3a14SMatthew G. Knepley 
628ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
6299566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
6309566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
6319566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
6329566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva));
633ca3d3a14SMatthew G. Knepley   if (l2g) {
634ca3d3a14SMatthew G. Knepley     switch (dof) {
635d71ae5a4SJacob Faibussowitsch     case 4:
636d71ae5a4SJacob Faibussowitsch       DMPlex_Mult2D_Internal(tva, 1, a, a);
637d71ae5a4SJacob Faibussowitsch       break;
638d71ae5a4SJacob Faibussowitsch     case 9:
639d71ae5a4SJacob Faibussowitsch       DMPlex_Mult3D_Internal(tva, 1, a, a);
640d71ae5a4SJacob Faibussowitsch       break;
641ca3d3a14SMatthew G. Knepley     }
642ca3d3a14SMatthew G. Knepley   } else {
643ca3d3a14SMatthew G. Knepley     switch (dof) {
644d71ae5a4SJacob Faibussowitsch     case 4:
645d71ae5a4SJacob Faibussowitsch       DMPlex_MultTranspose2D_Internal(tva, 1, a, a);
646d71ae5a4SJacob Faibussowitsch       break;
647d71ae5a4SJacob Faibussowitsch     case 9:
648d71ae5a4SJacob Faibussowitsch       DMPlex_MultTranspose3D_Internal(tva, 1, a, a);
649d71ae5a4SJacob Faibussowitsch       break;
650ca3d3a14SMatthew G. Knepley     }
651ca3d3a14SMatthew G. Knepley   }
6529566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
6533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
654ca3d3a14SMatthew G. Knepley }
655ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformFieldTensor_Internal(DM dm,DM tdm,Vec tv,PetscInt pf,PetscInt f,PetscInt pg,PetscInt g,PetscBool l2g,PetscInt lda,PetscScalar * a)656d71ae5a4SJacob 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)
657d71ae5a4SJacob Faibussowitsch {
658ca3d3a14SMatthew G. Knepley   PetscSection       s, ts;
659ca3d3a14SMatthew G. Knepley   const PetscScalar *ta, *tvaf, *tvag;
660ca3d3a14SMatthew G. Knepley   PetscInt           fdof, gdof, fpdof, gpdof;
661ca3d3a14SMatthew G. Knepley 
662ca3d3a14SMatthew G. Knepley   PetscFunctionBeginHot;
6639566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
6649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
6659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof));
6669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof));
6679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof));
6689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof));
6699566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
6709566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf));
6719566063dSJacob Faibussowitsch   PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag));
672ca3d3a14SMatthew G. Knepley   if (l2g) {
673ca3d3a14SMatthew G. Knepley     switch (fdof) {
674d71ae5a4SJacob Faibussowitsch     case 4:
675d71ae5a4SJacob Faibussowitsch       DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);
676d71ae5a4SJacob Faibussowitsch       break;
677d71ae5a4SJacob Faibussowitsch     case 9:
678d71ae5a4SJacob Faibussowitsch       DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);
679d71ae5a4SJacob Faibussowitsch       break;
680ca3d3a14SMatthew G. Knepley     }
681ca3d3a14SMatthew G. Knepley     switch (gdof) {
682d71ae5a4SJacob Faibussowitsch     case 4:
683d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);
684d71ae5a4SJacob Faibussowitsch       break;
685d71ae5a4SJacob Faibussowitsch     case 9:
686d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);
687d71ae5a4SJacob Faibussowitsch       break;
688ca3d3a14SMatthew G. Knepley     }
689ca3d3a14SMatthew G. Knepley   } else {
690ca3d3a14SMatthew G. Knepley     switch (fdof) {
691d71ae5a4SJacob Faibussowitsch     case 4:
692d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);
693d71ae5a4SJacob Faibussowitsch       break;
694d71ae5a4SJacob Faibussowitsch     case 9:
695d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);
696d71ae5a4SJacob Faibussowitsch       break;
697ca3d3a14SMatthew G. Knepley     }
698ca3d3a14SMatthew G. Knepley     switch (gdof) {
699d71ae5a4SJacob Faibussowitsch     case 4:
700d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);
701d71ae5a4SJacob Faibussowitsch       break;
702d71ae5a4SJacob Faibussowitsch     case 9:
703d71ae5a4SJacob Faibussowitsch       DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);
704d71ae5a4SJacob Faibussowitsch       break;
705ca3d3a14SMatthew G. Knepley     }
706ca3d3a14SMatthew G. Knepley   }
7079566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
7083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
709ca3d3a14SMatthew G. Knepley }
710ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformPoint_Internal(DM dm,DM tdm,Vec tv,PetscInt p,PetscBool fieldActive[],PetscBool l2g,PetscScalar * a)711d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a)
712d71ae5a4SJacob Faibussowitsch {
713ca3d3a14SMatthew G. Knepley   PetscSection    s;
714ca3d3a14SMatthew G. Knepley   PetscSection    clSection;
715ca3d3a14SMatthew G. Knepley   IS              clPoints;
716ca3d3a14SMatthew G. Knepley   const PetscInt *clp;
717ca3d3a14SMatthew G. Knepley   PetscInt       *points = NULL;
718ca3d3a14SMatthew G. Knepley   PetscInt        Nf, f, Np, cp, dof, d = 0;
719ca3d3a14SMatthew G. Knepley 
720ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
7219566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
7229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
72307218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp));
724ca3d3a14SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
725ca3d3a14SMatthew G. Knepley     for (cp = 0; cp < Np * 2; cp += 2) {
7269566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof));
727ca3d3a14SMatthew G. Knepley       if (!dof) continue;
7289566063dSJacob Faibussowitsch       if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]));
729ca3d3a14SMatthew G. Knepley       d += dof;
730ca3d3a14SMatthew G. Knepley     }
731ca3d3a14SMatthew G. Knepley   }
7329566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
7333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
734ca3d3a14SMatthew G. Knepley }
735ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransformPointTensor_Internal(DM dm,DM tdm,Vec tv,PetscInt p,PetscBool l2g,PetscInt lda,PetscScalar * a)736d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a)
737d71ae5a4SJacob Faibussowitsch {
738ca3d3a14SMatthew G. Knepley   PetscSection    s;
739ca3d3a14SMatthew G. Knepley   PetscSection    clSection;
740ca3d3a14SMatthew G. Knepley   IS              clPoints;
741ca3d3a14SMatthew G. Knepley   const PetscInt *clp;
742ca3d3a14SMatthew G. Knepley   PetscInt       *points = NULL;
7438bdb3c71SMatthew G. Knepley   PetscInt        Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0;
744ca3d3a14SMatthew G. Knepley 
745ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
7469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
7479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
74807218a29SMatthew G. Knepley   PetscCall(DMPlexGetCompressedClosure(dm, s, p, 0, &Np, &points, &clSection, &clPoints, &clp));
749ca3d3a14SMatthew G. Knepley   for (f = 0, r = 0; f < Nf; ++f) {
750ca3d3a14SMatthew G. Knepley     for (cpf = 0; cpf < Np * 2; cpf += 2) {
7519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof));
752ca3d3a14SMatthew G. Knepley       for (g = 0, c = 0; g < Nf; ++g) {
753ca3d3a14SMatthew G. Knepley         for (cpg = 0; cpg < Np * 2; cpg += 2) {
7549566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof));
7559566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c]));
756ca3d3a14SMatthew G. Knepley           c += gdof;
757ca3d3a14SMatthew G. Knepley         }
758ca3d3a14SMatthew G. Knepley       }
75963a3b9bcSJacob Faibussowitsch       PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda);
760ca3d3a14SMatthew G. Knepley       r += fdof;
761ca3d3a14SMatthew G. Knepley     }
762ca3d3a14SMatthew G. Knepley   }
76363a3b9bcSJacob Faibussowitsch   PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda);
7649566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp));
7653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
766ca3d3a14SMatthew G. Knepley }
767ca3d3a14SMatthew G. Knepley 
DMPlexBasisTransform_Internal(DM dm,Vec lv,PetscBool l2g)768d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g)
769d71ae5a4SJacob Faibussowitsch {
770ca3d3a14SMatthew G. Knepley   DM                 tdm;
771ca3d3a14SMatthew G. Knepley   Vec                tv;
772ca3d3a14SMatthew G. Knepley   PetscSection       ts, s;
773ca3d3a14SMatthew G. Knepley   const PetscScalar *ta;
774ca3d3a14SMatthew G. Knepley   PetscScalar       *a, *va;
775ca3d3a14SMatthew G. Knepley   PetscInt           pStart, pEnd, p, Nf, f;
776ca3d3a14SMatthew G. Knepley 
777ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
7789566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
7799566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
7809566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(tdm, &ts));
7819566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &s));
7829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
7839566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(s, &Nf));
7849566063dSJacob Faibussowitsch   PetscCall(VecGetArray(lv, &a));
7859566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(tv, &ta));
786ca3d3a14SMatthew G. Knepley   for (p = pStart; p < pEnd; ++p) {
787ca3d3a14SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
7889566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va));
7899566063dSJacob Faibussowitsch       PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va));
790ca3d3a14SMatthew G. Knepley     }
791ca3d3a14SMatthew G. Knepley   }
7929566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(lv, &a));
7939566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(tv, &ta));
7943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
795ca3d3a14SMatthew G. Knepley }
796ca3d3a14SMatthew G. Knepley 
797ca3d3a14SMatthew G. Knepley /*@
798ca3d3a14SMatthew G. Knepley   DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis
799ca3d3a14SMatthew G. Knepley 
800ca3d3a14SMatthew G. Knepley   Input Parameters:
801a1cb98faSBarry Smith + dm - The `DM`
802ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the global basis
803ca3d3a14SMatthew G. Knepley 
8042fe279fdSBarry Smith   Output Parameter:
805ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the local basis
806ca3d3a14SMatthew G. Knepley 
807ca3d3a14SMatthew G. Knepley   Level: developer
808ca3d3a14SMatthew G. Knepley 
809a1cb98faSBarry Smith   Note:
810a1cb98faSBarry 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.
811a1cb98faSBarry Smith 
8121cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
813ca3d3a14SMatthew G. Knepley @*/
DMPlexGlobalToLocalBasis(DM dm,Vec lv)814d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv)
815d71ae5a4SJacob Faibussowitsch {
816ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
817ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
818ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(lv, VEC_CLASSID, 2);
8199566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE));
8203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
821ca3d3a14SMatthew G. Knepley }
822ca3d3a14SMatthew G. Knepley 
823ca3d3a14SMatthew G. Knepley /*@
824ca3d3a14SMatthew G. Knepley   DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis
825ca3d3a14SMatthew G. Knepley 
826ca3d3a14SMatthew G. Knepley   Input Parameters:
827a1cb98faSBarry Smith + dm - The `DM`
828ca3d3a14SMatthew G. Knepley - lv - A local vector with values in the local basis
829ca3d3a14SMatthew G. Knepley 
8302fe279fdSBarry Smith   Output Parameter:
831ca3d3a14SMatthew G. Knepley . lv - A local vector with values in the global basis
832ca3d3a14SMatthew G. Knepley 
833ca3d3a14SMatthew G. Knepley   Level: developer
834ca3d3a14SMatthew G. Knepley 
835a1cb98faSBarry Smith   Note:
836a1cb98faSBarry 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.
837a1cb98faSBarry Smith 
8381cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()`
839ca3d3a14SMatthew G. Knepley @*/
DMPlexLocalToGlobalBasis(DM dm,Vec lv)840d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv)
841d71ae5a4SJacob Faibussowitsch {
842ca3d3a14SMatthew G. Knepley   PetscFunctionBegin;
843ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
844ca3d3a14SMatthew G. Knepley   PetscValidHeaderSpecific(lv, VEC_CLASSID, 2);
8459566063dSJacob Faibussowitsch   PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE));
8463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
847ca3d3a14SMatthew G. Knepley }
848ca3d3a14SMatthew G. Knepley 
849ca3d3a14SMatthew G. Knepley /*@
850ca3d3a14SMatthew G. Knepley   DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions
851ca3d3a14SMatthew G. Knepley   and global solutions, to a local basis, appropriate for discretization integrals and assembly.
852ca3d3a14SMatthew G. Knepley 
853ca3d3a14SMatthew G. Knepley   Input Parameters:
854a1cb98faSBarry Smith + dm    - The `DM`
855ca3d3a14SMatthew G. Knepley . alpha - The first Euler angle, and in 2D the only one
856ca3d3a14SMatthew G. Knepley . beta  - The second Euler angle
857f0fc11ceSJed Brown - gamma - The third Euler angle
858ca3d3a14SMatthew G. Knepley 
859ca3d3a14SMatthew G. Knepley   Level: developer
860ca3d3a14SMatthew G. Knepley 
861a1cb98faSBarry Smith   Note:
862a1cb98faSBarry Smith   Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that
863a1cb98faSBarry 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
864a1cb98faSBarry Smith .vb
865a1cb98faSBarry 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.
866a1cb98faSBarry 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.
867a1cb98faSBarry Smith    The XYZ system rotates a third time about the z axis by gamma.
868a1cb98faSBarry Smith .ve
869a1cb98faSBarry Smith 
8701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`
871ca3d3a14SMatthew G. Knepley @*/
DMPlexCreateBasisRotation(DM dm,PetscReal alpha,PetscReal beta,PetscReal gamma)872d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma)
873d71ae5a4SJacob Faibussowitsch {
874ca3d3a14SMatthew G. Knepley   RotCtx  *rc;
875ca3d3a14SMatthew G. Knepley   PetscInt cdim;
876ca3d3a14SMatthew G. Knepley 
877362febeeSStefano Zampini   PetscFunctionBegin;
8789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
8799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(1, &rc));
880ca3d3a14SMatthew G. Knepley   dm->transformCtx       = rc;
881ca3d3a14SMatthew G. Knepley   dm->transformSetUp     = DMPlexBasisTransformSetUp_Rotation_Internal;
882ca3d3a14SMatthew G. Knepley   dm->transformDestroy   = DMPlexBasisTransformDestroy_Rotation_Internal;
883ca3d3a14SMatthew G. Knepley   dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal;
884ca3d3a14SMatthew G. Knepley   rc->dim                = cdim;
885ca3d3a14SMatthew G. Knepley   rc->alpha              = alpha;
886ca3d3a14SMatthew G. Knepley   rc->beta               = beta;
887ca3d3a14SMatthew G. Knepley   rc->gamma              = gamma;
8889566063dSJacob Faibussowitsch   PetscCall((*dm->transformSetUp)(dm, dm->transformCtx));
8899566063dSJacob Faibussowitsch   PetscCall(DMConstructBasisTransform_Internal(dm));
8903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
891ca3d3a14SMatthew G. Knepley }
892ca3d3a14SMatthew G. Knepley 
893b278463cSMatthew G. Knepley /*@C
894ece3a9fcSMatthew G. Knepley   DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates
895b278463cSMatthew G. Knepley 
896b278463cSMatthew G. Knepley   Input Parameters:
897a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
898b278463cSMatthew G. Knepley . time   - The time
899b278463cSMatthew G. Knepley . field  - The field to constrain
9001c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
90120f4b53cSBarry Smith . comps  - An array of constrained component numbers, or `NULL` for all components
902a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
903a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
904b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
905b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
906*2a8381b2SBarry Smith - ctx    - An optional application context for `bcFunc`
907b278463cSMatthew G. Knepley 
908b278463cSMatthew G. Knepley   Output Parameter:
909b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values
910b278463cSMatthew G. Knepley 
911b278463cSMatthew G. Knepley   Level: developer
912b278463cSMatthew G. Knepley 
9131cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
914b278463cSMatthew G. Knepley @*/
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 *),PetscCtx ctx,Vec locX)915*2a8381b2SBarry Smith 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 *), PetscCtx ctx, Vec locX)
916d71ae5a4SJacob Faibussowitsch {
917*2a8381b2SBarry Smith   PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, PetscCtx ctx);
91855f2e967SMatthew G. Knepley   void   **ctxs;
919d7ddef95SMatthew G. Knepley   PetscInt numFields;
920d7ddef95SMatthew G. Knepley 
921d7ddef95SMatthew G. Knepley   PetscFunctionBegin;
9229566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
9239566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
924d7ddef95SMatthew G. Knepley   funcs[field] = func;
925d7ddef95SMatthew G. Knepley   ctxs[field]  = ctx;
9269566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX));
9279566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
9283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
929d7ddef95SMatthew G. Knepley }
930d7ddef95SMatthew G. Knepley 
931b278463cSMatthew G. Knepley /*@C
932ece3a9fcSMatthew G. Knepley   DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data
933b278463cSMatthew G. Knepley 
934b278463cSMatthew G. Knepley   Input Parameters:
935a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
936b278463cSMatthew G. Knepley . time   - The time
937b278463cSMatthew G. Knepley . locU   - A local vector with the input solution values
938b278463cSMatthew G. Knepley . field  - The field to constrain
9391c531cf8SMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
94020f4b53cSBarry Smith . comps  - An array of constrained component numbers, or `NULL` for all components
941a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
942a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
943b278463cSMatthew G. Knepley . ids    - An array of ids for constrained points
944b278463cSMatthew G. Knepley . func   - A pointwise function giving boundary values
945*2a8381b2SBarry Smith - ctx    - An optional application context for `bcFunc`
946b278463cSMatthew G. Knepley 
947b278463cSMatthew G. Knepley   Output Parameter:
948b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values
949b278463cSMatthew G. Knepley 
950b278463cSMatthew G. Knepley   Level: developer
951b278463cSMatthew G. Knepley 
9521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()`
953b278463cSMatthew G. Knepley @*/
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[]),PetscCtx ctx,Vec locX)954*2a8381b2SBarry Smith 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[]), PetscCtx ctx, Vec locX)
955d71ae5a4SJacob Faibussowitsch {
9569371c9d4SSatish 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[]);
957c60e475cSMatthew G. Knepley   void   **ctxs;
958c60e475cSMatthew G. Knepley   PetscInt numFields;
959c60e475cSMatthew G. Knepley 
960c60e475cSMatthew G. Knepley   PetscFunctionBegin;
9619566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
9629566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
963c60e475cSMatthew G. Knepley   funcs[field] = func;
964c60e475cSMatthew G. Knepley   ctxs[field]  = ctx;
9659566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX));
9669566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
9673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
968c60e475cSMatthew G. Knepley }
969c60e475cSMatthew G. Knepley 
970b278463cSMatthew G. Knepley /*@C
971d5b43468SJose E. Roman   DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data
972ece3a9fcSMatthew G. Knepley 
97320f4b53cSBarry Smith   Collective
974ece3a9fcSMatthew G. Knepley 
975ece3a9fcSMatthew G. Knepley   Input Parameters:
976a1cb98faSBarry Smith + dm     - The `DM`, with a `PetscDS` that matches the problem being constrained
977ece3a9fcSMatthew G. Knepley . time   - The time
978ece3a9fcSMatthew G. Knepley . locU   - A local vector with the input solution values
979ece3a9fcSMatthew G. Knepley . field  - The field to constrain
980ece3a9fcSMatthew G. Knepley . Nc     - The number of constrained field components, or 0 for all components
98120f4b53cSBarry Smith . comps  - An array of constrained component numbers, or `NULL` for all components
982a1cb98faSBarry Smith . label  - The `DMLabel` defining constrained points
983a1cb98faSBarry Smith . numids - The number of `DMLabel` ids for constrained points
984ece3a9fcSMatthew G. Knepley . ids    - An array of ids for constrained points
98520f4b53cSBarry Smith . func   - A pointwise function giving boundary values, the calling sequence is given in `DMProjectBdFieldLabelLocal()`
986*2a8381b2SBarry Smith - ctx    - An optional application context for `func`
987ece3a9fcSMatthew G. Knepley 
988ece3a9fcSMatthew G. Knepley   Output Parameter:
989ece3a9fcSMatthew G. Knepley . locX - A local vector to receive the boundary values
990ece3a9fcSMatthew G. Knepley 
991ece3a9fcSMatthew G. Knepley   Level: developer
992ece3a9fcSMatthew G. Knepley 
9931cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
994ece3a9fcSMatthew G. Knepley @*/
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[]),PetscCtx ctx,Vec locX)995*2a8381b2SBarry Smith 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[]), PetscCtx ctx, Vec locX)
996d71ae5a4SJacob Faibussowitsch {
9979371c9d4SSatish 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[]);
998ece3a9fcSMatthew G. Knepley   void   **ctxs;
999ece3a9fcSMatthew G. Knepley   PetscInt numFields;
1000ece3a9fcSMatthew G. Knepley 
1001ece3a9fcSMatthew G. Knepley   PetscFunctionBegin;
10029566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
10039566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs));
1004ece3a9fcSMatthew G. Knepley   funcs[field] = func;
1005ece3a9fcSMatthew G. Knepley   ctxs[field]  = ctx;
10069566063dSJacob Faibussowitsch   PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX));
10079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(funcs, ctxs));
10083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1009ece3a9fcSMatthew G. Knepley }
1010ece3a9fcSMatthew G. Knepley 
1011ece3a9fcSMatthew G. Knepley /*@C
1012b278463cSMatthew G. Knepley   DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector
1013b278463cSMatthew G. Knepley 
1014b278463cSMatthew G. Knepley   Input Parameters:
1015a1cb98faSBarry Smith + dm           - The `DM`, with a `PetscDS` that matches the problem being constrained
1016b278463cSMatthew G. Knepley . time         - The time
1017b278463cSMatthew G. Knepley . faceGeometry - A vector with the FVM face geometry information
1018b278463cSMatthew G. Knepley . cellGeometry - A vector with the FVM cell geometry information
1019b278463cSMatthew G. Knepley . Grad         - A vector with the FVM cell gradient information
1020b278463cSMatthew G. Knepley . field        - The field to constrain
10211c531cf8SMatthew G. Knepley . Nc           - The number of constrained field components, or 0 for all components
102220f4b53cSBarry Smith . comps        - An array of constrained component numbers, or `NULL` for all components
1023a1cb98faSBarry Smith . label        - The `DMLabel` defining constrained points
1024a1cb98faSBarry Smith . numids       - The number of `DMLabel` ids for constrained points
1025b278463cSMatthew G. Knepley . ids          - An array of ids for constrained points
1026b278463cSMatthew G. Knepley . func         - A pointwise function giving boundary values
1027*2a8381b2SBarry Smith - ctx          - An optional application context for bcFunc
1028b278463cSMatthew G. Knepley 
1029b278463cSMatthew G. Knepley   Output Parameter:
1030b278463cSMatthew G. Knepley . locX - A local vector to receives the boundary values
1031b278463cSMatthew G. Knepley 
1032b278463cSMatthew G. Knepley   Level: developer
1033b278463cSMatthew G. Knepley 
1034a1cb98faSBarry Smith   Note:
1035a1cb98faSBarry Smith   This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()`
1036a1cb98faSBarry Smith 
10371cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()`
1038b278463cSMatthew G. Knepley @*/
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 *),PetscCtx ctx,Vec locX)1039*2a8381b2SBarry Smith 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 *), PetscCtx ctx, Vec locX)
1040d71ae5a4SJacob Faibussowitsch {
104161f58d28SMatthew G. Knepley   PetscDS            prob;
1042da97024aSMatthew G. Knepley   PetscSF            sf;
1043d7ddef95SMatthew G. Knepley   DM                 dmFace, dmCell, dmGrad;
104420369375SToby Isaac   const PetscScalar *facegeom, *cellgeom = NULL, *grad;
1045da97024aSMatthew G. Knepley   const PetscInt    *leaves;
1046d7ddef95SMatthew G. Knepley   PetscScalar       *x, *fx;
1047520b3818SMatthew G. Knepley   PetscInt           dim, nleaves, loc, fStart, fEnd, pdim, i;
10483ba16761SJacob Faibussowitsch   PetscErrorCode     ierru = PETSC_SUCCESS;
1049d7ddef95SMatthew G. Knepley 
1050d7ddef95SMatthew G. Knepley   PetscFunctionBegin;
10519566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &sf));
10529566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
1053da97024aSMatthew G. Knepley   nleaves = PetscMax(0, nleaves);
10549566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
10559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
10569566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
10579566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
10589566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
105920369375SToby Isaac   if (cellGeometry) {
10609566063dSJacob Faibussowitsch     PetscCall(VecGetDM(cellGeometry, &dmCell));
10619566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
106220369375SToby Isaac   }
1063d7ddef95SMatthew G. Knepley   if (Grad) {
1064c0a6632aSMatthew G. Knepley     PetscFV fv;
1065c0a6632aSMatthew G. Knepley 
10669566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv));
10679566063dSJacob Faibussowitsch     PetscCall(VecGetDM(Grad, &dmGrad));
10689566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(Grad, &grad));
10699566063dSJacob Faibussowitsch     PetscCall(PetscFVGetNumComponents(fv, &pdim));
10709566063dSJacob Faibussowitsch     PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx));
1071d7ddef95SMatthew G. Knepley   }
10729566063dSJacob Faibussowitsch   PetscCall(VecGetArray(locX, &x));
1073d7ddef95SMatthew G. Knepley   for (i = 0; i < numids; ++i) {
1074d7ddef95SMatthew G. Knepley     IS              faceIS;
1075d7ddef95SMatthew G. Knepley     const PetscInt *faces;
1076d7ddef95SMatthew G. Knepley     PetscInt        numFaces, f;
1077d7ddef95SMatthew G. Knepley 
10789566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS));
1079d7ddef95SMatthew G. Knepley     if (!faceIS) continue; /* No points with that id on this process */
10809566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(faceIS, &numFaces));
10819566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(faceIS, &faces));
1082d7ddef95SMatthew G. Knepley     for (f = 0; f < numFaces; ++f) {
1083d7ddef95SMatthew G. Knepley       const PetscInt   face = faces[f], *cells;
1084640bce14SSatish Balay       PetscFVFaceGeom *fg;
1085d7ddef95SMatthew G. Knepley 
1086d7ddef95SMatthew G. Knepley       if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */
10879566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc));
1088da97024aSMatthew G. Knepley       if (loc >= 0) continue;
10899566063dSJacob Faibussowitsch       PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
10909566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, face, &cells));
1091d7ddef95SMatthew G. Knepley       if (Grad) {
1092640bce14SSatish Balay         PetscFVCellGeom *cg;
1093640bce14SSatish Balay         PetscScalar     *cx, *cgrad;
1094d7ddef95SMatthew G. Knepley         PetscScalar     *xG;
1095d7ddef95SMatthew G. Knepley         PetscReal        dx[3];
1096d7ddef95SMatthew G. Knepley         PetscInt         d;
1097d7ddef95SMatthew G. Knepley 
10989566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg));
10999566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx));
11009566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad));
11019566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG));
1102d7ddef95SMatthew G. Knepley         DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx);
1103d7ddef95SMatthew G. Knepley         for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx);
11049566063dSJacob Faibussowitsch         PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx));
1105d7ddef95SMatthew G. Knepley       } else {
1106640bce14SSatish Balay         PetscScalar *xI;
1107d7ddef95SMatthew G. Knepley         PetscScalar *xG;
1108d7ddef95SMatthew G. Knepley 
11099566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI));
11109566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG));
1111e735a8a9SMatthew G. Knepley         ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);
1112e735a8a9SMatthew G. Knepley         if (ierru) {
11139566063dSJacob Faibussowitsch           PetscCall(ISRestoreIndices(faceIS, &faces));
11149566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&faceIS));
1115e735a8a9SMatthew G. Knepley           goto cleanup;
1116e735a8a9SMatthew G. Knepley         }
1117d7ddef95SMatthew G. Knepley       }
1118d7ddef95SMatthew G. Knepley     }
11199566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(faceIS, &faces));
11209566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&faceIS));
1121d7ddef95SMatthew G. Knepley   }
1122e735a8a9SMatthew G. Knepley cleanup:
11239566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(locX, &x));
1124d7ddef95SMatthew G. Knepley   if (Grad) {
11259566063dSJacob Faibussowitsch     PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx));
11269566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(Grad, &grad));
1127d7ddef95SMatthew G. Knepley   }
11289566063dSJacob Faibussowitsch   if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
11299566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
11309566063dSJacob Faibussowitsch   PetscCall(ierru);
11313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1132d7ddef95SMatthew G. Knepley }
1133d7ddef95SMatthew G. Knepley 
zero(PetscInt dim,PetscReal time,const PetscReal x[],PetscInt Nc,PetscScalar * u,PetscCtx ctx)1134*2a8381b2SBarry Smith static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx)
1135d71ae5a4SJacob Faibussowitsch {
11360c364540SMatthew G. Knepley   PetscInt c;
11370c364540SMatthew G. Knepley   for (c = 0; c < Nc; ++c) u[c] = 0.0;
11383ba16761SJacob Faibussowitsch   return PETSC_SUCCESS;
11390c364540SMatthew G. Knepley }
11400c364540SMatthew G. Knepley 
DMPlexInsertBoundaryValues_Plex(DM dm,PetscBool insertEssential,Vec locX,PetscReal time,Vec faceGeomFVM,Vec cellGeomFVM,Vec gradFVM)1141d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1142d71ae5a4SJacob Faibussowitsch {
11430c364540SMatthew G. Knepley   PetscObject isZero;
1144e5e52638SMatthew G. Knepley   PetscDS     prob;
1145d7ddef95SMatthew G. Knepley   PetscInt    numBd, b;
114655f2e967SMatthew G. Knepley 
114755f2e967SMatthew G. Knepley   PetscFunctionBegin;
11489566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
11499566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
11509566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero));
1151450c7a9fSMatthew G. Knepley   PetscCall(PetscDSUpdateBoundaryLabels(prob, dm));
115255f2e967SMatthew G. Knepley   for (b = 0; b < numBd; ++b) {
115345480ffeSMatthew G. Knepley     PetscWeakForm           wf;
1154f971fd6bSMatthew G. Knepley     DMBoundaryConditionType type;
115545480ffeSMatthew G. Knepley     const char             *name;
1156d7ddef95SMatthew G. Knepley     DMLabel                 label;
11571c531cf8SMatthew G. Knepley     PetscInt                field, Nc;
11581c531cf8SMatthew G. Knepley     const PetscInt         *comps;
1159d7ddef95SMatthew G. Knepley     PetscObject             obj;
1160d7ddef95SMatthew G. Knepley     PetscClassId            id;
116157d50842SBarry Smith     PetscVoidFn            *bvfunc;
1162d7ddef95SMatthew G. Knepley     PetscInt                numids;
1163d7ddef95SMatthew G. Knepley     const PetscInt         *ids;
116455f2e967SMatthew G. Knepley     void                   *ctx;
116555f2e967SMatthew G. Knepley 
11669566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
1167f971fd6bSMatthew G. Knepley     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
11689566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
11699566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
1170d7ddef95SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
1171c60e475cSMatthew G. Knepley       switch (type) {
1172c60e475cSMatthew G. Knepley         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
11739371c9d4SSatish Balay       case DM_BC_ESSENTIAL: {
11748434afd1SBarry Smith         PetscSimplePointFn *func = (PetscSimplePointFn *)bvfunc;
117545480ffeSMatthew G. Knepley 
117645480ffeSMatthew G. Knepley         if (isZero) func = zero;
11779566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
11789566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX));
11799566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
11809371c9d4SSatish Balay       } break;
11819371c9d4SSatish Balay       case DM_BC_ESSENTIAL_FIELD: {
11822192575eSBarry Smith         PetscPointFn *func = (PetscPointFn *)bvfunc;
118345480ffeSMatthew G. Knepley 
11849566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
11859566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX));
11869566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
11879371c9d4SSatish Balay       } break;
1188d71ae5a4SJacob Faibussowitsch       default:
1189d71ae5a4SJacob Faibussowitsch         break;
1190c60e475cSMatthew G. Knepley       }
1191d7ddef95SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
119245480ffeSMatthew G. Knepley       {
119345480ffeSMatthew G. Knepley         PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode (*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc;
119445480ffeSMatthew G. Knepley 
119543ea7facSMatthew G. Knepley         if (!faceGeomFVM) continue;
11969566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX));
119745480ffeSMatthew G. Knepley       }
119863a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
119955f2e967SMatthew G. Knepley   }
12003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
120155f2e967SMatthew G. Knepley }
120255f2e967SMatthew G. Knepley 
DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm,PetscBool insertEssential,Vec locX,PetscReal time,Vec faceGeomFVM,Vec cellGeomFVM,Vec gradFVM)1203d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1204d71ae5a4SJacob Faibussowitsch {
120556cf3b9cSMatthew G. Knepley   PetscObject isZero;
120656cf3b9cSMatthew G. Knepley   PetscDS     prob;
120756cf3b9cSMatthew G. Knepley   PetscInt    numBd, b;
120856cf3b9cSMatthew G. Knepley 
120956cf3b9cSMatthew G. Knepley   PetscFunctionBegin;
12103ba16761SJacob Faibussowitsch   if (!locX) PetscFunctionReturn(PETSC_SUCCESS);
12119566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
12129566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
12139566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero));
121456cf3b9cSMatthew G. Knepley   for (b = 0; b < numBd; ++b) {
121545480ffeSMatthew G. Knepley     PetscWeakForm           wf;
121656cf3b9cSMatthew G. Knepley     DMBoundaryConditionType type;
121745480ffeSMatthew G. Knepley     const char             *name;
121856cf3b9cSMatthew G. Knepley     DMLabel                 label;
121956cf3b9cSMatthew G. Knepley     PetscInt                field, Nc;
122056cf3b9cSMatthew G. Knepley     const PetscInt         *comps;
122156cf3b9cSMatthew G. Knepley     PetscObject             obj;
122256cf3b9cSMatthew G. Knepley     PetscClassId            id;
122356cf3b9cSMatthew G. Knepley     PetscInt                numids;
122456cf3b9cSMatthew G. Knepley     const PetscInt         *ids;
122557d50842SBarry Smith     PetscVoidFn            *bvfunc;
122656cf3b9cSMatthew G. Knepley     void                   *ctx;
122756cf3b9cSMatthew G. Knepley 
12289566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx));
122956cf3b9cSMatthew G. Knepley     if (insertEssential != (type & DM_BC_ESSENTIAL)) continue;
12309566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
12319566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
123256cf3b9cSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
123356cf3b9cSMatthew G. Knepley       switch (type) {
123456cf3b9cSMatthew G. Knepley         /* for FEM, there is no insertion to be done for non-essential boundary conditions */
12359371c9d4SSatish Balay       case DM_BC_ESSENTIAL: {
12368434afd1SBarry Smith         PetscSimplePointFn *func_t = (PetscSimplePointFn *)bvfunc;
123745480ffeSMatthew G. Knepley 
123845480ffeSMatthew G. Knepley         if (isZero) func_t = zero;
12399566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
12409566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX));
12419566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
12429371c9d4SSatish Balay       } break;
12439371c9d4SSatish Balay       case DM_BC_ESSENTIAL_FIELD: {
12442192575eSBarry Smith         PetscPointFn *func_t = (PetscPointFn *)bvfunc;
124545480ffeSMatthew G. Knepley 
12469566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelAddCells(dm, label));
12479566063dSJacob Faibussowitsch         PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX));
12489566063dSJacob Faibussowitsch         PetscCall(DMPlexLabelClearCells(dm, label));
12499371c9d4SSatish Balay       } break;
1250d71ae5a4SJacob Faibussowitsch       default:
1251d71ae5a4SJacob Faibussowitsch         break;
125256cf3b9cSMatthew G. Knepley       }
125363a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
125456cf3b9cSMatthew G. Knepley   }
12553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
125656cf3b9cSMatthew G. Knepley }
125756cf3b9cSMatthew G. Knepley 
DMPlexInsertBounds_Plex(DM dm,PetscBool lower,PetscReal time,Vec locB)125801468941SMatthew G. Knepley PetscErrorCode DMPlexInsertBounds_Plex(DM dm, PetscBool lower, PetscReal time, Vec locB)
125901468941SMatthew G. Knepley {
126001468941SMatthew G. Knepley   PetscDS  ds;
126101468941SMatthew G. Knepley   PetscInt numBd;
126201468941SMatthew G. Knepley 
126301468941SMatthew G. Knepley   PetscFunctionBegin;
126401468941SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
126501468941SMatthew G. Knepley   PetscCall(PetscDSGetNumBoundary(ds, &numBd));
126601468941SMatthew G. Knepley   PetscCall(PetscDSUpdateBoundaryLabels(ds, dm));
126701468941SMatthew G. Knepley   for (PetscInt b = 0; b < numBd; ++b) {
126801468941SMatthew G. Knepley     PetscWeakForm           wf;
126901468941SMatthew G. Knepley     DMBoundaryConditionType type;
127001468941SMatthew G. Knepley     const char             *name;
127101468941SMatthew G. Knepley     DMLabel                 label;
127201468941SMatthew G. Knepley     PetscInt                numids;
127301468941SMatthew G. Knepley     const PetscInt         *ids;
127401468941SMatthew G. Knepley     PetscInt                field, Nc;
127501468941SMatthew G. Knepley     const PetscInt         *comps;
127657d50842SBarry Smith     PetscVoidFn            *bvfunc;
127701468941SMatthew G. Knepley     void                   *ctx;
127801468941SMatthew G. Knepley 
127901468941SMatthew G. Knepley     PetscCall(PetscDSGetBoundary(ds, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx));
128001468941SMatthew G. Knepley     if (lower && type != DM_BC_LOWER_BOUND) continue;
128101468941SMatthew G. Knepley     if (!lower && type != DM_BC_UPPER_BOUND) continue;
128201468941SMatthew G. Knepley     PetscCall(DMPlexLabelAddCells(dm, label));
128301468941SMatthew G. Knepley     {
1284*2a8381b2SBarry Smith       PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, PetscCtx ctx);
128501468941SMatthew G. Knepley       void   **ctxs;
128601468941SMatthew G. Knepley       PetscInt Nf;
128701468941SMatthew G. Knepley 
128801468941SMatthew G. Knepley       PetscCall(DMGetNumFields(dm, &Nf));
128901468941SMatthew G. Knepley       PetscCall(PetscCalloc2(Nf, &funcs, Nf, &ctxs));
129001468941SMatthew G. Knepley       funcs[field] = (PetscSimplePointFn *)bvfunc;
129101468941SMatthew G. Knepley       ctxs[field]  = ctx;
129201468941SMatthew G. Knepley       PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_ALL_VALUES, locB));
129301468941SMatthew G. Knepley       PetscCall(PetscFree2(funcs, ctxs));
129401468941SMatthew G. Knepley     }
129501468941SMatthew G. Knepley     PetscCall(DMPlexLabelClearCells(dm, label));
129601468941SMatthew G. Knepley   }
129701468941SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
129801468941SMatthew G. Knepley }
129901468941SMatthew G. Knepley 
1300f1d73a7aSMatthew G. Knepley /*@
1301f1d73a7aSMatthew G. Knepley   DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector
1302f1d73a7aSMatthew G. Knepley 
1303ed808b8fSJed Brown   Not Collective
1304ed808b8fSJed Brown 
1305f1d73a7aSMatthew G. Knepley   Input Parameters:
1306a1cb98faSBarry Smith + dm              - The `DM`
1307f1d73a7aSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
1308f1d73a7aSMatthew G. Knepley . time            - The time
1309f1d73a7aSMatthew G. Knepley . faceGeomFVM     - Face geometry data for FV discretizations
1310f1d73a7aSMatthew G. Knepley . cellGeomFVM     - Cell geometry data for FV discretizations
1311f1d73a7aSMatthew G. Knepley - gradFVM         - Gradient reconstruction data for FV discretizations
1312f1d73a7aSMatthew G. Knepley 
13132fe279fdSBarry Smith   Output Parameter:
1314f1d73a7aSMatthew G. Knepley . locX - Solution updated with boundary values
1315f1d73a7aSMatthew G. Knepley 
1316ed808b8fSJed Brown   Level: intermediate
1317f1d73a7aSMatthew G. Knepley 
13181cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()`
1319f1d73a7aSMatthew G. Knepley @*/
DMPlexInsertBoundaryValues(DM dm,PetscBool insertEssential,Vec locX,PetscReal time,Vec faceGeomFVM,Vec cellGeomFVM,Vec gradFVM)1320d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1321d71ae5a4SJacob Faibussowitsch {
1322f1d73a7aSMatthew G. Knepley   PetscFunctionBegin;
1323f1d73a7aSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1324064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
1325ad540459SPierre Jolivet   if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5);
1326ad540459SPierre Jolivet   if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6);
1327ad540459SPierre Jolivet   if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7);
1328cac4c232SBarry Smith   PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM));
13293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1330f1d73a7aSMatthew G. Knepley }
1331f1d73a7aSMatthew G. Knepley 
133256cf3b9cSMatthew G. Knepley /*@
1333a5b23f4aSJose E. Roman   DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector
133456cf3b9cSMatthew G. Knepley 
133556cf3b9cSMatthew G. Knepley   Input Parameters:
1336a1cb98faSBarry Smith + dm              - The `DM`
133756cf3b9cSMatthew G. Knepley . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions
133856cf3b9cSMatthew G. Knepley . time            - The time
133956cf3b9cSMatthew G. Knepley . faceGeomFVM     - Face geometry data for FV discretizations
134056cf3b9cSMatthew G. Knepley . cellGeomFVM     - Cell geometry data for FV discretizations
134156cf3b9cSMatthew G. Knepley - gradFVM         - Gradient reconstruction data for FV discretizations
134256cf3b9cSMatthew G. Knepley 
13432fe279fdSBarry Smith   Output Parameter:
134456cf3b9cSMatthew G. Knepley . locX_t - Solution updated with boundary values
134556cf3b9cSMatthew G. Knepley 
134656cf3b9cSMatthew G. Knepley   Level: developer
134756cf3b9cSMatthew G. Knepley 
13481cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`
134956cf3b9cSMatthew G. Knepley @*/
DMPlexInsertTimeDerivativeBoundaryValues(DM dm,PetscBool insertEssential,Vec locX_t,PetscReal time,Vec faceGeomFVM,Vec cellGeomFVM,Vec gradFVM)1350d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM)
1351d71ae5a4SJacob Faibussowitsch {
135256cf3b9cSMatthew G. Knepley   PetscFunctionBegin;
135356cf3b9cSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1354ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3);
1355ad540459SPierre Jolivet   if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5);
1356ad540459SPierre Jolivet   if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6);
1357ad540459SPierre Jolivet   if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7);
13586c51210dSStefano Zampini   PetscTryMethod(dm, "DMPlexInsertTimeDerivativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM));
13593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
136056cf3b9cSMatthew G. Knepley }
136156cf3b9cSMatthew G. Knepley 
136201468941SMatthew G. Knepley /*@
136301468941SMatthew G. Knepley   DMPlexInsertBounds - Puts coefficients which represent solution bounds into the local bounds vector
136401468941SMatthew G. Knepley 
136501468941SMatthew G. Knepley   Not Collective
136601468941SMatthew G. Knepley 
136701468941SMatthew G. Knepley   Input Parameters:
136801468941SMatthew G. Knepley + dm    - The `DM`
136901468941SMatthew G. Knepley . lower - If `PETSC_TRUE` use `DM_BC_LOWER_BOUND` conditions, otherwise use `DM_BC_UPPER_BOUND`
137001468941SMatthew G. Knepley - time  - The time
137101468941SMatthew G. Knepley 
137201468941SMatthew G. Knepley   Output Parameter:
137301468941SMatthew G. Knepley . locB - Bounds vector updated with new bounds
137401468941SMatthew G. Knepley 
137501468941SMatthew G. Knepley   Level: intermediate
137601468941SMatthew G. Knepley 
137701468941SMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `PetscDSAddBoundary()`
137801468941SMatthew G. Knepley @*/
DMPlexInsertBounds(DM dm,PetscBool lower,PetscReal time,Vec locB)137901468941SMatthew G. Knepley PetscErrorCode DMPlexInsertBounds(DM dm, PetscBool lower, PetscReal time, Vec locB)
138001468941SMatthew G. Knepley {
138101468941SMatthew G. Knepley   PetscFunctionBegin;
138201468941SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
138301468941SMatthew G. Knepley   PetscValidHeaderSpecific(locB, VEC_CLASSID, 4);
138401468941SMatthew G. Knepley   PetscTryMethod(dm, "DMPlexInsertBounds_C", (DM, PetscBool, PetscReal, Vec), (dm, lower, time, locB));
138501468941SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
138601468941SMatthew G. Knepley }
138701468941SMatthew G. Knepley 
13885962854dSMatthew G. Knepley // Handle non-essential (e.g. outflow) boundary values
DMPlexInsertBoundaryValuesFVM(DM dm,PetscFV fv,Vec locX,PetscReal time,Vec * locGradient)13895962854dSMatthew G. Knepley PetscErrorCode DMPlexInsertBoundaryValuesFVM(DM dm, PetscFV fv, Vec locX, PetscReal time, Vec *locGradient)
13905962854dSMatthew G. Knepley {
13915962854dSMatthew G. Knepley   DM  dmGrad;
13925962854dSMatthew G. Knepley   Vec cellGeometryFVM, faceGeometryFVM, locGrad = NULL;
13935962854dSMatthew G. Knepley 
13945962854dSMatthew G. Knepley   PetscFunctionBegin;
13955962854dSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13965962854dSMatthew G. Knepley   PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
13975962854dSMatthew G. Knepley   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
13985962854dSMatthew G. Knepley   if (locGradient) {
13995962854dSMatthew G. Knepley     PetscAssertPointer(locGradient, 5);
14005962854dSMatthew G. Knepley     *locGradient = NULL;
14015962854dSMatthew G. Knepley   }
14025962854dSMatthew G. Knepley   PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL));
14035962854dSMatthew G. Knepley   /* Reconstruct and limit cell gradients */
14045962854dSMatthew G. Knepley   PetscCall(DMPlexGetGradientDM(dm, fv, &dmGrad));
14055962854dSMatthew G. Knepley   if (dmGrad) {
14065962854dSMatthew G. Knepley     Vec      grad;
14075962854dSMatthew G. Knepley     PetscInt fStart, fEnd;
14085962854dSMatthew G. Knepley 
14095962854dSMatthew G. Knepley     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
14105962854dSMatthew G. Knepley     PetscCall(DMGetGlobalVector(dmGrad, &grad));
14115962854dSMatthew G. Knepley     PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad));
14125962854dSMatthew G. Knepley     /* Communicate gradient values */
14135962854dSMatthew G. Knepley     PetscCall(DMGetLocalVector(dmGrad, &locGrad));
14145962854dSMatthew G. Knepley     PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad));
14155962854dSMatthew G. Knepley     PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad));
14165962854dSMatthew G. Knepley     PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
14175962854dSMatthew G. Knepley   }
14185962854dSMatthew G. Knepley   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad));
14195962854dSMatthew G. Knepley   if (locGradient) *locGradient = locGrad;
14205962854dSMatthew G. Knepley   else if (locGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
14215962854dSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
14225962854dSMatthew G. Knepley }
14235962854dSMatthew G. Knepley 
DMComputeL2Diff_Plex(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,PetscReal * diff)1424d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1425d71ae5a4SJacob Faibussowitsch {
1426574a98acSMatthew G. Knepley   Vec localX;
1427574a98acSMatthew G. Knepley 
1428574a98acSMatthew G. Knepley   PetscFunctionBegin;
14299566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
14309566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL));
14319566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
14329566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
14339566063dSJacob Faibussowitsch   PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff));
14349566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
14353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1436574a98acSMatthew G. Knepley }
1437574a98acSMatthew G. Knepley 
1438574a98acSMatthew G. Knepley /*@C
143960225df5SJacob Faibussowitsch   DMPlexComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
1440574a98acSMatthew G. Knepley 
144120f4b53cSBarry Smith   Collective
1442c0f8e1fdSMatthew G. Knepley 
1443574a98acSMatthew G. Knepley   Input Parameters:
1444a1cb98faSBarry Smith + dm     - The `DM`
1445574a98acSMatthew G. Knepley . time   - The time
1446574a98acSMatthew G. Knepley . funcs  - The functions to evaluate for each field component
144720f4b53cSBarry Smith . ctxs   - Optional array of contexts to pass to each function, or `NULL`.
1448574a98acSMatthew G. Knepley - localX - The coefficient vector u_h, a local vector
1449574a98acSMatthew G. Knepley 
1450574a98acSMatthew G. Knepley   Output Parameter:
1451574a98acSMatthew G. Knepley . diff - The diff ||u - u_h||_2
1452574a98acSMatthew G. Knepley 
1453574a98acSMatthew G. Knepley   Level: developer
1454574a98acSMatthew G. Knepley 
14551cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1456574a98acSMatthew G. Knepley @*/
DMPlexComputeL2DiffLocal(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec localX,PetscReal * diff)1457d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff)
1458d71ae5a4SJacob Faibussowitsch {
14590f09c10fSMatthew G. Knepley   const PetscInt   debug = ((DM_Plex *)dm->data)->printL2;
1460ca3d3a14SMatthew G. Knepley   DM               tdm;
1461ca3d3a14SMatthew G. Knepley   Vec              tv;
1462cb1e1211SMatthew G Knepley   PetscSection     section;
1463c5bbbd5bSMatthew G. Knepley   PetscQuadrature  quad;
14644bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
146515496722SMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
14664bee2e38SMatthew G. Knepley   PetscReal       *coords, *gcoords;
1467cb1e1211SMatthew G Knepley   PetscReal        localDiff = 0.0;
14687318780aSToby Isaac   const PetscReal *quadWeights;
1469412e9a14SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset;
1470ca3d3a14SMatthew G. Knepley   PetscBool        transform;
1471cb1e1211SMatthew G Knepley 
1472cb1e1211SMatthew G Knepley   PetscFunctionBegin;
14739566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
14752a4e142eSMatthew G. Knepley   fegeom.dimEmbed = coordDim;
14769566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
14779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
14789566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
14799566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
14809566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
1481eae3dc7dSJacob Faibussowitsch   PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
1482cb1e1211SMatthew G Knepley   for (field = 0; field < numFields; ++field) {
148315496722SMatthew G. Knepley     PetscObject  obj;
148415496722SMatthew G. Knepley     PetscClassId id;
1485c5bbbd5bSMatthew G. Knepley     PetscInt     Nc;
1486c5bbbd5bSMatthew G. Knepley 
14879566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
14889566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
148915496722SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
149015496722SMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
149115496722SMatthew G. Knepley 
14929566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
14939566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
149415496722SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
149515496722SMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
149615496722SMatthew G. Knepley 
14979566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
14989566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
149963a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1500c5bbbd5bSMatthew G. Knepley     numComponents += Nc;
1501cb1e1211SMatthew G Knepley   }
15029566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
150363a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
1504c9cb6370SYANG Zongze   PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
15059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
15069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
1507cb1e1211SMatthew G Knepley   for (c = cStart; c < cEnd; ++c) {
1508a1e44745SMatthew G. Knepley     PetscScalar *x        = NULL;
1509cb1e1211SMatthew G Knepley     PetscReal    elemDiff = 0.0;
15109c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1511cb1e1211SMatthew G Knepley 
15129566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
151348162695SZach Atkins     PetscCall(DMPlexVecGetOrientedClosure(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x));
1514cb1e1211SMatthew G Knepley 
151515496722SMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
151615496722SMatthew G. Knepley       PetscObject  obj;
151715496722SMatthew G. Knepley       PetscClassId id;
1518c110b1eeSGeoffrey Irving       void *const  ctx = ctxs ? ctxs[field] : NULL;
151915496722SMatthew G. Knepley       PetscInt     Nb, Nc, q, fc;
1520cb1e1211SMatthew G Knepley 
15219566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, &obj));
15229566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
15239371c9d4SSatish Balay       if (id == PETSCFE_CLASSID) {
15249371c9d4SSatish Balay         PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
15259371c9d4SSatish Balay         PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
15269371c9d4SSatish Balay       } else if (id == PETSCFV_CLASSID) {
15279371c9d4SSatish Balay         PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
15289371c9d4SSatish Balay         Nb = 1;
15299371c9d4SSatish Balay       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1530cb1e1211SMatthew G Knepley       if (debug) {
1531cb1e1211SMatthew G Knepley         char title[1024];
153263a3b9bcSJacob Faibussowitsch         PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field));
15339566063dSJacob Faibussowitsch         PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset]));
1534cb1e1211SMatthew G Knepley       }
15357318780aSToby Isaac       for (q = 0; q < Nq; ++q) {
15362a4e142eSMatthew G. Knepley         PetscFEGeom    qgeom;
1537d0609cedSBarry Smith         PetscErrorCode ierr;
15382a4e142eSMatthew G. Knepley 
15392a4e142eSMatthew G. Knepley         qgeom.dimEmbed = fegeom.dimEmbed;
15402a4e142eSMatthew G. Knepley         qgeom.J        = &fegeom.J[q * coordDim * coordDim];
15412a4e142eSMatthew G. Knepley         qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
15422a4e142eSMatthew G. Knepley         qgeom.detJ     = &fegeom.detJ[q];
154363a3b9bcSJacob 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);
1544d3a7d86cSMatthew G. Knepley         if (transform) {
1545d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * Nq];
15469566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx));
1547d3a7d86cSMatthew G. Knepley         } else {
1548d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * q];
1549d3a7d86cSMatthew G. Knepley         }
15509566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(funcVal, Nc));
1551ca3d3a14SMatthew G. Knepley         ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx);
1552e735a8a9SMatthew G. Knepley         if (ierr) {
15539566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
15549566063dSJacob Faibussowitsch           PetscCall(DMRestoreLocalVector(dm, &localX));
15559566063dSJacob Faibussowitsch           PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1556e735a8a9SMatthew G. Knepley         }
15579566063dSJacob Faibussowitsch         if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
15589566063dSJacob Faibussowitsch         if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant));
15599566063dSJacob Faibussowitsch         else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant));
15602df84da0SMatthew G. Knepley         else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
156115496722SMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
1562beaa55a6SMatthew G. Knepley           const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
15639371c9d4SSatish Balay           if (debug)
1564835f2295SStefano Zampini             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),
15659371c9d4SSatish Balay                                   (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc])));
15664bee2e38SMatthew G. Knepley           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1567cb1e1211SMatthew G Knepley         }
1568cb1e1211SMatthew G Knepley       }
15699c3cf19fSMatthew G. Knepley       fieldOffset += Nb;
1570beaa55a6SMatthew G. Knepley       qc += Nc;
1571cb1e1211SMatthew G Knepley     }
15729566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
15739566063dSJacob Faibussowitsch     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff));
1574cb1e1211SMatthew G Knepley     localDiff += elemDiff;
1575cb1e1211SMatthew G Knepley   }
15769566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1577462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
1578cb1e1211SMatthew G Knepley   *diff = PetscSqrtReal(*diff);
15793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1580cb1e1211SMatthew G Knepley }
1581cb1e1211SMatthew G Knepley 
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)1582d71ae5a4SJacob 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)
1583d71ae5a4SJacob Faibussowitsch {
15840f09c10fSMatthew G. Knepley   const PetscInt   debug = ((DM_Plex *)dm->data)->printL2;
1585ca3d3a14SMatthew G. Knepley   DM               tdm;
1586cb1e1211SMatthew G Knepley   PetscSection     section;
158740e14135SMatthew G. Knepley   PetscQuadrature  quad;
1588ca3d3a14SMatthew G. Knepley   Vec              localX, tv;
15899c3cf19fSMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
15902a4e142eSMatthew G. Knepley   const PetscReal *quadWeights;
15914bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
15924bee2e38SMatthew G. Knepley   PetscReal       *coords, *gcoords;
159340e14135SMatthew G. Knepley   PetscReal        localDiff = 0.0;
1594485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset;
1595ca3d3a14SMatthew G. Knepley   PetscBool        transform;
1596cb1e1211SMatthew G Knepley 
1597cb1e1211SMatthew G Knepley   PetscFunctionBegin;
15989566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
15999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
16004bee2e38SMatthew G. Knepley   fegeom.dimEmbed = coordDim;
16019566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
16029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
16039566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
16049566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
16059566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
16069566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
16079566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
16089566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
1609652b88e8SMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
16100f2d7e86SMatthew G. Knepley     PetscFE  fe;
161140e14135SMatthew G. Knepley     PetscInt Nc;
1612652b88e8SMatthew G. Knepley 
16139566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe));
16149566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &quad));
16159566063dSJacob Faibussowitsch     PetscCall(PetscFEGetNumComponents(fe, &Nc));
161640e14135SMatthew G. Knepley     numComponents += Nc;
1617652b88e8SMatthew G. Knepley   }
16189566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
161963a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
16209566063dSJacob Faibussowitsch   /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */
1621c9cb6370SYANG 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));
16229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
162340e14135SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
162440e14135SMatthew G. Knepley     PetscScalar *x        = NULL;
162540e14135SMatthew G. Knepley     PetscReal    elemDiff = 0.0;
16269c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1627652b88e8SMatthew G. Knepley 
16289566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
162948162695SZach Atkins     PetscCall(DMPlexVecGetOrientedClosure(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x));
163040e14135SMatthew G. Knepley 
16319c3cf19fSMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
16320f2d7e86SMatthew G. Knepley       PetscFE     fe;
163351259fa3SMatthew G. Knepley       void *const ctx = ctxs ? ctxs[field] : NULL;
16349c3cf19fSMatthew G. Knepley       PetscInt    Nb, Nc, q, fc;
163540e14135SMatthew G. Knepley 
16369566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe));
16379566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
16389566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
163940e14135SMatthew G. Knepley       if (debug) {
164040e14135SMatthew G. Knepley         char title[1024];
16419566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field));
16429566063dSJacob Faibussowitsch         PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset]));
1643652b88e8SMatthew G. Knepley       }
16449c3cf19fSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
16452a4e142eSMatthew G. Knepley         PetscFEGeom    qgeom;
1646d0609cedSBarry Smith         PetscErrorCode ierr;
16472a4e142eSMatthew G. Knepley 
16482a4e142eSMatthew G. Knepley         qgeom.dimEmbed = fegeom.dimEmbed;
16492a4e142eSMatthew G. Knepley         qgeom.J        = &fegeom.J[q * coordDim * coordDim];
16502a4e142eSMatthew G. Knepley         qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
16512a4e142eSMatthew G. Knepley         qgeom.detJ     = &fegeom.detJ[q];
16522df84da0SMatthew 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);
1653d3a7d86cSMatthew G. Knepley         if (transform) {
1654d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * Nq];
16559566063dSJacob Faibussowitsch           PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx));
1656d3a7d86cSMatthew G. Knepley         } else {
1657d3a7d86cSMatthew G. Knepley           gcoords = &coords[coordDim * q];
1658d3a7d86cSMatthew G. Knepley         }
16599566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(funcVal, Nc));
16604bee2e38SMatthew G. Knepley         ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx);
1661e735a8a9SMatthew G. Knepley         if (ierr) {
16629566063dSJacob Faibussowitsch           PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
16639566063dSJacob Faibussowitsch           PetscCall(DMRestoreLocalVector(dm, &localX));
16649566063dSJacob Faibussowitsch           PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ));
1665e735a8a9SMatthew G. Knepley         }
16669566063dSJacob Faibussowitsch         if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
16679566063dSJacob Faibussowitsch         PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant));
16684bee2e38SMatthew G. Knepley         /* Overwrite with the dot product if the normal is given */
16694bee2e38SMatthew G. Knepley         if (n) {
16704bee2e38SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
16714bee2e38SMatthew G. Knepley             PetscScalar sum = 0.0;
16724bee2e38SMatthew G. Knepley             PetscInt    d;
16734bee2e38SMatthew G. Knepley             for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d];
16744bee2e38SMatthew G. Knepley             interpolant[fc] = sum;
16754bee2e38SMatthew G. Knepley           }
16764bee2e38SMatthew G. Knepley         }
16779c3cf19fSMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
1678beaa55a6SMatthew G. Knepley           const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
167963a3b9bcSJacob 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])));
16804bee2e38SMatthew G. Knepley           elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
168140e14135SMatthew G. Knepley         }
168240e14135SMatthew G. Knepley       }
16839c3cf19fSMatthew G. Knepley       fieldOffset += Nb;
16849c3cf19fSMatthew G. Knepley       qc += Nc;
168540e14135SMatthew G. Knepley     }
16869566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
168763a3b9bcSJacob Faibussowitsch     if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff));
168840e14135SMatthew G. Knepley     localDiff += elemDiff;
168940e14135SMatthew G. Knepley   }
16909566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ));
16919566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
1692462c564dSBarry Smith   PetscCallMPI(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
169340e14135SMatthew G. Knepley   *diff = PetscSqrtReal(*diff);
16943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1695cb1e1211SMatthew G Knepley }
1696cb1e1211SMatthew G Knepley 
DMComputeL2FieldDiff_Plex(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,PetscReal * diff)1697d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
1698d71ae5a4SJacob Faibussowitsch {
16990f09c10fSMatthew G. Knepley   const PetscInt debug = ((DM_Plex *)dm->data)->printL2;
1700ca3d3a14SMatthew G. Knepley   DM             tdm;
1701083401c6SMatthew G. Knepley   DMLabel        depthLabel;
170273d901b8SMatthew G. Knepley   PetscSection   section;
1703ca3d3a14SMatthew G. Knepley   Vec            localX, tv;
170473d901b8SMatthew G. Knepley   PetscReal     *localDiff;
1705083401c6SMatthew G. Knepley   PetscInt       dim, depth, dE, Nf, f, Nds, s;
1706ca3d3a14SMatthew G. Knepley   PetscBool      transform;
170773d901b8SMatthew G. Knepley 
170873d901b8SMatthew G. Knepley   PetscFunctionBegin;
17099566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
17109566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dE));
17119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
17129566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
17139566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
17149566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
17159566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
17169566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
17179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
17189566063dSJacob Faibussowitsch   PetscCall(DMLabelGetNumValues(depthLabel, &depth));
1719083401c6SMatthew G. Knepley 
17209566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
17219566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
17229566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
17239566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX));
17249566063dSJacob Faibussowitsch   PetscCall(DMGetNumDS(dm, &Nds));
17259566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(Nf, &localDiff));
1726083401c6SMatthew G. Knepley   for (s = 0; s < Nds; ++s) {
1727083401c6SMatthew G. Knepley     PetscDS          ds;
1728083401c6SMatthew G. Knepley     DMLabel          label;
1729083401c6SMatthew G. Knepley     IS               fieldIS, pointIS;
1730083401c6SMatthew G. Knepley     const PetscInt  *fields, *points = NULL;
1731083401c6SMatthew G. Knepley     PetscQuadrature  quad;
1732083401c6SMatthew G. Knepley     const PetscReal *quadPoints, *quadWeights;
1733083401c6SMatthew G. Knepley     PetscFEGeom      fegeom;
1734083401c6SMatthew G. Knepley     PetscReal       *coords, *gcoords;
1735083401c6SMatthew G. Knepley     PetscScalar     *funcVal, *interpolant;
17365fedec97SMatthew G. Knepley     PetscBool        isCohesive;
1737083401c6SMatthew G. Knepley     PetscInt         qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf;
173873d901b8SMatthew G. Knepley 
173907218a29SMatthew G. Knepley     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
17409566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(fieldIS, &fields));
17419566063dSJacob Faibussowitsch     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
17429566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(ds, &dsNf));
17439566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalComponents(ds, &totNc));
17449566063dSJacob Faibussowitsch     PetscCall(PetscDSGetQuadrature(ds, &quad));
17459566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
174663a3b9bcSJacob Faibussowitsch     PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc);
17479566063dSJacob Faibussowitsch     PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ));
1748083401c6SMatthew G. Knepley     if (!label) {
17499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1750083401c6SMatthew G. Knepley     } else {
17519566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
17529566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(pointIS, &cEnd));
17539566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(pointIS, &points));
1754083401c6SMatthew G. Knepley     }
175573d901b8SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
1756083401c6SMatthew G. Knepley       const PetscInt  cell = points ? points[c] : c;
175773d901b8SMatthew G. Knepley       PetscScalar    *x    = NULL;
17585fedec97SMatthew G. Knepley       const PetscInt *cone;
17595fedec97SMatthew G. Knepley       PetscInt        qc = 0, fOff = 0, dep;
176073d901b8SMatthew G. Knepley 
17619566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(depthLabel, cell, &dep));
1762083401c6SMatthew G. Knepley       if (dep != depth - 1) continue;
17635fedec97SMatthew G. Knepley       if (isCohesive) {
17649566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cell, &cone));
17659566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
176696959cd1SMatthew G. Knepley       } else {
17679566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
176896959cd1SMatthew G. Knepley       }
176948162695SZach Atkins       PetscCall(DMPlexVecGetOrientedClosure(dm, NULL, PETSC_FALSE, localX, cell, 0, NULL, &x));
17705fedec97SMatthew G. Knepley       for (f = 0; f < dsNf; ++f) {
177115496722SMatthew G. Knepley         PetscObject  obj;
177215496722SMatthew G. Knepley         PetscClassId id;
1773083401c6SMatthew G. Knepley         void *const  ctx = ctxs ? ctxs[fields[f]] : NULL;
177415496722SMatthew G. Knepley         PetscInt     Nb, Nc, q, fc;
177515496722SMatthew G. Knepley         PetscReal    elemDiff = 0.0;
17765fedec97SMatthew G. Knepley         PetscBool    cohesive;
177715496722SMatthew G. Knepley 
17789566063dSJacob Faibussowitsch         PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
17799566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
17809566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
17819371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
17829371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
17839371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
17849371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
17859371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
17869371c9d4SSatish Balay           Nb = 1;
17879371c9d4SSatish Balay         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
1788c82db6dbSMatthew G. Knepley         if (isCohesive && !cohesive) {
1789c82db6dbSMatthew G. Knepley           fOff += Nb * 2;
1790c82db6dbSMatthew G. Knepley           qc += Nc;
1791c82db6dbSMatthew G. Knepley           continue;
1792c82db6dbSMatthew G. Knepley         }
179373d901b8SMatthew G. Knepley         if (debug) {
179473d901b8SMatthew G. Knepley           char title[1024];
179563a3b9bcSJacob Faibussowitsch           PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f]));
17969566063dSJacob Faibussowitsch           PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff]));
179773d901b8SMatthew G. Knepley         }
17987318780aSToby Isaac         for (q = 0; q < Nq; ++q) {
17992a4e142eSMatthew G. Knepley           PetscFEGeom    qgeom;
1800d0609cedSBarry Smith           PetscErrorCode ierr;
18012a4e142eSMatthew G. Knepley 
18022a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
1803083401c6SMatthew G. Knepley           qgeom.J        = &fegeom.J[q * dE * dE];
1804083401c6SMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * dE * dE];
18052a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
180663a3b9bcSJacob 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);
1807d3a7d86cSMatthew G. Knepley           if (transform) {
1808083401c6SMatthew G. Knepley             gcoords = &coords[dE * Nq];
18099566063dSJacob Faibussowitsch             PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx));
1810d3a7d86cSMatthew G. Knepley           } else {
1811083401c6SMatthew G. Knepley             gcoords = &coords[dE * q];
1812d3a7d86cSMatthew G. Knepley           }
18132df84da0SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.;
1814083401c6SMatthew G. Knepley           ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx);
1815e735a8a9SMatthew G. Knepley           if (ierr) {
18169566063dSJacob Faibussowitsch             PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x));
18179566063dSJacob Faibussowitsch             PetscCall(DMRestoreLocalVector(dm, &localX));
18189566063dSJacob Faibussowitsch             PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
1819e735a8a9SMatthew G. Knepley           }
18209566063dSJacob Faibussowitsch           if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx));
182196959cd1SMatthew G. Knepley           /* Call once for each face, except for lagrange field */
18229566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant));
18239566063dSJacob Faibussowitsch           else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant));
182463a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]);
182515496722SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
1826beaa55a6SMatthew G. Knepley             const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
18279371c9d4SSatish Balay             if (debug)
1828835f2295SStefano Zampini               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),
18299371c9d4SSatish Balay                                     (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q])));
18304bee2e38SMatthew G. Knepley             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
183173d901b8SMatthew G. Knepley           }
183273d901b8SMatthew G. Knepley         }
1833083401c6SMatthew G. Knepley         fOff += Nb;
18349c3cf19fSMatthew G. Knepley         qc += Nc;
1835083401c6SMatthew G. Knepley         localDiff[fields[f]] += elemDiff;
183663a3b9bcSJacob 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]]));
183773d901b8SMatthew G. Knepley       }
18389566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x));
1839083401c6SMatthew G. Knepley     }
1840083401c6SMatthew G. Knepley     if (label) {
18419566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(pointIS, &points));
18429566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
1843083401c6SMatthew G. Knepley     }
18449566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(fieldIS, &fields));
18459566063dSJacob Faibussowitsch     PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
184673d901b8SMatthew G. Knepley   }
18479566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
1848e91c04dfSPierre Jolivet   PetscCallMPI(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
18499566063dSJacob Faibussowitsch   PetscCall(PetscFree(localDiff));
1850083401c6SMatthew G. Knepley   for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]);
18513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
185273d901b8SMatthew G. Knepley }
185373d901b8SMatthew G. Knepley 
1854e729f68cSMatthew G. Knepley /*@C
1855e729f68cSMatthew 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.
1856e729f68cSMatthew G. Knepley 
185720f4b53cSBarry Smith   Collective
1858c0f8e1fdSMatthew G. Knepley 
1859e729f68cSMatthew G. Knepley   Input Parameters:
1860a1cb98faSBarry Smith + dm    - The `DM`
18610163fd50SMatthew G. Knepley . time  - The time
186220f4b53cSBarry Smith . funcs - The functions to evaluate for each field component: `NULL` means that component does not contribute to error calculation
186320f4b53cSBarry Smith . ctxs  - Optional array of contexts to pass to each function, or `NULL`.
1864e729f68cSMatthew G. Knepley - X     - The coefficient vector u_h
1865e729f68cSMatthew G. Knepley 
1866e729f68cSMatthew G. Knepley   Output Parameter:
186720f4b53cSBarry Smith . D - A `Vec` which holds the difference ||u - u_h||_2 for each cell
1868e729f68cSMatthew G. Knepley 
1869e729f68cSMatthew G. Knepley   Level: developer
1870e729f68cSMatthew G. Knepley 
18711cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
1872e729f68cSMatthew G. Knepley @*/
DMPlexComputeL2DiffVec(DM dm,PetscReal time,PetscErrorCode (** funcs)(PetscInt,PetscReal,const PetscReal[],PetscInt,PetscScalar *,void *),void ** ctxs,Vec X,Vec D)1873d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D)
1874d71ae5a4SJacob Faibussowitsch {
1875e729f68cSMatthew G. Knepley   PetscSection     section;
1876e729f68cSMatthew G. Knepley   PetscQuadrature  quad;
1877e729f68cSMatthew G. Knepley   Vec              localX;
18784bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
1879e729f68cSMatthew G. Knepley   PetscScalar     *funcVal, *interpolant;
18804bee2e38SMatthew G. Knepley   PetscReal       *coords;
1881e729f68cSMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
1882485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset;
1883e729f68cSMatthew G. Knepley 
1884e729f68cSMatthew G. Knepley   PetscFunctionBegin;
18859566063dSJacob Faibussowitsch   PetscCall(VecSet(D, 0.0));
18869566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
18879566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
18889566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
18899566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &numFields));
18909566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &localX));
18919566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX));
18929566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX));
18939566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX));
1894e729f68cSMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
1895e729f68cSMatthew G. Knepley     PetscObject  obj;
1896e729f68cSMatthew G. Knepley     PetscClassId id;
1897e729f68cSMatthew G. Knepley     PetscInt     Nc;
1898e729f68cSMatthew G. Knepley 
18999566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
19009566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
1901e729f68cSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
1902e729f68cSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
1903e729f68cSMatthew G. Knepley 
19049566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
19059566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
1906e729f68cSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
1907e729f68cSMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
1908e729f68cSMatthew G. Knepley 
19099566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
19109566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
191163a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1912e729f68cSMatthew G. Knepley     numComponents += Nc;
1913e729f68cSMatthew G. Knepley   }
19149566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
191563a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
19169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ));
19179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
1918e729f68cSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
1919e729f68cSMatthew G. Knepley     PetscScalar *x        = NULL;
19206f288a59SMatthew G. Knepley     PetscScalar  elemDiff = 0.0;
19219c3cf19fSMatthew G. Knepley     PetscInt     qc       = 0;
1922e729f68cSMatthew G. Knepley 
19239566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
192448162695SZach Atkins     PetscCall(DMPlexVecGetOrientedClosure(dm, NULL, PETSC_FALSE, localX, c, 0, NULL, &x));
1925e729f68cSMatthew G. Knepley 
1926e729f68cSMatthew G. Knepley     for (field = 0, fieldOffset = 0; field < numFields; ++field) {
1927e729f68cSMatthew G. Knepley       PetscObject  obj;
1928e729f68cSMatthew G. Knepley       PetscClassId id;
1929e729f68cSMatthew G. Knepley       void *const  ctx = ctxs ? ctxs[field] : NULL;
1930e729f68cSMatthew G. Knepley       PetscInt     Nb, Nc, q, fc;
1931e729f68cSMatthew G. Knepley 
19329566063dSJacob Faibussowitsch       PetscCall(DMGetField(dm, field, NULL, &obj));
19339566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
19349371c9d4SSatish Balay       if (id == PETSCFE_CLASSID) {
19359371c9d4SSatish Balay         PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
19369371c9d4SSatish Balay         PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
19379371c9d4SSatish Balay       } else if (id == PETSCFV_CLASSID) {
19389371c9d4SSatish Balay         PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
19399371c9d4SSatish Balay         Nb = 1;
19409371c9d4SSatish Balay       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
194123f34ed2SToby Isaac       if (funcs[field]) {
19427318780aSToby Isaac         for (q = 0; q < Nq; ++q) {
19432a4e142eSMatthew G. Knepley           PetscFEGeom qgeom;
19442a4e142eSMatthew G. Knepley 
19452a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
19462a4e142eSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * coordDim * coordDim];
19472a4e142eSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
19482a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
194963a3b9bcSJacob 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);
19509566063dSJacob Faibussowitsch           PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx));
1951c3e24edfSBarry Smith #if defined(needs_fix_with_return_code_argument)
1952e735a8a9SMatthew G. Knepley           if (ierr) {
19539566063dSJacob Faibussowitsch             PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
19549566063dSJacob Faibussowitsch             PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
19559566063dSJacob Faibussowitsch             PetscCall(DMRestoreLocalVector(dm, &localX));
1956e735a8a9SMatthew G. Knepley           }
1957c3e24edfSBarry Smith #endif
19589566063dSJacob Faibussowitsch           if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant));
19599566063dSJacob Faibussowitsch           else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant));
196063a3b9bcSJacob Faibussowitsch           else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
1961e729f68cSMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
1962beaa55a6SMatthew G. Knepley             const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)];
19634bee2e38SMatthew G. Knepley             elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q];
1964e729f68cSMatthew G. Knepley           }
1965e729f68cSMatthew G. Knepley         }
196623f34ed2SToby Isaac       }
1967beaa55a6SMatthew G. Knepley       fieldOffset += Nb;
19689c3cf19fSMatthew G. Knepley       qc += Nc;
1969e729f68cSMatthew G. Knepley     }
19709566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x));
19719566063dSJacob Faibussowitsch     PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES));
1972e729f68cSMatthew G. Knepley   }
19739566063dSJacob Faibussowitsch   PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
19749566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &localX));
19759566063dSJacob Faibussowitsch   PetscCall(VecSqrtAbs(D));
19763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1977e729f68cSMatthew G. Knepley }
1978e729f68cSMatthew G. Knepley 
19795f0b18bfSMatthew G. Knepley /*@
19802353bfffSMatthew G. Knepley   DMPlexComputeL2FluxDiffVecLocal - This function computes the integral of the difference between the gradient of field `f`in `u` and field `mf` in `mu`
19812353bfffSMatthew G. Knepley 
19822353bfffSMatthew G. Knepley   Collective
19832353bfffSMatthew G. Knepley 
19842353bfffSMatthew G. Knepley   Input Parameters:
19852353bfffSMatthew G. Knepley + lu  - The local `Vec` containing the primal solution
19862353bfffSMatthew G. Knepley . f   - The field number for the potential
19872353bfffSMatthew G. Knepley . lmu - The local `Vec` containing the mixed solution
19882353bfffSMatthew G. Knepley - mf  - The field number for the flux
19892353bfffSMatthew G. Knepley 
19902353bfffSMatthew G. Knepley   Output Parameter:
19912353bfffSMatthew G. Knepley . eFlux - A global `Vec` which holds $||\nabla u_f - \mu_{mf}||$
19922353bfffSMatthew G. Knepley 
19932353bfffSMatthew G. Knepley   Level: advanced
19942353bfffSMatthew G. Knepley 
19952353bfffSMatthew G. Knepley   Notes:
19962353bfffSMatthew G. Knepley   We assume that the `DM` for each solution has the same topology, geometry, and quadrature.
19972353bfffSMatthew G. Knepley 
19982353bfffSMatthew G. Knepley   This is usually used to get an error estimate for the primal solution, using the flux from a mixed solution.
19992353bfffSMatthew G. Knepley 
20002353bfffSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeL2FluxDiffVec()`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
20012353bfffSMatthew G. Knepley @*/
DMPlexComputeL2FluxDiffVecLocal(Vec lu,PetscInt f,Vec lmu,PetscInt mf,Vec eFlux)20022353bfffSMatthew G. Knepley PetscErrorCode DMPlexComputeL2FluxDiffVecLocal(Vec lu, PetscInt f, Vec lmu, PetscInt mf, Vec eFlux)
20032353bfffSMatthew G. Knepley {
20042353bfffSMatthew G. Knepley   DM               dm, mdm, edm;
20052353bfffSMatthew G. Knepley   PetscFE          fe, mfe;
20062353bfffSMatthew G. Knepley   PetscFEGeom      fegeom;
20072353bfffSMatthew G. Knepley   PetscQuadrature  quad;
20082353bfffSMatthew G. Knepley   const PetscReal *quadWeights;
20092353bfffSMatthew G. Knepley   PetscReal       *coords;
20102353bfffSMatthew G. Knepley   PetscScalar     *interpolant, *minterpolant, *earray;
20112353bfffSMatthew G. Knepley   PetscInt         cdim, mcdim, cStart, cEnd, Nc, mNc, qNc, Nq;
20122353bfffSMatthew G. Knepley   MPI_Comm         comm;
20132353bfffSMatthew G. Knepley 
20142353bfffSMatthew G. Knepley   PetscFunctionBegin;
20152353bfffSMatthew G. Knepley   PetscCall(VecGetDM(lu, &dm));
20162353bfffSMatthew G. Knepley   PetscCall(VecGetDM(lmu, &mdm));
20172353bfffSMatthew G. Knepley   PetscCall(VecGetDM(eFlux, &edm));
20182353bfffSMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
20192353bfffSMatthew G. Knepley   PetscCall(VecSet(eFlux, 0.0));
20202353bfffSMatthew G. Knepley 
20212353bfffSMatthew G. Knepley   // Check if the both problems are on the same mesh
20222353bfffSMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &cdim));
20232353bfffSMatthew G. Knepley   PetscCall(DMGetCoordinateDim(mdm, &mcdim));
20242353bfffSMatthew G. Knepley   PetscCheck(cdim == mcdim, comm, PETSC_ERR_ARG_SIZ, "primal coordinate Dim %" PetscInt_FMT " != %" PetscInt_FMT " mixed coordinate Dim", cdim, mcdim);
20252353bfffSMatthew G. Knepley   fegeom.dimEmbed = cdim;
20262353bfffSMatthew G. Knepley 
20272353bfffSMatthew G. Knepley   PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
20282353bfffSMatthew G. Knepley   PetscCall(DMGetField(mdm, mf, NULL, (PetscObject *)&mfe));
20292353bfffSMatthew G. Knepley   PetscCall(PetscFEGetNumComponents(fe, &Nc));
20302353bfffSMatthew G. Knepley   PetscCall(PetscFEGetNumComponents(mfe, &mNc));
20312353bfffSMatthew G. Knepley   PetscCall(PetscFEGetQuadrature(fe, &quad));
20322353bfffSMatthew G. Knepley   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights));
20332353bfffSMatthew G. Knepley   PetscCheck(qNc == 1 || qNc == mNc, comm, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, mNc);
20342353bfffSMatthew G. Knepley 
20352353bfffSMatthew G. Knepley   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
20362353bfffSMatthew G. Knepley   PetscCall(VecGetArrayWrite(eFlux, &earray));
20372353bfffSMatthew G. Knepley   PetscCall(PetscMalloc6(Nc * cdim, &interpolant, mNc * cdim, &minterpolant, cdim * (Nq + 1), &coords, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ, Nq, &fegeom.detJ));
20382353bfffSMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
20392353bfffSMatthew G. Knepley     PetscScalar *x            = NULL;
20402353bfffSMatthew G. Knepley     PetscScalar *mx           = NULL;
20412353bfffSMatthew G. Knepley     PetscScalar *eval         = NULL;
20422353bfffSMatthew G. Knepley     PetscReal    fluxElemDiff = 0.0;
20432353bfffSMatthew G. Knepley 
20442353bfffSMatthew G. Knepley     PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
20452353bfffSMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dm, NULL, lu, c, NULL, &x));
20462353bfffSMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(mdm, NULL, lmu, c, NULL, &mx));
20472353bfffSMatthew G. Knepley 
20482353bfffSMatthew G. Knepley     for (PetscInt q = 0; q < Nq; ++q) {
20492353bfffSMatthew G. Knepley       PetscFEGeom qgeom;
20502353bfffSMatthew G. Knepley 
20512353bfffSMatthew G. Knepley       qgeom.dimEmbed = fegeom.dimEmbed;
20522353bfffSMatthew G. Knepley       qgeom.J        = &fegeom.J[q * cdim * cdim];
20532353bfffSMatthew G. Knepley       qgeom.invJ     = &fegeom.invJ[q * cdim * cdim];
20542353bfffSMatthew G. Knepley       qgeom.detJ     = &fegeom.detJ[q];
20552353bfffSMatthew G. Knepley 
20562353bfffSMatthew 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);
20572353bfffSMatthew G. Knepley 
20582353bfffSMatthew G. Knepley       PetscCall(PetscFEInterpolate_Static(mfe, &mx[0], &qgeom, q, minterpolant));
20592353bfffSMatthew G. Knepley       PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[0], &qgeom, q, interpolant));
20602353bfffSMatthew G. Knepley 
20612353bfffSMatthew G. Knepley       /* Now take the elementwise difference and store that in a vector. */
20622353bfffSMatthew G. Knepley       for (PetscInt fc = 0; fc < mNc; ++fc) {
20632353bfffSMatthew G. Knepley         const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : fc)];
20642353bfffSMatthew G. Knepley         fluxElemDiff += PetscSqr(PetscRealPart(interpolant[fc] - minterpolant[fc])) * wt * fegeom.detJ[q];
20652353bfffSMatthew G. Knepley       }
20662353bfffSMatthew G. Knepley     }
20672353bfffSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dm, NULL, lu, c, NULL, &x));
20682353bfffSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(mdm, NULL, lmu, c, NULL, &mx));
20692353bfffSMatthew G. Knepley     PetscCall(DMPlexPointGlobalRef(edm, c, earray, (void *)&eval));
20702353bfffSMatthew G. Knepley     if (eval) eval[0] = fluxElemDiff;
20712353bfffSMatthew G. Knepley   }
20722353bfffSMatthew G. Knepley   PetscCall(PetscFree6(interpolant, minterpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
20732353bfffSMatthew G. Knepley   PetscCall(VecRestoreArrayWrite(eFlux, &earray));
20742353bfffSMatthew G. Knepley 
20752353bfffSMatthew G. Knepley   PetscCall(VecAssemblyBegin(eFlux));
20762353bfffSMatthew G. Knepley   PetscCall(VecAssemblyEnd(eFlux));
20772353bfffSMatthew G. Knepley   PetscCall(VecSqrtAbs(eFlux));
20782353bfffSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
20792353bfffSMatthew G. Knepley }
20802353bfffSMatthew G. Knepley 
20812353bfffSMatthew G. Knepley /*@
20822353bfffSMatthew G. Knepley   DMPlexComputeL2FluxDiffVec - This function computes the integral of the difference between the gradient of field `f`in `u` and field `mf` in `mu`
20832353bfffSMatthew G. Knepley 
20842353bfffSMatthew G. Knepley   Collective
20852353bfffSMatthew G. Knepley 
20862353bfffSMatthew G. Knepley   Input Parameters:
20872353bfffSMatthew G. Knepley + u  - The global `Vec` containing the primal solution
20882353bfffSMatthew G. Knepley . f  - The field number for the potential
20892353bfffSMatthew G. Knepley . mu - The global `Vec` containing the mixed solution
20902353bfffSMatthew G. Knepley - mf - The field number for the flux
20912353bfffSMatthew G. Knepley 
20922353bfffSMatthew G. Knepley   Output Parameter:
20932353bfffSMatthew G. Knepley . eFlux - A global `Vec` which holds $||\nabla u_f - \mu_{mf}||$
20942353bfffSMatthew G. Knepley 
20952353bfffSMatthew G. Knepley   Level: advanced
20962353bfffSMatthew G. Knepley 
20972353bfffSMatthew G. Knepley   Notes:
20982353bfffSMatthew G. Knepley   We assume that the `DM` for each solution has the same topology, geometry, and quadrature.
20992353bfffSMatthew G. Knepley 
21002353bfffSMatthew G. Knepley   This is usually used to get an error estimate for the primal solution, using the flux from a mixed solution.
21012353bfffSMatthew G. Knepley 
21022353bfffSMatthew G. Knepley .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeL2FluxDiffVecLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
21032353bfffSMatthew G. Knepley @*/
DMPlexComputeL2FluxDiffVec(Vec u,PetscInt f,Vec mu,PetscInt mf,Vec eFlux)21042353bfffSMatthew G. Knepley PetscErrorCode DMPlexComputeL2FluxDiffVec(Vec u, PetscInt f, Vec mu, PetscInt mf, Vec eFlux)
21052353bfffSMatthew G. Knepley {
21062353bfffSMatthew G. Knepley   DM  dm, mdm;
21072353bfffSMatthew G. Knepley   Vec lu, lmu;
21082353bfffSMatthew G. Knepley 
21092353bfffSMatthew G. Knepley   PetscFunctionBegin;
21102353bfffSMatthew G. Knepley   PetscCall(VecGetDM(u, &dm));
21112353bfffSMatthew G. Knepley   PetscCall(DMGetLocalVector(dm, &lu));
21122353bfffSMatthew G. Knepley   PetscCall(DMGlobalToLocal(dm, u, INSERT_VALUES, lu));
21132353bfffSMatthew G. Knepley   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, lu, 0.0, NULL, NULL, NULL));
21142353bfffSMatthew G. Knepley 
21152353bfffSMatthew G. Knepley   PetscCall(VecGetDM(mu, &mdm));
21162353bfffSMatthew G. Knepley   PetscCall(DMGetLocalVector(mdm, &lmu));
21172353bfffSMatthew G. Knepley   PetscCall(DMGlobalToLocal(mdm, mu, INSERT_VALUES, lmu));
21182353bfffSMatthew G. Knepley   PetscCall(DMPlexInsertBoundaryValues(mdm, PETSC_TRUE, lmu, 0.0, NULL, NULL, NULL));
21192353bfffSMatthew G. Knepley 
21202353bfffSMatthew G. Knepley   PetscCall(DMPlexComputeL2FluxDiffVecLocal(lu, f, lmu, mf, eFlux));
21212353bfffSMatthew G. Knepley 
21222353bfffSMatthew G. Knepley   PetscCall(DMRestoreLocalVector(dm, &lu));
21232353bfffSMatthew G. Knepley   PetscCall(DMRestoreLocalVector(mdm, &lmu));
21242353bfffSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
21252353bfffSMatthew G. Knepley }
21262353bfffSMatthew G. Knepley 
21272353bfffSMatthew G. Knepley /*@
212820f4b53cSBarry Smith   DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1
21295f0b18bfSMatthew G. Knepley 
213020f4b53cSBarry Smith   Collective
21315f0b18bfSMatthew G. Knepley 
21325f0b18bfSMatthew G. Knepley   Input Parameters:
2133a1cb98faSBarry Smith + dm   - The `DM`
21345f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h
21355f0b18bfSMatthew G. Knepley 
21365f0b18bfSMatthew G. Knepley   Output Parameter:
2137a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the function
21385f0b18bfSMatthew G. Knepley 
21395f0b18bfSMatthew G. Knepley   Level: developer
21405f0b18bfSMatthew G. Knepley 
2141a1cb98faSBarry Smith   Note:
2142a1cb98faSBarry 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
2143a1cb98faSBarry Smith 
21441cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
21455f0b18bfSMatthew G. Knepley @*/
DMPlexComputeClementInterpolant(DM dm,Vec locX,Vec locC)2146d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC)
2147d71ae5a4SJacob Faibussowitsch {
21485f0b18bfSMatthew G. Knepley   PetscInt         debug = ((DM_Plex *)dm->data)->printFEM;
21495f0b18bfSMatthew G. Knepley   DM               dmc;
21505f0b18bfSMatthew G. Knepley   PetscQuadrature  quad;
21515f0b18bfSMatthew G. Knepley   PetscScalar     *interpolant, *valsum;
21525f0b18bfSMatthew G. Knepley   PetscFEGeom      fegeom;
21535f0b18bfSMatthew G. Knepley   PetscReal       *coords;
21545f0b18bfSMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
21555f0b18bfSMatthew G. Knepley   PetscInt         dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v;
21565f0b18bfSMatthew G. Knepley 
21575f0b18bfSMatthew G. Knepley   PetscFunctionBegin;
21589566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite));
21599566063dSJacob Faibussowitsch   PetscCall(VecGetDM(locC, &dmc));
21609566063dSJacob Faibussowitsch   PetscCall(VecSet(locC, 0.0));
21619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
21629566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cdim));
21635f0b18bfSMatthew G. Knepley   fegeom.dimEmbed = cdim;
21649566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
21655f0b18bfSMatthew G. Knepley   PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
21665f0b18bfSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
21675f0b18bfSMatthew G. Knepley     PetscObject  obj;
21685f0b18bfSMatthew G. Knepley     PetscClassId id;
21695f0b18bfSMatthew G. Knepley     PetscInt     fNc;
21705f0b18bfSMatthew G. Knepley 
21719566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, f, NULL, &obj));
21729566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
21735f0b18bfSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
21745f0b18bfSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
21755f0b18bfSMatthew G. Knepley 
21769566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
21779566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &fNc));
21785f0b18bfSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
21795f0b18bfSMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
21805f0b18bfSMatthew G. Knepley 
21819566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
21829566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &fNc));
218363a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
21845f0b18bfSMatthew G. Knepley     Nc += fNc;
21855f0b18bfSMatthew G. Knepley   }
21869566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
218763a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc);
21889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ));
21899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
21909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
21915f0b18bfSMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
21925f0b18bfSMatthew G. Knepley     PetscScalar volsum = 0.0;
21935f0b18bfSMatthew G. Knepley     PetscInt   *star   = NULL;
21945f0b18bfSMatthew G. Knepley     PetscInt    starSize, st, fc;
21955f0b18bfSMatthew G. Knepley 
21969566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(valsum, Nc));
21979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
21985f0b18bfSMatthew G. Knepley     for (st = 0; st < starSize * 2; st += 2) {
21995f0b18bfSMatthew G. Knepley       const PetscInt cell = star[st];
22005f0b18bfSMatthew G. Knepley       PetscScalar   *val  = &valsum[Nc];
22015f0b18bfSMatthew G. Knepley       PetscScalar   *x    = NULL;
22025f0b18bfSMatthew G. Knepley       PetscReal      vol  = 0.0;
22035f0b18bfSMatthew G. Knepley       PetscInt       foff = 0;
22045f0b18bfSMatthew G. Knepley 
22055f0b18bfSMatthew G. Knepley       if ((cell < cStart) || (cell >= cEnd)) continue;
22069566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
22079566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x));
22085f0b18bfSMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
22095f0b18bfSMatthew G. Knepley         PetscObject  obj;
22105f0b18bfSMatthew G. Knepley         PetscClassId id;
22115f0b18bfSMatthew G. Knepley         PetscInt     Nb, fNc, q;
22125f0b18bfSMatthew G. Knepley 
22139566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(val, Nc));
22149566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, f, NULL, &obj));
22159566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
22169371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
22179371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc));
22189371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
22199371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
22209371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc));
22219371c9d4SSatish Balay           Nb = 1;
22229371c9d4SSatish Balay         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
22235f0b18bfSMatthew G. Knepley         for (q = 0; q < Nq; ++q) {
22245f0b18bfSMatthew G. Knepley           const PetscReal wt = quadWeights[q] * fegeom.detJ[q];
22255f0b18bfSMatthew G. Knepley           PetscFEGeom     qgeom;
22265f0b18bfSMatthew G. Knepley 
22275f0b18bfSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
22285f0b18bfSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * cdim * cdim];
22295f0b18bfSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * cdim * cdim];
22305f0b18bfSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
223163a3b9bcSJacob 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);
2232966bd95aSPierre Jolivet           PetscCheck(id == PETSCFE_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
2233966bd95aSPierre Jolivet           PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant));
22345f0b18bfSMatthew G. Knepley           for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt;
22355f0b18bfSMatthew G. Knepley           vol += wt;
22365f0b18bfSMatthew G. Knepley         }
22375f0b18bfSMatthew G. Knepley         foff += Nb;
22385f0b18bfSMatthew G. Knepley       }
22399566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x));
22405f0b18bfSMatthew G. Knepley       for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc];
22415f0b18bfSMatthew G. Knepley       volsum += vol;
22425f0b18bfSMatthew G. Knepley       if (debug) {
22439566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell));
22445f0b18bfSMatthew G. Knepley         for (fc = 0; fc < Nc; ++fc) {
22459566063dSJacob Faibussowitsch           if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
22469566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc])));
22475f0b18bfSMatthew G. Knepley         }
22489566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
22495f0b18bfSMatthew G. Knepley       }
22505f0b18bfSMatthew G. Knepley     }
22515f0b18bfSMatthew G. Knepley     for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum;
22529566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
22539566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES));
22545f0b18bfSMatthew G. Knepley   }
22559566063dSJacob Faibussowitsch   PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
22563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22575f0b18bfSMatthew G. Knepley }
22585f0b18bfSMatthew G. Knepley 
22595f0b18bfSMatthew G. Knepley /*@
226020f4b53cSBarry Smith   DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1
22611555c271SMatthew G. Knepley 
226220f4b53cSBarry Smith   Collective
2263c0f8e1fdSMatthew G. Knepley 
22641555c271SMatthew G. Knepley   Input Parameters:
2265a1cb98faSBarry Smith + dm   - The `DM`
22665f0b18bfSMatthew G. Knepley - locX - The coefficient vector u_h
22671555c271SMatthew G. Knepley 
22681555c271SMatthew G. Knepley   Output Parameter:
2269a1cb98faSBarry Smith . locC - A `Vec` which holds the Clement interpolant of the gradient
22701555c271SMatthew G. Knepley 
22711555c271SMatthew G. Knepley   Level: developer
22721555c271SMatthew G. Knepley 
2273a1cb98faSBarry Smith   Note:
2274a1cb98faSBarry 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
2275a1cb98faSBarry Smith 
22761cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
22771555c271SMatthew G. Knepley @*/
DMPlexComputeGradientClementInterpolant(DM dm,Vec locX,Vec locC)2278d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC)
2279d71ae5a4SJacob Faibussowitsch {
2280db1066baSMatthew G. Knepley   DM_Plex         *mesh  = (DM_Plex *)dm->data;
2281db1066baSMatthew G. Knepley   PetscInt         debug = mesh->printFEM;
22821555c271SMatthew G. Knepley   DM               dmC;
22831555c271SMatthew G. Knepley   PetscQuadrature  quad;
22841555c271SMatthew G. Knepley   PetscScalar     *interpolant, *gradsum;
22854bee2e38SMatthew G. Knepley   PetscFEGeom      fegeom;
22864bee2e38SMatthew G. Knepley   PetscReal       *coords;
22871555c271SMatthew G. Knepley   const PetscReal *quadPoints, *quadWeights;
2288485ad865SMatthew G. Knepley   PetscInt         dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset;
22891555c271SMatthew G. Knepley 
22901555c271SMatthew G. Knepley   PetscFunctionBegin;
22919566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite));
22929566063dSJacob Faibussowitsch   PetscCall(VecGetDM(locC, &dmC));
22939566063dSJacob Faibussowitsch   PetscCall(VecSet(locC, 0.0));
22949566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
22959566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &coordDim));
22964bee2e38SMatthew G. Knepley   fegeom.dimEmbed = coordDim;
22979566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &numFields));
22985f80ce2aSJacob Faibussowitsch   PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!");
22991555c271SMatthew G. Knepley   for (field = 0; field < numFields; ++field) {
23001555c271SMatthew G. Knepley     PetscObject  obj;
23011555c271SMatthew G. Knepley     PetscClassId id;
23021555c271SMatthew G. Knepley     PetscInt     Nc;
23031555c271SMatthew G. Knepley 
23049566063dSJacob Faibussowitsch     PetscCall(DMGetField(dm, field, NULL, &obj));
23059566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
23061555c271SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
23071555c271SMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
23081555c271SMatthew G. Knepley 
23099566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &quad));
23109566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
23111555c271SMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
23121555c271SMatthew G. Knepley       PetscFV fv = (PetscFV)obj;
23131555c271SMatthew G. Knepley 
23149566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature(fv, &quad));
23159566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
231663a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
23171555c271SMatthew G. Knepley     numComponents += Nc;
23181555c271SMatthew G. Knepley   }
23199566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
232063a3b9bcSJacob Faibussowitsch   PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents);
23219566063dSJacob 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));
23229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
23239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
23241555c271SMatthew G. Knepley   for (v = vStart; v < vEnd; ++v) {
23251555c271SMatthew G. Knepley     PetscScalar volsum = 0.0;
23261555c271SMatthew G. Knepley     PetscInt   *star   = NULL;
23271555c271SMatthew G. Knepley     PetscInt    starSize, st, d, fc;
23281555c271SMatthew G. Knepley 
23299566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gradsum, coordDim * numComponents));
23309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
23311555c271SMatthew G. Knepley     for (st = 0; st < starSize * 2; st += 2) {
23321555c271SMatthew G. Knepley       const PetscInt cell = star[st];
23331555c271SMatthew G. Knepley       PetscScalar   *grad = &gradsum[coordDim * numComponents];
23341555c271SMatthew G. Knepley       PetscScalar   *x    = NULL;
23351555c271SMatthew G. Knepley       PetscReal      vol  = 0.0;
23361555c271SMatthew G. Knepley 
23371555c271SMatthew G. Knepley       if ((cell < cStart) || (cell >= cEnd)) continue;
23389566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ));
23399566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x));
23401555c271SMatthew G. Knepley       for (field = 0, fieldOffset = 0; field < numFields; ++field) {
23411555c271SMatthew G. Knepley         PetscObject  obj;
23421555c271SMatthew G. Knepley         PetscClassId id;
23431555c271SMatthew G. Knepley         PetscInt     Nb, Nc, q, qc = 0;
23441555c271SMatthew G. Knepley 
23459566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(grad, coordDim * numComponents));
23469566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, field, NULL, &obj));
23479566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
23489371c9d4SSatish Balay         if (id == PETSCFE_CLASSID) {
23499371c9d4SSatish Balay           PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
23509371c9d4SSatish Balay           PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb));
23519371c9d4SSatish Balay         } else if (id == PETSCFV_CLASSID) {
23529371c9d4SSatish Balay           PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
23539371c9d4SSatish Balay           Nb = 1;
23549371c9d4SSatish Balay         } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
23551555c271SMatthew G. Knepley         for (q = 0; q < Nq; ++q) {
23562a4e142eSMatthew G. Knepley           PetscFEGeom qgeom;
23572a4e142eSMatthew G. Knepley 
23582a4e142eSMatthew G. Knepley           qgeom.dimEmbed = fegeom.dimEmbed;
23592a4e142eSMatthew G. Knepley           qgeom.J        = &fegeom.J[q * coordDim * coordDim];
23602a4e142eSMatthew G. Knepley           qgeom.invJ     = &fegeom.invJ[q * coordDim * coordDim];
23612a4e142eSMatthew G. Knepley           qgeom.detJ     = &fegeom.detJ[q];
236263a3b9bcSJacob 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);
2363966bd95aSPierre Jolivet           PetscCheck(id == PETSCFE_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
2364966bd95aSPierre Jolivet           PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant));
23651555c271SMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
236653d2db2dSJoe Wallwork             const PetscReal wt = quadWeights[q * qNc + qc];
23671555c271SMatthew G. Knepley 
23684bee2e38SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q];
23691555c271SMatthew G. Knepley           }
23704bee2e38SMatthew G. Knepley           vol += quadWeights[q * qNc] * fegeom.detJ[q];
23711555c271SMatthew G. Knepley         }
23721555c271SMatthew G. Knepley         fieldOffset += Nb;
23731555c271SMatthew G. Knepley         qc += Nc;
23741555c271SMatthew G. Knepley       }
23759566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x));
2376f8527842SMatthew G. Knepley       for (fc = 0; fc < numComponents; ++fc) {
2377ad540459SPierre Jolivet         for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d];
2378f8527842SMatthew G. Knepley       }
2379f8527842SMatthew G. Knepley       volsum += vol;
2380db1066baSMatthew G. Knepley       if (debug) {
23819566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell));
23821555c271SMatthew G. Knepley         for (fc = 0; fc < numComponents; ++fc) {
23831555c271SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) {
23849566063dSJacob Faibussowitsch             if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
23859566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d])));
23861555c271SMatthew G. Knepley           }
23871555c271SMatthew G. Knepley         }
23889566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n"));
2389db1066baSMatthew G. Knepley       }
23901555c271SMatthew G. Knepley     }
23911555c271SMatthew G. Knepley     for (fc = 0; fc < numComponents; ++fc) {
23921555c271SMatthew G. Knepley       for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum;
23931555c271SMatthew G. Knepley     }
23949566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
23959566063dSJacob Faibussowitsch     PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES));
23961555c271SMatthew G. Knepley   }
23979566063dSJacob Faibussowitsch   PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ));
23983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23991555c271SMatthew G. Knepley }
24001555c271SMatthew G. Knepley 
DMPlexComputeIntegral_Internal(DM dm,Vec locX,PetscInt cStart,PetscInt cEnd,PetscScalar * cintegral,PetscCtx ctx)2401*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec locX, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, PetscCtx ctx)
2402d71ae5a4SJacob Faibussowitsch {
2403cbf8eb3cSStefano Zampini   DM           dmAux = NULL, plexA = NULL;
240461aaff12SToby Isaac   PetscDS      prob, probAux       = NULL;
240573d901b8SMatthew G. Knepley   PetscSection section, sectionAux;
24066493148fSStefano Zampini   Vec          locA;
2407c330f8ffSToby Isaac   PetscInt     dim, numCells = cEnd - cStart, c, f;
2408c330f8ffSToby Isaac   PetscBool    useFVM = PETSC_FALSE;
2409338f77d5SMatthew G. Knepley   /* DS */
2410338f77d5SMatthew G. Knepley   PetscInt           Nf, totDim, *uOff, *uOff_x, numConstants;
2411338f77d5SMatthew G. Knepley   PetscInt           NfAux, totDimAux, *aOff;
24128e3a54c0SPierre Jolivet   PetscScalar       *u, *a = NULL;
2413338f77d5SMatthew G. Knepley   const PetscScalar *constants;
2414338f77d5SMatthew G. Knepley   /* Geometry */
2415c330f8ffSToby Isaac   PetscFEGeom       *cgeomFEM;
2416338f77d5SMatthew G. Knepley   DM                 dmGrad;
2417c330f8ffSToby Isaac   PetscQuadrature    affineQuad      = NULL;
2418338f77d5SMatthew G. Knepley   Vec                cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
2419b5a3613cSMatthew G. Knepley   PetscFVCellGeom   *cgeomFVM;
2420338f77d5SMatthew G. Knepley   const PetscScalar *lgrad;
2421b7260050SToby Isaac   PetscInt           maxDegree;
2422c330f8ffSToby Isaac   DMField            coordField;
2423c330f8ffSToby Isaac   IS                 cellIS;
242473d901b8SMatthew G. Knepley 
242573d901b8SMatthew G. Knepley   PetscFunctionBegin;
24269566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
24279566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
24289566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
24299566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
2430338f77d5SMatthew G. Knepley   /* Determine which discretizations we have */
2431b5a3613cSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
2432b5a3613cSMatthew G. Knepley     PetscObject  obj;
2433b5a3613cSMatthew G. Knepley     PetscClassId id;
2434b5a3613cSMatthew G. Knepley 
24359566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
24369566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
2437338f77d5SMatthew G. Knepley     if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE;
2438338f77d5SMatthew G. Knepley   }
2439338f77d5SMatthew G. Knepley   /* Read DS information */
24409566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
24419566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(prob, &uOff));
24429566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x));
24439566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS));
24449566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(prob, &numConstants, &constants));
2445338f77d5SMatthew G. Knepley   /* Read Auxiliary DS information */
24469566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
24479a2a23afSMatthew G. Knepley   if (locA) {
24489566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
2449cbf8eb3cSStefano Zampini     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
24509566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
24519566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(probAux, &NfAux));
24529566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
24539566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
24549566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(probAux, &aOff));
2455338f77d5SMatthew G. Knepley   }
2456338f77d5SMatthew G. Knepley   /* Allocate data  arrays */
24579566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(numCells * totDim, &u));
24589566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
2459338f77d5SMatthew G. Knepley   /* Read out geometry */
24609566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
24619566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
2462b7260050SToby Isaac   if (maxDegree <= 1) {
24639566063dSJacob Faibussowitsch     PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
2464ac9d17c7SMatthew G. Knepley     if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FEGEOM_BASIC, &cgeomFEM));
2465b5a3613cSMatthew G. Knepley   }
2466b5a3613cSMatthew G. Knepley   if (useFVM) {
2467338f77d5SMatthew G. Knepley     PetscFV   fv = NULL;
2468b5a3613cSMatthew G. Knepley     Vec       grad;
2469b5a3613cSMatthew G. Knepley     PetscInt  fStart, fEnd;
2470b5a3613cSMatthew G. Knepley     PetscBool compGrad;
2471b5a3613cSMatthew G. Knepley 
2472338f77d5SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
2473338f77d5SMatthew G. Knepley       PetscObject  obj;
2474338f77d5SMatthew G. Knepley       PetscClassId id;
2475338f77d5SMatthew G. Knepley 
24769566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
24779566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
24789371c9d4SSatish Balay       if (id == PETSCFV_CLASSID) {
24799371c9d4SSatish Balay         fv = (PetscFV)obj;
24809371c9d4SSatish Balay         break;
24819371c9d4SSatish Balay       }
2482338f77d5SMatthew G. Knepley     }
24839566063dSJacob Faibussowitsch     PetscCall(PetscFVGetComputeGradients(fv, &compGrad));
24849566063dSJacob Faibussowitsch     PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE));
24859566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM));
24869566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad));
24879566063dSJacob Faibussowitsch     PetscCall(PetscFVSetComputeGradients(fv, compGrad));
24889566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
2489b5a3613cSMatthew G. Knepley     /* Reconstruct and limit cell gradients */
24909566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
24919566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmGrad, &grad));
24929566063dSJacob Faibussowitsch     PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad));
2493b5a3613cSMatthew G. Knepley     /* Communicate gradient values */
24949566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmGrad, &locGrad));
24959566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad));
24969566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad));
24979566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmGrad, &grad));
2498b5a3613cSMatthew G. Knepley     /* Handle non-essential (e.g. outflow) boundary values */
24999566063dSJacob Faibussowitsch     PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad));
25009566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &lgrad));
2501b5a3613cSMatthew G. Knepley   }
2502338f77d5SMatthew G. Knepley   /* Read out data from inputs */
250373d901b8SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
250473d901b8SMatthew G. Knepley     PetscScalar *x = NULL;
250573d901b8SMatthew G. Knepley     PetscInt     i;
250673d901b8SMatthew G. Knepley 
25079566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x));
25080f2d7e86SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
25099566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x));
251073d901b8SMatthew G. Knepley     if (dmAux) {
2511cbf8eb3cSStefano Zampini       PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, c, NULL, &x));
25120f2d7e86SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
2513cbf8eb3cSStefano Zampini       PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, c, NULL, &x));
251473d901b8SMatthew G. Knepley     }
251573d901b8SMatthew G. Knepley   }
2516338f77d5SMatthew G. Knepley   /* Do integration for each field */
251773d901b8SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
2518c1f031eeSMatthew G. Knepley     PetscObject  obj;
2519c1f031eeSMatthew G. Knepley     PetscClassId id;
2520c1f031eeSMatthew G. Knepley     PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
252173d901b8SMatthew G. Knepley 
25229566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
25239566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
2524c1f031eeSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
2525c1f031eeSMatthew G. Knepley       PetscFE         fe = (PetscFE)obj;
2526c1f031eeSMatthew G. Knepley       PetscQuadrature q;
2527c330f8ffSToby Isaac       PetscFEGeom    *chunkGeom = NULL;
2528c1f031eeSMatthew G. Knepley       PetscInt        Nq, Nb;
2529c1f031eeSMatthew G. Knepley 
25309566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
25319566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &q));
25329566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
25339566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
2534c1f031eeSMatthew G. Knepley       blockSize = Nb * Nq;
253573d901b8SMatthew G. Knepley       batchSize = numBlocks * blockSize;
25369566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
253773d901b8SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
253873d901b8SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
253973d901b8SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
254073d901b8SMatthew G. Knepley       offset    = numCells - Nr;
2541ac9d17c7SMatthew G. Knepley       if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FEGEOM_BASIC, &cgeomFEM));
25429566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
25439566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral));
25449566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom));
25458e3a54c0SPierre Jolivet       PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &cintegral[offset * Nf]));
25469566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom));
254748a46eb9SPierre Jolivet       if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM));
2548c1f031eeSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
2549c1f031eeSMatthew G. Knepley       PetscInt      foff;
25502192575eSBarry Smith       PetscPointFn *obj_func;
2551c1f031eeSMatthew G. Knepley 
25529566063dSJacob Faibussowitsch       PetscCall(PetscDSGetObjective(prob, f, &obj_func));
25539566063dSJacob Faibussowitsch       PetscCall(PetscDSGetFieldOffset(prob, f, &foff));
2554c1f031eeSMatthew G. Knepley       if (obj_func) {
2555c1f031eeSMatthew G. Knepley         for (c = 0; c < numCells; ++c) {
2556b5a3613cSMatthew G. Knepley           PetscScalar *u_x;
2557d627b919SMatthew G. Knepley           PetscScalar  lint = 0.;
2558b5a3613cSMatthew G. Knepley 
25599566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x));
256055bffe1bSPierre Jolivet           obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim * c + foff], NULL, u_x, aOff, NULL, PetscSafePointerPlusOffset(a, totDimAux * c), NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint);
2561338f77d5SMatthew G. Knepley           cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume;
256273d901b8SMatthew G. Knepley         }
2563c1f031eeSMatthew G. Knepley       }
256463a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
2565c1f031eeSMatthew G. Knepley   }
2566338f77d5SMatthew G. Knepley   /* Cleanup data arrays */
2567b5a3613cSMatthew G. Knepley   if (useFVM) {
25689566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(locGrad, &lgrad));
25699566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM));
25709566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
25719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&faceGeometryFVM));
25729566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&cellGeometryFVM));
25739566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&dmGrad));
2574b5a3613cSMatthew G. Knepley   }
25759566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscFree(a));
2576cbf8eb3cSStefano Zampini   PetscCall(DMDestroy(&plexA));
25779566063dSJacob Faibussowitsch   PetscCall(PetscFree(u));
2578338f77d5SMatthew G. Knepley   /* Cleanup */
257948a46eb9SPierre Jolivet   if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM));
25809566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&affineQuad));
25819566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cellIS));
25823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2583338f77d5SMatthew G. Knepley }
2584338f77d5SMatthew G. Knepley 
2585338f77d5SMatthew G. Knepley /*@
2586338f77d5SMatthew G. Knepley   DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user
2587338f77d5SMatthew G. Knepley 
2588338f77d5SMatthew G. Knepley   Input Parameters:
2589338f77d5SMatthew G. Knepley + dm  - The mesh
2590338f77d5SMatthew G. Knepley . X   - Global input vector
2591*2a8381b2SBarry Smith - ctx - The application context
2592338f77d5SMatthew G. Knepley 
2593338f77d5SMatthew G. Knepley   Output Parameter:
2594338f77d5SMatthew G. Knepley . integral - Integral for each field
2595338f77d5SMatthew G. Knepley 
2596338f77d5SMatthew G. Knepley   Level: developer
2597338f77d5SMatthew G. Knepley 
25981cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2599338f77d5SMatthew G. Knepley @*/
DMPlexComputeIntegralFEM(DM dm,Vec X,PetscScalar * integral,PetscCtx ctx)2600*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, PetscCtx ctx)
2601d71ae5a4SJacob Faibussowitsch {
2602cbf8eb3cSStefano Zampini   PetscInt     printFEM;
2603b8feb594SMatthew G. Knepley   PetscScalar *cintegral, *lintegral;
2604412e9a14SMatthew G. Knepley   PetscInt     Nf, f, cellHeight, cStart, cEnd, cell;
26056493148fSStefano Zampini   Vec          locX;
2606338f77d5SMatthew G. Knepley 
2607338f77d5SMatthew G. Knepley   PetscFunctionBegin;
2608338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2609338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
26104f572ea9SToby Isaac   PetscAssertPointer(integral, 3);
26119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
2612cbf8eb3cSStefano Zampini   PetscCall(DMPlexConvertPlex(dm, &dm, PETSC_TRUE));
26139566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
26149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
26159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2616338f77d5SMatthew G. Knepley   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
26179566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral));
26186493148fSStefano Zampini   /* Get local solution with boundary values */
26196493148fSStefano Zampini   PetscCall(DMGetLocalVector(dm, &locX));
26206493148fSStefano Zampini   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
26216493148fSStefano Zampini   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
26226493148fSStefano Zampini   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
2623*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, ctx));
26246493148fSStefano Zampini   PetscCall(DMRestoreLocalVector(dm, &locX));
2625cbf8eb3cSStefano Zampini   printFEM = ((DM_Plex *)dm->data)->printFEM;
2626338f77d5SMatthew G. Knepley   /* Sum up values */
2627338f77d5SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
2628338f77d5SMatthew G. Knepley     const PetscInt c = cell - cStart;
2629338f77d5SMatthew G. Knepley 
2630cbf8eb3cSStefano Zampini     if (printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]));
2631b8feb594SMatthew G. Knepley     for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f];
2632338f77d5SMatthew G. Knepley   }
2633e91c04dfSPierre Jolivet   PetscCallMPI(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm)));
2634cbf8eb3cSStefano Zampini   if (printFEM) {
26359566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:"));
26369566063dSJacob Faibussowitsch     for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f])));
26379566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n"));
263873d901b8SMatthew G. Knepley   }
26399566063dSJacob Faibussowitsch   PetscCall(PetscFree2(lintegral, cintegral));
26409566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
2641cbf8eb3cSStefano Zampini   PetscCall(DMDestroy(&dm));
26423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2643338f77d5SMatthew G. Knepley }
2644338f77d5SMatthew G. Knepley 
2645338f77d5SMatthew G. Knepley /*@
2646338f77d5SMatthew G. Knepley   DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user
2647338f77d5SMatthew G. Knepley 
2648338f77d5SMatthew G. Knepley   Input Parameters:
2649338f77d5SMatthew G. Knepley + dm  - The mesh
2650338f77d5SMatthew G. Knepley . X   - Global input vector
2651*2a8381b2SBarry Smith - ctx - The application context
2652338f77d5SMatthew G. Knepley 
2653338f77d5SMatthew G. Knepley   Output Parameter:
265460225df5SJacob Faibussowitsch . F - Cellwise integrals for each field
2655338f77d5SMatthew G. Knepley 
2656338f77d5SMatthew G. Knepley   Level: developer
2657338f77d5SMatthew G. Knepley 
26581cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()`
2659338f77d5SMatthew G. Knepley @*/
DMPlexComputeCellwiseIntegralFEM(DM dm,Vec X,Vec F,PetscCtx ctx)2660*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, PetscCtx ctx)
2661d71ae5a4SJacob Faibussowitsch {
2662cbf8eb3cSStefano Zampini   PetscInt     printFEM;
2663338f77d5SMatthew G. Knepley   DM           dmF;
26649c8ab049SStefano Zampini   PetscSection sectionF = NULL;
2665338f77d5SMatthew G. Knepley   PetscScalar *cintegral, *af;
26669c8ab049SStefano Zampini   PetscInt     Nf, f, cellHeight, cStart, cEnd, cell, n;
26676493148fSStefano Zampini   Vec          locX;
2668338f77d5SMatthew G. Knepley 
2669338f77d5SMatthew G. Knepley   PetscFunctionBegin;
2670338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2671338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2672338f77d5SMatthew G. Knepley   PetscValidHeaderSpecific(F, VEC_CLASSID, 3);
26739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
2674cbf8eb3cSStefano Zampini   PetscCall(DMPlexConvertPlex(dm, &dm, PETSC_TRUE));
26759566063dSJacob Faibussowitsch   PetscCall(DMGetNumFields(dm, &Nf));
26769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight));
26779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd));
2678338f77d5SMatthew G. Knepley   /* TODO Introduce a loop over large chunks (right now this is a single chunk) */
26799566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral));
26806493148fSStefano Zampini   /* Get local solution with boundary values */
26816493148fSStefano Zampini   PetscCall(DMGetLocalVector(dm, &locX));
26826493148fSStefano Zampini   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
26836493148fSStefano Zampini   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
26846493148fSStefano Zampini   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
2685*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegral_Internal(dm, locX, cStart, cEnd, cintegral, ctx));
26866493148fSStefano Zampini   PetscCall(DMRestoreLocalVector(dm, &locX));
2687338f77d5SMatthew G. Knepley   /* Put values in F */
26889566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &af));
26899c8ab049SStefano Zampini   PetscCall(VecGetDM(F, &dmF));
26909c8ab049SStefano Zampini   if (dmF) PetscCall(DMGetLocalSection(dmF, &sectionF));
26919c8ab049SStefano Zampini   PetscCall(VecGetLocalSize(F, &n));
26929c8ab049SStefano Zampini   PetscCheck(n >= (cEnd - cStart) * Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vector size %" PetscInt_FMT " < %" PetscInt_FMT, n, (cEnd - cStart) * Nf);
2693cbf8eb3cSStefano Zampini   printFEM = ((DM_Plex *)dm->data)->printFEM;
2694338f77d5SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
2695338f77d5SMatthew G. Knepley     const PetscInt c   = cell - cStart;
26969c8ab049SStefano Zampini     PetscInt       dof = Nf, off = c * Nf;
2697338f77d5SMatthew G. Knepley 
2698cbf8eb3cSStefano Zampini     if (printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf]));
26999c8ab049SStefano Zampini     if (sectionF) {
27009566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(sectionF, cell, &dof));
27019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(sectionF, cell, &off));
27029c8ab049SStefano Zampini     }
270363a3b9bcSJacob Faibussowitsch     PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf);
2704338f77d5SMatthew G. Knepley     for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f];
2705338f77d5SMatthew G. Knepley   }
27069566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &af));
27079566063dSJacob Faibussowitsch   PetscCall(PetscFree(cintegral));
27089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
2709cbf8eb3cSStefano Zampini   PetscCall(DMDestroy(&dm));
27103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
271173d901b8SMatthew G. Knepley }
271273d901b8SMatthew G. Knepley 
DMPlexComputeBdIntegral_Internal(DM dm,Vec locX,IS pointIS,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[]),PetscScalar * fintegral,PetscCtx ctx)2713*2a8381b2SBarry Smith static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, 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[]), PetscScalar *fintegral, PetscCtx ctx)
2714d71ae5a4SJacob Faibussowitsch {
27159b6f715bSMatthew G. Knepley   DM                 plex = NULL, plexA = NULL;
2716a6e0b375SMatthew G. Knepley   DMEnclosureType    encAux;
27179b6f715bSMatthew G. Knepley   PetscDS            prob, probAux       = NULL;
27189b6f715bSMatthew G. Knepley   PetscSection       section, sectionAux = NULL;
27199b6f715bSMatthew G. Knepley   Vec                locA = NULL;
27209b6f715bSMatthew G. Knepley   DMField            coordField;
27219b6f715bSMatthew G. Knepley   PetscInt           Nf, totDim, *uOff, *uOff_x;
27229b6f715bSMatthew G. Knepley   PetscInt           NfAux = 0, totDimAux = 0, *aOff = NULL;
27239b6f715bSMatthew G. Knepley   PetscScalar       *u, *a = NULL;
272464c72086SMatthew G. Knepley   const PetscScalar *constants;
27259b6f715bSMatthew G. Knepley   PetscInt           numConstants, f;
272664c72086SMatthew G. Knepley 
272764c72086SMatthew G. Knepley   PetscFunctionBegin;
27289566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
27299566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
27309566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
27319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
27329566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
273364c72086SMatthew G. Knepley   /* Determine which discretizations we have */
27349b6f715bSMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
273564c72086SMatthew G. Knepley     PetscObject  obj;
273664c72086SMatthew G. Knepley     PetscClassId id;
273764c72086SMatthew G. Knepley 
27389566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
27399566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
274063a3b9bcSJacob Faibussowitsch     PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f);
274164c72086SMatthew G. Knepley   }
274264c72086SMatthew G. Knepley   /* Read DS information */
27439566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
27449566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(prob, &uOff));
27459566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x));
27469566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(prob, &numConstants, &constants));
274764c72086SMatthew G. Knepley   /* Read Auxiliary DS information */
27489566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
27499b6f715bSMatthew G. Knepley   if (locA) {
27509b6f715bSMatthew G. Knepley     DM dmAux;
27519b6f715bSMatthew G. Knepley 
27529566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
27539566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
27549566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
27559566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
27569566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(probAux, &NfAux));
27579566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
27589566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
27599566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(probAux, &aOff));
276064c72086SMatthew G. Knepley   }
27619b6f715bSMatthew G. Knepley   /* Integrate over points */
27629b6f715bSMatthew G. Knepley   {
27639b6f715bSMatthew G. Knepley     PetscFEGeom    *fgeom, *chunkGeom = NULL;
2764b7260050SToby Isaac     PetscInt        maxDegree;
27659b6f715bSMatthew G. Knepley     PetscQuadrature qGeom = NULL;
27669b6f715bSMatthew G. Knepley     const PetscInt *points;
27679b6f715bSMatthew G. Knepley     PetscInt        numFaces, face, Nq, field;
27689b6f715bSMatthew G. Knepley     PetscInt        numChunks, chunkSize, chunk, Nr, offset;
276964c72086SMatthew G. Knepley 
27709566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
27719566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
277232603206SJames Wright     PetscCall(PetscCalloc2(numFaces * totDim, &u, (locA ? (size_t)numFaces * totDimAux : 0), &a));
27739566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
277479ab67a3SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
277579ab67a3SMatthew G. Knepley       const PetscInt point = points[face], *support;
277679ab67a3SMatthew G. Knepley       PetscScalar   *x     = NULL;
277779ab67a3SMatthew G. Knepley 
277879ab67a3SMatthew G. Knepley       PetscCall(DMPlexGetSupport(dm, point, &support));
277979ab67a3SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
278079ab67a3SMatthew G. Knepley       for (PetscInt i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
278179ab67a3SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
278279ab67a3SMatthew G. Knepley       if (locA) {
278379ab67a3SMatthew G. Knepley         PetscInt subp;
278479ab67a3SMatthew G. Knepley         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
278579ab67a3SMatthew G. Knepley         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
278679ab67a3SMatthew G. Knepley         for (PetscInt i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i];
278779ab67a3SMatthew G. Knepley         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
278879ab67a3SMatthew G. Knepley       }
278979ab67a3SMatthew G. Knepley     }
279064c72086SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
279164c72086SMatthew G. Knepley       PetscFE fe;
279264c72086SMatthew G. Knepley 
27939566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe));
27949566063dSJacob Faibussowitsch       if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
27959b6f715bSMatthew G. Knepley       if (!qGeom) {
27969566063dSJacob Faibussowitsch         PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
27979566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)qGeom));
27989b6f715bSMatthew G. Knepley       }
27999566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
2800ac9d17c7SMatthew G. Knepley       PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_FEGEOM_BOUNDARY, &fgeom));
28019b6f715bSMatthew G. Knepley       /* Get blocking */
28029b6f715bSMatthew G. Knepley       {
28039b6f715bSMatthew G. Knepley         PetscQuadrature q;
28049b6f715bSMatthew G. Knepley         PetscInt        numBatches, batchSize, numBlocks, blockSize;
28059b6f715bSMatthew G. Knepley         PetscInt        Nq, Nb;
28069b6f715bSMatthew G. Knepley 
28079566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
28089566063dSJacob Faibussowitsch         PetscCall(PetscFEGetQuadrature(fe, &q));
28099566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
28109566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
281164c72086SMatthew G. Knepley         blockSize = Nb * Nq;
281264c72086SMatthew G. Knepley         batchSize = numBlocks * blockSize;
28139b6f715bSMatthew G. Knepley         chunkSize = numBatches * batchSize;
28149566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
28159b6f715bSMatthew G. Knepley         numChunks = numFaces / chunkSize;
28169b6f715bSMatthew G. Knepley         Nr        = numFaces % chunkSize;
281764c72086SMatthew G. Knepley         offset    = numFaces - Nr;
281864c72086SMatthew G. Knepley       }
28199b6f715bSMatthew G. Knepley       /* Do integration for each field */
28209b6f715bSMatthew G. Knepley       for (chunk = 0; chunk < numChunks; ++chunk) {
28219566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom));
282279ab67a3SMatthew G. Knepley         PetscCall(PetscFEIntegrateBd(prob, field, funcs[field], chunkSize, chunkGeom, &u[chunk * chunkSize * totDim], probAux, PetscSafePointerPlusOffset(a, chunk * chunkSize * totDimAux), &fintegral[chunk * chunkSize * Nf]));
28239566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom));
282464c72086SMatthew G. Knepley       }
28259566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
282679ab67a3SMatthew G. Knepley       PetscCall(PetscFEIntegrateBd(prob, field, funcs[field], Nr, chunkGeom, &u[offset * totDim], probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), &fintegral[offset * Nf]));
28279566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
282864c72086SMatthew G. Knepley       /* Cleanup data arrays */
2829ac9d17c7SMatthew G. Knepley       PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_FEGEOM_BOUNDARY, &fgeom));
28309566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&qGeom));
283179ab67a3SMatthew G. Knepley     }
28329566063dSJacob Faibussowitsch     PetscCall(PetscFree2(u, a));
28339566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
283464c72086SMatthew G. Knepley   }
28359566063dSJacob Faibussowitsch   if (plex) PetscCall(DMDestroy(&plex));
28369566063dSJacob Faibussowitsch   if (plexA) PetscCall(DMDestroy(&plexA));
28373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28389b6f715bSMatthew G. Knepley }
28399b6f715bSMatthew G. Knepley 
284060225df5SJacob Faibussowitsch /*@C
28419b6f715bSMatthew G. Knepley   DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user
28429b6f715bSMatthew G. Knepley 
28439b6f715bSMatthew G. Knepley   Input Parameters:
28449b6f715bSMatthew G. Knepley + dm      - The mesh
28459b6f715bSMatthew G. Knepley . X       - Global input vector
2846a1cb98faSBarry Smith . label   - The boundary `DMLabel`
2847a1cb98faSBarry Smith . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values
2848a1cb98faSBarry Smith . vals    - The label values to use, or NULL for all values
284979ab67a3SMatthew G. Knepley . funcs   - The functions to integrate along the boundary for each field
2850*2a8381b2SBarry Smith - ctx     - The application context
28519b6f715bSMatthew G. Knepley 
28529b6f715bSMatthew G. Knepley   Output Parameter:
28539b6f715bSMatthew G. Knepley . integral - Integral for each field
28549b6f715bSMatthew G. Knepley 
28559b6f715bSMatthew G. Knepley   Level: developer
28569b6f715bSMatthew G. Knepley 
28571cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()`
28589b6f715bSMatthew G. Knepley @*/
DMPlexComputeBdIntegral(DM dm,Vec X,DMLabel label,PetscInt numVals,const PetscInt vals[],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[]),PetscScalar * integral,PetscCtx ctx)2859*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], 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[]), PetscScalar *integral, PetscCtx ctx)
2860d71ae5a4SJacob Faibussowitsch {
28619b6f715bSMatthew G. Knepley   Vec          locX;
28629b6f715bSMatthew G. Knepley   PetscSection section;
28639b6f715bSMatthew G. Knepley   DMLabel      depthLabel;
28649b6f715bSMatthew G. Knepley   IS           facetIS;
28659b6f715bSMatthew G. Knepley   PetscInt     dim, Nf, f, v;
28669b6f715bSMatthew G. Knepley 
28679b6f715bSMatthew G. Knepley   PetscFunctionBegin;
28689b6f715bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28699b6f715bSMatthew G. Knepley   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
2870292bffcbSToby Isaac   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
28714f572ea9SToby Isaac   if (vals) PetscAssertPointer(vals, 5);
28724f572ea9SToby Isaac   PetscAssertPointer(integral, 7);
28739566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0));
28749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
28759566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
28769566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
28779566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
28789566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(section, &Nf));
28799b6f715bSMatthew G. Knepley   /* Get local solution with boundary values */
28809566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dm, &locX));
28819566063dSJacob Faibussowitsch   PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL));
28829566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
28839566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
28849b6f715bSMatthew G. Knepley   /* Loop over label values */
28859566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(integral, Nf));
28869b6f715bSMatthew G. Knepley   for (v = 0; v < numVals; ++v) {
28879b6f715bSMatthew G. Knepley     IS           pointIS;
28889b6f715bSMatthew G. Knepley     PetscInt     numFaces, face;
28899b6f715bSMatthew G. Knepley     PetscScalar *fintegral;
28909b6f715bSMatthew G. Knepley 
28919566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS));
28929b6f715bSMatthew G. Knepley     if (!pointIS) continue; /* No points with that id on this process */
28939b6f715bSMatthew G. Knepley     {
28949b6f715bSMatthew G. Knepley       IS isectIS;
28959b6f715bSMatthew G. Knepley 
28969b6f715bSMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
28979566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
28989566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
28999b6f715bSMatthew G. Knepley       pointIS = isectIS;
29009b6f715bSMatthew G. Knepley     }
29019566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
29029566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(numFaces * Nf, &fintegral));
2903*2a8381b2SBarry Smith     PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, funcs, fintegral, ctx));
29049b6f715bSMatthew G. Knepley     /* Sum point contributions into integral */
29059371c9d4SSatish Balay     for (f = 0; f < Nf; ++f)
29069371c9d4SSatish Balay       for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f];
29079566063dSJacob Faibussowitsch     PetscCall(PetscFree(fintegral));
29089566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
29099b6f715bSMatthew G. Knepley   }
29109566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(dm, &locX));
29119566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
29129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0));
29133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
291464c72086SMatthew G. Knepley }
291564c72086SMatthew G. Knepley 
2916d69c5d34SMatthew G. Knepley /*@
29170318f8a0SStefano Zampini   DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix from the coarse `DM` to a uniformly refined `DM`.
2918d69c5d34SMatthew G. Knepley 
2919d69c5d34SMatthew G. Knepley   Input Parameters:
2920cf51de39SMatthew G. Knepley + dmc       - The coarse mesh
2921cf51de39SMatthew G. Knepley . dmf       - The fine mesh
2922cf51de39SMatthew G. Knepley . isRefined - Flag indicating regular refinement, rather than the same topology
2923*2a8381b2SBarry Smith - ctx       - The application context
2924d69c5d34SMatthew G. Knepley 
2925d69c5d34SMatthew G. Knepley   Output Parameter:
2926934789fcSMatthew G. Knepley . In - The interpolation matrix
2927d69c5d34SMatthew G. Knepley 
2928d69c5d34SMatthew G. Knepley   Level: developer
2929d69c5d34SMatthew G. Knepley 
2930ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`
2931d69c5d34SMatthew G. Knepley @*/
DMPlexComputeInterpolatorNested(DM dmc,DM dmf,PetscBool isRefined,Mat In,PetscCtx ctx)2932*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, PetscCtx ctx)
2933d71ae5a4SJacob Faibussowitsch {
2934d69c5d34SMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmc->data;
2935d69c5d34SMatthew G. Knepley   const char  *name = "Interpolator";
2936d69c5d34SMatthew G. Knepley   PetscFE     *feRef;
293797c42addSMatthew G. Knepley   PetscFV     *fvRef;
2938d69c5d34SMatthew G. Knepley   PetscSection fsection, fglobalSection;
2939d69c5d34SMatthew G. Knepley   PetscSection csection, cglobalSection;
2940d69c5d34SMatthew G. Knepley   PetscScalar *elemMat;
2941485ad865SMatthew G. Knepley   PetscInt     dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c;
29422ea9c922SToby Isaac   PetscInt     cTotDim = 0, rTotDim = 0;
2943d69c5d34SMatthew G. Knepley 
2944d69c5d34SMatthew G. Knepley   PetscFunctionBegin;
29459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
29469566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmf, &dim));
29479566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
29489566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &fglobalSection));
29499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
29509566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
29519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &Nf));
29529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd));
29539566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef));
2954d69c5d34SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
29552ea9c922SToby Isaac     PetscObject  obj, objc;
29562ea9c922SToby Isaac     PetscClassId id, idc;
29572ea9c922SToby Isaac     PetscInt     rNb = 0, Nc = 0, cNb = 0;
2958d69c5d34SMatthew G. Knepley 
29599566063dSJacob Faibussowitsch     PetscCall(DMGetField(dmf, f, NULL, &obj));
29609566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
296197c42addSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
296297c42addSMatthew G. Knepley       PetscFE fe = (PetscFE)obj;
296397c42addSMatthew G. Knepley 
2964cf51de39SMatthew G. Knepley       if (isRefined) {
29659566063dSJacob Faibussowitsch         PetscCall(PetscFERefine(fe, &feRef[f]));
2966cf51de39SMatthew G. Knepley       } else {
29679566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)fe));
2968cf51de39SMatthew G. Knepley         feRef[f] = fe;
2969cf51de39SMatthew G. Knepley       }
29709566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feRef[f], &rNb));
29719566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
297297c42addSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
297397c42addSMatthew G. Knepley       PetscFV        fv = (PetscFV)obj;
297497c42addSMatthew G. Knepley       PetscDualSpace Q;
297597c42addSMatthew G. Knepley 
2976cf51de39SMatthew G. Knepley       if (isRefined) {
29779566063dSJacob Faibussowitsch         PetscCall(PetscFVRefine(fv, &fvRef[f]));
2978cf51de39SMatthew G. Knepley       } else {
29799566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)fv));
2980cf51de39SMatthew G. Knepley         fvRef[f] = fv;
2981cf51de39SMatthew G. Knepley       }
29829566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[f], &Q));
29839566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &rNb));
29849566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &Q));
29859566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
298697c42addSMatthew G. Knepley     }
29879566063dSJacob Faibussowitsch     PetscCall(DMGetField(dmc, f, NULL, &objc));
29889566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(objc, &idc));
29892ea9c922SToby Isaac     if (idc == PETSCFE_CLASSID) {
29902ea9c922SToby Isaac       PetscFE fe = (PetscFE)objc;
29912ea9c922SToby Isaac 
29929566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &cNb));
29932ea9c922SToby Isaac     } else if (id == PETSCFV_CLASSID) {
29942ea9c922SToby Isaac       PetscFV        fv = (PetscFV)obj;
29952ea9c922SToby Isaac       PetscDualSpace Q;
29962ea9c922SToby Isaac 
29979566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fv, &Q));
29989566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &cNb));
2999d69c5d34SMatthew G. Knepley     }
30002ea9c922SToby Isaac     rTotDim += rNb;
30012ea9c922SToby Isaac     cTotDim += cNb;
30022ea9c922SToby Isaac   }
30039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat));
30049566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim));
3005d69c5d34SMatthew G. Knepley   for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) {
3006d69c5d34SMatthew G. Knepley     PetscDualSpace   Qref;
3007d69c5d34SMatthew G. Knepley     PetscQuadrature  f;
3008d69c5d34SMatthew G. Knepley     const PetscReal *qpoints, *qweights;
3009d69c5d34SMatthew G. Knepley     PetscReal       *points;
3010d69c5d34SMatthew G. Knepley     PetscInt         npoints = 0, Nc, Np, fpdim, i, k, p, d;
3011d69c5d34SMatthew G. Knepley 
3012d69c5d34SMatthew G. Knepley     /* Compose points from all dual basis functionals */
301397c42addSMatthew G. Knepley     if (feRef[fieldI]) {
30149566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref));
30159566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc));
301697c42addSMatthew G. Knepley     } else {
30179566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref));
30189566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc));
301997c42addSMatthew G. Knepley     }
30209566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim));
3021d69c5d34SMatthew G. Knepley     for (i = 0; i < fpdim; ++i) {
30229566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
30239566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL));
3024d69c5d34SMatthew G. Knepley       npoints += Np;
3025d69c5d34SMatthew G. Knepley     }
30269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(npoints * dim, &points));
3027d69c5d34SMatthew G. Knepley     for (i = 0, k = 0; i < fpdim; ++i) {
30289566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
30299566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL));
30309371c9d4SSatish Balay       for (p = 0; p < Np; ++p, ++k)
30319371c9d4SSatish Balay         for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d];
3032d69c5d34SMatthew G. Knepley     }
3033d69c5d34SMatthew G. Knepley 
3034d69c5d34SMatthew G. Knepley     for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) {
303597c42addSMatthew G. Knepley       PetscObject  obj;
303697c42addSMatthew G. Knepley       PetscClassId id;
30379c3cf19fSMatthew G. Knepley       PetscInt     NcJ = 0, cpdim = 0, j, qNc;
3038d69c5d34SMatthew G. Knepley 
30399566063dSJacob Faibussowitsch       PetscCall(DMGetField(dmc, fieldJ, NULL, &obj));
30409566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
304197c42addSMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
304297c42addSMatthew G. Knepley         PetscFE         fe = (PetscFE)obj;
3043ef0bb6c7SMatthew G. Knepley         PetscTabulation T  = NULL;
3044d69c5d34SMatthew G. Knepley 
3045d69c5d34SMatthew G. Knepley         /* Evaluate basis at points */
30469566063dSJacob Faibussowitsch         PetscCall(PetscFEGetNumComponents(fe, &NcJ));
30479566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &cpdim));
3048ffe73a53SMatthew G. Knepley         /* For now, fields only interpolate themselves */
3049ffe73a53SMatthew G. Knepley         if (fieldI == fieldJ) {
305063a3b9bcSJacob 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);
30519566063dSJacob Faibussowitsch           PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T));
3052d69c5d34SMatthew G. Knepley           for (i = 0, k = 0; i < fpdim; ++i) {
30539566063dSJacob Faibussowitsch             PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
30549566063dSJacob Faibussowitsch             PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights));
305563a3b9bcSJacob 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);
3056d69c5d34SMatthew G. Knepley             for (p = 0; p < Np; ++p, ++k) {
305736a6d9c0SMatthew G. Knepley               for (j = 0; j < cpdim; ++j) {
3058d172c84bSMatthew G. Knepley                 /*
3059d172c84bSMatthew G. Knepley                    cTotDim:            Total columns in element interpolation matrix, sum of number of dual basis functionals in each field
3060d172c84bSMatthew G. Knepley                    offsetI, offsetJ:   Offsets into the larger element interpolation matrix for different fields
3061d172c84bSMatthew G. Knepley                    fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals
3062d172c84bSMatthew G. Knepley                    qNC, Nc, Ncj, c:    Number of components in this field
3063d172c84bSMatthew G. Knepley                    Np, p:              Number of quad points in the fine grid functional i
3064d172c84bSMatthew G. Knepley                    k:                  i*Np + p, overall point number for the interpolation
3065d172c84bSMatthew G. Knepley                 */
3066ef0bb6c7SMatthew 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];
306736a6d9c0SMatthew G. Knepley               }
3068d69c5d34SMatthew G. Knepley             }
3069d69c5d34SMatthew G. Knepley           }
30709566063dSJacob Faibussowitsch           PetscCall(PetscTabulationDestroy(&T));
3071ffe73a53SMatthew G. Knepley         }
307297c42addSMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
307397c42addSMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
307497c42addSMatthew G. Knepley 
307597c42addSMatthew G. Knepley         /* Evaluate constant function at points */
30769566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &NcJ));
307797c42addSMatthew G. Knepley         cpdim = 1;
307897c42addSMatthew G. Knepley         /* For now, fields only interpolate themselves */
307997c42addSMatthew G. Knepley         if (fieldI == fieldJ) {
308063a3b9bcSJacob 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);
308197c42addSMatthew G. Knepley           for (i = 0, k = 0; i < fpdim; ++i) {
30829566063dSJacob Faibussowitsch             PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f));
30839566063dSJacob Faibussowitsch             PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights));
308463a3b9bcSJacob 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);
308597c42addSMatthew G. Knepley             for (p = 0; p < Np; ++p, ++k) {
308697c42addSMatthew G. Knepley               for (j = 0; j < cpdim; ++j) {
3087458eb97cSMatthew G. Knepley                 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c];
308897c42addSMatthew G. Knepley               }
308997c42addSMatthew G. Knepley             }
309097c42addSMatthew G. Knepley           }
309197c42addSMatthew G. Knepley         }
309297c42addSMatthew G. Knepley       }
3093d172c84bSMatthew G. Knepley       offsetJ += cpdim;
3094d69c5d34SMatthew G. Knepley     }
3095d172c84bSMatthew G. Knepley     offsetI += fpdim;
30969566063dSJacob Faibussowitsch     PetscCall(PetscFree(points));
3097d69c5d34SMatthew G. Knepley   }
30989566063dSJacob Faibussowitsch   if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat));
30997f5b169aSMatthew G. Knepley   /* Preallocate matrix */
31007f5b169aSMatthew G. Knepley   {
3101c094ef40SMatthew G. Knepley     Mat          preallocator;
3102c094ef40SMatthew G. Knepley     PetscScalar *vals;
3103c094ef40SMatthew G. Knepley     PetscInt    *cellCIndices, *cellFIndices;
3104c094ef40SMatthew G. Knepley     PetscInt     locRows, locCols, cell;
31057f5b169aSMatthew G. Knepley 
31069566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(In, &locRows, &locCols));
31079566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator));
31089566063dSJacob Faibussowitsch     PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
31099566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE));
31109566063dSJacob Faibussowitsch     PetscCall(MatSetUp(preallocator));
31119566063dSJacob Faibussowitsch     PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices));
3112b4ec2976SMatthew G. Knepley     if (locRows || locCols) {
31137f5b169aSMatthew G. Knepley       for (cell = cStart; cell < cEnd; ++cell) {
3114cf51de39SMatthew G. Knepley         if (isRefined) {
31159566063dSJacob Faibussowitsch           PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices));
31169566063dSJacob Faibussowitsch           PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES));
3117cf51de39SMatthew G. Knepley         } else {
3118e8e188d2SZach Atkins           PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, preallocator, cell, vals, INSERT_VALUES));
3119cf51de39SMatthew G. Knepley         }
31207f5b169aSMatthew G. Knepley       }
3121b4ec2976SMatthew G. Knepley     }
31229566063dSJacob Faibussowitsch     PetscCall(PetscFree3(vals, cellCIndices, cellFIndices));
31239566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
31249566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
31259566063dSJacob Faibussowitsch     PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In));
31269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&preallocator));
31277f5b169aSMatthew G. Knepley   }
31287f5b169aSMatthew G. Knepley   /* Fill matrix */
31299566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(In));
3130d69c5d34SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
3131cf51de39SMatthew G. Knepley     if (isRefined) {
31329566063dSJacob Faibussowitsch       PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES));
3133cf51de39SMatthew G. Knepley     } else {
3134e8e188d2SZach Atkins       PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, PETSC_FALSE, dmc, csection, cglobalSection, PETSC_FALSE, In, c, elemMat, INSERT_VALUES));
3135cf51de39SMatthew G. Knepley     }
3136d69c5d34SMatthew G. Knepley   }
31379566063dSJacob Faibussowitsch   for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f]));
31389566063dSJacob Faibussowitsch   PetscCall(PetscFree2(feRef, fvRef));
31399566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
31409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY));
31419566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY));
31429318fe57SMatthew G. Knepley   if (mesh->printFEM > 1) {
31439566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name));
31442ce66baaSPierre Jolivet     PetscCall(MatFilter(In, 1.0e-10, PETSC_FALSE, PETSC_FALSE));
31459566063dSJacob Faibussowitsch     PetscCall(MatView(In, NULL));
3146d69c5d34SMatthew G. Knepley   }
31479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
31483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3149d69c5d34SMatthew G. Knepley }
31506c73c22cSMatthew G. Knepley 
DMPlexComputeMassMatrixNested(DM dmc,DM dmf,Mat mass,PetscCtx ctx)3151*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, PetscCtx ctx)
3152d71ae5a4SJacob Faibussowitsch {
3153bd041c0cSMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness");
3154bd041c0cSMatthew G. Knepley }
3155bd041c0cSMatthew G. Knepley 
315668132eb9SMatthew G. Knepley /*@
31570318f8a0SStefano Zampini   DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix from the coarse `DM` to a non-nested fine `DM`.
315868132eb9SMatthew G. Knepley 
315968132eb9SMatthew G. Knepley   Input Parameters:
316068132eb9SMatthew G. Knepley + dmf - The fine mesh
316168132eb9SMatthew G. Knepley . dmc - The coarse mesh
3162*2a8381b2SBarry Smith - ctx - The application context
316368132eb9SMatthew G. Knepley 
316468132eb9SMatthew G. Knepley   Output Parameter:
316568132eb9SMatthew G. Knepley . In - The interpolation matrix
316668132eb9SMatthew G. Knepley 
316768132eb9SMatthew G. Knepley   Level: developer
316868132eb9SMatthew G. Knepley 
3169ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`
317068132eb9SMatthew G. Knepley @*/
DMPlexComputeInterpolatorGeneral(DM dmc,DM dmf,Mat In,PetscCtx ctx)3171*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, PetscCtx ctx)
3172d71ae5a4SJacob Faibussowitsch {
317364e98e1dSMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmf->data;
317464e98e1dSMatthew G. Knepley   const char  *name = "Interpolator";
31754ef9d792SMatthew G. Knepley   PetscDS      prob;
3176a0806964SMatthew G. Knepley   Mat          interp;
3177a0806964SMatthew G. Knepley   PetscSection fsection, globalFSection;
3178a0806964SMatthew G. Knepley   PetscSection csection, globalCSection;
3179a0806964SMatthew G. Knepley   PetscInt     locRows, locCols;
31804ef9d792SMatthew G. Knepley   PetscReal   *x, *v0, *J, *invJ, detJ;
31814ef9d792SMatthew G. Knepley   PetscReal   *v0c, *Jc, *invJc, detJc;
31824ef9d792SMatthew G. Knepley   PetscScalar *elemMat;
3183a0806964SMatthew G. Knepley   PetscInt     dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s;
31844ef9d792SMatthew G. Knepley 
31854ef9d792SMatthew G. Knepley   PetscFunctionBegin;
31869566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
31879566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmc, &dim));
31889566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
31899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL));
31909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
31919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
31929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc));
31939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
31949566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
31959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
31969566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &globalCSection));
3197a0806964SMatthew G. Knepley   PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd));
31989566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
31999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(totDim, &elemMat));
32004ef9d792SMatthew G. Knepley 
3201a0806964SMatthew G. Knepley   PetscCall(MatGetLocalSize(In, &locRows, &locCols));
3202a0806964SMatthew G. Knepley   PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp));
3203a0806964SMatthew G. Knepley   PetscCall(MatSetType(interp, MATPREALLOCATOR));
3204a0806964SMatthew G. Knepley   PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE));
3205a0806964SMatthew G. Knepley   PetscCall(MatSetUp(interp));
3206a0806964SMatthew G. Knepley   for (s = 0; s < 2; ++s) {
32074ef9d792SMatthew G. Knepley     for (field = 0; field < Nf; ++field) {
32084ef9d792SMatthew G. Knepley       PetscObject      obj;
32094ef9d792SMatthew G. Knepley       PetscClassId     id;
3210c0d7054bSMatthew G. Knepley       PetscDualSpace   Q = NULL;
3211ef0bb6c7SMatthew G. Knepley       PetscTabulation  T = NULL;
32124ef9d792SMatthew G. Knepley       PetscQuadrature  f;
32134ef9d792SMatthew G. Knepley       const PetscReal *qpoints, *qweights;
3214d0f6233fSMatthew G. Knepley       PetscInt         Nc, qNc, Np, fpdim, off, i, d;
32154ef9d792SMatthew G. Knepley 
3216d0f6233fSMatthew G. Knepley       PetscCall(PetscDSGetFieldOffset(prob, field, &off));
32179566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, &obj));
32189566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
32194ef9d792SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
32204ef9d792SMatthew G. Knepley         PetscFE fe = (PetscFE)obj;
32214ef9d792SMatthew G. Knepley 
32229566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDualSpace(fe, &Q));
32239566063dSJacob Faibussowitsch         PetscCall(PetscFEGetNumComponents(fe, &Nc));
3224a0806964SMatthew G. Knepley         if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T));
32254ef9d792SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
32264ef9d792SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
32274ef9d792SMatthew G. Knepley 
32289566063dSJacob Faibussowitsch         PetscCall(PetscFVGetDualSpace(fv, &Q));
32294ef9d792SMatthew G. Knepley         Nc = 1;
323063a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field);
32319566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &fpdim));
32324ef9d792SMatthew G. Knepley       /* For each fine grid cell */
32334ef9d792SMatthew G. Knepley       for (cell = cStart; cell < cEnd; ++cell) {
32344ef9d792SMatthew G. Knepley         PetscInt *findices, *cindices;
32354ef9d792SMatthew G. Knepley         PetscInt  numFIndices, numCIndices;
32364ef9d792SMatthew G. Knepley 
32379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
32389566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3239d0f6233fSMatthew 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);
32404ef9d792SMatthew G. Knepley         for (i = 0; i < fpdim; ++i) {
32414ef9d792SMatthew G. Knepley           Vec                pointVec;
32424ef9d792SMatthew G. Knepley           PetscScalar       *pV;
324312111d7cSToby Isaac           PetscSF            coarseCellSF = NULL;
32443a93e3b7SToby Isaac           const PetscSFNode *coarseCells;
3245d0f6233fSMatthew G. Knepley           PetscInt           numCoarseCells, cpdim, row = findices[i + off], q, c, j;
32464ef9d792SMatthew G. Knepley 
32474ef9d792SMatthew G. Knepley           /* Get points from the dual basis functional quadrature */
32489566063dSJacob Faibussowitsch           PetscCall(PetscDualSpaceGetFunctional(Q, i, &f));
32499566063dSJacob Faibussowitsch           PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights));
325063a3b9bcSJacob 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);
32519566063dSJacob Faibussowitsch           PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec));
32529566063dSJacob Faibussowitsch           PetscCall(VecSetBlockSize(pointVec, dim));
32539566063dSJacob Faibussowitsch           PetscCall(VecGetArray(pointVec, &pV));
32544ef9d792SMatthew G. Knepley           for (q = 0; q < Np; ++q) {
3255c330f8ffSToby Isaac             const PetscReal xi0[3] = {-1., -1., -1.};
3256c330f8ffSToby Isaac 
32574ef9d792SMatthew G. Knepley             /* Transform point to real space */
3258c330f8ffSToby Isaac             CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
32594ef9d792SMatthew G. Knepley             for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
32604ef9d792SMatthew G. Knepley           }
32619566063dSJacob Faibussowitsch           PetscCall(VecRestoreArray(pointVec, &pV));
32624ef9d792SMatthew G. Knepley           /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
32631555c271SMatthew G. Knepley           /* OPT: Read this out from preallocation information */
32649566063dSJacob Faibussowitsch           PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
32654ef9d792SMatthew G. Knepley           /* Update preallocation info */
32669566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
32675f80ce2aSJacob Faibussowitsch           PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
32689566063dSJacob Faibussowitsch           PetscCall(VecGetArray(pointVec, &pV));
32694ef9d792SMatthew G. Knepley           for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3270826eb36dSMatthew G. Knepley             PetscReal       pVReal[3];
3271c330f8ffSToby Isaac             const PetscReal xi0[3] = {-1., -1., -1.};
3272826eb36dSMatthew G. Knepley 
32739566063dSJacob Faibussowitsch             PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3274a0806964SMatthew G. Knepley             if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim));
3275a0806964SMatthew G. Knepley             else cpdim = 1;
3276a0806964SMatthew G. Knepley 
3277a0806964SMatthew G. Knepley             if (s) {
32784ef9d792SMatthew G. Knepley               /* Transform points from real space to coarse reference space */
32799566063dSJacob Faibussowitsch               PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc));
3280e2d86523SMatthew G. Knepley               for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
3281c330f8ffSToby Isaac               CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
32824ef9d792SMatthew G. Knepley 
32834ef9d792SMatthew G. Knepley               if (id == PETSCFE_CLASSID) {
32844ef9d792SMatthew G. Knepley                 /* Evaluate coarse basis on contained point */
3285a0806964SMatthew G. Knepley                 PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T));
32869566063dSJacob Faibussowitsch                 PetscCall(PetscArrayzero(elemMat, cpdim));
32874ef9d792SMatthew G. Knepley                 /* Get elemMat entries by multiplying by weight */
32884ef9d792SMatthew G. Knepley                 for (j = 0; j < cpdim; ++j) {
3289ef0bb6c7SMatthew G. Knepley                   for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c];
32904ef9d792SMatthew G. Knepley                 }
32914ef9d792SMatthew G. Knepley               } else {
32924ef9d792SMatthew G. Knepley                 for (j = 0; j < cpdim; ++j) {
32939c3cf19fSMatthew G. Knepley                   for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c];
32944ef9d792SMatthew G. Knepley                 }
32954ef9d792SMatthew G. Knepley               }
32969566063dSJacob Faibussowitsch               if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
3297a0806964SMatthew G. Knepley             }
3298a0806964SMatthew G. Knepley             /* Update interpolator */
3299d0f6233fSMatthew G. Knepley             PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim);
3300a0806964SMatthew G. Knepley             PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES));
33019566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
33024ef9d792SMatthew G. Knepley           }
33039566063dSJacob Faibussowitsch           PetscCall(VecRestoreArray(pointVec, &pV));
33049566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseCellSF));
33059566063dSJacob Faibussowitsch           PetscCall(VecDestroy(&pointVec));
33064ef9d792SMatthew G. Knepley         }
33079566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
33084ef9d792SMatthew G. Knepley       }
3309a0806964SMatthew G. Knepley       if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T));
3310a0806964SMatthew G. Knepley     }
3311a0806964SMatthew G. Knepley     if (!s) {
3312a0806964SMatthew G. Knepley       PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY));
3313a0806964SMatthew G. Knepley       PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY));
3314a0806964SMatthew G. Knepley       PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In));
3315a0806964SMatthew G. Knepley       PetscCall(MatDestroy(&interp));
3316a0806964SMatthew G. Knepley       interp = In;
3317a0806964SMatthew G. Knepley     }
33184ef9d792SMatthew G. Knepley   }
33199566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
33209566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0c, Jc, invJc));
33219566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
33229566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY));
33239566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY));
33249566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0));
33253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33264ef9d792SMatthew G. Knepley }
33274ef9d792SMatthew G. Knepley 
332846fa42a0SMatthew G. Knepley /*@
33290318f8a0SStefano Zampini   DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix from the coarse `DM` to a non-nested fine `DM`.
3330bd041c0cSMatthew G. Knepley 
3331bd041c0cSMatthew G. Knepley   Input Parameters:
3332bd041c0cSMatthew G. Knepley + dmf - The fine mesh
3333bd041c0cSMatthew G. Knepley . dmc - The coarse mesh
3334*2a8381b2SBarry Smith - ctx - The application context
3335bd041c0cSMatthew G. Knepley 
3336bd041c0cSMatthew G. Knepley   Output Parameter:
3337bd041c0cSMatthew G. Knepley . mass - The mass matrix
3338bd041c0cSMatthew G. Knepley 
3339bd041c0cSMatthew G. Knepley   Level: developer
3340bd041c0cSMatthew G. Knepley 
3341ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`
3342bd041c0cSMatthew G. Knepley @*/
DMPlexComputeMassMatrixGeneral(DM dmc,DM dmf,Mat mass,PetscCtx ctx)3343*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, PetscCtx ctx)
3344d71ae5a4SJacob Faibussowitsch {
3345bd041c0cSMatthew G. Knepley   DM_Plex     *mesh = (DM_Plex *)dmf->data;
3346bd041c0cSMatthew G. Knepley   const char  *name = "Mass Matrix";
3347bd041c0cSMatthew G. Knepley   PetscDS      prob;
3348bd041c0cSMatthew G. Knepley   PetscSection fsection, csection, globalFSection, globalCSection;
3349e8f14785SLisandro Dalcin   PetscHSetIJ  ht;
3350bd041c0cSMatthew G. Knepley   PetscLayout  rLayout;
3351bd041c0cSMatthew G. Knepley   PetscInt    *dnz, *onz;
3352bd041c0cSMatthew G. Knepley   PetscInt     locRows, rStart, rEnd;
3353bd041c0cSMatthew G. Knepley   PetscReal   *x, *v0, *J, *invJ, detJ;
3354bd041c0cSMatthew G. Knepley   PetscReal   *v0c, *Jc, *invJc, detJc;
3355bd041c0cSMatthew G. Knepley   PetscScalar *elemMat;
3356bd041c0cSMatthew G. Knepley   PetscInt     dim, Nf, field, totDim, cStart, cEnd, cell, ccell;
3357bd041c0cSMatthew G. Knepley 
3358bd041c0cSMatthew G. Knepley   PetscFunctionBegin;
33599566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dmc, &dim));
33609566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
33619566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL));
33629566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
33639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ));
33649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc));
33659566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
33669566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &globalFSection));
33679566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
33689566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &globalCSection));
33699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd));
33709566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
33719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(totDim, &elemMat));
3372bd041c0cSMatthew G. Knepley 
33739566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mass, &locRows, NULL));
33749566063dSJacob Faibussowitsch   PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout));
33759566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(rLayout, locRows));
33769566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetBlockSize(rLayout, 1));
33779566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(rLayout));
33789566063dSJacob Faibussowitsch   PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd));
33799566063dSJacob Faibussowitsch   PetscCall(PetscLayoutDestroy(&rLayout));
33809566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz));
33819566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJCreate(&ht));
3382bd041c0cSMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3383bd041c0cSMatthew G. Knepley     PetscObject      obj;
3384bd041c0cSMatthew G. Knepley     PetscClassId     id;
3385bd041c0cSMatthew G. Knepley     PetscQuadrature  quad;
3386bd041c0cSMatthew G. Knepley     const PetscReal *qpoints;
3387bd041c0cSMatthew G. Knepley     PetscInt         Nq, Nc, i, d;
3388bd041c0cSMatthew G. Knepley 
33899566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
33909566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
33919566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad));
33929566063dSJacob Faibussowitsch     else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad));
33939566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL));
3394bd041c0cSMatthew G. Knepley     /* For each fine grid cell */
3395bd041c0cSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3396bd041c0cSMatthew G. Knepley       Vec                pointVec;
3397bd041c0cSMatthew G. Knepley       PetscScalar       *pV;
3398bd041c0cSMatthew G. Knepley       PetscSF            coarseCellSF = NULL;
3399bd041c0cSMatthew G. Knepley       const PetscSFNode *coarseCells;
3400bd041c0cSMatthew G. Knepley       PetscInt           numCoarseCells, q, c;
3401bd041c0cSMatthew G. Knepley       PetscInt          *findices, *cindices;
3402bd041c0cSMatthew G. Knepley       PetscInt           numFIndices, numCIndices;
3403bd041c0cSMatthew G. Knepley 
34049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
34059566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3406bd041c0cSMatthew G. Knepley       /* Get points from the quadrature */
34079566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec));
34089566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(pointVec, dim));
34099566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3410bd041c0cSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
3411c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3412c330f8ffSToby Isaac 
3413bd041c0cSMatthew G. Knepley         /* Transform point to real space */
3414c330f8ffSToby Isaac         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3415bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3416bd041c0cSMatthew G. Knepley       }
34179566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
3418bd041c0cSMatthew G. Knepley       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
34199566063dSJacob Faibussowitsch       PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
34209566063dSJacob Faibussowitsch       PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view"));
3421bd041c0cSMatthew G. Knepley       /* Update preallocation info */
34229566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
34235f80ce2aSJacob Faibussowitsch       PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
3424bd041c0cSMatthew G. Knepley       {
3425e8f14785SLisandro Dalcin         PetscHashIJKey key;
3426e8f14785SLisandro Dalcin         PetscBool      missing;
3427bd041c0cSMatthew G. Knepley 
3428bd041c0cSMatthew G. Knepley         for (i = 0; i < numFIndices; ++i) {
3429e8f14785SLisandro Dalcin           key.i = findices[i];
3430e8f14785SLisandro Dalcin           if (key.i >= 0) {
3431bd041c0cSMatthew G. Knepley             /* Get indices for coarse elements */
3432bd041c0cSMatthew G. Knepley             for (ccell = 0; ccell < numCoarseCells; ++ccell) {
34339566063dSJacob Faibussowitsch               PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3434bd041c0cSMatthew G. Knepley               for (c = 0; c < numCIndices; ++c) {
3435e8f14785SLisandro Dalcin                 key.j = cindices[c];
3436e8f14785SLisandro Dalcin                 if (key.j < 0) continue;
34379566063dSJacob Faibussowitsch                 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing));
3438bd041c0cSMatthew G. Knepley                 if (missing) {
3439e8f14785SLisandro Dalcin                   if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart];
3440e8f14785SLisandro Dalcin                   else ++onz[key.i - rStart];
3441bd041c0cSMatthew G. Knepley                 }
3442bd041c0cSMatthew G. Knepley               }
34439566063dSJacob Faibussowitsch               PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3444bd041c0cSMatthew G. Knepley             }
3445bd041c0cSMatthew G. Knepley           }
3446bd041c0cSMatthew G. Knepley         }
3447bd041c0cSMatthew G. Knepley       }
34489566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coarseCellSF));
34499566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&pointVec));
34509566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3451bd041c0cSMatthew G. Knepley     }
3452bd041c0cSMatthew G. Knepley   }
34539566063dSJacob Faibussowitsch   PetscCall(PetscHSetIJDestroy(&ht));
34549566063dSJacob Faibussowitsch   PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL));
34559566063dSJacob Faibussowitsch   PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE));
34569566063dSJacob Faibussowitsch   PetscCall(PetscFree2(dnz, onz));
3457bd041c0cSMatthew G. Knepley   for (field = 0; field < Nf; ++field) {
3458bd041c0cSMatthew G. Knepley     PetscObject      obj;
3459bd041c0cSMatthew G. Knepley     PetscClassId     id;
3460ef0bb6c7SMatthew G. Knepley     PetscTabulation  T, Tfine;
3461bd041c0cSMatthew G. Knepley     PetscQuadrature  quad;
3462bd041c0cSMatthew G. Knepley     const PetscReal *qpoints, *qweights;
3463bd041c0cSMatthew G. Knepley     PetscInt         Nq, Nc, i, d;
3464bd041c0cSMatthew G. Knepley 
34659566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
34669566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
3467ef0bb6c7SMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
34689566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad));
34699566063dSJacob Faibussowitsch       PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine));
34709566063dSJacob Faibussowitsch       PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T));
3471ef0bb6c7SMatthew G. Knepley     } else {
34729566063dSJacob Faibussowitsch       PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad));
3473ef0bb6c7SMatthew G. Knepley     }
34749566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights));
3475bd041c0cSMatthew G. Knepley     /* For each fine grid cell */
3476bd041c0cSMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
3477bd041c0cSMatthew G. Knepley       Vec                pointVec;
3478bd041c0cSMatthew G. Knepley       PetscScalar       *pV;
3479bd041c0cSMatthew G. Knepley       PetscSF            coarseCellSF = NULL;
3480bd041c0cSMatthew G. Knepley       const PetscSFNode *coarseCells;
3481bd041c0cSMatthew G. Knepley       PetscInt           numCoarseCells, cpdim, q, c, j;
3482bd041c0cSMatthew G. Knepley       PetscInt          *findices, *cindices;
3483bd041c0cSMatthew G. Knepley       PetscInt           numFIndices, numCIndices;
3484bd041c0cSMatthew G. Knepley 
34859566063dSJacob Faibussowitsch       PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
34869566063dSJacob Faibussowitsch       PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ));
3487bd041c0cSMatthew G. Knepley       /* Get points from the quadrature */
34889566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec));
34899566063dSJacob Faibussowitsch       PetscCall(VecSetBlockSize(pointVec, dim));
34909566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3491bd041c0cSMatthew G. Knepley       for (q = 0; q < Nq; ++q) {
3492c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3493c330f8ffSToby Isaac 
3494bd041c0cSMatthew G. Knepley         /* Transform point to real space */
3495c330f8ffSToby Isaac         CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x);
3496bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d];
3497bd041c0cSMatthew G. Knepley       }
34989566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
3499bd041c0cSMatthew G. Knepley       /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */
35009566063dSJacob Faibussowitsch       PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF));
3501bd041c0cSMatthew G. Knepley       /* Update matrix */
35029566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells));
35035f80ce2aSJacob Faibussowitsch       PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located");
35049566063dSJacob Faibussowitsch       PetscCall(VecGetArray(pointVec, &pV));
3505bd041c0cSMatthew G. Knepley       for (ccell = 0; ccell < numCoarseCells; ++ccell) {
3506bd041c0cSMatthew G. Knepley         PetscReal       pVReal[3];
3507c330f8ffSToby Isaac         const PetscReal xi0[3] = {-1., -1., -1.};
3508c330f8ffSToby Isaac 
35099566063dSJacob Faibussowitsch         PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3510bd041c0cSMatthew G. Knepley         /* Transform points from real space to coarse reference space */
35119566063dSJacob Faibussowitsch         PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc));
3512bd041c0cSMatthew G. Knepley         for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]);
3513c330f8ffSToby Isaac         CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x);
3514bd041c0cSMatthew G. Knepley 
3515bd041c0cSMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
3516bd041c0cSMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
3517bd041c0cSMatthew G. Knepley 
3518bd041c0cSMatthew G. Knepley           /* Evaluate coarse basis on contained point */
35199566063dSJacob Faibussowitsch           PetscCall(PetscFEGetDimension(fe, &cpdim));
35209566063dSJacob Faibussowitsch           PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T));
3521bd041c0cSMatthew G. Knepley           /* Get elemMat entries by multiplying by weight */
3522bd041c0cSMatthew G. Knepley           for (i = 0; i < numFIndices; ++i) {
35239566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(elemMat, cpdim));
3524bd041c0cSMatthew G. Knepley             for (j = 0; j < cpdim; ++j) {
3525ef0bb6c7SMatthew 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;
3526bd041c0cSMatthew G. Knepley             }
3527bd041c0cSMatthew G. Knepley             /* Update interpolator */
35289566063dSJacob Faibussowitsch             if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
352963a3b9bcSJacob Faibussowitsch             PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim);
35309566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES));
3531bd041c0cSMatthew G. Knepley           }
3532bd041c0cSMatthew G. Knepley         } else {
3533bd041c0cSMatthew G. Knepley           cpdim = 1;
3534bd041c0cSMatthew G. Knepley           for (i = 0; i < numFIndices; ++i) {
35359566063dSJacob Faibussowitsch             PetscCall(PetscArrayzero(elemMat, cpdim));
3536bd041c0cSMatthew G. Knepley             for (j = 0; j < cpdim; ++j) {
3537bd041c0cSMatthew G. Knepley               for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ;
3538bd041c0cSMatthew G. Knepley             }
3539bd041c0cSMatthew G. Knepley             /* Update interpolator */
35409566063dSJacob Faibussowitsch             if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat));
354163a3b9bcSJacob 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));
354263a3b9bcSJacob Faibussowitsch             PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim);
35439566063dSJacob Faibussowitsch             PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES));
3544bd041c0cSMatthew G. Knepley           }
3545bd041c0cSMatthew G. Knepley         }
35469566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL));
3547bd041c0cSMatthew G. Knepley       }
35489566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(pointVec, &pV));
35499566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coarseCellSF));
35509566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&pointVec));
35519566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL));
3552bd041c0cSMatthew G. Knepley     }
35539566063dSJacob Faibussowitsch     if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T));
3554bd041c0cSMatthew G. Knepley   }
35559566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, J, invJ));
35569566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0c, Jc, invJc));
35579566063dSJacob Faibussowitsch   PetscCall(PetscFree(elemMat));
35589566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY));
35599566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY));
35603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3561bd041c0cSMatthew G. Knepley }
3562bd041c0cSMatthew G. Knepley 
3563bd041c0cSMatthew G. Knepley /*@
356446fa42a0SMatthew G. Knepley   DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns
356546fa42a0SMatthew G. Knepley 
356646fa42a0SMatthew G. Knepley   Input Parameters:
356746fa42a0SMatthew G. Knepley + dmc - The coarse mesh
356860225df5SJacob Faibussowitsch . dmf - The fine mesh
3569*2a8381b2SBarry Smith - ctx - The application context
357046fa42a0SMatthew G. Knepley 
357146fa42a0SMatthew G. Knepley   Output Parameter:
357246fa42a0SMatthew G. Knepley . sc - The mapping
357346fa42a0SMatthew G. Knepley 
357446fa42a0SMatthew G. Knepley   Level: developer
357546fa42a0SMatthew G. Knepley 
3576ae3cf2c1SStefano Zampini .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`
357746fa42a0SMatthew G. Knepley @*/
DMPlexComputeInjectorFEM(DM dmc,DM dmf,VecScatter * sc,PetscCtx ctx)3578*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, PetscCtx ctx)
3579d71ae5a4SJacob Faibussowitsch {
3580e9d4ef1bSMatthew G. Knepley   PetscDS      prob;
35817c927364SMatthew G. Knepley   PetscFE     *feRef;
358297c42addSMatthew G. Knepley   PetscFV     *fvRef;
35837c927364SMatthew G. Knepley   Vec          fv, cv;
35847c927364SMatthew G. Knepley   IS           fis, cis;
35857c927364SMatthew G. Knepley   PetscSection fsection, fglobalSection, csection, cglobalSection;
35867c927364SMatthew G. Knepley   PetscInt    *cmap, *cellCIndices, *cellFIndices, *cindices, *findices;
3587485ad865SMatthew G. Knepley   PetscInt     cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m;
35886f3d3cbcSMatthew G. Knepley   PetscBool   *needAvg;
35897c927364SMatthew G. Knepley 
35907c927364SMatthew G. Knepley   PetscFunctionBegin;
35919566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0));
35929566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dmf, &dim));
35939566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmf, &fsection));
35949566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmf, &fglobalSection));
35959566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dmc, &csection));
35969566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
35979566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetNumFields(fsection, &Nf));
35989566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd));
35999566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmc, &prob));
36009566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg));
36017c927364SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
360297c42addSMatthew G. Knepley     PetscObject  obj;
360397c42addSMatthew G. Knepley     PetscClassId id;
3604aa7890ccSMatthew G. Knepley     PetscInt     fNb = 0, Nc = 0;
36057c927364SMatthew G. Knepley 
36069566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
36079566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
360897c42addSMatthew G. Knepley     if (id == PETSCFE_CLASSID) {
360997c42addSMatthew G. Knepley       PetscFE    fe = (PetscFE)obj;
36106f3d3cbcSMatthew G. Knepley       PetscSpace sp;
36119b2fc754SMatthew G. Knepley       PetscInt   maxDegree;
361297c42addSMatthew G. Knepley 
36139566063dSJacob Faibussowitsch       PetscCall(PetscFERefine(fe, &feRef[f]));
36149566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feRef[f], &fNb));
36159566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(fe, &Nc));
36169566063dSJacob Faibussowitsch       PetscCall(PetscFEGetBasisSpace(fe, &sp));
36179566063dSJacob Faibussowitsch       PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree));
36189b2fc754SMatthew G. Knepley       if (!maxDegree) needAvg[f] = PETSC_TRUE;
361997c42addSMatthew G. Knepley     } else if (id == PETSCFV_CLASSID) {
362097c42addSMatthew G. Knepley       PetscFV        fv = (PetscFV)obj;
362197c42addSMatthew G. Knepley       PetscDualSpace Q;
362297c42addSMatthew G. Knepley 
36239566063dSJacob Faibussowitsch       PetscCall(PetscFVRefine(fv, &fvRef[f]));
36249566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[f], &Q));
36259566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(Q, &fNb));
36269566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &Nc));
36276f3d3cbcSMatthew G. Knepley       needAvg[f] = PETSC_TRUE;
362897c42addSMatthew G. Knepley     }
3629d172c84bSMatthew G. Knepley     fTotDim += fNb;
36307c927364SMatthew G. Knepley   }
36319566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &cTotDim));
36329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cTotDim, &cmap));
36337c927364SMatthew G. Knepley   for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) {
36347c927364SMatthew G. Knepley     PetscFE        feC;
363597c42addSMatthew G. Knepley     PetscFV        fvC;
36367c927364SMatthew G. Knepley     PetscDualSpace QF, QC;
3637d172c84bSMatthew G. Knepley     PetscInt       order = -1, NcF, NcC, fpdim, cpdim;
36387c927364SMatthew G. Knepley 
363997c42addSMatthew G. Knepley     if (feRef[field]) {
36409566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC));
36419566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feC, &NcC));
36429566063dSJacob Faibussowitsch       PetscCall(PetscFEGetNumComponents(feRef[field], &NcF));
36439566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feRef[field], &QF));
36449566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetOrder(QF, &order));
36459566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QF, &fpdim));
36469566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDualSpace(feC, &QC));
36479566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QC, &cpdim));
364897c42addSMatthew G. Knepley     } else {
36499566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC));
36509566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvC, &NcC));
36519566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF));
36529566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvRef[field], &QF));
36539566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QF, &fpdim));
36549566063dSJacob Faibussowitsch       PetscCall(PetscFVGetDualSpace(fvC, &QC));
36559566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetDimension(QC, &cpdim));
365697c42addSMatthew G. Knepley     }
365763a3b9bcSJacob 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);
36587c927364SMatthew G. Knepley     for (c = 0; c < cpdim; ++c) {
36597c927364SMatthew G. Knepley       PetscQuadrature  cfunc;
3660d172c84bSMatthew G. Knepley       const PetscReal *cqpoints, *cqweights;
3661d172c84bSMatthew G. Knepley       PetscInt         NqcC, NpC;
366297c42addSMatthew G. Knepley       PetscBool        found = PETSC_FALSE;
36637c927364SMatthew G. Knepley 
36649566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc));
36659566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights));
366663a3b9bcSJacob 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);
36671dca8a05SBarry Smith       PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments");
36687c927364SMatthew G. Knepley       for (f = 0; f < fpdim; ++f) {
36697c927364SMatthew G. Knepley         PetscQuadrature  ffunc;
3670d172c84bSMatthew G. Knepley         const PetscReal *fqpoints, *fqweights;
36717c927364SMatthew G. Knepley         PetscReal        sum = 0.0;
3672d172c84bSMatthew G. Knepley         PetscInt         NqcF, NpF;
36737c927364SMatthew G. Knepley 
36749566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc));
36759566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights));
367663a3b9bcSJacob 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);
36777c927364SMatthew G. Knepley         if (NpC != NpF) continue;
36787c927364SMatthew G. Knepley         for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]);
36797c927364SMatthew G. Knepley         if (sum > 1.0e-9) continue;
3680d172c84bSMatthew G. Knepley         for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]);
3681d172c84bSMatthew G. Knepley         if (sum < 1.0e-9) continue;
3682d172c84bSMatthew G. Knepley         cmap[offsetC + c] = offsetF + f;
368397c42addSMatthew G. Knepley         found             = PETSC_TRUE;
36847c927364SMatthew G. Knepley         break;
36857c927364SMatthew G. Knepley       }
368697c42addSMatthew G. Knepley       if (!found) {
368797c42addSMatthew G. Knepley         /* TODO We really want the average here, but some asshole put VecScatter in the interface */
3688966bd95aSPierre Jolivet         PetscCheck(fvRef[field] || (feRef[field] && order == 0), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection");
3689d172c84bSMatthew G. Knepley         cmap[offsetC + c] = offsetF + 0;
369097c42addSMatthew G. Knepley       }
36917c927364SMatthew G. Knepley     }
3692d172c84bSMatthew G. Knepley     offsetC += cpdim;
3693d172c84bSMatthew G. Knepley     offsetF += fpdim;
36947c927364SMatthew G. Knepley   }
36959371c9d4SSatish Balay   for (f = 0; f < Nf; ++f) {
36969371c9d4SSatish Balay     PetscCall(PetscFEDestroy(&feRef[f]));
36979371c9d4SSatish Balay     PetscCall(PetscFVDestroy(&fvRef[f]));
36989371c9d4SSatish Balay   }
36999566063dSJacob Faibussowitsch   PetscCall(PetscFree3(feRef, fvRef, needAvg));
37007c927364SMatthew G. Knepley 
37019566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmf, &fv));
37029566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalVector(dmc, &cv));
37039566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(cv, &startC, &endC));
37049566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m));
37059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices));
37069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &cindices));
37079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m, &findices));
37087c927364SMatthew G. Knepley   for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1;
37097c927364SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
37109566063dSJacob Faibussowitsch     PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices));
37117c927364SMatthew G. Knepley     for (d = 0; d < cTotDim; ++d) {
37120bd915a7SMatthew G. Knepley       if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue;
3713d2457c26SMatthew 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]]);
37147c927364SMatthew G. Knepley       cindices[cellCIndices[d] - startC] = cellCIndices[d];
37157c927364SMatthew G. Knepley       findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]];
37167c927364SMatthew G. Knepley     }
37177c927364SMatthew G. Knepley   }
37189566063dSJacob Faibussowitsch   PetscCall(PetscFree(cmap));
37199566063dSJacob Faibussowitsch   PetscCall(PetscFree2(cellCIndices, cellFIndices));
37207c927364SMatthew G. Knepley 
37219566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis));
37229566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis));
37239566063dSJacob Faibussowitsch   PetscCall(VecScatterCreate(cv, cis, fv, fis, sc));
37249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&cis));
37259566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&fis));
37269566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmf, &fv));
37279566063dSJacob Faibussowitsch   PetscCall(DMRestoreGlobalVector(dmc, &cv));
37289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0));
37293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3730cb1e1211SMatthew G Knepley }
3731a1cf66bbSMatthew G. Knepley 
37322f856554SMatthew G. Knepley /*@C
37332f856554SMatthew G. Knepley   DMPlexGetCellFields - Retrieve the field values values for a chunk of cells
37342f856554SMatthew G. Knepley 
37352f856554SMatthew G. Knepley   Input Parameters:
3736a1cb98faSBarry Smith + dm     - The `DM`
37372f856554SMatthew G. Knepley . cellIS - The cells to include
37382f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
3739ce78bad3SBarry Smith . locX_t - A local vector with solution field time derivatives, or `NULL`
3740ce78bad3SBarry Smith - locA   - A local vector with auxiliary fields, or `NULL`
37412f856554SMatthew G. Knepley 
37422f856554SMatthew G. Knepley   Output Parameters:
37432f856554SMatthew G. Knepley + u   - The field coefficients
37442f856554SMatthew G. Knepley . u_t - The fields derivative coefficients
37452f856554SMatthew G. Knepley - a   - The auxiliary field coefficients
37462f856554SMatthew G. Knepley 
37472f856554SMatthew G. Knepley   Level: developer
37482f856554SMatthew G. Knepley 
37491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
37502f856554SMatthew G. Knepley @*/
DMPlexGetCellFields(DM dm,IS cellIS,Vec locX,PeOp Vec locX_t,PeOp Vec locA,PetscScalar * u[],PetscScalar * u_t[],PetscScalar * a[])3751ce78bad3SBarry Smith PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, PeOp Vec locX_t, PeOp Vec locA, PetscScalar *u[], PetscScalar *u_t[], PetscScalar *a[])
3752d71ae5a4SJacob Faibussowitsch {
37532f856554SMatthew G. Knepley   DM              plex, plexA = NULL;
3754a6e0b375SMatthew G. Knepley   DMEnclosureType encAux;
37552f856554SMatthew G. Knepley   PetscSection    section, sectionAux;
37562f856554SMatthew G. Knepley   PetscDS         prob;
37572f856554SMatthew G. Knepley   const PetscInt *cells;
37582f856554SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, totDim, totDimAux, c;
37592f856554SMatthew G. Knepley 
37602f856554SMatthew G. Knepley   PetscFunctionBegin;
37612f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3762064a246eSJacob Faibussowitsch   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
3763ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4);
3764ad540459SPierre Jolivet   if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5);
37654f572ea9SToby Isaac   PetscAssertPointer(u, 6);
37664f572ea9SToby Isaac   PetscAssertPointer(u_t, 7);
37674f572ea9SToby Isaac   PetscAssertPointer(a, 8);
37689566063dSJacob Faibussowitsch   PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE));
37699566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
37709566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
377107218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL));
37729566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
37732f856554SMatthew G. Knepley   if (locA) {
37742f856554SMatthew G. Knepley     DM      dmAux;
37752f856554SMatthew G. Knepley     PetscDS probAux;
37762f856554SMatthew G. Knepley 
37779566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
37789566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
37799566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE));
37809566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
37819566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
37829566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
37832f856554SMatthew G. Knepley   }
37842f856554SMatthew G. Knepley   numCells = cEnd - cStart;
37859566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u));
37869371c9d4SSatish Balay   if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t));
3787ad540459SPierre Jolivet   else *u_t = NULL;
37889371c9d4SSatish Balay   if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a));
3789ad540459SPierre Jolivet   else *a = NULL;
37902f856554SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
37912f856554SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
37922f856554SMatthew G. Knepley     const PetscInt cind = c - cStart;
37932f856554SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a;
37942f856554SMatthew G. Knepley     PetscInt       i;
37952f856554SMatthew G. Knepley 
37969566063dSJacob Faibussowitsch     PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x));
37972f856554SMatthew G. Knepley     for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i];
37989566063dSJacob Faibussowitsch     PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x));
37992f856554SMatthew G. Knepley     if (locX_t) {
38009566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t));
38012f856554SMatthew G. Knepley       for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i];
38029566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t));
38032f856554SMatthew G. Knepley     }
38042f856554SMatthew G. Knepley     if (locA) {
38052f856554SMatthew G. Knepley       PetscInt subcell;
38069566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell));
38079566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x));
38082f856554SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i];
38099566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x));
38102f856554SMatthew G. Knepley     }
38112f856554SMatthew G. Knepley   }
38129566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
38139566063dSJacob Faibussowitsch   if (locA) PetscCall(DMDestroy(&plexA));
38149566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
38153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38162f856554SMatthew G. Knepley }
38172f856554SMatthew G. Knepley 
38182f856554SMatthew G. Knepley /*@C
38192f856554SMatthew G. Knepley   DMPlexRestoreCellFields - Restore the field values values for a chunk of cells
38202f856554SMatthew G. Knepley 
38212f856554SMatthew G. Knepley   Input Parameters:
3822a1cb98faSBarry Smith + dm     - The `DM`
38232f856554SMatthew G. Knepley . cellIS - The cells to include
38242f856554SMatthew G. Knepley . locX   - A local vector with the solution fields
3825ce78bad3SBarry Smith . locX_t - A local vector with solution field time derivatives, or `NULL`
3826ce78bad3SBarry Smith - locA   - A local vector with auxiliary fields, or `NULL`
38272f856554SMatthew G. Knepley 
38282f856554SMatthew G. Knepley   Output Parameters:
38292f856554SMatthew G. Knepley + u   - The field coefficients
38302f856554SMatthew G. Knepley . u_t - The fields derivative coefficients
38312f856554SMatthew G. Knepley - a   - The auxiliary field coefficients
38322f856554SMatthew G. Knepley 
38332f856554SMatthew G. Knepley   Level: developer
38342f856554SMatthew G. Knepley 
38351cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
38362f856554SMatthew G. Knepley @*/
DMPlexRestoreCellFields(DM dm,IS cellIS,Vec locX,PeOp Vec locX_t,PeOp Vec locA,PetscScalar * u[],PetscScalar * u_t[],PetscScalar * a[])3837ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, PeOp Vec locX_t, PeOp Vec locA, PetscScalar *u[], PetscScalar *u_t[], PetscScalar *a[])
3838d71ae5a4SJacob Faibussowitsch {
38392f856554SMatthew G. Knepley   PetscFunctionBegin;
38409566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u));
38419566063dSJacob Faibussowitsch   if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t));
38429566063dSJacob Faibussowitsch   if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a));
38433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38442f856554SMatthew G. Knepley }
38452f856554SMatthew G. Knepley 
DMPlexGetHybridCellFields(DM dm,IS cellIS,Vec locX,Vec locX_t,Vec locA,PetscScalar ** u,PetscScalar ** u_t,PetscScalar ** a)3846a4e35b19SJacob Faibussowitsch static PetscErrorCode DMPlexGetHybridCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a)
3847d71ae5a4SJacob Faibussowitsch {
384807218a29SMatthew G. Knepley   DM              plex, plexA = NULL;
384907218a29SMatthew G. Knepley   DMEnclosureType encAux;
385007218a29SMatthew G. Knepley   PetscSection    section, sectionAux;
385107218a29SMatthew G. Knepley   PetscDS         ds, dsIn;
38526528b96dSMatthew G. Knepley   const PetscInt *cells;
385307218a29SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, c, totDim, totDimAux, Nf, f;
38546528b96dSMatthew G. Knepley 
38556528b96dSMatthew G. Knepley   PetscFunctionBegin;
385607218a29SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
385707218a29SMatthew G. Knepley   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 2);
385807218a29SMatthew G. Knepley   PetscValidHeaderSpecific(locX, VEC_CLASSID, 3);
3859ac530a7eSPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4);
3860ac530a7eSPierre Jolivet   if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5);
38614f572ea9SToby Isaac   PetscAssertPointer(u, 6);
38624f572ea9SToby Isaac   PetscAssertPointer(u_t, 7);
38634f572ea9SToby Isaac   PetscAssertPointer(a, 8);
386407218a29SMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
386507218a29SMatthew G. Knepley   numCells = cEnd - cStart;
386607218a29SMatthew G. Knepley   PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE));
386707218a29SMatthew G. Knepley   PetscCall(DMGetLocalSection(dm, &section));
386807218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn));
386907218a29SMatthew G. Knepley   PetscCall(PetscDSGetNumFields(dsIn, &Nf));
387007218a29SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(dsIn, &totDim));
387107218a29SMatthew G. Knepley   if (locA) {
387207218a29SMatthew G. Knepley     DM      dmAux;
387307218a29SMatthew G. Knepley     PetscDS probAux;
387407218a29SMatthew G. Knepley 
387507218a29SMatthew G. Knepley     PetscCall(VecGetDM(locA, &dmAux));
387607218a29SMatthew G. Knepley     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
387707218a29SMatthew G. Knepley     PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE));
387807218a29SMatthew G. Knepley     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
387907218a29SMatthew G. Knepley     PetscCall(DMGetDS(dmAux, &probAux));
388007218a29SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
388107218a29SMatthew G. Knepley   }
388207218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u));
388307218a29SMatthew G. Knepley   if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t));
388407218a29SMatthew G. Knepley   else {
388507218a29SMatthew G. Knepley     *u_t = NULL;
388607218a29SMatthew G. Knepley   }
388707218a29SMatthew G. Knepley   if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a));
388807218a29SMatthew G. Knepley   else {
388907218a29SMatthew G. Knepley     *a = NULL;
389007218a29SMatthew G. Knepley   }
389107218a29SMatthew G. Knepley   // Loop over cohesive cells
389207218a29SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
389307218a29SMatthew G. Knepley     const PetscInt  cell = cells ? cells[c] : c;
389407218a29SMatthew G. Knepley     const PetscInt  cind = c - cStart;
389574a0c561SMatthew G. Knepley     PetscScalar    *xf = NULL, *xc = NULL, *x = NULL, *xf_t = NULL, *xc_t = NULL;
38968e3a54c0SPierre Jolivet     PetscScalar    *ul = &(*u)[cind * totDim], *ul_t = PetscSafePointerPlusOffset(*u_t, cind * totDim);
389707218a29SMatthew G. Knepley     const PetscInt *cone, *ornt;
389807218a29SMatthew G. Knepley     PetscInt        Nx = 0, Nxf, s;
389907218a29SMatthew G. Knepley 
390007218a29SMatthew G. Knepley     PetscCall(DMPlexGetCone(dm, cell, &cone));
390107218a29SMatthew G. Knepley     PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
390207218a29SMatthew G. Knepley     // Put in cohesive unknowns
390307218a29SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, &Nxf, &xf));
390474a0c561SMatthew G. Knepley     if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &xf_t));
390507218a29SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
390607218a29SMatthew G. Knepley       PetscInt  fdofIn, foff, foffIn;
390707218a29SMatthew G. Knepley       PetscBool cohesive;
390807218a29SMatthew G. Knepley 
390907218a29SMatthew G. Knepley       PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive));
391007218a29SMatthew G. Knepley       if (!cohesive) continue;
391107218a29SMatthew G. Knepley       PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn));
391207218a29SMatthew G. Knepley       PetscCall(PetscDSGetFieldOffsetCohesive(ds, f, &foff));
391307218a29SMatthew G. Knepley       PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn));
391407218a29SMatthew G. Knepley       for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + i] = xf[foff + i];
391574a0c561SMatthew G. Knepley       if (locX_t)
391674a0c561SMatthew G. Knepley         for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + i] = xf_t[foff + i];
391707218a29SMatthew G. Knepley       Nx += fdofIn;
391807218a29SMatthew G. Knepley     }
391907218a29SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, &Nxf, &xf));
392074a0c561SMatthew G. Knepley     if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &xf_t));
392107218a29SMatthew G. Knepley     // Loop over sides of surface
392207218a29SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
392307218a29SMatthew G. Knepley       const PetscInt *support;
392407218a29SMatthew G. Knepley       const PetscInt  face = cone[s];
3925989fa639SBrad Aagaard       PetscDS         dsC;
392607218a29SMatthew G. Knepley       PetscInt        ssize, ncell, Nxc;
392707218a29SMatthew G. Knepley 
392807218a29SMatthew G. Knepley       // I don't think I need the face to have 0 orientation in the hybrid cell
392907218a29SMatthew 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]);
393007218a29SMatthew G. Knepley       PetscCall(DMPlexGetSupport(dm, face, &support));
393107218a29SMatthew G. Knepley       PetscCall(DMPlexGetSupportSize(dm, face, &ssize));
393207218a29SMatthew G. Knepley       if (support[0] == cell) ncell = support[1];
393307218a29SMatthew G. Knepley       else if (support[1] == cell) ncell = support[0];
393407218a29SMatthew 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);
393507218a29SMatthew G. Knepley       // Get closure of both face and cell, stick in cell for normal fields and face for cohesive fields
3936989fa639SBrad Aagaard       PetscCall(DMGetCellDS(dm, ncell, &dsC, NULL));
393707218a29SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plex, section, locX, ncell, &Nxc, &xc));
393874a0c561SMatthew G. Knepley       if (locX_t) PetscCall(DMPlexVecGetClosure(plex, section, locX_t, ncell, NULL, &xc_t));
393907218a29SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
3940989fa639SBrad Aagaard         PetscInt  fdofIn, foffIn, foff;
394107218a29SMatthew G. Knepley         PetscBool cohesive;
394207218a29SMatthew G. Knepley 
394307218a29SMatthew G. Knepley         PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive));
394407218a29SMatthew G. Knepley         if (cohesive) continue;
394507218a29SMatthew G. Knepley         PetscCall(PetscDSGetFieldSize(dsIn, f, &fdofIn));
3946989fa639SBrad Aagaard         PetscCall(PetscDSGetFieldOffset(dsC, f, &foff));
394707218a29SMatthew G. Knepley         PetscCall(PetscDSGetFieldOffsetCohesive(dsIn, f, &foffIn));
3948989fa639SBrad Aagaard         for (PetscInt i = 0; i < fdofIn; ++i) ul[foffIn + s * fdofIn + i] = xc[foff + i];
394974a0c561SMatthew G. Knepley         if (locX_t)
3950989fa639SBrad Aagaard           for (PetscInt i = 0; i < fdofIn; ++i) ul_t[foffIn + s * fdofIn + i] = xc_t[foff + i];
395107218a29SMatthew G. Knepley         Nx += fdofIn;
395207218a29SMatthew G. Knepley       }
395307218a29SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, ncell, &Nxc, &xc));
395474a0c561SMatthew G. Knepley       if (locX_t) PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, ncell, NULL, &xc_t));
395507218a29SMatthew G. Knepley     }
395607218a29SMatthew 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);
395707218a29SMatthew G. Knepley 
395807218a29SMatthew G. Knepley     if (locA) {
395907218a29SMatthew G. Knepley       PetscScalar *al = &(*a)[cind * totDimAux];
396007218a29SMatthew G. Knepley       PetscInt     subcell;
396107218a29SMatthew G. Knepley 
396207218a29SMatthew G. Knepley       PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell));
396307218a29SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, &Nx, &x));
396407218a29SMatthew 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);
396507218a29SMatthew G. Knepley       for (PetscInt i = 0; i < totDimAux; ++i) al[i] = x[i];
396607218a29SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, &Nx, &x));
396707218a29SMatthew G. Knepley     }
396807218a29SMatthew G. Knepley   }
396907218a29SMatthew G. Knepley   PetscCall(DMDestroy(&plex));
397007218a29SMatthew G. Knepley   PetscCall(DMDestroy(&plexA));
397107218a29SMatthew G. Knepley   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
397207218a29SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
397307218a29SMatthew G. Knepley }
397407218a29SMatthew G. Knepley 
397507218a29SMatthew G. Knepley /*
39763e2b0218SMatthew G. Knepley   DMPlexGetHybridFields - Get the field values for the negative side (s = 0) and positive side (s = 1) of the interface
397707218a29SMatthew G. Knepley 
397807218a29SMatthew G. Knepley   Input Parameters:
397907218a29SMatthew G. Knepley + dm      - The full domain DM
398007218a29SMatthew G. Knepley . dmX     - An array of DM for the field, say an auxiliary DM, indexed by s
398107218a29SMatthew G. Knepley . dsX     - An array of PetscDS for the field, indexed by s
398207218a29SMatthew G. Knepley . cellIS  - The interface cells for which we want values
398307218a29SMatthew G. Knepley . locX    - An array of local vectors with the field values, indexed by s
398407218a29SMatthew G. Knepley - useCell - Flag to have values come from neighboring cell rather than endcap face
398507218a29SMatthew G. Knepley 
398607218a29SMatthew G. Knepley   Output Parameter:
398707218a29SMatthew G. Knepley . x       - An array of field values, indexed by s
398807218a29SMatthew G. Knepley 
398907218a29SMatthew G. Knepley   Note:
399076fbde31SPierre Jolivet   The arrays in `x` will be allocated using `DMGetWorkArray()`, and must be returned using `DMPlexRestoreHybridFields()`.
399107218a29SMatthew G. Knepley 
399207218a29SMatthew G. Knepley   Level: advanced
399307218a29SMatthew G. Knepley 
399476fbde31SPierre Jolivet .seealso: `DMPlexRestoreHybridFields()`, `DMGetWorkArray()`
399507218a29SMatthew G. Knepley */
DMPlexGetHybridFields(DM dm,DM dmX[],PetscDS dsX[],IS cellIS,Vec locX[],PetscBool useCell,PetscScalar * x[])399607218a29SMatthew G. Knepley static PetscErrorCode DMPlexGetHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[])
399707218a29SMatthew G. Knepley {
399807218a29SMatthew G. Knepley   DM              plexX[2];
399907218a29SMatthew G. Knepley   DMEnclosureType encX[2];
400007218a29SMatthew G. Knepley   PetscSection    sectionX[2];
400107218a29SMatthew G. Knepley   const PetscInt *cells;
400207218a29SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells, c, s, totDimX[2];
400307218a29SMatthew G. Knepley 
400407218a29SMatthew G. Knepley   PetscFunctionBegin;
40054f572ea9SToby Isaac   PetscAssertPointer(locX, 5);
400607218a29SMatthew G. Knepley   if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS);
40074f572ea9SToby Isaac   PetscAssertPointer(dmX, 2);
40084f572ea9SToby Isaac   PetscAssertPointer(dsX, 3);
400907218a29SMatthew G. Knepley   PetscValidHeaderSpecific(cellIS, IS_CLASSID, 4);
40104f572ea9SToby Isaac   PetscAssertPointer(x, 7);
40119566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
40126528b96dSMatthew G. Knepley   numCells = cEnd - cStart;
4013148442b3SMatthew G. Knepley   for (s = 0; s < 2; ++s) {
401407218a29SMatthew G. Knepley     PetscValidHeaderSpecific(dmX[s], DM_CLASSID, 2);
401507218a29SMatthew G. Knepley     PetscValidHeaderSpecific(dsX[s], PETSCDS_CLASSID, 3);
401607218a29SMatthew G. Knepley     PetscValidHeaderSpecific(locX[s], VEC_CLASSID, 5);
401707218a29SMatthew G. Knepley     PetscCall(DMPlexConvertPlex(dmX[s], &plexX[s], PETSC_FALSE));
401807218a29SMatthew G. Knepley     PetscCall(DMGetEnclosureRelation(dmX[s], dm, &encX[s]));
401907218a29SMatthew G. Knepley     PetscCall(DMGetLocalSection(dmX[s], &sectionX[s]));
402007218a29SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsX[s], &totDimX[s]));
402107218a29SMatthew G. Knepley     PetscCall(DMGetWorkArray(dmX[s], numCells * totDimX[s], MPIU_SCALAR, &x[s]));
402204c51a94SMatthew G. Knepley   }
4023148442b3SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
40246528b96dSMatthew G. Knepley     const PetscInt  cell = cells ? cells[c] : c;
40256528b96dSMatthew G. Knepley     const PetscInt  cind = c - cStart;
40266528b96dSMatthew G. Knepley     const PetscInt *cone, *ornt;
40276528b96dSMatthew G. Knepley 
40289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, cell, &cone));
40299566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
403007218a29SMatthew 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]);
4031148442b3SMatthew G. Knepley     for (s = 0; s < 2; ++s) {
403207218a29SMatthew G. Knepley       const PetscInt tdX     = totDimX[s];
403307218a29SMatthew G. Knepley       PetscScalar   *closure = NULL, *xl = &x[s][cind * tdX];
403407218a29SMatthew G. Knepley       PetscInt       face = cone[s], point = face, subpoint, Nx, i;
403507218a29SMatthew G. Knepley 
403607218a29SMatthew G. Knepley       if (useCell) {
40375fedec97SMatthew G. Knepley         const PetscInt *support;
403807218a29SMatthew G. Knepley         PetscInt        ssize;
40396528b96dSMatthew G. Knepley 
404007218a29SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, face, &support));
404107218a29SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, face, &ssize));
404207218a29SMatthew 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);
404307218a29SMatthew G. Knepley         if (support[0] == cell) point = support[1];
404407218a29SMatthew G. Knepley         else if (support[1] == cell) point = support[0];
404507218a29SMatthew 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);
404607218a29SMatthew G. Knepley       }
404707218a29SMatthew G. Knepley       PetscCall(DMGetEnclosurePoint(plexX[s], dm, encX[s], point, &subpoint));
404848162695SZach Atkins       PetscCall(DMPlexVecGetOrientedClosure(plexX[s], sectionX[s], PETSC_FALSE, locX[s], subpoint, ornt[s], &Nx, &closure));
404907218a29SMatthew 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);
405007218a29SMatthew G. Knepley       for (i = 0; i < Nx; ++i) xl[i] = closure[i];
405107218a29SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plexX[s], sectionX[s], locX[s], subpoint, &Nx, &closure));
40526528b96dSMatthew G. Knepley     }
40536528b96dSMatthew G. Knepley   }
405407218a29SMatthew G. Knepley   for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexX[s]));
40559566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
40563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40576528b96dSMatthew G. Knepley }
40586528b96dSMatthew G. Knepley 
DMPlexRestoreHybridFields(DM dm,DM dmX[],PetscDS dsX[],IS cellIS,Vec locX[],PetscBool useCell,PetscScalar * x[])405907218a29SMatthew G. Knepley static PetscErrorCode DMPlexRestoreHybridFields(DM dm, DM dmX[], PetscDS dsX[], IS cellIS, Vec locX[], PetscBool useCell, PetscScalar *x[])
4060d71ae5a4SJacob Faibussowitsch {
40616528b96dSMatthew G. Knepley   PetscFunctionBegin;
406207218a29SMatthew G. Knepley   if (!locX[0] || !locX[1]) PetscFunctionReturn(PETSC_SUCCESS);
406307218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dmX[0], 0, MPIU_SCALAR, &x[0]));
406407218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dmX[1], 0, MPIU_SCALAR, &x[1]));
40653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40666528b96dSMatthew G. Knepley }
40676528b96dSMatthew G. Knepley 
40682f856554SMatthew G. Knepley /*@C
40692f856554SMatthew G. Knepley   DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces
40702f856554SMatthew G. Knepley 
40712f856554SMatthew G. Knepley   Input Parameters:
4072a1cb98faSBarry Smith + dm           - The `DM`
40732f856554SMatthew G. Knepley . fStart       - The first face to include
40742f856554SMatthew G. Knepley . fEnd         - The first face to exclude
40752f856554SMatthew G. Knepley . locX         - A local vector with the solution fields
4076ce78bad3SBarry Smith . locX_t       - A local vector with solution field time derivatives, or `NULL`
40772f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
40782f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry
4079ce78bad3SBarry Smith - locGrad      - A local vector with field gradients, or `NULL`
40802f856554SMatthew G. Knepley 
40812f856554SMatthew G. Knepley   Output Parameters:
40822f856554SMatthew G. Knepley + Nface - The number of faces with field values
40832f856554SMatthew G. Knepley . uL    - The field values at the left side of the face
40842f856554SMatthew G. Knepley - uR    - The field values at the right side of the face
40852f856554SMatthew G. Knepley 
40862f856554SMatthew G. Knepley   Level: developer
40872f856554SMatthew G. Knepley 
40881cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
40892f856554SMatthew G. Knepley @*/
DMPlexGetFaceFields(DM dm,PetscInt fStart,PetscInt fEnd,Vec locX,PeOp Vec locX_t,Vec faceGeometry,Vec cellGeometry,PeOp Vec locGrad,PetscInt * Nface,PetscScalar * uL[],PetscScalar * uR[])4090ce78bad3SBarry Smith PetscErrorCode DMPlexGetFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, PeOp Vec locX_t, Vec faceGeometry, Vec cellGeometry, PeOp Vec locGrad, PetscInt *Nface, PetscScalar *uL[], PetscScalar *uR[])
4091d71ae5a4SJacob Faibussowitsch {
40922f856554SMatthew G. Knepley   DM                 dmFace, dmCell, dmGrad = NULL;
40932f856554SMatthew G. Knepley   PetscSection       section;
40942f856554SMatthew G. Knepley   PetscDS            prob;
40952f856554SMatthew G. Knepley   DMLabel            ghostLabel;
40962f856554SMatthew G. Knepley   const PetscScalar *facegeom, *cellgeom, *x, *lgrad;
40972f856554SMatthew G. Knepley   PetscBool         *isFE;
40982f856554SMatthew G. Knepley   PetscInt           dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face;
40992f856554SMatthew G. Knepley 
41002f856554SMatthew G. Knepley   PetscFunctionBegin;
41012f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41022f856554SMatthew G. Knepley   PetscValidHeaderSpecific(locX, VEC_CLASSID, 4);
4103ad540459SPierre Jolivet   if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);
41042f856554SMatthew G. Knepley   PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6);
41052f856554SMatthew G. Knepley   PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7);
4106ad540459SPierre Jolivet   if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);
41074f572ea9SToby Isaac   PetscAssertPointer(uL, 10);
41084f572ea9SToby Isaac   PetscAssertPointer(uR, 11);
41099566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
41109566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
41119566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
41129566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
41139566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalComponents(prob, &Nc));
41149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(Nf, &isFE));
41152f856554SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
41162f856554SMatthew G. Knepley     PetscObject  obj;
41172f856554SMatthew G. Knepley     PetscClassId id;
41182f856554SMatthew G. Knepley 
41199566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
41209566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
41219371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
41229371c9d4SSatish Balay       isFE[f] = PETSC_TRUE;
41239371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
41249371c9d4SSatish Balay       isFE[f] = PETSC_FALSE;
41259371c9d4SSatish Balay     } else {
41269371c9d4SSatish Balay       isFE[f] = PETSC_FALSE;
41279371c9d4SSatish Balay     }
41282f856554SMatthew G. Knepley   }
41299566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
41309566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(locX, &x));
41319566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
41329566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
41339566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
41349566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
41352f856554SMatthew G. Knepley   if (locGrad) {
41369566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locGrad, &dmGrad));
41379566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(locGrad, &lgrad));
41382f856554SMatthew G. Knepley   }
41399566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL));
41409566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR));
41412f856554SMatthew G. Knepley   /* Right now just eat the extra work for FE (could make a cell loop) */
41422f856554SMatthew G. Knepley   for (face = fStart, iface = 0; face < fEnd; ++face) {
41432f856554SMatthew G. Knepley     const PetscInt  *cells;
41442f856554SMatthew G. Knepley     PetscFVFaceGeom *fg;
41452f856554SMatthew G. Knepley     PetscFVCellGeom *cgL, *cgR;
41462f856554SMatthew G. Knepley     PetscScalar     *xL, *xR, *gL, *gR;
41472f856554SMatthew G. Knepley     PetscScalar     *uLl = *uL, *uRl = *uR;
41482f856554SMatthew G. Knepley     PetscInt         ghost, nsupp, nchild;
41492f856554SMatthew G. Knepley 
41509566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
41519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
41529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
41532f856554SMatthew G. Knepley     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
41549566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
41559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, face, &cells));
41569566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL));
41579566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR));
41582f856554SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
41592f856554SMatthew G. Knepley       PetscInt off;
41602f856554SMatthew G. Knepley 
41619566063dSJacob Faibussowitsch       PetscCall(PetscDSGetComponentOffset(prob, f, &off));
41622f856554SMatthew G. Knepley       if (isFE[f]) {
41632f856554SMatthew G. Knepley         const PetscInt *cone;
41642f856554SMatthew G. Knepley         PetscInt        comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d;
41652f856554SMatthew G. Knepley 
41662f856554SMatthew G. Knepley         xL = xR = NULL;
41679566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetFieldComponents(section, f, &comp));
4168835f2295SStefano Zampini         PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, &xL));
4169835f2295SStefano Zampini         PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, &xR));
41709566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cells[0], &cone));
41719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL));
41729371c9d4SSatish Balay         for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL)
41739371c9d4SSatish Balay           if (cone[faceLocL] == face) break;
41749566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCone(dm, cells[1], &cone));
41759566063dSJacob Faibussowitsch         PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR));
41769371c9d4SSatish Balay         for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR)
41779371c9d4SSatish Balay           if (cone[faceLocR] == face) break;
41781dca8a05SBarry 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]);
41792f856554SMatthew G. Knepley         /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */
41802f856554SMatthew G. Knepley         /* TODO: this is a hack that might not be right for nonconforming */
41812f856554SMatthew G. Knepley         if (faceLocL < coneSizeL) {
41829566063dSJacob Faibussowitsch           PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off]));
41839566063dSJacob Faibussowitsch           if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]));
41842f856554SMatthew G. Knepley           else {
41859371c9d4SSatish Balay             for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d];
41869371c9d4SSatish Balay           }
41879371c9d4SSatish Balay         } else {
41889566063dSJacob Faibussowitsch           PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off]));
41899566063dSJacob Faibussowitsch           PetscCall(PetscSectionGetFieldComponents(section, f, &comp));
41902f856554SMatthew G. Knepley           for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d];
41912f856554SMatthew G. Knepley         }
4192835f2295SStefano Zampini         PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, &xL));
4193835f2295SStefano Zampini         PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, &xR));
41942f856554SMatthew G. Knepley       } else {
41952f856554SMatthew G. Knepley         PetscFV  fv;
41962f856554SMatthew G. Knepley         PetscInt numComp, c;
41972f856554SMatthew G. Knepley 
41989566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv));
41999566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &numComp));
42009566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL));
42019566063dSJacob Faibussowitsch         PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR));
42022f856554SMatthew G. Knepley         if (dmGrad) {
42032f856554SMatthew G. Knepley           PetscReal dxL[3], dxR[3];
42042f856554SMatthew G. Knepley 
42059566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL));
42069566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR));
42072f856554SMatthew G. Knepley           DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL);
42082f856554SMatthew G. Knepley           DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR);
42092f856554SMatthew G. Knepley           for (c = 0; c < numComp; ++c) {
42102f856554SMatthew G. Knepley             uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL);
42112f856554SMatthew G. Knepley             uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR);
42122f856554SMatthew G. Knepley           }
42132f856554SMatthew G. Knepley         } else {
42142f856554SMatthew G. Knepley           for (c = 0; c < numComp; ++c) {
42152f856554SMatthew G. Knepley             uLl[iface * Nc + off + c] = xL[c];
42162f856554SMatthew G. Knepley             uRl[iface * Nc + off + c] = xR[c];
42172f856554SMatthew G. Knepley           }
42182f856554SMatthew G. Knepley         }
42192f856554SMatthew G. Knepley       }
42202f856554SMatthew G. Knepley     }
42212f856554SMatthew G. Knepley     ++iface;
42222f856554SMatthew G. Knepley   }
42232f856554SMatthew G. Knepley   *Nface = iface;
42249566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(locX, &x));
42259566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
42269566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
422748a46eb9SPierre Jolivet   if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad));
42289566063dSJacob Faibussowitsch   PetscCall(PetscFree(isFE));
42293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42302f856554SMatthew G. Knepley }
42312f856554SMatthew G. Knepley 
42322f856554SMatthew G. Knepley /*@C
42332f856554SMatthew G. Knepley   DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces
42342f856554SMatthew G. Knepley 
42352f856554SMatthew G. Knepley   Input Parameters:
4236a1cb98faSBarry Smith + dm           - The `DM`
42372f856554SMatthew G. Knepley . fStart       - The first face to include
42382f856554SMatthew G. Knepley . fEnd         - The first face to exclude
42392f856554SMatthew G. Knepley . locX         - A local vector with the solution fields
4240ce78bad3SBarry Smith . locX_t       - A local vector with solution field time derivatives, or `NULL`
42412f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
42422f856554SMatthew G. Knepley . cellGeometry - A local vector with cell geometry
4243ce78bad3SBarry Smith - locGrad      - A local vector with field gradients, or `NULL`
42442f856554SMatthew G. Knepley 
42452f856554SMatthew G. Knepley   Output Parameters:
42462f856554SMatthew G. Knepley + Nface - The number of faces with field values
42472f856554SMatthew G. Knepley . uL    - The field values at the left side of the face
42482f856554SMatthew G. Knepley - uR    - The field values at the right side of the face
42492f856554SMatthew G. Knepley 
42502f856554SMatthew G. Knepley   Level: developer
42512f856554SMatthew G. Knepley 
42521cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
42532f856554SMatthew G. Knepley @*/
DMPlexRestoreFaceFields(DM dm,PetscInt fStart,PetscInt fEnd,Vec locX,PeOp Vec locX_t,Vec faceGeometry,Vec cellGeometry,PeOp Vec locGrad,PetscInt * Nface,PetscScalar * uL[],PetscScalar * uR[])4254ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, PeOp Vec locX_t, Vec faceGeometry, Vec cellGeometry, PeOp Vec locGrad, PetscInt *Nface, PetscScalar *uL[], PetscScalar *uR[])
4255d71ae5a4SJacob Faibussowitsch {
42562f856554SMatthew G. Knepley   PetscFunctionBegin;
42579566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL));
42589566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR));
42593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42602f856554SMatthew G. Knepley }
42612f856554SMatthew G. Knepley 
42622f856554SMatthew G. Knepley /*@C
42632f856554SMatthew G. Knepley   DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces
42642f856554SMatthew G. Knepley 
42652f856554SMatthew G. Knepley   Input Parameters:
4266a1cb98faSBarry Smith + dm           - The `DM`
42672f856554SMatthew G. Knepley . fStart       - The first face to include
42682f856554SMatthew G. Knepley . fEnd         - The first face to exclude
42692f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
42702f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry
42712f856554SMatthew G. Knepley 
42722f856554SMatthew G. Knepley   Output Parameters:
42732f856554SMatthew G. Knepley + Nface - The number of faces with field values
4274ce78bad3SBarry Smith . fgeom - The face centroid and normals
4275ce78bad3SBarry Smith - vol   - The cell volumes
42762f856554SMatthew G. Knepley 
42772f856554SMatthew G. Knepley   Level: developer
42782f856554SMatthew G. Knepley 
42791cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()`
42802f856554SMatthew G. Knepley @*/
DMPlexGetFaceGeometry(DM dm,PetscInt fStart,PetscInt fEnd,Vec faceGeometry,Vec cellGeometry,PetscInt * Nface,PetscFVFaceGeom * fgeom[],PetscReal * vol[])4281ce78bad3SBarry Smith PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom *fgeom[], PetscReal *vol[])
4282d71ae5a4SJacob Faibussowitsch {
42832f856554SMatthew G. Knepley   DM                 dmFace, dmCell;
42842f856554SMatthew G. Knepley   DMLabel            ghostLabel;
42852f856554SMatthew G. Knepley   const PetscScalar *facegeom, *cellgeom;
42862f856554SMatthew G. Knepley   PetscInt           dim, numFaces = fEnd - fStart, iface, face;
42872f856554SMatthew G. Knepley 
42882f856554SMatthew G. Knepley   PetscFunctionBegin;
42892f856554SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
42902f856554SMatthew G. Knepley   PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4);
42912f856554SMatthew G. Knepley   PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5);
42924f572ea9SToby Isaac   PetscAssertPointer(fgeom, 7);
42934f572ea9SToby Isaac   PetscAssertPointer(vol, 8);
42949566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
42959566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
42969566063dSJacob Faibussowitsch   PetscCall(VecGetDM(faceGeometry, &dmFace));
42979566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(faceGeometry, &facegeom));
42989566063dSJacob Faibussowitsch   PetscCall(VecGetDM(cellGeometry, &dmCell));
42999566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(cellGeometry, &cellgeom));
43009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFaces, fgeom));
43019566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol));
43022f856554SMatthew G. Knepley   for (face = fStart, iface = 0; face < fEnd; ++face) {
43032f856554SMatthew G. Knepley     const PetscInt  *cells;
43042f856554SMatthew G. Knepley     PetscFVFaceGeom *fg;
43052f856554SMatthew G. Knepley     PetscFVCellGeom *cgL, *cgR;
43062f856554SMatthew G. Knepley     PetscFVFaceGeom *fgeoml = *fgeom;
43072f856554SMatthew G. Knepley     PetscReal       *voll   = *vol;
43082f856554SMatthew G. Knepley     PetscInt         ghost, d, nchild, nsupp;
43092f856554SMatthew G. Knepley 
43109566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
43119566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
43129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
43132f856554SMatthew G. Knepley     if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
43149566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg));
43159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, face, &cells));
43169566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL));
43179566063dSJacob Faibussowitsch     PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR));
43182f856554SMatthew G. Knepley     for (d = 0; d < dim; ++d) {
43192f856554SMatthew G. Knepley       fgeoml[iface].centroid[d] = fg->centroid[d];
43202f856554SMatthew G. Knepley       fgeoml[iface].normal[d]   = fg->normal[d];
43212f856554SMatthew G. Knepley     }
43222f856554SMatthew G. Knepley     voll[iface * 2 + 0] = cgL->volume;
43232f856554SMatthew G. Knepley     voll[iface * 2 + 1] = cgR->volume;
43242f856554SMatthew G. Knepley     ++iface;
43252f856554SMatthew G. Knepley   }
43262f856554SMatthew G. Knepley   *Nface = iface;
43279566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom));
43289566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom));
43293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43302f856554SMatthew G. Knepley }
43312f856554SMatthew G. Knepley 
43322f856554SMatthew G. Knepley /*@C
43332f856554SMatthew G. Knepley   DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces
43342f856554SMatthew G. Knepley 
43352f856554SMatthew G. Knepley   Input Parameters:
4336a1cb98faSBarry Smith + dm           - The `DM`
43372f856554SMatthew G. Knepley . fStart       - The first face to include
43382f856554SMatthew G. Knepley . fEnd         - The first face to exclude
43392f856554SMatthew G. Knepley . faceGeometry - A local vector with face geometry
43402f856554SMatthew G. Knepley - cellGeometry - A local vector with cell geometry
43412f856554SMatthew G. Knepley 
43422f856554SMatthew G. Knepley   Output Parameters:
43432f856554SMatthew G. Knepley + Nface - The number of faces with field values
4344ce78bad3SBarry Smith . fgeom - The face centroid and normals
4345ce78bad3SBarry Smith - vol   - The cell volumes
43462f856554SMatthew G. Knepley 
43472f856554SMatthew G. Knepley   Level: developer
43482f856554SMatthew G. Knepley 
43491cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()`
43502f856554SMatthew G. Knepley @*/
DMPlexRestoreFaceGeometry(DM dm,PetscInt fStart,PetscInt fEnd,Vec faceGeometry,Vec cellGeometry,PetscInt * Nface,PetscFVFaceGeom * fgeom[],PetscReal * vol[])4351ce78bad3SBarry Smith PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom *fgeom[], PetscReal *vol[])
4352d71ae5a4SJacob Faibussowitsch {
43532f856554SMatthew G. Knepley   PetscFunctionBegin;
43549566063dSJacob Faibussowitsch   PetscCall(PetscFree(*fgeom));
43559566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol));
43563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43572f856554SMatthew G. Knepley }
43582f856554SMatthew G. Knepley 
DMSNESGetFEGeom(DMField coordField,IS pointIS,PetscQuadrature quad,PetscFEGeomMode mode,PetscFEGeom ** geom)4359ac9d17c7SMatthew G. Knepley PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscFEGeomMode mode, PetscFEGeom **geom)
4360d71ae5a4SJacob Faibussowitsch {
4361a1cf66bbSMatthew G. Knepley   char           composeStr[33] = {0};
4362a1cf66bbSMatthew G. Knepley   PetscObjectId  id;
4363a1cf66bbSMatthew G. Knepley   PetscContainer container;
4364a1cf66bbSMatthew G. Knepley 
4365a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
43669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetId((PetscObject)quad, &id));
436763a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id));
43689566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container));
4369a1cf66bbSMatthew G. Knepley   if (container) {
4370*2a8381b2SBarry Smith     PetscCall(PetscContainerGetPointer(container, geom));
4371a1cf66bbSMatthew G. Knepley   } else {
4372ac9d17c7SMatthew G. Knepley     PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, mode, geom));
43739566063dSJacob Faibussowitsch     PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
43749566063dSJacob Faibussowitsch     PetscCall(PetscContainerSetPointer(container, (void *)*geom));
437549abdd8aSBarry Smith     PetscCall(PetscContainerSetCtxDestroy(container, PetscContainerCtxDestroy_PetscFEGeom));
43769566063dSJacob Faibussowitsch     PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container));
43779566063dSJacob Faibussowitsch     PetscCall(PetscContainerDestroy(&container));
4378a1cf66bbSMatthew G. Knepley   }
43793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4380a1cf66bbSMatthew G. Knepley }
4381a1cf66bbSMatthew G. Knepley 
DMSNESRestoreFEGeom(DMField coordField,IS pointIS,PetscQuadrature quad,PetscBool faceData,PetscFEGeom ** geom)4382d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom)
4383d71ae5a4SJacob Faibussowitsch {
4384a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
4385a1cf66bbSMatthew G. Knepley   *geom = NULL;
43863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4387a1cf66bbSMatthew G. Knepley }
4388a1cf66bbSMatthew G. Knepley 
DMPlexComputeResidual_Patch_Internal(DM dm,PetscSection section,IS cellIS,PetscReal t,Vec locX,Vec locX_t,Vec locF,PetscCtx ctx)4389*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, PetscCtx ctx)
4390d71ae5a4SJacob Faibussowitsch {
439192d50984SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
439292d50984SMatthew G. Knepley   const char     *name       = "Residual";
439392d50984SMatthew G. Knepley   DM              dmAux      = NULL;
439492d50984SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
439592d50984SMatthew G. Knepley   PetscDS         prob       = NULL;
439692d50984SMatthew G. Knepley   PetscDS         probAux    = NULL;
439792d50984SMatthew G. Knepley   PetscBool       useFEM     = PETSC_FALSE;
439892d50984SMatthew G. Knepley   PetscBool       isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
439992d50984SMatthew G. Knepley   DMField         coordField = NULL;
4400c0006e53SPatrick Farrell   Vec             locA;
4401c0006e53SPatrick Farrell   PetscScalar    *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL;
440292d50984SMatthew G. Knepley   IS              chunkIS;
440392d50984SMatthew G. Knepley   const PetscInt *cells;
440492d50984SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
4405364207b6SKarl Rupp   PetscInt        Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd;
44061690c2aeSBarry Smith   PetscInt        maxDegree = PETSC_INT_MAX;
440706ad1575SMatthew G. Knepley   PetscFormKey    key;
440892d50984SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
440992d50984SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
441092d50984SMatthew G. Knepley 
441192d50984SMatthew G. Knepley   PetscFunctionBegin;
44129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
441392d50984SMatthew G. Knepley   /* FEM+FVM */
441492d50984SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
44159566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
44169566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
44179566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
44189566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
44199566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA));
442092d50984SMatthew G. Knepley   if (locA) {
44219566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
44229566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
44239566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
442492d50984SMatthew G. Knepley   }
442592d50984SMatthew G. Knepley   /* 2: Get geometric data */
442692d50984SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
442792d50984SMatthew G. Knepley     PetscObject  obj;
442892d50984SMatthew G. Knepley     PetscClassId id;
442992d50984SMatthew G. Knepley     PetscBool    fimp;
443092d50984SMatthew G. Knepley 
44319566063dSJacob Faibussowitsch     PetscCall(PetscDSGetImplicit(prob, f, &fimp));
443292d50984SMatthew G. Knepley     if (isImplicit != fimp) continue;
44339566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
44349566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
4435ad540459SPierre Jolivet     if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
44365f80ce2aSJacob Faibussowitsch     PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented");
443792d50984SMatthew G. Knepley   }
443892d50984SMatthew G. Knepley   if (useFEM) {
44399566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
44409566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
444192d50984SMatthew G. Knepley     if (maxDegree <= 1) {
44429566063dSJacob Faibussowitsch       PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
4443ac9d17c7SMatthew G. Knepley       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FEGEOM_BASIC, &affineGeom));
444492d50984SMatthew G. Knepley     } else {
44459566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
444692d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
444792d50984SMatthew G. Knepley         PetscObject  obj;
444892d50984SMatthew G. Knepley         PetscClassId id;
444992d50984SMatthew G. Knepley         PetscBool    fimp;
445092d50984SMatthew G. Knepley 
44519566063dSJacob Faibussowitsch         PetscCall(PetscDSGetImplicit(prob, f, &fimp));
445292d50984SMatthew G. Knepley         if (isImplicit != fimp) continue;
44539566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, &obj));
44549566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
445592d50984SMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
445692d50984SMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
445792d50984SMatthew G. Knepley 
44589566063dSJacob Faibussowitsch           PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
44599566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)quads[f]));
4460ac9d17c7SMatthew G. Knepley           PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FEGEOM_BASIC, &geoms[f]));
446192d50984SMatthew G. Knepley         }
446292d50984SMatthew G. Knepley       }
446392d50984SMatthew G. Knepley     }
446492d50984SMatthew G. Knepley   }
446592d50984SMatthew G. Knepley   /* Loop over chunks */
44669566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
44679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
44689566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS));
446992d50984SMatthew G. Knepley   numCells      = cEnd - cStart;
447092d50984SMatthew G. Knepley   numChunks     = 1;
447192d50984SMatthew G. Knepley   cellChunkSize = numCells / numChunks;
447292d50984SMatthew G. Knepley   numChunks     = PetscMin(1, numCells);
44736528b96dSMatthew G. Knepley   key.label     = NULL;
44746528b96dSMatthew G. Knepley   key.value     = 0;
447506ad1575SMatthew G. Knepley   key.part      = 0;
447692d50984SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
4477c0006e53SPatrick Farrell     PetscScalar     *elemVec, *fluxL = NULL, *fluxR = NULL;
4478c0006e53SPatrick Farrell     PetscReal       *vol   = NULL;
4479c0006e53SPatrick Farrell     PetscFVFaceGeom *fgeom = NULL;
448092d50984SMatthew G. Knepley     PetscInt         cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
4481c0006e53SPatrick Farrell     PetscInt         numFaces = 0;
448292d50984SMatthew G. Knepley 
448392d50984SMatthew G. Knepley     /* Extract field coefficients */
448492d50984SMatthew G. Knepley     if (useFEM) {
44859566063dSJacob Faibussowitsch       PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells));
44869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
44879566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
44889566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemVec, numCells * totDim));
448992d50984SMatthew G. Knepley     }
449092d50984SMatthew 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 */
449192d50984SMatthew G. Knepley     /* Loop over fields */
449292d50984SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
449392d50984SMatthew G. Knepley       PetscObject  obj;
449492d50984SMatthew G. Knepley       PetscClassId id;
449592d50984SMatthew G. Knepley       PetscBool    fimp;
449692d50984SMatthew G. Knepley       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
449792d50984SMatthew G. Knepley 
44986528b96dSMatthew G. Knepley       key.field = f;
44999566063dSJacob Faibussowitsch       PetscCall(PetscDSGetImplicit(prob, f, &fimp));
450092d50984SMatthew G. Knepley       if (isImplicit != fimp) continue;
45019566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
45029566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
450392d50984SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
450492d50984SMatthew G. Knepley         PetscFE         fe        = (PetscFE)obj;
450592d50984SMatthew G. Knepley         PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
450692d50984SMatthew G. Knepley         PetscFEGeom    *chunkGeom = NULL;
450792d50984SMatthew G. Knepley         PetscQuadrature quad      = affineQuad ? affineQuad : quads[f];
450892d50984SMatthew G. Knepley         PetscInt        Nq, Nb;
450992d50984SMatthew G. Knepley 
45109566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
45119566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
45129566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
451392d50984SMatthew G. Knepley         blockSize = Nb;
451492d50984SMatthew G. Knepley         batchSize = numBlocks * blockSize;
45159566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
451692d50984SMatthew G. Knepley         numChunks = numCells / (numBatches * batchSize);
451792d50984SMatthew G. Knepley         Ne        = numChunks * numBatches * batchSize;
451892d50984SMatthew G. Knepley         Nr        = numCells % (numBatches * batchSize);
451992d50984SMatthew G. Knepley         offset    = numCells - Nr;
452092d50984SMatthew G. Knepley         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
452192d50984SMatthew 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) */
45229566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
45239566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec));
45249566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom));
45258e3a54c0SPierre Jolivet         PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim]));
45269566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom));
452792d50984SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
452892d50984SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
452992d50984SMatthew G. Knepley 
453092d50984SMatthew G. Knepley         Ne = numFaces;
453192d50984SMatthew G. Knepley         /* Riemann solve over faces (need fields at face centroids) */
453292d50984SMatthew G. Knepley         /*   We need to evaluate FE fields at those coordinates */
45339566063dSJacob Faibussowitsch         PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR));
453463a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
453592d50984SMatthew G. Knepley     }
453692d50984SMatthew G. Knepley     /* Loop over domain */
453792d50984SMatthew G. Knepley     if (useFEM) {
453892d50984SMatthew G. Knepley       /* Add elemVec to locX */
453992d50984SMatthew G. Knepley       for (c = cS; c < cE; ++c) {
454092d50984SMatthew G. Knepley         const PetscInt cell = cells ? cells[c] : c;
454192d50984SMatthew G. Knepley         const PetscInt cind = c - cStart;
454292d50984SMatthew G. Knepley 
45439566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
454492d50984SMatthew G. Knepley         if (ghostLabel) {
454592d50984SMatthew G. Knepley           PetscInt ghostVal;
454692d50984SMatthew G. Knepley 
45479566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
454892d50984SMatthew G. Knepley           if (ghostVal > 0) continue;
454992d50984SMatthew G. Knepley         }
45509566063dSJacob Faibussowitsch         PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
455192d50984SMatthew G. Knepley       }
455292d50984SMatthew G. Knepley     }
455392d50984SMatthew G. Knepley     /* Handle time derivative */
455492d50984SMatthew G. Knepley     if (locX_t) {
455592d50984SMatthew G. Knepley       PetscScalar *x_t, *fa;
455692d50984SMatthew G. Knepley 
45579566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
45589566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locX_t, &x_t));
455992d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
456092d50984SMatthew G. Knepley         PetscFV      fv;
456192d50984SMatthew G. Knepley         PetscObject  obj;
456292d50984SMatthew G. Knepley         PetscClassId id;
456392d50984SMatthew G. Knepley         PetscInt     pdim, d;
456492d50984SMatthew G. Knepley 
45659566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, f, &obj));
45669566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
456792d50984SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
456892d50984SMatthew G. Knepley         fv = (PetscFV)obj;
45699566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
457092d50984SMatthew G. Knepley         for (c = cS; c < cE; ++c) {
457192d50984SMatthew G. Knepley           const PetscInt cell = cells ? cells[c] : c;
457292d50984SMatthew G. Knepley           PetscScalar   *u_t, *r;
457392d50984SMatthew G. Knepley 
457492d50984SMatthew G. Knepley           if (ghostLabel) {
457592d50984SMatthew G. Knepley             PetscInt ghostVal;
457692d50984SMatthew G. Knepley 
45779566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
457892d50984SMatthew G. Knepley             if (ghostVal > 0) continue;
457992d50984SMatthew G. Knepley           }
45809566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t));
45819566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r));
458292d50984SMatthew G. Knepley           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
458392d50984SMatthew G. Knepley         }
458492d50984SMatthew G. Knepley       }
45859566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locX_t, &x_t));
45869566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
458792d50984SMatthew G. Knepley     }
458892d50984SMatthew G. Knepley     if (useFEM) {
45899566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
45909566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
459192d50984SMatthew G. Knepley     }
459292d50984SMatthew G. Knepley   }
45939566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISDestroy(&chunkIS));
45949566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
4595754e4fbaSMatthew G. Knepley   /* TODO Could include boundary residual here (see DMPlexComputeResidualByKey) */
459692d50984SMatthew G. Knepley   if (useFEM) {
459792d50984SMatthew G. Knepley     if (maxDegree <= 1) {
45989566063dSJacob Faibussowitsch       PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
45999566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&affineQuad));
460092d50984SMatthew G. Knepley     } else {
460192d50984SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
46029566063dSJacob Faibussowitsch         PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
46039566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureDestroy(&quads[f]));
460492d50984SMatthew G. Knepley       }
46059566063dSJacob Faibussowitsch       PetscCall(PetscFree2(quads, geoms));
460692d50984SMatthew G. Knepley     }
460792d50984SMatthew G. Knepley   }
46089566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
46093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
461092d50984SMatthew G. Knepley }
461192d50984SMatthew G. Knepley 
4612a1cf66bbSMatthew G. Knepley /*
4613a1cf66bbSMatthew 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
4614a1cf66bbSMatthew G. Knepley 
4615a1cf66bbSMatthew G. Knepley   X   - The local solution vector
4616a5b23f4aSJose E. Roman   X_t - The local solution time derivative vector, or NULL
4617a1cf66bbSMatthew G. Knepley */
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,PetscCtx ctx)4618*2a8381b2SBarry Smith 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, PetscCtx ctx)
4619d71ae5a4SJacob Faibussowitsch {
4620a1cf66bbSMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
4621a1cf66bbSMatthew G. Knepley   const char     *name = "Jacobian", *nameP = "JacobianPre";
4622a1cf66bbSMatthew G. Knepley   DM              dmAux = NULL;
4623a1cf66bbSMatthew G. Knepley   PetscDS         prob, probAux = NULL;
4624a1cf66bbSMatthew G. Knepley   PetscSection    sectionAux = NULL;
4625a1cf66bbSMatthew G. Knepley   Vec             A;
4626a1cf66bbSMatthew G. Knepley   DMField         coordField;
4627a1cf66bbSMatthew G. Knepley   PetscFEGeom    *cgeomFEM;
4628a1cf66bbSMatthew G. Knepley   PetscQuadrature qGeom = NULL;
4629a1cf66bbSMatthew G. Knepley   Mat             J = Jac, JP = JacP;
4630a1cf66bbSMatthew G. Knepley   PetscScalar    *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL;
4631e432b41dSStefano Zampini   PetscBool       hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE;
4632a1cf66bbSMatthew G. Knepley   const PetscInt *cells;
463306ad1575SMatthew G. Knepley   PetscFormKey    key;
46349b2fc754SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0;
4635a1cf66bbSMatthew G. Knepley 
4636a1cf66bbSMatthew G. Knepley   PetscFunctionBegin;
46379566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
46389566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
46399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
46409566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
46419566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A));
46429a2a23afSMatthew G. Knepley   if (A) {
46439566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
46449566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmAux, &sectionAux));
46459566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
4646a1cf66bbSMatthew G. Knepley   }
4647a1cf66bbSMatthew G. Knepley   /* Get flags */
46489566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
46495440e5dcSBarry Smith   PetscCall(DMGetWorkArray(dm, Nf, MPI_C_BOOL, &isFE));
4650a1cf66bbSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
4651a1cf66bbSMatthew G. Knepley     PetscObject  disc;
4652a1cf66bbSMatthew G. Knepley     PetscClassId id;
46539566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc));
46549566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(disc, &id));
46559371c9d4SSatish Balay     if (id == PETSCFE_CLASSID) {
46569371c9d4SSatish Balay       isFE[fieldI] = PETSC_TRUE;
46579371c9d4SSatish Balay     } else if (id == PETSCFV_CLASSID) {
46589371c9d4SSatish Balay       hasFV        = PETSC_TRUE;
46599371c9d4SSatish Balay       isFE[fieldI] = PETSC_FALSE;
46609371c9d4SSatish Balay     }
4661a1cf66bbSMatthew G. Knepley   }
46629566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(prob, &hasJac));
46639566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
46649566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
4665a1cf66bbSMatthew G. Knepley   assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE;
4666a1cf66bbSMatthew G. Knepley   hasDyn      = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
46679566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */
46689566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
46699566063dSJacob Faibussowitsch   if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
4670a1cf66bbSMatthew G. Knepley   /* Compute batch sizes */
4671a1cf66bbSMatthew G. Knepley   if (isFE[0]) {
4672a1cf66bbSMatthew G. Knepley     PetscFE         fe;
4673a1cf66bbSMatthew G. Knepley     PetscQuadrature q;
4674a1cf66bbSMatthew G. Knepley     PetscInt        numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb;
4675a1cf66bbSMatthew G. Knepley 
46769566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe));
46779566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &q));
46789566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL));
46799566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
46809566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
4681a1cf66bbSMatthew G. Knepley     blockSize = Nb * numQuadPoints;
4682a1cf66bbSMatthew G. Knepley     batchSize = numBlocks * blockSize;
4683a1cf66bbSMatthew G. Knepley     chunkSize = numBatches * batchSize;
4684a1cf66bbSMatthew G. Knepley     numChunks = numCells / chunkSize + numCells % chunkSize;
46859566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
4686a1cf66bbSMatthew G. Knepley   } else {
4687a1cf66bbSMatthew G. Knepley     chunkSize = numCells;
4688a1cf66bbSMatthew G. Knepley     numChunks = 1;
4689a1cf66bbSMatthew G. Knepley   }
4690a1cf66bbSMatthew G. Knepley   /* Get work space */
46912358c221SStefano Zampini   wsz = (((X ? 1 : 0) + (X_t ? 1 : 0)) * totDim + (dmAux ? 1 : 0) * totDimAux + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize;
46929566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work));
46939566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(work, wsz));
4694a1cf66bbSMatthew G. Knepley   off      = 0;
4695a1cf66bbSMatthew G. Knepley   u        = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4696a1cf66bbSMatthew G. Knepley   u_t      = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL;
4697a1cf66bbSMatthew G. Knepley   a        = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL;
4698a1cf66bbSMatthew G. Knepley   elemMat  = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4699a1cf66bbSMatthew G. Knepley   elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
4700a1cf66bbSMatthew G. Knepley   elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL;
470163a3b9bcSJacob Faibussowitsch   PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz);
4702a1cf66bbSMatthew G. Knepley   /* Setup geometry */
47039566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
47049566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
47059566063dSJacob Faibussowitsch   if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
4706a1cf66bbSMatthew G. Knepley   if (!qGeom) {
4707a1cf66bbSMatthew G. Knepley     PetscFE fe;
4708a1cf66bbSMatthew G. Knepley 
47099566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe));
47109566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &qGeom));
47119566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)qGeom));
4712a1cf66bbSMatthew G. Knepley   }
4713ac9d17c7SMatthew G. Knepley   PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FEGEOM_BASIC, &cgeomFEM));
4714a1cf66bbSMatthew G. Knepley   /* Compute volume integrals */
47159566063dSJacob Faibussowitsch   if (assembleJac) PetscCall(MatZeroEntries(J));
47169566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(JP));
47176528b96dSMatthew G. Knepley   key.label = NULL;
47186528b96dSMatthew G. Knepley   key.value = 0;
471906ad1575SMatthew G. Knepley   key.part  = 0;
4720a1cf66bbSMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) {
4721a1cf66bbSMatthew G. Knepley     const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell);
4722a1cf66bbSMatthew G. Knepley     PetscInt       c;
4723a1cf66bbSMatthew G. Knepley 
4724a1cf66bbSMatthew G. Knepley     /* Extract values */
4725a1cf66bbSMatthew G. Knepley     for (c = 0; c < Ncell; ++c) {
4726a1cf66bbSMatthew G. Knepley       const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4727a1cf66bbSMatthew G. Knepley       PetscScalar   *x = NULL, *x_t = NULL;
4728a1cf66bbSMatthew G. Knepley       PetscInt       i;
4729a1cf66bbSMatthew G. Knepley 
4730a1cf66bbSMatthew G. Knepley       if (X) {
47319566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x));
4732a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i];
47339566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x));
4734a1cf66bbSMatthew G. Knepley       }
4735a1cf66bbSMatthew G. Knepley       if (X_t) {
47369566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t));
4737a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i];
47389566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t));
4739a1cf66bbSMatthew G. Knepley       }
4740a1cf66bbSMatthew G. Knepley       if (dmAux) {
47419566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x));
4742a1cf66bbSMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i];
47439566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x));
4744a1cf66bbSMatthew G. Knepley       }
4745a1cf66bbSMatthew G. Knepley     }
4746a1cf66bbSMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
4747a1cf66bbSMatthew G. Knepley       PetscFE fe;
47489566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
4749a1cf66bbSMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
47506528b96dSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
47514561e6c9SMatthew G. Knepley         if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat));
47524561e6c9SMatthew G. Knepley         if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP));
47534561e6c9SMatthew G. Knepley         if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD));
4754a1cf66bbSMatthew G. Knepley       }
4755a1cf66bbSMatthew G. Knepley       /* For finite volume, add the identity */
4756a1cf66bbSMatthew G. Knepley       if (!isFE[fieldI]) {
4757a1cf66bbSMatthew G. Knepley         PetscFV  fv;
4758a1cf66bbSMatthew G. Knepley         PetscInt eOffset = 0, Nc, fc, foff;
4759a1cf66bbSMatthew G. Knepley 
47609566063dSJacob Faibussowitsch         PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff));
47619566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv));
47629566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &Nc));
4763a1cf66bbSMatthew G. Knepley         for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) {
4764a1cf66bbSMatthew G. Knepley           for (fc = 0; fc < Nc; ++fc) {
4765a1cf66bbSMatthew G. Knepley             const PetscInt i = foff + fc;
4766ad540459SPierre Jolivet             if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0;
4767ad540459SPierre Jolivet             if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0;
4768a1cf66bbSMatthew G. Knepley           }
4769a1cf66bbSMatthew G. Knepley         }
4770a1cf66bbSMatthew G. Knepley       }
4771a1cf66bbSMatthew G. Knepley     }
4772a1cf66bbSMatthew G. Knepley     /*   Add contribution from X_t */
47739371c9d4SSatish Balay     if (hasDyn) {
47749371c9d4SSatish Balay       for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
47759371c9d4SSatish Balay     }
4776a1cf66bbSMatthew G. Knepley     /* Insert values into matrix */
4777a1cf66bbSMatthew G. Knepley     for (c = 0; c < Ncell; ++c) {
4778a1cf66bbSMatthew G. Knepley       const PetscInt cell = cells ? cells[c + offCell] : c + offCell;
4779a1cf66bbSMatthew G. Knepley       if (mesh->printFEM > 1) {
47809566063dSJacob Faibussowitsch         if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim]));
47819566063dSJacob Faibussowitsch         if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim]));
4782a1cf66bbSMatthew G. Knepley       }
4783e8e188d2SZach Atkins       if (assembleJac) PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES));
4784e8e188d2SZach Atkins       PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES));
4785a1cf66bbSMatthew G. Knepley     }
4786a1cf66bbSMatthew G. Knepley   }
4787a1cf66bbSMatthew G. Knepley   /* Cleanup */
47889566063dSJacob Faibussowitsch   PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
47899566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&qGeom));
47909566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
47915440e5dcSBarry Smith   PetscCall(DMRestoreWorkArray(dm, Nf, MPI_C_BOOL, &isFE));
47929566063dSJacob 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));
4793a1cf66bbSMatthew G. Knepley   /* Compute boundary integrals */
47949566063dSJacob Faibussowitsch   /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */
4795a1cf66bbSMatthew G. Knepley   /* Assemble matrix */
47969371c9d4SSatish Balay   if (assembleJac) {
47979371c9d4SSatish Balay     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
47989371c9d4SSatish Balay     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
47999371c9d4SSatish Balay   }
48009371c9d4SSatish Balay   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
48019371c9d4SSatish Balay   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
48029566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
48033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4804a1cf66bbSMatthew G. Knepley }
48053e9753d6SMatthew G. Knepley 
48064ee01570SBarry Smith /* FEM Assembly Function */
48073e9753d6SMatthew G. Knepley 
DMConvertPlex_Internal(DM dm,DM * plex,PetscBool copy)4808d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy)
4809d71ae5a4SJacob Faibussowitsch {
48103e9753d6SMatthew G. Knepley   PetscBool isPlex;
48113e9753d6SMatthew G. Knepley 
48123e9753d6SMatthew G. Knepley   PetscFunctionBegin;
48139566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
48143e9753d6SMatthew G. Knepley   if (isPlex) {
48153e9753d6SMatthew G. Knepley     *plex = dm;
48169566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dm));
48173e9753d6SMatthew G. Knepley   } else {
48189566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex));
48193e9753d6SMatthew G. Knepley     if (!*plex) {
48209566063dSJacob Faibussowitsch       PetscCall(DMConvert(dm, DMPLEX, plex));
48219566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex));
48223e9753d6SMatthew G. Knepley     } else {
48239566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)*plex));
48243e9753d6SMatthew G. Knepley     }
4825cbf8eb3cSStefano Zampini     if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex));
48263e9753d6SMatthew G. Knepley   }
48273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48283e9753d6SMatthew G. Knepley }
48293e9753d6SMatthew G. Knepley 
48303e9753d6SMatthew G. Knepley /*@
48313e9753d6SMatthew G. Knepley   DMPlexGetGeometryFVM - Return precomputed geometric data
48323e9753d6SMatthew G. Knepley 
483320f4b53cSBarry Smith   Collective
48343e9753d6SMatthew G. Knepley 
48353e9753d6SMatthew G. Knepley   Input Parameter:
4836a1cb98faSBarry Smith . dm - The `DM`
48373e9753d6SMatthew G. Knepley 
48383e9753d6SMatthew G. Knepley   Output Parameters:
48393e9753d6SMatthew G. Knepley + facegeom  - The values precomputed from face geometry
48403e9753d6SMatthew G. Knepley . cellgeom  - The values precomputed from cell geometry
4841ce78bad3SBarry Smith - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell, or `NULL` if not needed
48423e9753d6SMatthew G. Knepley 
48433e9753d6SMatthew G. Knepley   Level: developer
48443e9753d6SMatthew G. Knepley 
48451cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()`
48463e9753d6SMatthew G. Knepley @*/
DMPlexGetGeometryFVM(DM dm,Vec * facegeom,Vec * cellgeom,PeOp PetscReal * minRadius)4847ce78bad3SBarry Smith PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PeOp PetscReal *minRadius)
4848d71ae5a4SJacob Faibussowitsch {
48493e9753d6SMatthew G. Knepley   DM plex;
48503e9753d6SMatthew G. Knepley 
48513e9753d6SMatthew G. Knepley   PetscFunctionBegin;
48523e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48539566063dSJacob Faibussowitsch   PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE));
48549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL));
48559566063dSJacob Faibussowitsch   if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius));
48569566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
48573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48583e9753d6SMatthew G. Knepley }
48593e9753d6SMatthew G. Knepley 
48603e9753d6SMatthew G. Knepley /*@
48613e9753d6SMatthew G. Knepley   DMPlexGetGradientDM - Return gradient data layout
48623e9753d6SMatthew G. Knepley 
486320f4b53cSBarry Smith   Collective
48643e9753d6SMatthew G. Knepley 
48653e9753d6SMatthew G. Knepley   Input Parameters:
4866a1cb98faSBarry Smith + dm - The `DM`
486720f4b53cSBarry Smith - fv - The `PetscFV`
48683e9753d6SMatthew G. Knepley 
48693e9753d6SMatthew G. Knepley   Output Parameter:
48703e9753d6SMatthew G. Knepley . dmGrad - The layout for gradient values
48713e9753d6SMatthew G. Knepley 
48723e9753d6SMatthew G. Knepley   Level: developer
48733e9753d6SMatthew G. Knepley 
48741cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()`
48753e9753d6SMatthew G. Knepley @*/
DMPlexGetGradientDM(DM dm,PetscFV fv,DM * dmGrad)4876d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad)
4877d71ae5a4SJacob Faibussowitsch {
48783e9753d6SMatthew G. Knepley   DM        plex;
48793e9753d6SMatthew G. Knepley   PetscBool computeGradients;
48803e9753d6SMatthew G. Knepley 
48813e9753d6SMatthew G. Knepley   PetscFunctionBegin;
48823e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48833e9753d6SMatthew G. Knepley   PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2);
48844f572ea9SToby Isaac   PetscAssertPointer(dmGrad, 3);
48859566063dSJacob Faibussowitsch   PetscCall(PetscFVGetComputeGradients(fv, &computeGradients));
48869371c9d4SSatish Balay   if (!computeGradients) {
48879371c9d4SSatish Balay     *dmGrad = NULL;
48883ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
48899371c9d4SSatish Balay   }
48909566063dSJacob Faibussowitsch   PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE));
48919566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad));
48929566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
48933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48943e9753d6SMatthew G. Knepley }
48953e9753d6SMatthew G. Knepley 
4896997bf629SMatthew G. Knepley /*@
4897997bf629SMatthew G. Knepley   DMPlexComputeBdResidualSingleByKey - Compute the local boundary residual for terms matching the input key
4898997bf629SMatthew G. Knepley 
4899997bf629SMatthew G. Knepley   Not collective
4900997bf629SMatthew G. Knepley 
4901997bf629SMatthew G. Knepley   Input Parameters:
4902997bf629SMatthew G. Knepley + dm         - The output `DM`
4903997bf629SMatthew G. Knepley . wf         - The `PetscWeakForm` holding forms on this boundary
4904997bf629SMatthew G. Knepley . key        - The `PetscFormKey` indicating what should be integrated
4905997bf629SMatthew G. Knepley . facetIS    - The `IS` giving a set of faces to integrate over
4906997bf629SMatthew G. Knepley . locX       - The local solution
4907997bf629SMatthew G. Knepley . locX_t     - The time derivative of the local solution, or `NULL` for time-independent problems
4908997bf629SMatthew G. Knepley . t          - The time
4909997bf629SMatthew G. Knepley - coordField - The `DMField` object with coordinates for these faces
4910997bf629SMatthew G. Knepley 
4911997bf629SMatthew G. Knepley   Output Parameter:
4912997bf629SMatthew G. Knepley . locF - The local residual
4913997bf629SMatthew G. Knepley 
4914997bf629SMatthew G. Knepley   Level: developer
4915997bf629SMatthew G. Knepley 
4916997bf629SMatthew G. Knepley .seealso: `DMPlexComputeBdResidualSingle()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
4917997bf629SMatthew G. Knepley @*/
DMPlexComputeBdResidualSingleByKey(DM dm,PetscWeakForm wf,PetscFormKey key,IS facetIS,Vec locX,Vec locX_t,PetscReal t,DMField coordField,Vec locF)4918997bf629SMatthew G. Knepley PetscErrorCode DMPlexComputeBdResidualSingleByKey(DM dm, PetscWeakForm wf, PetscFormKey key, IS facetIS, Vec locX, Vec locX_t, PetscReal t, DMField coordField, Vec locF)
4919d71ae5a4SJacob Faibussowitsch {
49203e9753d6SMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
49213e9753d6SMatthew G. Knepley   DM              plex = NULL, plexA = NULL;
4922673019faSMatthew G. Knepley   const char     *name = "BdResidual";
49233e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
49243e9753d6SMatthew G. Knepley   PetscDS         prob, probAux       = NULL;
49253e9753d6SMatthew G. Knepley   PetscSection    section, sectionAux = NULL;
49263e9753d6SMatthew G. Knepley   Vec             locA = NULL;
49273e9753d6SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL;
49283e9753d6SMatthew G. Knepley   PetscInt        totDim, totDimAux = 0;
49293e9753d6SMatthew G. Knepley 
49303e9753d6SMatthew G. Knepley   PetscFunctionBegin;
49319566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
49329566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
49339566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
49349566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
49359566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA));
49363e9753d6SMatthew G. Knepley   if (locA) {
49373e9753d6SMatthew G. Knepley     DM dmAux;
49383e9753d6SMatthew G. Knepley 
49399566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
49409566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
49419566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
49429566063dSJacob Faibussowitsch     PetscCall(DMGetDS(plexA, &probAux));
49439566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
49449566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexA, &sectionAux));
49453e9753d6SMatthew G. Knepley   }
49460c290148SMatthew G. Knepley   {
49473e9753d6SMatthew G. Knepley     PetscFEGeom    *fgeom;
49483e9753d6SMatthew G. Knepley     PetscInt        maxDegree;
49493e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
49503e9753d6SMatthew G. Knepley     IS              pointIS;
49513e9753d6SMatthew G. Knepley     const PetscInt *points;
49523e9753d6SMatthew G. Knepley     PetscInt        numFaces, face, Nq;
49533e9753d6SMatthew G. Knepley 
49549566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS));
49550c290148SMatthew G. Knepley     if (!pointIS) goto end; /* No points with that id on this process */
49563e9753d6SMatthew G. Knepley     {
49573e9753d6SMatthew G. Knepley       IS isectIS;
49583e9753d6SMatthew G. Knepley 
49593e9753d6SMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */
49609566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
49619566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
49623e9753d6SMatthew G. Knepley       pointIS = isectIS;
49633e9753d6SMatthew G. Knepley     }
49649566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
49659566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
496632603206SJames Wright     PetscCall(PetscMalloc4(numFaces * totDim, &u, (locX_t ? (size_t)numFaces * totDim : 0), &u_t, numFaces * totDim, &elemVec, (locA ? (size_t)numFaces * totDimAux : 0), &a));
49679566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
496848a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
49693e9753d6SMatthew G. Knepley     if (!qGeom) {
49703e9753d6SMatthew G. Knepley       PetscFE fe;
49713e9753d6SMatthew G. Knepley 
49729566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe));
49739566063dSJacob Faibussowitsch       PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
49749566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
49753e9753d6SMatthew G. Knepley     }
49769566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
4977ac9d17c7SMatthew G. Knepley     PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_FEGEOM_BOUNDARY, &fgeom));
49783e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
4979f15274beSMatthew Knepley       const PetscInt point = points[face], *support;
49803e9753d6SMatthew G. Knepley       PetscScalar   *x     = NULL;
4981f15274beSMatthew Knepley       PetscInt       i;
49823e9753d6SMatthew G. Knepley 
49839566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, point, &support));
49849566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
49853e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
49869566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
49873e9753d6SMatthew G. Knepley       if (locX_t) {
49889566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x));
49893e9753d6SMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
49909566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x));
49913e9753d6SMatthew G. Knepley       }
49923e9753d6SMatthew G. Knepley       if (locA) {
49933e9753d6SMatthew G. Knepley         PetscInt subp;
49943e9753d6SMatthew G. Knepley 
49959566063dSJacob Faibussowitsch         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
49969566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
49973e9753d6SMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
49989566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
49993e9753d6SMatthew G. Knepley       }
50003e9753d6SMatthew G. Knepley     }
50019566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(elemVec, numFaces * totDim));
50023e9753d6SMatthew G. Knepley     {
50033e9753d6SMatthew G. Knepley       PetscFE      fe;
50043e9753d6SMatthew G. Knepley       PetscInt     Nb;
50053e9753d6SMatthew G. Knepley       PetscFEGeom *chunkGeom = NULL;
50063e9753d6SMatthew G. Knepley       /* Conforming batches */
50073e9753d6SMatthew G. Knepley       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
50083e9753d6SMatthew G. Knepley       /* Remainder */
50093e9753d6SMatthew G. Knepley       PetscInt Nr, offset;
50103e9753d6SMatthew G. Knepley 
50119566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe));
50129566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
50139566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
50143e9753d6SMatthew G. Knepley       /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */
50153e9753d6SMatthew G. Knepley       blockSize = Nb;
50163e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
50179566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
50183e9753d6SMatthew G. Knepley       numChunks = numFaces / (numBatches * batchSize);
50193e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
50203e9753d6SMatthew G. Knepley       Nr        = numFaces % (numBatches * batchSize);
50213e9753d6SMatthew G. Knepley       offset    = numFaces - Nr;
50229566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom));
50239566063dSJacob Faibussowitsch       PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec));
50249566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom));
50259566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
50268e3a54c0SPierre Jolivet       PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim]));
50279566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
50283e9753d6SMatthew G. Knepley     }
50293e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
50303e9753d6SMatthew G. Knepley       const PetscInt point = points[face], *support;
50313e9753d6SMatthew G. Knepley 
5032673019faSMatthew G. Knepley       if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, name, totDim, &elemVec[face * totDim]));
50339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(plex, point, &support));
50349566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES));
50353e9753d6SMatthew G. Knepley     }
50369566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
50379566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
50389566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
50399566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
50409566063dSJacob Faibussowitsch     PetscCall(PetscFree4(u, u_t, elemVec, a));
50413e9753d6SMatthew G. Knepley   }
50420c290148SMatthew G. Knepley end:
5043673019faSMatthew G. Knepley   if (mesh->printFEM) {
5044673019faSMatthew G. Knepley     PetscSection s;
5045673019faSMatthew G. Knepley     Vec          locFbc;
5046673019faSMatthew G. Knepley     PetscInt     pStart, pEnd, maxDof;
5047673019faSMatthew G. Knepley     PetscScalar *zeroes;
5048673019faSMatthew G. Knepley 
5049673019faSMatthew G. Knepley     PetscCall(DMGetLocalSection(dm, &s));
5050673019faSMatthew G. Knepley     PetscCall(VecDuplicate(locF, &locFbc));
5051673019faSMatthew G. Knepley     PetscCall(VecCopy(locF, locFbc));
5052673019faSMatthew G. Knepley     PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
5053673019faSMatthew G. Knepley     PetscCall(PetscSectionGetMaxDof(s, &maxDof));
5054673019faSMatthew G. Knepley     PetscCall(PetscCalloc1(maxDof, &zeroes));
5055673019faSMatthew G. Knepley     for (PetscInt p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, s, p, zeroes, INSERT_BC_VALUES));
5056673019faSMatthew G. Knepley     PetscCall(PetscFree(zeroes));
5057673019faSMatthew G. Knepley     PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc));
5058673019faSMatthew G. Knepley     PetscCall(VecDestroy(&locFbc));
5059673019faSMatthew G. Knepley   }
50609566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
50619566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plexA));
50623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50633e9753d6SMatthew G. Knepley }
50643e9753d6SMatthew G. Knepley 
5065997bf629SMatthew G. Knepley /*@
5066997bf629SMatthew G. Knepley   DMPlexComputeBdResidualSingle - Compute the local boundary residual
5067997bf629SMatthew G. Knepley 
5068997bf629SMatthew G. Knepley   Not collective
5069997bf629SMatthew G. Knepley 
5070997bf629SMatthew G. Knepley   Input Parameters:
5071997bf629SMatthew G. Knepley + dm     - The output `DM`
5072997bf629SMatthew G. Knepley . wf     - The `PetscWeakForm` holding forms on this boundary
5073997bf629SMatthew G. Knepley . key    - The `PetscFormKey` indicating what should be integrated
5074997bf629SMatthew G. Knepley . locX   - The local solution
5075997bf629SMatthew G. Knepley . locX_t - The time derivative of the local solution, or `NULL` for time-independent problems
5076997bf629SMatthew G. Knepley - t      - The time
5077997bf629SMatthew G. Knepley 
5078997bf629SMatthew G. Knepley   Output Parameter:
5079997bf629SMatthew G. Knepley . locF - The local residual
5080997bf629SMatthew G. Knepley 
5081997bf629SMatthew G. Knepley   Level: developer
5082997bf629SMatthew G. Knepley 
5083997bf629SMatthew G. Knepley .seealso: `DMPlexComputeBdResidualSingleByKey()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
5084997bf629SMatthew G. Knepley @*/
DMPlexComputeBdResidualSingle(DM dm,PetscWeakForm wf,PetscFormKey key,Vec locX,Vec locX_t,PetscReal t,Vec locF)5085997bf629SMatthew G. Knepley PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, PetscReal t, Vec locF)
5086d71ae5a4SJacob Faibussowitsch {
50873e9753d6SMatthew G. Knepley   DMField  coordField;
50883e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
50893e9753d6SMatthew G. Knepley   IS       facetIS;
50903e9753d6SMatthew G. Knepley   PetscInt dim;
50913e9753d6SMatthew G. Knepley 
50923e9753d6SMatthew G. Knepley   PetscFunctionBegin;
50939566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
50949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
50959566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
50969566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
5097997bf629SMatthew G. Knepley   PetscCall(DMPlexComputeBdResidualSingleByKey(dm, wf, key, facetIS, locX, locX_t, t, coordField, locF));
50989566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
50993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51003e9753d6SMatthew G. Knepley }
51013e9753d6SMatthew G. Knepley 
DMPlexComputeBdResidual_Internal(DM dm,Vec locX,Vec locX_t,PetscReal t,Vec locF,PetscCtx ctx)5102*2a8381b2SBarry Smith static PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, PetscCtx ctx)
5103d71ae5a4SJacob Faibussowitsch {
51043e9753d6SMatthew G. Knepley   PetscDS  prob;
51053e9753d6SMatthew G. Knepley   PetscInt numBd, bd;
51063e9753d6SMatthew G. Knepley   DMField  coordField = NULL;
51073e9753d6SMatthew G. Knepley   IS       facetIS    = NULL;
51083e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
51093e9753d6SMatthew G. Knepley   PetscInt dim;
51103e9753d6SMatthew G. Knepley 
51113e9753d6SMatthew G. Knepley   PetscFunctionBegin;
51129566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
51139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
51149566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
51159566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
51169566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
51173e9753d6SMatthew G. Knepley   for (bd = 0; bd < numBd; ++bd) {
511845480ffeSMatthew G. Knepley     PetscWeakForm           wf;
51193e9753d6SMatthew G. Knepley     DMBoundaryConditionType type;
51203e9753d6SMatthew G. Knepley     DMLabel                 label;
51213e9753d6SMatthew G. Knepley     const PetscInt         *values;
51220c290148SMatthew G. Knepley     PetscInt                field, numValues, v;
51233e9753d6SMatthew G. Knepley     PetscObject             obj;
51243e9753d6SMatthew G. Knepley     PetscClassId            id;
51250c290148SMatthew G. Knepley     PetscFormKey            key;
51263e9753d6SMatthew G. Knepley 
51279566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL));
51283d3e5d66SMatthew G. Knepley     if (type & DM_BC_ESSENTIAL) continue;
51299566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, field, &obj));
51309566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
51313d3e5d66SMatthew G. Knepley     if (id != PETSCFE_CLASSID) continue;
51323e9753d6SMatthew G. Knepley     if (!facetIS) {
51333e9753d6SMatthew G. Knepley       DMLabel  depthLabel;
51343e9753d6SMatthew G. Knepley       PetscInt dim;
51353e9753d6SMatthew G. Knepley 
51369566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
51379566063dSJacob Faibussowitsch       PetscCall(DMGetDimension(dm, &dim));
51389566063dSJacob Faibussowitsch       PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
51393e9753d6SMatthew G. Knepley     }
51409566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
51410c290148SMatthew G. Knepley     for (v = 0; v < numValues; ++v) {
51420c290148SMatthew G. Knepley       key.label = label;
51430c290148SMatthew G. Knepley       key.value = values[v];
51440c290148SMatthew G. Knepley       key.field = field;
51450c290148SMatthew G. Knepley       key.part  = 0;
5146997bf629SMatthew G. Knepley       PetscCall(DMPlexComputeBdResidualSingleByKey(dm, wf, key, facetIS, locX, locX_t, t, coordField, locF));
51470c290148SMatthew G. Knepley     }
51483e9753d6SMatthew G. Knepley   }
51499566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
51503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51513e9753d6SMatthew G. Knepley }
51523e9753d6SMatthew G. Knepley 
5153754e4fbaSMatthew G. Knepley /*@
5154754e4fbaSMatthew G. Knepley   DMPlexComputeResidualByKey - Compute the local residual for terms matching the input key
5155754e4fbaSMatthew G. Knepley 
5156754e4fbaSMatthew G. Knepley   Collective
5157754e4fbaSMatthew G. Knepley 
5158754e4fbaSMatthew G. Knepley   Input Parameters:
5159754e4fbaSMatthew G. Knepley + dm     - The output `DM`
5160754e4fbaSMatthew G. Knepley . key    - The `PetscFormKey` indicating what should be integrated
5161754e4fbaSMatthew G. Knepley . cellIS - The `IS` giving a set of cells to integrate over
5162754e4fbaSMatthew G. Knepley . time   - The time, or `PETSC_MIN_REAL` to include implicit terms in a time-independent problems
5163754e4fbaSMatthew G. Knepley . locX   - The local solution
5164754e4fbaSMatthew G. Knepley . locX_t - The time derivative of the local solution, or `NULL` for time-independent problems
5165754e4fbaSMatthew G. Knepley . t      - The time
5166*2a8381b2SBarry Smith - ctx    - An optional application context, passed to the pointwise functions
5167754e4fbaSMatthew G. Knepley 
5168754e4fbaSMatthew G. Knepley   Output Parameter:
5169754e4fbaSMatthew G. Knepley . locF - The local residual
5170754e4fbaSMatthew G. Knepley 
5171754e4fbaSMatthew G. Knepley   Level: developer
5172754e4fbaSMatthew G. Knepley 
5173754e4fbaSMatthew G. Knepley .seealso: `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
5174754e4fbaSMatthew G. Knepley @*/
DMPlexComputeResidualByKey(DM dm,PetscFormKey key,IS cellIS,PetscReal time,Vec locX,Vec locX_t,PetscReal t,Vec locF,PetscCtx ctx)5175*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeResidualByKey(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, PetscCtx ctx)
5176d71ae5a4SJacob Faibussowitsch {
51773e9753d6SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
51783e9753d6SMatthew G. Knepley   const char     *name       = "Residual";
51793e9753d6SMatthew G. Knepley   DM              dmAux      = NULL;
51803e9753d6SMatthew G. Knepley   DM              dmGrad     = NULL;
51813e9753d6SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
51826528b96dSMatthew G. Knepley   PetscDS         ds         = NULL;
51836528b96dSMatthew G. Knepley   PetscDS         dsAux      = NULL;
51843e9753d6SMatthew G. Knepley   PetscSection    section    = NULL;
51853e9753d6SMatthew G. Knepley   PetscBool       useFEM     = PETSC_FALSE;
51863e9753d6SMatthew G. Knepley   PetscBool       useFVM     = PETSC_FALSE;
51873e9753d6SMatthew G. Knepley   PetscBool       isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE;
51883e9753d6SMatthew G. Knepley   PetscFV         fvm        = NULL;
51893e9753d6SMatthew G. Knepley   DMField         coordField = NULL;
51905962854dSMatthew G. Knepley   Vec             locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL;
51913e9753d6SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t, *a, *uL, *uR;
51923e9753d6SMatthew G. Knepley   IS              chunkIS;
51933e9753d6SMatthew G. Knepley   const PetscInt *cells;
51943e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
51953e9753d6SMatthew G. Knepley   PetscInt        Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd;
51961690c2aeSBarry Smith   PetscInt        maxDegree  = PETSC_INT_MAX;
51973e9753d6SMatthew G. Knepley   PetscQuadrature affineQuad = NULL, *quads = NULL;
51983e9753d6SMatthew G. Knepley   PetscFEGeom    *affineGeom = NULL, **geoms = NULL;
51993e9753d6SMatthew G. Knepley 
52003e9753d6SMatthew G. Knepley   PetscFunctionBegin;
52019566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
52023cc88e6aSStefano Zampini   if (!cellIS) goto end;
52033cc88e6aSStefano Zampini   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
52043cc88e6aSStefano Zampini   if (cStart >= cEnd) goto end;
52053e9753d6SMatthew G. Knepley   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
52063e9753d6SMatthew G. Knepley   /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */
52073e9753d6SMatthew G. Knepley   /* FEM+FVM */
52089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
52093e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
52109566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
52119566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
521207218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, NULL));
52139566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
52149566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
52159566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA));
52163e9753d6SMatthew G. Knepley   if (locA) {
52173e9753d6SMatthew G. Knepley     PetscInt subcell;
52189566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
52191059d808SMatthew G. Knepley     PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell));
522007218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux, subcell, &dsAux, NULL));
52219566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
52223e9753d6SMatthew G. Knepley   }
52233e9753d6SMatthew G. Knepley   /* 2: Get geometric data */
52243e9753d6SMatthew G. Knepley   for (f = 0; f < Nf; ++f) {
52253e9753d6SMatthew G. Knepley     PetscObject  obj;
52263e9753d6SMatthew G. Knepley     PetscClassId id;
52273e9753d6SMatthew G. Knepley     PetscBool    fimp;
52283e9753d6SMatthew G. Knepley 
52299566063dSJacob Faibussowitsch     PetscCall(PetscDSGetImplicit(ds, f, &fimp));
52303e9753d6SMatthew G. Knepley     if (isImplicit != fimp) continue;
52319566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
52329566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
5233ad540459SPierre Jolivet     if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE;
52349371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) {
52359371c9d4SSatish Balay       useFVM = PETSC_TRUE;
52369371c9d4SSatish Balay       fvm    = (PetscFV)obj;
52379371c9d4SSatish Balay     }
52383e9753d6SMatthew G. Knepley   }
52393e9753d6SMatthew G. Knepley   if (useFEM) {
52409566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateField(dm, &coordField));
52419566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
52423e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
52439566063dSJacob Faibussowitsch       PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad));
5244ac9d17c7SMatthew G. Knepley       if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FEGEOM_BASIC, &affineGeom));
52453e9753d6SMatthew G. Knepley     } else {
52469566063dSJacob Faibussowitsch       PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms));
52473e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
52483e9753d6SMatthew G. Knepley         PetscObject  obj;
52493e9753d6SMatthew G. Knepley         PetscClassId id;
52503e9753d6SMatthew G. Knepley         PetscBool    fimp;
52513e9753d6SMatthew G. Knepley 
52529566063dSJacob Faibussowitsch         PetscCall(PetscDSGetImplicit(ds, f, &fimp));
52533e9753d6SMatthew G. Knepley         if (isImplicit != fimp) continue;
52549566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
52559566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
52563e9753d6SMatthew G. Knepley         if (id == PETSCFE_CLASSID) {
52573e9753d6SMatthew G. Knepley           PetscFE fe = (PetscFE)obj;
52583e9753d6SMatthew G. Knepley 
52599566063dSJacob Faibussowitsch           PetscCall(PetscFEGetQuadrature(fe, &quads[f]));
52609566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)quads[f]));
5261ac9d17c7SMatthew G. Knepley           PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FEGEOM_BASIC, &geoms[f]));
52623e9753d6SMatthew G. Knepley         }
52633e9753d6SMatthew G. Knepley       }
52643e9753d6SMatthew G. Knepley     }
52653e9753d6SMatthew G. Knepley   }
52665962854dSMatthew G. Knepley   // Handle non-essential (e.g. outflow) boundary values
52673e9753d6SMatthew G. Knepley   if (useFVM) {
52685962854dSMatthew G. Knepley     PetscCall(DMPlexInsertBoundaryValuesFVM(dm, fvm, locX, time, &locGrad));
52699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL));
52709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad));
52713e9753d6SMatthew G. Knepley   }
52723e9753d6SMatthew G. Knepley   /* Loop over chunks */
52739566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS));
52743e9753d6SMatthew G. Knepley   numCells      = cEnd - cStart;
52753e9753d6SMatthew G. Knepley   numChunks     = 1;
52763e9753d6SMatthew G. Knepley   cellChunkSize = numCells / numChunks;
52773e9753d6SMatthew G. Knepley   faceChunkSize = (fEnd - fStart) / numChunks;
52783e9753d6SMatthew G. Knepley   numChunks     = PetscMin(1, numCells);
52793e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
52803e9753d6SMatthew G. Knepley     PetscScalar     *elemVec, *fluxL, *fluxR;
52813e9753d6SMatthew G. Knepley     PetscReal       *vol;
52823e9753d6SMatthew G. Knepley     PetscFVFaceGeom *fgeom;
52833e9753d6SMatthew G. Knepley     PetscInt         cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
52843e9753d6SMatthew G. Knepley     PetscInt         fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face;
52853e9753d6SMatthew G. Knepley 
52863e9753d6SMatthew G. Knepley     /* Extract field coefficients */
52873e9753d6SMatthew G. Knepley     if (useFEM) {
52889566063dSJacob Faibussowitsch       PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells));
52899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
52909566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
52919566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(elemVec, numCells * totDim));
52923e9753d6SMatthew G. Knepley     }
52933e9753d6SMatthew G. Knepley     if (useFVM) {
52949566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR));
52959566063dSJacob Faibussowitsch       PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol));
52969566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL));
52979566063dSJacob Faibussowitsch       PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR));
52989566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(fluxL, numFaces * totDim));
52999566063dSJacob Faibussowitsch       PetscCall(PetscArrayzero(fluxR, numFaces * totDim));
53003e9753d6SMatthew G. Knepley     }
53013e9753d6SMatthew 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 */
53023e9753d6SMatthew G. Knepley     /* Loop over fields */
53033e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
53043e9753d6SMatthew G. Knepley       PetscObject  obj;
53053e9753d6SMatthew G. Knepley       PetscClassId id;
53063e9753d6SMatthew G. Knepley       PetscBool    fimp;
53073e9753d6SMatthew G. Knepley       PetscInt     numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset;
53083e9753d6SMatthew G. Knepley 
53096528b96dSMatthew G. Knepley       key.field = f;
53109566063dSJacob Faibussowitsch       PetscCall(PetscDSGetImplicit(ds, f, &fimp));
53113e9753d6SMatthew G. Knepley       if (isImplicit != fimp) continue;
53129566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, &obj));
53139566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId(obj, &id));
53143e9753d6SMatthew G. Knepley       if (id == PETSCFE_CLASSID) {
53153e9753d6SMatthew G. Knepley         PetscFE         fe        = (PetscFE)obj;
53163e9753d6SMatthew G. Knepley         PetscFEGeom    *geom      = affineGeom ? affineGeom : geoms[f];
53173e9753d6SMatthew G. Knepley         PetscFEGeom    *chunkGeom = NULL;
53183e9753d6SMatthew G. Knepley         PetscQuadrature quad      = affineQuad ? affineQuad : quads[f];
53193e9753d6SMatthew G. Knepley         PetscInt        Nq, Nb;
53203e9753d6SMatthew G. Knepley 
53219566063dSJacob Faibussowitsch         PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
53229566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
53239566063dSJacob Faibussowitsch         PetscCall(PetscFEGetDimension(fe, &Nb));
53243e9753d6SMatthew G. Knepley         blockSize = Nb;
53253e9753d6SMatthew G. Knepley         batchSize = numBlocks * blockSize;
53269566063dSJacob Faibussowitsch         PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
53273e9753d6SMatthew G. Knepley         numChunks = numCells / (numBatches * batchSize);
53283e9753d6SMatthew G. Knepley         Ne        = numChunks * numBatches * batchSize;
53293e9753d6SMatthew G. Knepley         Nr        = numCells % (numBatches * batchSize);
53303e9753d6SMatthew G. Knepley         offset    = numCells - Nr;
53313e9753d6SMatthew G. Knepley         /* Integrate FE residual to get elemVec (need fields at quadrature points) */
53323e9753d6SMatthew 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) */
53339566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom));
53349566063dSJacob Faibussowitsch         PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec));
53359566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom));
53368e3a54c0SPierre Jolivet         PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, &elemVec[offset * totDim]));
53379566063dSJacob Faibussowitsch         PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom));
53383e9753d6SMatthew G. Knepley       } else if (id == PETSCFV_CLASSID) {
53393e9753d6SMatthew G. Knepley         PetscFV fv = (PetscFV)obj;
53403e9753d6SMatthew G. Knepley 
53413e9753d6SMatthew G. Knepley         Ne = numFaces;
53423e9753d6SMatthew G. Knepley         /* Riemann solve over faces (need fields at face centroids) */
53433e9753d6SMatthew G. Knepley         /*   We need to evaluate FE fields at those coordinates */
53449566063dSJacob Faibussowitsch         PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR));
534563a3b9bcSJacob Faibussowitsch       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
53463e9753d6SMatthew G. Knepley     }
53473e9753d6SMatthew G. Knepley     /* Loop over domain */
53483e9753d6SMatthew G. Knepley     if (useFEM) {
53493e9753d6SMatthew G. Knepley       /* Add elemVec to locX */
53503e9753d6SMatthew G. Knepley       for (c = cS; c < cE; ++c) {
53513e9753d6SMatthew G. Knepley         const PetscInt cell = cells ? cells[c] : c;
53523e9753d6SMatthew G. Knepley         const PetscInt cind = c - cStart;
53533e9753d6SMatthew G. Knepley 
53549566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim]));
53553e9753d6SMatthew G. Knepley         if (ghostLabel) {
53563e9753d6SMatthew G. Knepley           PetscInt ghostVal;
53573e9753d6SMatthew G. Knepley 
53589566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
53593e9753d6SMatthew G. Knepley           if (ghostVal > 0) continue;
53603e9753d6SMatthew G. Knepley         }
53619566063dSJacob Faibussowitsch         PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES));
53623e9753d6SMatthew G. Knepley       }
53633e9753d6SMatthew G. Knepley     }
53643e9753d6SMatthew G. Knepley     if (useFVM) {
53653e9753d6SMatthew G. Knepley       PetscScalar *fa;
53663e9753d6SMatthew G. Knepley       PetscInt     iface;
53673e9753d6SMatthew G. Knepley 
53689566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
53693e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
53703e9753d6SMatthew G. Knepley         PetscFV      fv;
53713e9753d6SMatthew G. Knepley         PetscObject  obj;
53723e9753d6SMatthew G. Knepley         PetscClassId id;
53735962854dSMatthew G. Knepley         PetscInt     cdim, foff, pdim;
53743e9753d6SMatthew G. Knepley 
53755962854dSMatthew G. Knepley         PetscCall(DMGetCoordinateDim(dm, &cdim));
53769566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
53779566063dSJacob Faibussowitsch         PetscCall(PetscDSGetFieldOffset(ds, f, &foff));
53789566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
53793e9753d6SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
53803e9753d6SMatthew G. Knepley         fv = (PetscFV)obj;
53819566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
53823e9753d6SMatthew G. Knepley         /* Accumulate fluxes to cells */
53833e9753d6SMatthew G. Knepley         for (face = fS, iface = 0; face < fE; ++face) {
53843e9753d6SMatthew G. Knepley           const PetscInt *scells;
53853e9753d6SMatthew G. Knepley           PetscScalar    *fL = NULL, *fR = NULL;
53863e9753d6SMatthew G. Knepley           PetscInt        ghost, d, nsupp, nchild;
53873e9753d6SMatthew G. Knepley 
53889566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, face, &ghost));
53899566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(dm, face, &nsupp));
53909566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL));
53913e9753d6SMatthew G. Knepley           if (ghost >= 0 || nsupp > 2 || nchild > 0) continue;
53929566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupport(dm, face, &scells));
53939566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost));
53949566063dSJacob Faibussowitsch           if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL));
53959566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost));
53969566063dSJacob Faibussowitsch           if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR));
53975962854dSMatthew G. Knepley           if (mesh->printFVM > 1) {
53985962854dSMatthew G. Knepley             PetscCall(DMPrintCellVectorReal(face, "Residual: normal", cdim, fgeom[iface].normal));
53995962854dSMatthew G. Knepley             PetscCall(DMPrintCellVector(face, "Residual: left state", pdim, &uL[iface * totDim + foff]));
54005962854dSMatthew G. Knepley             PetscCall(DMPrintCellVector(face, "Residual: right state", pdim, &uR[iface * totDim + foff]));
54015962854dSMatthew G. Knepley             PetscCall(DMPrintCellVector(face, "Residual: left flux", pdim, &fluxL[iface * totDim + foff]));
54025962854dSMatthew G. Knepley             PetscCall(DMPrintCellVector(face, "Residual: right flux", pdim, &fluxR[iface * totDim + foff]));
54035962854dSMatthew G. Knepley           }
54043e9753d6SMatthew G. Knepley           for (d = 0; d < pdim; ++d) {
54053e9753d6SMatthew G. Knepley             if (fL) fL[d] -= fluxL[iface * totDim + foff + d];
54063e9753d6SMatthew G. Knepley             if (fR) fR[d] += fluxR[iface * totDim + foff + d];
54073e9753d6SMatthew G. Knepley           }
54083e9753d6SMatthew G. Knepley           ++iface;
54093e9753d6SMatthew G. Knepley         }
54103e9753d6SMatthew G. Knepley       }
54119566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
54123e9753d6SMatthew G. Knepley     }
54133e9753d6SMatthew G. Knepley     /* Handle time derivative */
54143e9753d6SMatthew G. Knepley     if (locX_t) {
54153e9753d6SMatthew G. Knepley       PetscScalar *x_t, *fa;
54163e9753d6SMatthew G. Knepley 
54179566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locF, &fa));
54189566063dSJacob Faibussowitsch       PetscCall(VecGetArray(locX_t, &x_t));
54193e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
54203e9753d6SMatthew G. Knepley         PetscFV      fv;
54213e9753d6SMatthew G. Knepley         PetscObject  obj;
54223e9753d6SMatthew G. Knepley         PetscClassId id;
54233e9753d6SMatthew G. Knepley         PetscInt     pdim, d;
54243e9753d6SMatthew G. Knepley 
54259566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, f, &obj));
54269566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetClassId(obj, &id));
54273e9753d6SMatthew G. Knepley         if (id != PETSCFV_CLASSID) continue;
54283e9753d6SMatthew G. Knepley         fv = (PetscFV)obj;
54299566063dSJacob Faibussowitsch         PetscCall(PetscFVGetNumComponents(fv, &pdim));
54303e9753d6SMatthew G. Knepley         for (c = cS; c < cE; ++c) {
54313e9753d6SMatthew G. Knepley           const PetscInt cell = cells ? cells[c] : c;
54323e9753d6SMatthew G. Knepley           PetscScalar   *u_t, *r;
54333e9753d6SMatthew G. Knepley 
54343e9753d6SMatthew G. Knepley           if (ghostLabel) {
54353e9753d6SMatthew G. Knepley             PetscInt ghostVal;
54363e9753d6SMatthew G. Knepley 
54379566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
54383e9753d6SMatthew G. Knepley             if (ghostVal > 0) continue;
54393e9753d6SMatthew G. Knepley           }
54409566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t));
54419566063dSJacob Faibussowitsch           PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r));
54423e9753d6SMatthew G. Knepley           for (d = 0; d < pdim; ++d) r[d] += u_t[d];
54433e9753d6SMatthew G. Knepley         }
54443e9753d6SMatthew G. Knepley       }
54459566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locX_t, &x_t));
54469566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(locF, &fa));
54473e9753d6SMatthew G. Knepley     }
54483e9753d6SMatthew G. Knepley     if (useFEM) {
54499566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a));
54509566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec));
54513e9753d6SMatthew G. Knepley     }
54523e9753d6SMatthew G. Knepley     if (useFVM) {
54539566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR));
54549566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol));
54559566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL));
54569566063dSJacob Faibussowitsch       PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR));
54579566063dSJacob Faibussowitsch       if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad));
54583e9753d6SMatthew G. Knepley     }
54593e9753d6SMatthew G. Knepley   }
54609566063dSJacob Faibussowitsch   if (useFEM) PetscCall(ISDestroy(&chunkIS));
54619566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
54623e9753d6SMatthew G. Knepley 
54633e9753d6SMatthew G. Knepley   if (useFEM) {
5464*2a8381b2SBarry Smith     PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, ctx));
54653e9753d6SMatthew G. Knepley 
54663e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
54679566063dSJacob Faibussowitsch       PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom));
54689566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureDestroy(&affineQuad));
54693e9753d6SMatthew G. Knepley     } else {
54703e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
54719566063dSJacob Faibussowitsch         PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f]));
54729566063dSJacob Faibussowitsch         PetscCall(PetscQuadratureDestroy(&quads[f]));
54733e9753d6SMatthew G. Knepley       }
54749566063dSJacob Faibussowitsch       PetscCall(PetscFree2(quads, geoms));
54753e9753d6SMatthew G. Knepley     }
54763e9753d6SMatthew G. Knepley   }
54773e9753d6SMatthew G. Knepley 
54783e9753d6SMatthew G. Knepley   /* FEM */
54793e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
54803e9753d6SMatthew G. Knepley   /* 2: Get geometric data */
54813e9753d6SMatthew G. Knepley   /* 3: Handle boundary values */
54823e9753d6SMatthew G. Knepley   /* 4: Loop over domain */
54833e9753d6SMatthew G. Knepley   /*   Extract coefficients */
54843e9753d6SMatthew G. Knepley   /* Loop over fields */
54853e9753d6SMatthew G. Knepley   /*   Set tiling for FE*/
54863e9753d6SMatthew G. Knepley   /*   Integrate FE residual to get elemVec */
54873e9753d6SMatthew G. Knepley   /*     Loop over subdomain */
54883e9753d6SMatthew G. Knepley   /*       Loop over quad points */
54893e9753d6SMatthew G. Knepley   /*         Transform coords to real space */
54903e9753d6SMatthew G. Knepley   /*         Evaluate field and aux fields at point */
54913e9753d6SMatthew G. Knepley   /*         Evaluate residual at point */
54923e9753d6SMatthew G. Knepley   /*         Transform residual to real space */
54933e9753d6SMatthew G. Knepley   /*       Add residual to elemVec */
54943e9753d6SMatthew G. Knepley   /* Loop over domain */
54953e9753d6SMatthew G. Knepley   /*   Add elemVec to locX */
54963e9753d6SMatthew G. Knepley 
54973e9753d6SMatthew G. Knepley   /* FVM */
54983e9753d6SMatthew G. Knepley   /* Get geometric data */
54993e9753d6SMatthew G. Knepley   /* If using gradients */
55003e9753d6SMatthew G. Knepley   /*   Compute gradient data */
55013e9753d6SMatthew G. Knepley   /*   Loop over domain faces */
55023e9753d6SMatthew G. Knepley   /*     Count computational faces */
55033e9753d6SMatthew G. Knepley   /*     Reconstruct cell gradient */
55043e9753d6SMatthew G. Knepley   /*   Loop over domain cells */
55053e9753d6SMatthew G. Knepley   /*     Limit cell gradients */
55063e9753d6SMatthew G. Knepley   /* Handle boundary values */
55073e9753d6SMatthew G. Knepley   /* Loop over domain faces */
55083e9753d6SMatthew G. Knepley   /*   Read out field, centroid, normal, volume for each side of face */
55093e9753d6SMatthew G. Knepley   /* Riemann solve over faces */
55103e9753d6SMatthew G. Knepley   /* Loop over domain faces */
55113e9753d6SMatthew G. Knepley   /*   Accumulate fluxes to cells */
55123e9753d6SMatthew G. Knepley   /* TODO Change printFEM to printDisc here */
55133e9753d6SMatthew G. Knepley   if (mesh->printFEM) {
55143e9753d6SMatthew G. Knepley     Vec          locFbc;
55153e9753d6SMatthew G. Knepley     PetscInt     pStart, pEnd, p, maxDof;
55163e9753d6SMatthew G. Knepley     PetscScalar *zeroes;
55173e9753d6SMatthew G. Knepley 
55189566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(locF, &locFbc));
55199566063dSJacob Faibussowitsch     PetscCall(VecCopy(locF, locFbc));
55209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
55219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetMaxDof(section, &maxDof));
55229566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(maxDof, &zeroes));
552348a46eb9SPierre Jolivet     for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES));
55249566063dSJacob Faibussowitsch     PetscCall(PetscFree(zeroes));
55259566063dSJacob Faibussowitsch     PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc));
55269566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&locFbc));
55273e9753d6SMatthew G. Knepley   }
55283cc88e6aSStefano Zampini end:
55299566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
55303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55313e9753d6SMatthew G. Knepley }
55323e9753d6SMatthew G. Knepley 
5533754e4fbaSMatthew G. Knepley /*@
5534754e4fbaSMatthew G. Knepley   DMPlexComputeResidualHybridByKey - Compute the local residual over hybrid cells for terms matching the input key
55356528b96dSMatthew G. Knepley 
5536754e4fbaSMatthew G. Knepley   Collective
55376528b96dSMatthew G. Knepley 
5538754e4fbaSMatthew G. Knepley   Input Parameters:
5539754e4fbaSMatthew G. Knepley + dm     - The output `DM`
5540754e4fbaSMatthew G. Knepley . key    - The `PetscFormKey` array (left cell, right cell, cohesive cell) indicating what should be integrated
5541754e4fbaSMatthew G. Knepley . cellIS - The `IS` give a set of cells to integrate over
5542754e4fbaSMatthew G. Knepley . time   - The time, or `PETSC_MIN_REAL` to include implicit terms in a time-independent problems
5543754e4fbaSMatthew G. Knepley . locX   - The local solution
5544754e4fbaSMatthew G. Knepley . locX_t - The time derivative of the local solution, or `NULL` for time-independent problems
5545754e4fbaSMatthew G. Knepley . t      - The time
5546*2a8381b2SBarry Smith - ctx    - An optional application context, passed to the pointwise functions
55476528b96dSMatthew G. Knepley 
5548754e4fbaSMatthew G. Knepley   Output Parameter:
5549754e4fbaSMatthew G. Knepley . locF - The local residual
5550754e4fbaSMatthew G. Knepley 
5551754e4fbaSMatthew G. Knepley   Level: developer
5552754e4fbaSMatthew G. Knepley 
5553754e4fbaSMatthew G. Knepley .seealso: `DMPlexComputeResidualByKey()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
5554754e4fbaSMatthew G. Knepley @*/
DMPlexComputeResidualHybridByKey(DM dm,PetscFormKey key[],IS cellIS,PetscReal time,Vec locX,Vec locX_t,PetscReal t,Vec locF,PetscCtx ctx)5555*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeResidualHybridByKey(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, PetscCtx ctx)
5556d71ae5a4SJacob Faibussowitsch {
55573e9753d6SMatthew G. Knepley   DM_Plex        *mesh       = (DM_Plex *)dm->data;
55583e9753d6SMatthew G. Knepley   const char     *name       = "Hybrid Residual";
555904c51a94SMatthew G. Knepley   DM              dmAux[3]   = {NULL, NULL, NULL};
55603e9753d6SMatthew G. Knepley   DMLabel         ghostLabel = NULL;
55616528b96dSMatthew G. Knepley   PetscDS         ds         = NULL;
556207218a29SMatthew G. Knepley   PetscDS         dsIn       = NULL;
55636528b96dSMatthew G. Knepley   PetscDS         dsAux[3]   = {NULL, NULL, NULL};
556404c51a94SMatthew G. Knepley   Vec             locA[3]    = {NULL, NULL, NULL};
556507218a29SMatthew G. Knepley   DM              dmScale[3] = {NULL, NULL, NULL};
556607218a29SMatthew G. Knepley   PetscDS         dsScale[3] = {NULL, NULL, NULL};
556707218a29SMatthew G. Knepley   Vec             locS[3]    = {NULL, NULL, NULL};
55683e9753d6SMatthew G. Knepley   PetscSection    section    = NULL;
55693e9753d6SMatthew G. Knepley   DMField         coordField = NULL;
557007218a29SMatthew G. Knepley   PetscScalar    *a[3]       = {NULL, NULL, NULL};
557107218a29SMatthew G. Knepley   PetscScalar    *s[3]       = {NULL, NULL, NULL};
5572b2ab40e6SMatthew G. Knepley   PetscScalar    *u          = NULL, *u_t;
557307218a29SMatthew G. Knepley   PetscScalar    *elemVecNeg, *elemVecPos, *elemVecCoh;
5574989fa639SBrad Aagaard   IS              chunkISF, chunkISN;
55753e9753d6SMatthew G. Knepley   const PetscInt *cells;
5576989fa639SBrad Aagaard   PetscInt       *faces, *neighbors;
55773e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
55783e2b0218SMatthew G. Knepley   PetscInt        Nf, f, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk;
55791690c2aeSBarry Smith   PetscInt        maxDegree   = PETSC_INT_MAX;
5580989fa639SBrad Aagaard   PetscQuadrature affineQuadF = NULL, *quadsF = NULL;
5581989fa639SBrad Aagaard   PetscFEGeom    *affineGeomF = NULL, **geomsF = NULL;
5582989fa639SBrad Aagaard   PetscQuadrature affineQuadN = NULL, *quadsN = NULL;
5583989fa639SBrad Aagaard   PetscFEGeom    *affineGeomN = NULL, **geomsN = NULL;
55843e9753d6SMatthew G. Knepley 
55853e9753d6SMatthew G. Knepley   PetscFunctionBegin;
55863cc88e6aSStefano Zampini   PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0));
55873cc88e6aSStefano Zampini   if (!cellIS) goto end;
5588437e83fbSMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
5589437e83fbSMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
55903cc88e6aSStefano Zampini   if (cStart >= cEnd) goto end;
55915fedec97SMatthew G. Knepley   if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
55925fedec97SMatthew G. Knepley     const char *name;
55939566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name));
559463a3b9bcSJacob 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);
55955fedec97SMatthew G. Knepley   }
55963e9753d6SMatthew G. Knepley   /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */
55973e9753d6SMatthew G. Knepley   /* FEM */
55983e9753d6SMatthew G. Knepley   /* 1: Get sizes from dm and dmAux */
5599b98a7184SJames Wright   PetscCall(DMGetLocalSection(dm, &section));
56009566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
560107218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn));
56029566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
56039566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
560407218a29SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn));
56059566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]));
560604c51a94SMatthew G. Knepley   if (locA[2]) {
56071059d808SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
56081059d808SMatthew G. Knepley 
56099566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA[2], &dmAux[2]));
561007218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL));
56119566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]));
56126528b96dSMatthew G. Knepley     {
56136528b96dSMatthew G. Knepley       const PetscInt *cone;
56146528b96dSMatthew G. Knepley       PetscInt        c;
56156528b96dSMatthew G. Knepley 
56161059d808SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
56176528b96dSMatthew G. Knepley       for (c = 0; c < 2; ++c) {
56186528b96dSMatthew G. Knepley         const PetscInt *support;
56196528b96dSMatthew G. Knepley         PetscInt        ssize, s;
56206528b96dSMatthew G. Knepley 
56219566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
56229566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
56231059d808SMatthew 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);
56241059d808SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
56251059d808SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
56261059d808SMatthew 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);
56279566063dSJacob Faibussowitsch         PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]));
5628c75bfeddSPierre 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);
56299566063dSJacob Faibussowitsch         if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c]));
5630ad540459SPierre Jolivet         else dmAux[c] = dmAux[2];
563107218a29SMatthew G. Knepley         PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL));
56329566063dSJacob Faibussowitsch         PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]));
56336528b96dSMatthew G. Knepley       }
56346528b96dSMatthew G. Knepley     }
56353e9753d6SMatthew G. Knepley   }
563607218a29SMatthew G. Knepley   /* Handle mass matrix scaling
563707218a29SMatthew G. Knepley        The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */
563807218a29SMatthew G. Knepley   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2]));
563907218a29SMatthew G. Knepley   if (locS[2]) {
56403e2b0218SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
564107218a29SMatthew G. Knepley     PetscInt       Nb, Nbs;
564207218a29SMatthew G. Knepley 
564307218a29SMatthew G. Knepley     PetscCall(VecGetDM(locS[2], &dmScale[2]));
56443e2b0218SMatthew G. Knepley     PetscCall(DMGetCellDS(dmScale[2], cellStart, &dsScale[2], NULL));
56453e2b0218SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2]));
564607218a29SMatthew G. Knepley     // BRAD: This is not set correctly
564707218a29SMatthew G. Knepley     key[2].field = 2;
564807218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb));
564907218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs));
565007218a29SMatthew 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);
56513e2b0218SMatthew G. Knepley     {
56523e2b0218SMatthew G. Knepley       const PetscInt *cone;
56533e2b0218SMatthew G. Knepley       PetscInt        c;
56543e2b0218SMatthew G. Knepley 
56553e2b0218SMatthew G. Knepley       locS[1] = locS[0] = locS[2];
56563e2b0218SMatthew G. Knepley       dmScale[1] = dmScale[0] = dmScale[2];
56573e2b0218SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
56583e2b0218SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
56593e2b0218SMatthew G. Knepley         const PetscInt *support;
56603e2b0218SMatthew G. Knepley         PetscInt        ssize, s;
56613e2b0218SMatthew G. Knepley 
56623e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
56633e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
56643e2b0218SMatthew 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);
56653e2b0218SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
56663e2b0218SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
56673e2b0218SMatthew 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);
56683e2b0218SMatthew G. Knepley         PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL));
56693e2b0218SMatthew G. Knepley         PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c]));
56703e2b0218SMatthew G. Knepley       }
56713e2b0218SMatthew G. Knepley     }
567207218a29SMatthew G. Knepley   }
56733e9753d6SMatthew G. Knepley   /* 2: Setup geometric data */
56749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
56759566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
56763e9753d6SMatthew G. Knepley   if (maxDegree > 1) {
5677989fa639SBrad Aagaard     PetscCall(PetscCalloc4(Nf, &quadsF, Nf, &geomsF, Nf, &quadsN, Nf, &geomsN));
56783e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
56793e9753d6SMatthew G. Knepley       PetscFE   fe;
5680989fa639SBrad Aagaard       PetscBool isCohesiveField;
56813e9753d6SMatthew G. Knepley 
56829566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
56833e9753d6SMatthew G. Knepley       if (fe) {
5684989fa639SBrad Aagaard         PetscCall(PetscFEGetQuadrature(fe, &quadsF[f]));
5685989fa639SBrad Aagaard         PetscCall(PetscObjectReference((PetscObject)quadsF[f]));
5686989fa639SBrad Aagaard       }
5687989fa639SBrad Aagaard       PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *)&fe));
5688989fa639SBrad Aagaard       PetscCall(PetscDSGetCohesive(dsIn, f, &isCohesiveField));
5689989fa639SBrad Aagaard       if (fe) {
5690989fa639SBrad Aagaard         if (isCohesiveField) {
5691989fa639SBrad Aagaard           for (PetscInt g = 0; g < Nf; ++g) {
5692989fa639SBrad Aagaard             PetscCall(PetscDSGetDiscretization(dsIn, g, (PetscObject *)&fe));
5693989fa639SBrad Aagaard             PetscCall(PetscDSGetCohesive(dsIn, g, &isCohesiveField));
5694989fa639SBrad Aagaard             if (!isCohesiveField) break;
5695989fa639SBrad Aagaard           }
5696989fa639SBrad Aagaard         }
5697989fa639SBrad Aagaard         PetscCall(PetscFEGetQuadrature(fe, &quadsN[f]));
5698989fa639SBrad Aagaard         PetscCall(PetscObjectReference((PetscObject)quadsN[f]));
56993e9753d6SMatthew G. Knepley       }
57003e9753d6SMatthew G. Knepley     }
57013e9753d6SMatthew G. Knepley   }
57023e9753d6SMatthew G. Knepley   /* Loop over chunks */
57033e9753d6SMatthew G. Knepley   cellChunkSize = numCells;
57043e9753d6SMatthew G. Knepley   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
5705989fa639SBrad Aagaard   PetscCall(PetscCalloc2(2 * cellChunkSize, &faces, 2 * cellChunkSize, &neighbors));
5706989fa639SBrad Aagaard   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkISF));
5707989fa639SBrad Aagaard   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, neighbors, PETSC_USE_POINTER, &chunkISN));
57083e9753d6SMatthew G. Knepley   /* Extract field coefficients */
57093e9753d6SMatthew G. Knepley   /* NOTE This needs the end cap faces to have identical orientations */
571007218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
571107218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
57123e2b0218SMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s));
571307218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecNeg));
571407218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecPos));
571507218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVecCoh));
57163e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
57173e9753d6SMatthew G. Knepley     PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
57183e9753d6SMatthew G. Knepley 
571907218a29SMatthew G. Knepley     PetscCall(PetscArrayzero(elemVecNeg, cellChunkSize * totDim));
572007218a29SMatthew G. Knepley     PetscCall(PetscArrayzero(elemVecPos, cellChunkSize * totDim));
572107218a29SMatthew G. Knepley     PetscCall(PetscArrayzero(elemVecCoh, cellChunkSize * totDim));
5722989fa639SBrad Aagaard     /* Get faces and neighbors */
57233e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
57243e9753d6SMatthew G. Knepley       const PetscInt  cell = cells ? cells[c] : c;
5725989fa639SBrad Aagaard       const PetscInt *cone, *support;
57269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, cell, &cone));
572707218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 0] = cone[0];
572807218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 1] = cone[1];
5729989fa639SBrad Aagaard       PetscCall(DMPlexGetSupport(dm, cone[0], &support));
5730989fa639SBrad Aagaard       neighbors[(c - cS) * 2 + 0] = support[0] == cell ? support[1] : support[0];
5731989fa639SBrad Aagaard       PetscCall(DMPlexGetSupport(dm, cone[1], &support));
5732989fa639SBrad Aagaard       neighbors[(c - cS) * 2 + 1] = support[0] == cell ? support[1] : support[0];
57333e9753d6SMatthew G. Knepley     }
5734989fa639SBrad Aagaard     PetscCall(ISGeneralSetIndices(chunkISF, 2 * cellChunkSize, faces, PETSC_USE_POINTER));
5735989fa639SBrad Aagaard     PetscCall(ISGeneralSetIndices(chunkISN, 2 * cellChunkSize, neighbors, PETSC_USE_POINTER));
57363e9753d6SMatthew G. Knepley     /* Get geometric data */
57373e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
5738989fa639SBrad Aagaard       if (!affineQuadF) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkISF, &affineQuadF));
5739989fa639SBrad Aagaard       if (affineQuadF) PetscCall(DMSNESGetFEGeom(coordField, chunkISF, affineQuadF, PETSC_FEGEOM_COHESIVE, &affineGeomF));
5740989fa639SBrad Aagaard       if (!affineQuadN) {
5741989fa639SBrad Aagaard         PetscInt dim;
5742989fa639SBrad Aagaard         PetscCall(PetscQuadratureGetData(affineQuadF, &dim, NULL, NULL, NULL, NULL));
5743989fa639SBrad Aagaard         PetscCall(DMFieldCreateDefaultFaceQuadrature(coordField, chunkISN, &affineQuadN));
5744989fa639SBrad Aagaard         PetscCall(PetscQuadratureSetData(affineQuadN, dim + 1, PETSC_DECIDE, PETSC_DECIDE, NULL, NULL));
5745989fa639SBrad Aagaard       }
5746989fa639SBrad Aagaard       if (affineQuadN) PetscCall(DMSNESGetFEGeom(coordField, chunkISN, affineQuadN, PETSC_FEGEOM_BASIC, &affineGeomN));
57473e9753d6SMatthew G. Knepley     } else {
57483e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
5749989fa639SBrad Aagaard         if (quadsF[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkISF, quadsF[f], PETSC_FEGEOM_COHESIVE, &geomsF[f]));
5750989fa639SBrad Aagaard         if (quadsN[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkISN, quadsN[f], PETSC_FEGEOM_BASIC, &geomsN[f]));
57513e9753d6SMatthew G. Knepley       }
57523e9753d6SMatthew G. Knepley     }
57533e9753d6SMatthew G. Knepley     /* Loop over fields */
57543e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
57553e9753d6SMatthew G. Knepley       PetscFE         fe;
5756989fa639SBrad Aagaard       PetscFEGeom    *geomF      = affineGeomF ? affineGeomF : geomsF[f];
5757989fa639SBrad Aagaard       PetscFEGeom    *chunkGeomF = NULL, *remGeomF = NULL;
5758989fa639SBrad Aagaard       PetscFEGeom    *geomN      = affineGeomN ? affineGeomN : geomsN[f];
5759989fa639SBrad Aagaard       PetscFEGeom    *chunkGeomN = NULL, *remGeomN = NULL;
5760989fa639SBrad Aagaard       PetscQuadrature quadF = affineQuadF ? affineQuadF : quadsF[f];
57613e9753d6SMatthew G. Knepley       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
57625fedec97SMatthew G. Knepley       PetscBool       isCohesiveField;
57633e9753d6SMatthew G. Knepley 
57649566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
57653e9753d6SMatthew G. Knepley       if (!fe) continue;
57669566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
5767989fa639SBrad Aagaard       PetscCall(PetscQuadratureGetData(quadF, NULL, NULL, &Nq, NULL, NULL));
57689566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
57693e9753d6SMatthew G. Knepley       blockSize = Nb;
57703e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
57719566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
57723e9753d6SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
57733e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
57743e9753d6SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
57753e9753d6SMatthew G. Knepley       offset    = numCells - Nr;
5776989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomF, 0, offset * 2, &chunkGeomF));
5777989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomF, offset * 2, numCells * 2, &remGeomF));
5778989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomN, 0, offset * 2, &chunkGeomN));
5779989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomN, offset * 2, numCells * 2, &remGeomN));
57809566063dSJacob Faibussowitsch       PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
5781989fa639SBrad Aagaard       // TODO Do I need to set isCohesive on the chunks?
57826528b96dSMatthew G. Knepley       key[0].field = f;
57836528b96dSMatthew G. Knepley       key[1].field = f;
57845fedec97SMatthew G. Knepley       key[2].field = f;
5785989fa639SBrad Aagaard       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[0], a[0], t, elemVecNeg));
5786989fa639SBrad Aagaard       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[0], 0, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], PetscSafePointerPlusOffset(a[0], offset * totDimAux[0]), t, &elemVecNeg[offset * totDim]));
5787989fa639SBrad Aagaard       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[1], a[1], t, elemVecPos));
5788989fa639SBrad Aagaard       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[1], 1, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], PetscSafePointerPlusOffset(a[1], offset * totDimAux[1]), t, &elemVecPos[offset * totDim]));
5789989fa639SBrad Aagaard       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[2], a[2], t, elemVecCoh));
5790989fa639SBrad Aagaard       PetscCall(PetscFEIntegrateHybridResidual(ds, dsIn, key[2], 2, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], PetscSafePointerPlusOffset(a[2], offset * totDimAux[2]), t, &elemVecCoh[offset * totDim]));
5791989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomF, offset, numCells, &remGeomF));
5792989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomF, 0, offset, &chunkGeomF));
5793989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomN, offset, numCells, &remGeomN));
5794989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomN, 0, offset, &chunkGeomN));
57953e9753d6SMatthew G. Knepley     }
57963e9753d6SMatthew G. Knepley     /* Add elemVec to locX */
57973e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
57983e9753d6SMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
57993e9753d6SMatthew G. Knepley       const PetscInt cind = c - cStart;
580007218a29SMatthew G. Knepley       PetscInt       i;
58013e9753d6SMatthew G. Knepley 
580207218a29SMatthew G. Knepley       /* Scale element values */
580307218a29SMatthew G. Knepley       if (locS[0]) {
58043e2b0218SMatthew G. Knepley         PetscInt  Nb, off = cind * totDim, soff = cind * totDimScale[0];
580507218a29SMatthew G. Knepley         PetscBool cohesive;
580607218a29SMatthew G. Knepley 
580707218a29SMatthew G. Knepley         for (f = 0; f < Nf; ++f) {
580807218a29SMatthew G. Knepley           PetscCall(PetscDSGetFieldSize(ds, f, &Nb));
580907218a29SMatthew G. Knepley           PetscCall(PetscDSGetCohesive(ds, f, &cohesive));
581007218a29SMatthew G. Knepley           if (f == key[2].field) {
581107218a29SMatthew G. Knepley             PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields");
581207218a29SMatthew G. Knepley             // No cohesive scaling field is currently input
581307218a29SMatthew 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];
581407218a29SMatthew G. Knepley             off += Nb;
581507218a29SMatthew G. Knepley           } else {
581607218a29SMatthew G. Knepley             const PetscInt N = cohesive ? Nb : Nb * 2;
581707218a29SMatthew G. Knepley 
581807218a29SMatthew G. Knepley             for (i = 0; i < N; ++i) elemVecCoh[off + i] += elemVecNeg[off + i] + elemVecPos[off + i];
581907218a29SMatthew G. Knepley             off += N;
582007218a29SMatthew G. Knepley           }
582107218a29SMatthew G. Knepley         }
582207218a29SMatthew G. Knepley       } else {
582307218a29SMatthew G. Knepley         for (i = cind * totDim; i < (cind + 1) * totDim; ++i) elemVecCoh[i] += elemVecNeg[i] + elemVecPos[i];
582407218a29SMatthew G. Knepley       }
582507218a29SMatthew G. Knepley       if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVecCoh[cind * totDim]));
58263e9753d6SMatthew G. Knepley       if (ghostLabel) {
58273e9753d6SMatthew G. Knepley         PetscInt ghostVal;
58283e9753d6SMatthew G. Knepley 
58299566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal));
58303e9753d6SMatthew G. Knepley         if (ghostVal > 0) continue;
58313e9753d6SMatthew G. Knepley       }
583207218a29SMatthew G. Knepley       PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVecCoh[cind * totDim], ADD_ALL_VALUES));
58333e9753d6SMatthew G. Knepley     }
58343e9753d6SMatthew G. Knepley   }
58359566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
583607218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
58373e2b0218SMatthew G. Knepley   PetscCall(DMPlexRestoreHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s));
583807218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecNeg));
583907218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecPos));
584007218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVecCoh));
5841989fa639SBrad Aagaard   PetscCall(PetscFree2(faces, neighbors));
5842989fa639SBrad Aagaard   PetscCall(ISDestroy(&chunkISF));
5843989fa639SBrad Aagaard   PetscCall(ISDestroy(&chunkISN));
58449566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
58453e9753d6SMatthew G. Knepley   if (maxDegree <= 1) {
5846989fa639SBrad Aagaard     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuadF, PETSC_FALSE, &affineGeomF));
5847989fa639SBrad Aagaard     PetscCall(PetscQuadratureDestroy(&affineQuadF));
5848989fa639SBrad Aagaard     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuadN, PETSC_FALSE, &affineGeomN));
5849989fa639SBrad Aagaard     PetscCall(PetscQuadratureDestroy(&affineQuadN));
58503e9753d6SMatthew G. Knepley   } else {
58513e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
5852989fa639SBrad Aagaard       if (geomsF) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quadsF[f], PETSC_FALSE, &geomsF[f]));
5853989fa639SBrad Aagaard       if (quadsF) PetscCall(PetscQuadratureDestroy(&quadsF[f]));
5854989fa639SBrad Aagaard       if (geomsN) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quadsN[f], PETSC_FALSE, &geomsN[f]));
5855989fa639SBrad Aagaard       if (quadsN) PetscCall(PetscQuadratureDestroy(&quadsN[f]));
58563e9753d6SMatthew G. Knepley     }
5857989fa639SBrad Aagaard     PetscCall(PetscFree4(quadsF, geomsF, quadsN, geomsN));
58583e9753d6SMatthew G. Knepley   }
585985cc2951SMatthew G. Knepley   if (mesh->printFEM) {
586085cc2951SMatthew G. Knepley     Vec          locFbc;
586185cc2951SMatthew G. Knepley     PetscInt     pStart, pEnd, p, maxDof;
586285cc2951SMatthew G. Knepley     PetscScalar *zeroes;
586385cc2951SMatthew G. Knepley 
586485cc2951SMatthew G. Knepley     PetscCall(VecDuplicate(locF, &locFbc));
586585cc2951SMatthew G. Knepley     PetscCall(VecCopy(locF, locFbc));
586685cc2951SMatthew G. Knepley     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
586785cc2951SMatthew G. Knepley     PetscCall(PetscSectionGetMaxDof(section, &maxDof));
586885cc2951SMatthew G. Knepley     PetscCall(PetscCalloc1(maxDof, &zeroes));
586985cc2951SMatthew G. Knepley     for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES));
587085cc2951SMatthew G. Knepley     PetscCall(PetscFree(zeroes));
587185cc2951SMatthew G. Knepley     PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc));
587285cc2951SMatthew G. Knepley     PetscCall(VecDestroy(&locFbc));
587385cc2951SMatthew G. Knepley   }
58743cc88e6aSStefano Zampini end:
58759566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0));
58763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58773e9753d6SMatthew G. Knepley }
58783e9753d6SMatthew G. Knepley 
5879997bf629SMatthew G. Knepley /*@
5880997bf629SMatthew G. Knepley   DMPlexComputeBdJacobianSingleByLabel - Compute the local boundary Jacobian for terms matching the input label
5881997bf629SMatthew G. Knepley 
5882997bf629SMatthew G. Knepley   Not collective
5883997bf629SMatthew G. Knepley 
5884997bf629SMatthew G. Knepley   Input Parameters:
5885997bf629SMatthew G. Knepley + dm         - The output `DM`
5886997bf629SMatthew G. Knepley . wf         - The `PetscWeakForm` holding forms on this boundary
5887997bf629SMatthew G. Knepley . label      - The `DMLabel` indicating what faces should be integrated over
5888997bf629SMatthew G. Knepley . numValues  - The number of label values
5889997bf629SMatthew G. Knepley . values     - The array of label values
5890997bf629SMatthew G. Knepley . fieldI     - The test field for these integrals
5891997bf629SMatthew G. Knepley . facetIS    - The `IS` giving the set of possible faces to integrate over (intersected with the label)
5892997bf629SMatthew G. Knepley . locX       - The local solution
5893997bf629SMatthew G. Knepley . locX_t     - The time derivative of the local solution, or `NULL` for time-independent problems
5894997bf629SMatthew G. Knepley . t          - The time
5895997bf629SMatthew G. Knepley . coordField - The `DMField` object with coordinates for these faces
5896997bf629SMatthew G. Knepley - X_tShift   - The multiplier for dF/dxdot
5897997bf629SMatthew G. Knepley 
5898997bf629SMatthew G. Knepley   Output Parameters:
5899997bf629SMatthew G. Knepley + Jac  - The local Jacobian
5900997bf629SMatthew G. Knepley - JacP - The local Jacobian preconditioner
5901997bf629SMatthew G. Knepley 
5902997bf629SMatthew G. Knepley   Level: developer
5903997bf629SMatthew G. Knepley 
5904997bf629SMatthew G. Knepley .seealso: `DMPlexComputeBdJacobianSingle()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
5905997bf629SMatthew G. Knepley @*/
DMPlexComputeBdJacobianSingleByLabel(DM dm,PetscWeakForm wf,DMLabel label,PetscInt numValues,const PetscInt values[],PetscInt fieldI,IS facetIS,Vec locX,Vec locX_t,PetscReal t,DMField coordField,PetscReal X_tShift,Mat Jac,Mat JacP)5906997bf629SMatthew G. Knepley PetscErrorCode DMPlexComputeBdJacobianSingleByLabel(DM dm, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt fieldI, IS facetIS, Vec locX, Vec locX_t, PetscReal t, DMField coordField, PetscReal X_tShift, Mat Jac, Mat JacP)
5907d71ae5a4SJacob Faibussowitsch {
59083e9753d6SMatthew G. Knepley   DM_Plex        *mesh = (DM_Plex *)dm->data;
59093e9753d6SMatthew G. Knepley   DM              plex = NULL, plexA = NULL, tdm;
59103e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
5911be62b2b4SMatthew G. Knepley   PetscDS         ds, dsAux           = NULL;
59123e9753d6SMatthew G. Knepley   PetscSection    section, sectionAux = NULL;
5913e432b41dSStefano Zampini   PetscSection    globalSection;
59143e9753d6SMatthew G. Knepley   Vec             locA = NULL, tv;
5915be62b2b4SMatthew G. Knepley   PetscScalar    *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL;
59163e9753d6SMatthew G. Knepley   PetscInt        v;
59173e9753d6SMatthew G. Knepley   PetscInt        Nf, totDim, totDimAux = 0;
5918be62b2b4SMatthew G. Knepley   PetscBool       hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, transform;
59193e9753d6SMatthew G. Knepley 
59203e9753d6SMatthew G. Knepley   PetscFunctionBegin;
59219566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
59229566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
59239566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
59249566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
5925be62b2b4SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
5926be62b2b4SMatthew G. Knepley   PetscCall(PetscDSGetNumFields(ds, &Nf));
5927be62b2b4SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
592821a4fad8SMatthew G. Knepley   PetscCall(PetscWeakFormHasBdJacobian(wf, &hasJac));
592921a4fad8SMatthew G. Knepley   PetscCall(PetscWeakFormHasBdJacobianPreconditioner(wf, &hasPrec));
593021a4fad8SMatthew G. Knepley   if (!hasJac && !hasPrec) PetscFunctionReturn(PETSC_SUCCESS);
593121a4fad8SMatthew G. Knepley   PetscCall(DMConvert(dm, DMPLEX, &plex));
59329566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA));
59333e9753d6SMatthew G. Knepley   if (locA) {
59343e9753d6SMatthew G. Knepley     DM dmAux;
59353e9753d6SMatthew G. Knepley 
59369566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA, &dmAux));
59379566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
59389566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexA));
5939be62b2b4SMatthew G. Knepley     PetscCall(DMGetDS(plexA, &dsAux));
5940be62b2b4SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
59419566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexA, &sectionAux));
59423e9753d6SMatthew G. Knepley   }
59433e9753d6SMatthew G. Knepley 
59449566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
59453e9753d6SMatthew G. Knepley   for (v = 0; v < numValues; ++v) {
59463e9753d6SMatthew G. Knepley     PetscFEGeom    *fgeom;
59473e9753d6SMatthew G. Knepley     PetscInt        maxDegree;
59483e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
59493e9753d6SMatthew G. Knepley     IS              pointIS;
59503e9753d6SMatthew G. Knepley     const PetscInt *points;
595106ad1575SMatthew G. Knepley     PetscFormKey    key;
59523e9753d6SMatthew G. Knepley     PetscInt        numFaces, face, Nq;
59533e9753d6SMatthew G. Knepley 
595445480ffeSMatthew G. Knepley     key.label = label;
595545480ffeSMatthew G. Knepley     key.value = values[v];
595606ad1575SMatthew G. Knepley     key.part  = 0;
59579566063dSJacob Faibussowitsch     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
59583e9753d6SMatthew G. Knepley     if (!pointIS) continue; /* No points with that id on this process */
59593e9753d6SMatthew G. Knepley     {
59603e9753d6SMatthew G. Knepley       IS isectIS;
59613e9753d6SMatthew G. Knepley 
59623e9753d6SMatthew G. Knepley       /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */
59639566063dSJacob Faibussowitsch       PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS));
59649566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&pointIS));
59653e9753d6SMatthew G. Knepley       pointIS = isectIS;
59663e9753d6SMatthew G. Knepley     }
59679566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(pointIS, &numFaces));
59689566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(pointIS, &points));
596932603206SJames Wright     PetscCall(PetscMalloc5(numFaces * totDim, &u, (locX_t ? (size_t)numFaces * totDim : 0), &u_t, (hasJac ? (size_t)numFaces * totDim * totDim : 0), &elemMat, (hasPrec ? (size_t)numFaces * totDim * totDim : 0), &elemMatP, (locA ? (size_t)numFaces * totDimAux : 0), &a));
59709566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree));
597148a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom));
59723e9753d6SMatthew G. Knepley     if (!qGeom) {
59733e9753d6SMatthew G. Knepley       PetscFE fe;
59743e9753d6SMatthew G. Knepley 
5975be62b2b4SMatthew G. Knepley       PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe));
59769566063dSJacob Faibussowitsch       PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom));
59779566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
59783e9753d6SMatthew G. Knepley     }
59799566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
5980ac9d17c7SMatthew G. Knepley     PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_FEGEOM_BOUNDARY, &fgeom));
59813e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
5982f15274beSMatthew Knepley       const PetscInt point = points[face], *support;
59833e9753d6SMatthew G. Knepley       PetscScalar   *x     = NULL;
5984f15274beSMatthew Knepley       PetscInt       i;
59853e9753d6SMatthew G. Knepley 
59869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(dm, point, &support));
59879566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x));
59883e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i];
59899566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x));
59903e9753d6SMatthew G. Knepley       if (locX_t) {
59919566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x));
59923e9753d6SMatthew G. Knepley         for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i];
59939566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x));
59943e9753d6SMatthew G. Knepley       }
59953e9753d6SMatthew G. Knepley       if (locA) {
59963e9753d6SMatthew G. Knepley         PetscInt subp;
59979566063dSJacob Faibussowitsch         PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp));
59989566063dSJacob Faibussowitsch         PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x));
59993e9753d6SMatthew G. Knepley         for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i];
60009566063dSJacob Faibussowitsch         PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x));
60013e9753d6SMatthew G. Knepley       }
60023e9753d6SMatthew G. Knepley     }
600321a4fad8SMatthew G. Knepley     if (elemMat) PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim));
600421a4fad8SMatthew G. Knepley     if (elemMatP) PetscCall(PetscArrayzero(elemMatP, numFaces * totDim * totDim));
60053e9753d6SMatthew G. Knepley     {
60063e9753d6SMatthew G. Knepley       PetscFE  fe;
60073e9753d6SMatthew G. Knepley       PetscInt Nb;
60083e9753d6SMatthew G. Knepley       /* Conforming batches */
60093e9753d6SMatthew G. Knepley       PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
60103e9753d6SMatthew G. Knepley       /* Remainder */
60113e9753d6SMatthew G. Knepley       PetscFEGeom *chunkGeom = NULL;
60123e9753d6SMatthew G. Knepley       PetscInt     fieldJ, Nr, offset;
60133e9753d6SMatthew G. Knepley 
6014be62b2b4SMatthew G. Knepley       PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&fe));
60159566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(fe, &Nb));
60169566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
60173e9753d6SMatthew G. Knepley       blockSize = Nb;
60183e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
60199566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
60203e9753d6SMatthew G. Knepley       numChunks = numFaces / (numBatches * batchSize);
60213e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
60223e9753d6SMatthew G. Knepley       Nr        = numFaces % (numBatches * batchSize);
60233e9753d6SMatthew G. Knepley       offset    = numFaces - Nr;
60249566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom));
60253e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
602645480ffeSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
6027be62b2b4SMatthew G. Knepley         if (hasJac) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMat));
6028be62b2b4SMatthew G. Knepley         if (hasPrec) PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMatP));
60293e9753d6SMatthew G. Knepley       }
60309566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom));
60313e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
603245480ffeSMatthew G. Knepley         key.field = fieldI * Nf + fieldJ;
6033be62b2b4SMatthew G. Knepley         if (hasJac)
60348e3a54c0SPierre Jolivet           PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim]));
6035be62b2b4SMatthew G. Knepley         if (hasPrec)
60368e3a54c0SPierre Jolivet           PetscCall(PetscFEIntegrateBdJacobian(ds, wf, PETSCFE_JACOBIAN_PRE, key, Nr, chunkGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * totDim]));
60373e9753d6SMatthew G. Knepley       }
60389566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom));
60393e9753d6SMatthew G. Knepley     }
60403e9753d6SMatthew G. Knepley     for (face = 0; face < numFaces; ++face) {
60413e9753d6SMatthew G. Knepley       const PetscInt point = points[face], *support;
60423e9753d6SMatthew G. Knepley 
60433e9753d6SMatthew G. Knepley       /* Transform to global basis before insertion in Jacobian */
60449566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSupport(plex, point, &support));
604521a4fad8SMatthew G. Knepley       if (hasJac && transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim]));
604621a4fad8SMatthew G. Knepley       if (hasPrec && transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMatP[face * totDim * totDim]));
6047be62b2b4SMatthew G. Knepley       if (hasPrec) {
6048be62b2b4SMatthew G. Knepley         if (hasJac) {
60499566063dSJacob Faibussowitsch           if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim]));
605021a4fad8SMatthew G. Knepley           PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, support[0], &elemMat[face * totDim * totDim], ADD_VALUES));
60513e9753d6SMatthew G. Knepley         }
6052be62b2b4SMatthew G. Knepley         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMatP[face * totDim * totDim]));
6053be62b2b4SMatthew G. Knepley         PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, support[0], &elemMatP[face * totDim * totDim], ADD_VALUES));
6054be62b2b4SMatthew G. Knepley       } else {
6055be62b2b4SMatthew G. Knepley         if (hasJac) {
6056be62b2b4SMatthew G. Knepley           if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim]));
605721a4fad8SMatthew G. Knepley           PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, support[0], &elemMat[face * totDim * totDim], ADD_VALUES));
6058be62b2b4SMatthew G. Knepley         }
6059be62b2b4SMatthew G. Knepley       }
6060be62b2b4SMatthew G. Knepley     }
60619566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom));
60629566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
60639566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(pointIS, &points));
60649566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&pointIS));
6065be62b2b4SMatthew G. Knepley     PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, a));
60663e9753d6SMatthew G. Knepley   }
60679566063dSJacob Faibussowitsch   if (plex) PetscCall(DMDestroy(&plex));
60689566063dSJacob Faibussowitsch   if (plexA) PetscCall(DMDestroy(&plexA));
60693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60703e9753d6SMatthew G. Knepley }
60713e9753d6SMatthew G. Knepley 
6072997bf629SMatthew G. Knepley /*@
6073997bf629SMatthew G. Knepley   DMPlexComputeBdJacobianSingle - Compute the local boundary Jacobian
6074997bf629SMatthew G. Knepley 
6075997bf629SMatthew G. Knepley   Not collective
6076997bf629SMatthew G. Knepley 
6077997bf629SMatthew G. Knepley   Input Parameters:
6078997bf629SMatthew G. Knepley + dm        - The output `DM`
6079997bf629SMatthew G. Knepley . wf        - The `PetscWeakForm` holding forms on this boundary
6080997bf629SMatthew G. Knepley . label     - The `DMLabel` indicating what faces should be integrated over
6081997bf629SMatthew G. Knepley . numValues - The number of label values
6082997bf629SMatthew G. Knepley . values    - The array of label values
6083997bf629SMatthew G. Knepley . fieldI    - The test field for these integrals
6084997bf629SMatthew G. Knepley . locX      - The local solution
6085997bf629SMatthew G. Knepley . locX_t    - The time derivative of the local solution, or `NULL` for time-independent problems
6086997bf629SMatthew G. Knepley . t         - The time
6087997bf629SMatthew G. Knepley - X_tShift  - The multiplier for dF/dxdot
6088997bf629SMatthew G. Knepley 
6089997bf629SMatthew G. Knepley   Output Parameters:
6090997bf629SMatthew G. Knepley + Jac  - The local Jacobian
6091997bf629SMatthew G. Knepley - JacP - The local Jacobian preconditioner
6092997bf629SMatthew G. Knepley 
6093997bf629SMatthew G. Knepley   Level: developer
6094997bf629SMatthew G. Knepley 
6095997bf629SMatthew G. Knepley .seealso: `DMPlexComputeBdJacobianSingleByLabel()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
6096997bf629SMatthew G. Knepley @*/
DMPlexComputeBdJacobianSingle(DM dm,PetscWeakForm wf,DMLabel label,PetscInt numValues,const PetscInt values[],PetscInt fieldI,Vec locX,Vec locX_t,PetscReal t,PetscReal X_tShift,Mat Jac,Mat JacP)6097997bf629SMatthew G. Knepley PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt fieldI, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP)
6098d71ae5a4SJacob Faibussowitsch {
60993e9753d6SMatthew G. Knepley   DMField  coordField;
61003e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
61013e9753d6SMatthew G. Knepley   IS       facetIS;
61023e9753d6SMatthew G. Knepley   PetscInt dim;
61033e9753d6SMatthew G. Knepley 
61043e9753d6SMatthew G. Knepley   PetscFunctionBegin;
61059566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
61069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
61079566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
61089566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
6109997bf629SMatthew G. Knepley   PetscCall(DMPlexComputeBdJacobianSingleByLabel(dm, wf, label, numValues, values, fieldI, facetIS, locX, locX_t, t, coordField, X_tShift, Jac, JacP));
61109566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
61113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61123e9753d6SMatthew G. Knepley }
61133e9753d6SMatthew G. Knepley 
DMPlexComputeBdJacobian_Internal(DM dm,Vec locX,Vec locX_t,PetscReal t,PetscReal X_tShift,Mat Jac,Mat JacP,PetscCtx ctx)6114*2a8381b2SBarry Smith static PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, PetscCtx ctx)
6115d71ae5a4SJacob Faibussowitsch {
61163e9753d6SMatthew G. Knepley   PetscDS  prob;
61173e9753d6SMatthew G. Knepley   PetscInt dim, numBd, bd;
61183e9753d6SMatthew G. Knepley   DMLabel  depthLabel;
61193e9753d6SMatthew G. Knepley   DMField  coordField = NULL;
61203e9753d6SMatthew G. Knepley   IS       facetIS;
61213e9753d6SMatthew G. Knepley 
61223e9753d6SMatthew G. Knepley   PetscFunctionBegin;
61239566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dm, &prob));
61249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
61259566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
61269566063dSJacob Faibussowitsch   PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS));
61279566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumBoundary(prob, &numBd));
61289566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
61293e9753d6SMatthew G. Knepley   for (bd = 0; bd < numBd; ++bd) {
613045480ffeSMatthew G. Knepley     PetscWeakForm           wf;
61313e9753d6SMatthew G. Knepley     DMBoundaryConditionType type;
61323e9753d6SMatthew G. Knepley     DMLabel                 label;
61333e9753d6SMatthew G. Knepley     const PetscInt         *values;
61343e9753d6SMatthew G. Knepley     PetscInt                fieldI, numValues;
61353e9753d6SMatthew G. Knepley     PetscObject             obj;
61363e9753d6SMatthew G. Knepley     PetscClassId            id;
61373e9753d6SMatthew G. Knepley 
61389566063dSJacob Faibussowitsch     PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL));
61393d3e5d66SMatthew G. Knepley     if (type & DM_BC_ESSENTIAL) continue;
61409566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj));
61419566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId(obj, &id));
61423d3e5d66SMatthew G. Knepley     if (id != PETSCFE_CLASSID) continue;
6143997bf629SMatthew G. Knepley     PetscCall(DMPlexComputeBdJacobianSingleByLabel(dm, wf, label, numValues, values, fieldI, facetIS, locX, locX_t, t, coordField, X_tShift, Jac, JacP));
61443e9753d6SMatthew G. Knepley   }
61459566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&facetIS));
61463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
61473e9753d6SMatthew G. Knepley }
61483e9753d6SMatthew G. Knepley 
6149754e4fbaSMatthew G. Knepley /*@
6150754e4fbaSMatthew G. Knepley   DMPlexComputeJacobianByKey - Compute the local Jacobian for terms matching the input key
6151754e4fbaSMatthew G. Knepley 
6152754e4fbaSMatthew G. Knepley   Collective
6153754e4fbaSMatthew G. Knepley 
6154754e4fbaSMatthew G. Knepley   Input Parameters:
6155754e4fbaSMatthew G. Knepley + dm       - The output `DM`
6156754e4fbaSMatthew G. Knepley . key      - The `PetscFormKey` indicating what should be integrated
6157754e4fbaSMatthew G. Knepley . cellIS   - The `IS` give a set of cells to integrate over
6158754e4fbaSMatthew G. Knepley . t        - The time
6159754e4fbaSMatthew G. Knepley . X_tShift - The multiplier for the Jacobian with respect to $X_t$
6160754e4fbaSMatthew G. Knepley . locX     - The local solution
6161754e4fbaSMatthew G. Knepley . locX_t   - The time derivative of the local solution, or `NULL` for time-independent problems
6162*2a8381b2SBarry Smith - ctx      - An optional application context, passed to the pointwise functions
6163754e4fbaSMatthew G. Knepley 
6164754e4fbaSMatthew G. Knepley   Output Parameters:
6165754e4fbaSMatthew G. Knepley + Jac  - The local Jacobian
6166754e4fbaSMatthew G. Knepley - JacP - The local Jacobian preconditioner
6167754e4fbaSMatthew G. Knepley 
6168754e4fbaSMatthew G. Knepley   Level: developer
6169754e4fbaSMatthew G. Knepley 
6170754e4fbaSMatthew G. Knepley .seealso: `DMPlexComputeResidualByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
6171754e4fbaSMatthew G. Knepley @*/
DMPlexComputeJacobianByKey(DM dm,PetscFormKey key,IS cellIS,PetscReal t,PetscReal X_tShift,Vec locX,Vec locX_t,Mat Jac,Mat JacP,PetscCtx ctx)6172*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeJacobianByKey(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, PetscCtx ctx)
6173d71ae5a4SJacob Faibussowitsch {
61743e9753d6SMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
61753e9753d6SMatthew G. Knepley   const char     *name  = "Jacobian";
61769a2a23afSMatthew G. Knepley   DM              dmAux = NULL, plex, tdm;
61773e9753d6SMatthew G. Knepley   DMEnclosureType encAux;
61783e9753d6SMatthew G. Knepley   Vec             A, tv;
61793e9753d6SMatthew G. Knepley   DMField         coordField;
61803e9753d6SMatthew G. Knepley   PetscDS         prob, probAux = NULL;
6181e432b41dSStefano Zampini   PetscSection    section, globalSection, sectionAux;
61823e9753d6SMatthew G. Knepley   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
61833e9753d6SMatthew G. Knepley   const PetscInt *cells;
61843e9753d6SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ;
618528351e22SJed Brown   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
6186e04ae0b4SMatthew G. Knepley   PetscBool       hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform;
61873e9753d6SMatthew G. Knepley 
61883e9753d6SMatthew G. Knepley   PetscFunctionBegin;
6189af18b51aSmarkadams4   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
6190ae3cf2c1SStefano Zampini   PetscCall(DMGetLocalSection(dm, &section));
6191ae3cf2c1SStefano Zampini   PetscCall(DMGetGlobalSection(dm, &globalSection));
6192ae3cf2c1SStefano Zampini   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A));
6193ae3cf2c1SStefano Zampini   if (A) {
6194ae3cf2c1SStefano Zampini     PetscCall(VecGetDM(A, &dmAux));
6195ae3cf2c1SStefano Zampini     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
6196ae3cf2c1SStefano Zampini     PetscCall(DMConvert(dmAux, DMPLEX, &plex));
6197ae3cf2c1SStefano Zampini     PetscCall(DMGetLocalSection(plex, &sectionAux));
6198ae3cf2c1SStefano Zampini     PetscCall(DMGetDS(dmAux, &probAux));
6199ae3cf2c1SStefano Zampini     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
6200ae3cf2c1SStefano Zampini   }
6201ae3cf2c1SStefano Zampini   PetscCall(DMGetCoordinateField(dm, &coordField));
6202e04ae0b4SMatthew G. Knepley   if (!cellIS) goto end;
62039566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
6204437e83fbSMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
6205437e83fbSMatthew G. Knepley   if (cStart >= cEnd) goto end;
62069566063dSJacob Faibussowitsch   PetscCall(DMHasBasisTransform(dm, &transform));
62079566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm));
62089566063dSJacob Faibussowitsch   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
620907218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL));
62109566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
62119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
62129566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobian(prob, &hasJac));
62139566063dSJacob Faibussowitsch   PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec));
62143e9753d6SMatthew G. Knepley   /* user passed in the same matrix, avoid double contributions and
62153e9753d6SMatthew G. Knepley      only assemble the Jacobian */
62163e9753d6SMatthew G. Knepley   if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
62179566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
62183e9753d6SMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
6219754e4fbaSMatthew G. Knepley   PetscCall(PetscMalloc5(numCells * totDim, &u, (locX_t ? (size_t)numCells * totDim : 0), &u_t, (hasJac ? (size_t)numCells * totDim * totDim : 0), &elemMat, (hasPrec ? (size_t)numCells * totDim * totDim : 0), &elemMatP, (hasDyn ? (size_t)numCells * totDim * totDim : 0), &elemMatD));
62209566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
62213e9753d6SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
62223e9753d6SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
62233e9753d6SMatthew G. Knepley     const PetscInt cind = c - cStart;
62243e9753d6SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
62253e9753d6SMatthew G. Knepley     PetscInt       i;
62263e9753d6SMatthew G. Knepley 
6227754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dm, section, locX, cell, NULL, &x));
62283e9753d6SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
6229754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cell, NULL, &x));
6230754e4fbaSMatthew G. Knepley     if (locX_t) {
6231754e4fbaSMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(dm, section, locX_t, cell, NULL, &x_t));
62323e9753d6SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
6233754e4fbaSMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(dm, section, locX_t, cell, NULL, &x_t));
62343e9753d6SMatthew G. Knepley     }
62353e9753d6SMatthew G. Knepley     if (dmAux) {
62363e9753d6SMatthew G. Knepley       PetscInt subcell;
62379566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell));
62389566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x));
62393e9753d6SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
62409566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x));
62413e9753d6SMatthew G. Knepley     }
62423e9753d6SMatthew G. Knepley   }
62439566063dSJacob Faibussowitsch   if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim));
62449566063dSJacob Faibussowitsch   if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim));
62459566063dSJacob Faibussowitsch   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim));
62463e9753d6SMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
62473e9753d6SMatthew G. Knepley     PetscClassId    id;
62483e9753d6SMatthew G. Knepley     PetscFE         fe;
62493e9753d6SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
62503e9753d6SMatthew G. Knepley     PetscInt        Nb;
62513e9753d6SMatthew G. Knepley     /* Conforming batches */
62523e9753d6SMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
62533e9753d6SMatthew G. Knepley     /* Remainder */
62543e9753d6SMatthew G. Knepley     PetscInt     Nr, offset, Nq;
62553e9753d6SMatthew G. Knepley     PetscInt     maxDegree;
62563e9753d6SMatthew G. Knepley     PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
62573e9753d6SMatthew G. Knepley 
62589566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
62599566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
62609371c9d4SSatish Balay     if (id == PETSCFV_CLASSID) {
62619371c9d4SSatish Balay       hasFV = PETSC_TRUE;
62629371c9d4SSatish Balay       continue;
62639371c9d4SSatish Balay     }
62649566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
62659566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
62669566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
626748a46eb9SPierre Jolivet     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
62683e9753d6SMatthew G. Knepley     if (!qGeom) {
62699566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
62709566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
62713e9753d6SMatthew G. Knepley     }
62729566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
6273ac9d17c7SMatthew G. Knepley     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FEGEOM_BASIC, &cgeomFEM));
62743e9753d6SMatthew G. Knepley     blockSize = Nb;
62753e9753d6SMatthew G. Knepley     batchSize = numBlocks * blockSize;
62769566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
62773e9753d6SMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
62783e9753d6SMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
62793e9753d6SMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
62803e9753d6SMatthew G. Knepley     offset    = numCells - Nr;
62819566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
62829566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
62833e9753d6SMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
62846528b96dSMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
62853e9753d6SMatthew G. Knepley       if (hasJac) {
62864561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
62874561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim]));
62883e9753d6SMatthew G. Knepley       }
62893e9753d6SMatthew G. Knepley       if (hasPrec) {
62904561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP));
62914561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * totDim]));
62923e9753d6SMatthew G. Knepley       }
62933e9753d6SMatthew G. Knepley       if (hasDyn) {
62944561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD));
62954561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatD[offset * totDim * totDim]));
62963e9753d6SMatthew G. Knepley       }
62973e9753d6SMatthew G. Knepley     }
62989566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
62999566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
63009566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
63019566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
63023e9753d6SMatthew G. Knepley   }
63033e9753d6SMatthew G. Knepley   /*   Add contribution from X_t */
63049371c9d4SSatish Balay   if (hasDyn) {
63059371c9d4SSatish Balay     for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
63069371c9d4SSatish Balay   }
63073e9753d6SMatthew G. Knepley   if (hasFV) {
63083e9753d6SMatthew G. Knepley     PetscClassId id;
63093e9753d6SMatthew G. Knepley     PetscFV      fv;
63103e9753d6SMatthew G. Knepley     PetscInt     offsetI, NcI, NbI = 1, fc, f;
63113e9753d6SMatthew G. Knepley 
63123e9753d6SMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
63139566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv));
63149566063dSJacob Faibussowitsch       PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI));
63159566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetClassId((PetscObject)fv, &id));
63163e9753d6SMatthew G. Knepley       if (id != PETSCFV_CLASSID) continue;
63172f86f8c5SMatthew G. Knepley       /* Put in the weighted identity */
63189566063dSJacob Faibussowitsch       PetscCall(PetscFVGetNumComponents(fv, &NcI));
63193e9753d6SMatthew G. Knepley       for (c = cStart; c < cEnd; ++c) {
63203e9753d6SMatthew G. Knepley         const PetscInt cind    = c - cStart;
63213e9753d6SMatthew G. Knepley         const PetscInt eOffset = cind * totDim * totDim;
63222f86f8c5SMatthew G. Knepley         PetscReal      vol;
63232f86f8c5SMatthew G. Knepley 
63242f86f8c5SMatthew G. Knepley         PetscCall(DMPlexComputeCellGeometryFVM(dm, c, &vol, NULL, NULL));
63253e9753d6SMatthew G. Knepley         for (fc = 0; fc < NcI; ++fc) {
63263e9753d6SMatthew G. Knepley           for (f = 0; f < NbI; ++f) {
63273e9753d6SMatthew G. Knepley             const PetscInt i = offsetI + f * NcI + fc;
63283e9753d6SMatthew G. Knepley             if (hasPrec) {
63292f86f8c5SMatthew G. Knepley               if (hasJac) elemMat[eOffset + i * totDim + i] = vol;
63302f86f8c5SMatthew G. Knepley               elemMatP[eOffset + i * totDim + i] = vol;
63319371c9d4SSatish Balay             } else {
63322f86f8c5SMatthew G. Knepley               elemMat[eOffset + i * totDim + i] = vol;
63339371c9d4SSatish Balay             }
63343e9753d6SMatthew G. Knepley           }
63353e9753d6SMatthew G. Knepley         }
63363e9753d6SMatthew G. Knepley       }
63373e9753d6SMatthew G. Knepley     }
63383e9753d6SMatthew G. Knepley     /* No allocated space for FV stuff, so ignore the zero entries */
63399566063dSJacob Faibussowitsch     PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
63403e9753d6SMatthew G. Knepley   }
63413e9753d6SMatthew G. Knepley   /* Insert values into matrix */
63423e9753d6SMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
63433e9753d6SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
63443e9753d6SMatthew G. Knepley     const PetscInt cind = c - cStart;
63453e9753d6SMatthew G. Knepley 
63463e9753d6SMatthew G. Knepley     /* Transform to global basis before insertion in Jacobian */
63479566063dSJacob Faibussowitsch     if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim]));
63483e9753d6SMatthew G. Knepley     if (hasPrec) {
63493e9753d6SMatthew G. Knepley       if (hasJac) {
63509566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
6351e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
63523e9753d6SMatthew G. Knepley       }
63539566063dSJacob Faibussowitsch       if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim]));
6354be62b2b4SMatthew G. Knepley       PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES));
63553e9753d6SMatthew G. Knepley     } else {
63563e9753d6SMatthew G. Knepley       if (hasJac) {
63579566063dSJacob Faibussowitsch         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
6358e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosure_Internal(dm, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES));
63593e9753d6SMatthew G. Knepley       }
63603e9753d6SMatthew G. Knepley     }
63613e9753d6SMatthew G. Knepley   }
63629566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
63639566063dSJacob Faibussowitsch   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
63649566063dSJacob Faibussowitsch   PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD));
6365d9302694SMatthew G. Knepley   if (dmAux) PetscCall(PetscFree(a));
63663e9753d6SMatthew G. Knepley   /* Compute boundary integrals */
6367*2a8381b2SBarry Smith   PetscCall(DMPlexComputeBdJacobian_Internal(dm, locX, locX_t, t, X_tShift, Jac, JacP, ctx));
63683e9753d6SMatthew G. Knepley   /* Assemble matrix */
63699371c9d4SSatish Balay end: {
6370e04ae0b4SMatthew G. Knepley   PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp;
6371e04ae0b4SMatthew G. Knepley 
6372d9302694SMatthew G. Knepley   if (dmAux) PetscCall(DMDestroy(&plex));
63735440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&assOp, &gassOp, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
63743e9753d6SMatthew G. Knepley   if (hasJac && hasPrec) {
63759566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
63769566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
63773e9753d6SMatthew G. Knepley   }
6378e04ae0b4SMatthew G. Knepley }
63799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
63809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
63819566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
63823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63833e9753d6SMatthew G. Knepley }
63843e9753d6SMatthew G. Knepley 
DMPlexComputeJacobianByKeyGeneral(DM dmr,DM dmc,PetscFormKey key,IS cellIS,PetscReal t,PetscReal X_tShift,Vec locX,Vec locX_t,Mat Jac,Mat JacP,PetscCtx ctx)6385*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeJacobianByKeyGeneral(DM dmr, DM dmc, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, PetscCtx ctx)
63864561e6c9SMatthew G. Knepley {
63874561e6c9SMatthew G. Knepley   DM_Plex        *mesh     = (DM_Plex *)dmr->data;
63884561e6c9SMatthew G. Knepley   const char     *name     = "Jacobian";
63894561e6c9SMatthew G. Knepley   DM              dmAux    = NULL, plex, tdm;
63904561e6c9SMatthew G. Knepley   PetscInt        printFEM = mesh->printFEM;
63914561e6c9SMatthew G. Knepley   PetscBool       clPerm   = mesh->useMatClPerm;
63924561e6c9SMatthew G. Knepley   DMEnclosureType encAux;
63934561e6c9SMatthew G. Knepley   Vec             A, tv;
63944561e6c9SMatthew G. Knepley   DMField         coordField;
63954561e6c9SMatthew G. Knepley   PetscDS         rds, cds, dsAux = NULL;
63964561e6c9SMatthew G. Knepley   PetscSection    rsection, rglobalSection, csection, cglobalSection, sectionAux;
63974561e6c9SMatthew G. Knepley   PetscScalar    *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL;
63984561e6c9SMatthew G. Knepley   const PetscInt *cells;
63994561e6c9SMatthew G. Knepley   PetscInt        Nf, cNf;
64004561e6c9SMatthew G. Knepley   PetscInt        totDim, ctotDim, totDimAux = 0, cStart, cEnd, numCells;
64014561e6c9SMatthew G. Knepley   PetscBool       hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform;
64024561e6c9SMatthew G. Knepley   MPI_Comm        comm;
64034561e6c9SMatthew G. Knepley 
64044561e6c9SMatthew G. Knepley   PetscFunctionBegin;
64054561e6c9SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dmr, &comm));
64064561e6c9SMatthew G. Knepley   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dmr, 0, 0, 0));
64074561e6c9SMatthew G. Knepley   PetscCall(DMGetLocalSection(dmr, &rsection));
64084561e6c9SMatthew G. Knepley   PetscCall(DMGetGlobalSection(dmr, &rglobalSection));
64094561e6c9SMatthew G. Knepley   PetscCall(DMGetLocalSection(dmc, &csection));
64104561e6c9SMatthew G. Knepley   PetscCall(DMGetGlobalSection(dmc, &cglobalSection));
64114561e6c9SMatthew G. Knepley   PetscCall(DMGetAuxiliaryVec(dmr, key.label, key.value, key.part, &A));
64124561e6c9SMatthew G. Knepley   if (A) {
64134561e6c9SMatthew G. Knepley     PetscCall(VecGetDM(A, &dmAux));
64144561e6c9SMatthew G. Knepley     PetscCall(DMGetEnclosureRelation(dmAux, dmr, &encAux));
64154561e6c9SMatthew G. Knepley     PetscCall(DMConvert(dmAux, DMPLEX, &plex));
64164561e6c9SMatthew G. Knepley     PetscCall(DMGetLocalSection(plex, &sectionAux));
64174561e6c9SMatthew G. Knepley     PetscCall(DMGetDS(dmAux, &dsAux));
64184561e6c9SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
64194561e6c9SMatthew G. Knepley   }
64204561e6c9SMatthew G. Knepley   PetscCall(DMGetCoordinateField(dmr, &coordField));
64214561e6c9SMatthew G. Knepley   if (!cellIS) goto end;
64224561e6c9SMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
64234561e6c9SMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
64244561e6c9SMatthew G. Knepley   if (cStart >= cEnd) goto end;
64254561e6c9SMatthew G. Knepley   PetscCall(DMHasBasisTransform(dmr, &transform));
64264561e6c9SMatthew G. Knepley   PetscCall(DMGetBasisTransformDM_Internal(dmr, &tdm));
64274561e6c9SMatthew G. Knepley   PetscCall(DMGetBasisTransformVec_Internal(dmr, &tv));
64284561e6c9SMatthew G. Knepley   PetscCall(DMGetCellDS(dmr, cells ? cells[cStart] : cStart, &rds, NULL));
64294561e6c9SMatthew G. Knepley   PetscCall(DMGetCellDS(dmc, cells ? cells[cStart] : cStart, &cds, NULL));
64304561e6c9SMatthew G. Knepley   PetscCall(PetscDSGetNumFields(rds, &Nf));
64314561e6c9SMatthew G. Knepley   PetscCall(PetscDSGetNumFields(cds, &cNf));
64324561e6c9SMatthew G. Knepley   PetscCheck(Nf == cNf, comm, PETSC_ERR_ARG_WRONG, "Number of row fields %" PetscInt_FMT " != %" PetscInt_FMT " number of columns field", Nf, cNf);
64334561e6c9SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(rds, &totDim));
64344561e6c9SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(cds, &ctotDim));
64354561e6c9SMatthew G. Knepley   PetscCall(PetscDSHasJacobian(rds, &hasJac));
64364561e6c9SMatthew G. Knepley   PetscCall(PetscDSHasJacobianPreconditioner(rds, &hasPrec));
64374561e6c9SMatthew G. Knepley   /* user passed in the same matrix, avoid double contributions and
64384561e6c9SMatthew G. Knepley      only assemble the Jacobian */
64394561e6c9SMatthew G. Knepley   if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE;
64404561e6c9SMatthew G. Knepley   PetscCall(PetscDSHasDynamicJacobian(rds, &hasDyn));
64414561e6c9SMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
64424561e6c9SMatthew G. Knepley   PetscCall(PetscMalloc5(numCells * totDim, &u, (locX_t ? (size_t)numCells * totDim : 0), &u_t, (hasJac ? (size_t)numCells * totDim * ctotDim : 0), &elemMat, (hasPrec ? (size_t)numCells * totDim * ctotDim : 0), &elemMatP, (hasDyn ? (size_t)numCells * totDim * ctotDim : 0), &elemMatD));
64434561e6c9SMatthew G. Knepley   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
64444561e6c9SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
64454561e6c9SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
64464561e6c9SMatthew G. Knepley     const PetscInt cind = c - cStart;
64474561e6c9SMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
64484561e6c9SMatthew G. Knepley     PetscInt       i;
64494561e6c9SMatthew G. Knepley 
64504561e6c9SMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(dmr, rsection, locX, cell, NULL, &x));
64514561e6c9SMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
64524561e6c9SMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(dmr, rsection, locX, cell, NULL, &x));
64534561e6c9SMatthew G. Knepley     if (locX_t) {
64544561e6c9SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(dmr, rsection, locX_t, cell, NULL, &x_t));
64554561e6c9SMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
64564561e6c9SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(dmr, rsection, locX_t, cell, NULL, &x_t));
64574561e6c9SMatthew G. Knepley     }
64584561e6c9SMatthew G. Knepley     if (dmAux) {
64594561e6c9SMatthew G. Knepley       PetscInt subcell;
64604561e6c9SMatthew G. Knepley       PetscCall(DMGetEnclosurePoint(dmAux, dmr, encAux, cell, &subcell));
64614561e6c9SMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x));
64624561e6c9SMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
64634561e6c9SMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x));
64644561e6c9SMatthew G. Knepley     }
64654561e6c9SMatthew G. Knepley   }
64664561e6c9SMatthew G. Knepley   if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * ctotDim));
64674561e6c9SMatthew G. Knepley   if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * ctotDim));
64684561e6c9SMatthew G. Knepley   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * ctotDim));
64694561e6c9SMatthew G. Knepley   for (PetscInt fieldI = 0; fieldI < Nf; ++fieldI) {
64704561e6c9SMatthew G. Knepley     PetscClassId    id;
64714561e6c9SMatthew G. Knepley     PetscFE         fe;
64724561e6c9SMatthew G. Knepley     PetscQuadrature qGeom = NULL;
64734561e6c9SMatthew G. Knepley     PetscInt        Nb;
64744561e6c9SMatthew G. Knepley     /* Conforming batches */
64754561e6c9SMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
64764561e6c9SMatthew G. Knepley     /* Remainder */
64774561e6c9SMatthew G. Knepley     PetscInt     Nr, offset, Nq;
64784561e6c9SMatthew G. Knepley     PetscInt     maxDegree;
64794561e6c9SMatthew G. Knepley     PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
64804561e6c9SMatthew G. Knepley 
64814561e6c9SMatthew G. Knepley     PetscCall(PetscDSGetDiscretization(rds, fieldI, (PetscObject *)&fe));
64824561e6c9SMatthew G. Knepley     PetscCall(PetscObjectGetClassId((PetscObject)fe, &id));
64834561e6c9SMatthew G. Knepley     if (id == PETSCFV_CLASSID) {
64844561e6c9SMatthew G. Knepley       hasFV = PETSC_TRUE;
64854561e6c9SMatthew G. Knepley       continue;
64864561e6c9SMatthew G. Knepley     }
64874561e6c9SMatthew G. Knepley     PetscCall(PetscFEGetDimension(fe, &Nb));
64884561e6c9SMatthew G. Knepley     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
64894561e6c9SMatthew G. Knepley     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
64904561e6c9SMatthew G. Knepley     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
64914561e6c9SMatthew G. Knepley     if (!qGeom) {
64924561e6c9SMatthew G. Knepley       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
64934561e6c9SMatthew G. Knepley       PetscCall(PetscObjectReference((PetscObject)qGeom));
64944561e6c9SMatthew G. Knepley     }
64954561e6c9SMatthew G. Knepley     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
64964561e6c9SMatthew G. Knepley     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FEGEOM_BASIC, &cgeomFEM));
64974561e6c9SMatthew G. Knepley     blockSize = Nb;
64984561e6c9SMatthew G. Knepley     batchSize = numBlocks * blockSize;
64994561e6c9SMatthew G. Knepley     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
65004561e6c9SMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
65014561e6c9SMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
65024561e6c9SMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
65034561e6c9SMatthew G. Knepley     offset    = numCells - Nr;
65044561e6c9SMatthew G. Knepley     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
65054561e6c9SMatthew G. Knepley     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
65064561e6c9SMatthew G. Knepley     for (PetscInt fieldJ = 0; fieldJ < Nf; ++fieldJ) {
65074561e6c9SMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
65084561e6c9SMatthew G. Knepley       if (hasJac) {
65094561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(rds, cds, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMat));
65104561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(rds, cds, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * ctotDim]));
65114561e6c9SMatthew G. Knepley       }
65124561e6c9SMatthew G. Knepley       if (hasPrec) {
65134561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(rds, cds, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMatP));
65144561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(rds, cds, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatP[offset * totDim * ctotDim]));
65154561e6c9SMatthew G. Knepley       }
65164561e6c9SMatthew G. Knepley       if (hasDyn) {
65174561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(rds, cds, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, dsAux, a, t, X_tShift, elemMatD));
65184561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(rds, cds, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), dsAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMatD[offset * totDim * ctotDim]));
65194561e6c9SMatthew G. Knepley       }
65204561e6c9SMatthew G. Knepley     }
65214561e6c9SMatthew G. Knepley     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
65224561e6c9SMatthew G. Knepley     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
65234561e6c9SMatthew G. Knepley     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
65244561e6c9SMatthew G. Knepley     PetscCall(PetscQuadratureDestroy(&qGeom));
65254561e6c9SMatthew G. Knepley   }
65264561e6c9SMatthew G. Knepley   /*   Add contribution from X_t */
65274561e6c9SMatthew G. Knepley   if (hasDyn) {
65284561e6c9SMatthew G. Knepley     for (PetscInt c = 0; c < numCells * totDim * ctotDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
65294561e6c9SMatthew G. Knepley   }
65304561e6c9SMatthew G. Knepley   if (hasFV) {
65314561e6c9SMatthew G. Knepley     PetscClassId id;
65324561e6c9SMatthew G. Knepley     PetscFV      fv;
65334561e6c9SMatthew G. Knepley     PetscInt     offsetI, NcI, NbI = 1;
65344561e6c9SMatthew G. Knepley 
65354561e6c9SMatthew G. Knepley     for (PetscInt fieldI = 0; fieldI < Nf; ++fieldI) {
65364561e6c9SMatthew G. Knepley       PetscCall(PetscDSGetDiscretization(rds, fieldI, (PetscObject *)&fv));
65374561e6c9SMatthew G. Knepley       PetscCall(PetscDSGetFieldOffset(rds, fieldI, &offsetI));
65384561e6c9SMatthew G. Knepley       PetscCall(PetscObjectGetClassId((PetscObject)fv, &id));
65394561e6c9SMatthew G. Knepley       if (id != PETSCFV_CLASSID) continue;
65404561e6c9SMatthew G. Knepley       /* Put in the weighted identity */
65414561e6c9SMatthew G. Knepley       PetscCall(PetscFVGetNumComponents(fv, &NcI));
65424561e6c9SMatthew G. Knepley       for (PetscInt c = cStart; c < cEnd; ++c) {
65434561e6c9SMatthew G. Knepley         const PetscInt cind    = c - cStart;
65444561e6c9SMatthew G. Knepley         const PetscInt eOffset = cind * totDim * ctotDim;
65454561e6c9SMatthew G. Knepley         PetscReal      vol;
65464561e6c9SMatthew G. Knepley 
65474561e6c9SMatthew G. Knepley         PetscCall(DMPlexComputeCellGeometryFVM(dmr, c, &vol, NULL, NULL));
65484561e6c9SMatthew G. Knepley         for (PetscInt fc = 0; fc < NcI; ++fc) {
65494561e6c9SMatthew G. Knepley           for (PetscInt f = 0; f < NbI; ++f) {
65504561e6c9SMatthew G. Knepley             const PetscInt i = offsetI + f * NcI + fc;
65514561e6c9SMatthew G. Knepley             if (hasPrec) {
65524561e6c9SMatthew G. Knepley               if (hasJac) elemMat[eOffset + i * ctotDim + i] = vol;
65534561e6c9SMatthew G. Knepley               elemMatP[eOffset + i * ctotDim + i] = vol;
65544561e6c9SMatthew G. Knepley             } else {
65554561e6c9SMatthew G. Knepley               elemMat[eOffset + i * ctotDim + i] = vol;
65564561e6c9SMatthew G. Knepley             }
65574561e6c9SMatthew G. Knepley           }
65584561e6c9SMatthew G. Knepley         }
65594561e6c9SMatthew G. Knepley       }
65604561e6c9SMatthew G. Knepley     }
65614561e6c9SMatthew G. Knepley     /* No allocated space for FV stuff, so ignore the zero entries */
65624561e6c9SMatthew G. Knepley     PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE));
65634561e6c9SMatthew G. Knepley   }
65644561e6c9SMatthew G. Knepley   /* Insert values into matrix */
65654561e6c9SMatthew G. Knepley   for (PetscInt c = cStart; c < cEnd; ++c) {
65664561e6c9SMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
65674561e6c9SMatthew G. Knepley     const PetscInt cind = c - cStart;
65684561e6c9SMatthew G. Knepley 
65694561e6c9SMatthew G. Knepley     /* Transform to global basis before insertion in Jacobian */
65704561e6c9SMatthew G. Knepley     if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dmr, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * ctotDim]));
65714561e6c9SMatthew G. Knepley     if (hasPrec) {
65724561e6c9SMatthew G. Knepley       if (hasJac) {
65734561e6c9SMatthew G. Knepley         if (printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, ctotDim, &elemMat[cind * totDim * ctotDim]));
65744561e6c9SMatthew G. Knepley         PetscCall(DMPlexMatSetClosureGeneral(dmr, rsection, rglobalSection, clPerm, dmc, csection, cglobalSection, clPerm, Jac, cell, &elemMat[cind * totDim * ctotDim], ADD_VALUES));
65754561e6c9SMatthew G. Knepley       }
65764561e6c9SMatthew G. Knepley       if (printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, ctotDim, &elemMatP[cind * totDim * ctotDim]));
65774561e6c9SMatthew G. Knepley       PetscCall(DMPlexMatSetClosureGeneral(dmr, rsection, rglobalSection, clPerm, dmc, csection, cglobalSection, clPerm, JacP, cell, &elemMatP[cind * totDim * ctotDim], ADD_VALUES));
65784561e6c9SMatthew G. Knepley     } else {
65794561e6c9SMatthew G. Knepley       if (hasJac) {
65804561e6c9SMatthew G. Knepley         if (printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, ctotDim, &elemMat[cind * totDim * ctotDim]));
65814561e6c9SMatthew G. Knepley         PetscCall(DMPlexMatSetClosureGeneral(dmr, rsection, rglobalSection, clPerm, dmc, csection, cglobalSection, clPerm, JacP, cell, &elemMat[cind * totDim * ctotDim], ADD_VALUES));
65824561e6c9SMatthew G. Knepley       }
65834561e6c9SMatthew G. Knepley     }
65844561e6c9SMatthew G. Knepley   }
65854561e6c9SMatthew G. Knepley   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
65864561e6c9SMatthew G. Knepley   if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE));
65874561e6c9SMatthew G. Knepley   PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD));
65884561e6c9SMatthew G. Knepley   if (dmAux) PetscCall(PetscFree(a));
65894561e6c9SMatthew G. Knepley   /* Compute boundary integrals */
6590*2a8381b2SBarry Smith   PetscCall(DMPlexComputeBdJacobian_Internal(dmr, locX, locX_t, t, X_tShift, Jac, JacP, ctx));
65914561e6c9SMatthew G. Knepley   /* Assemble matrix */
65924561e6c9SMatthew G. Knepley end: {
65934561e6c9SMatthew G. Knepley   PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp;
65944561e6c9SMatthew G. Knepley 
65954561e6c9SMatthew G. Knepley   if (dmAux) PetscCall(DMDestroy(&plex));
65965440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&assOp, &gassOp, 1, MPI_C_BOOL, MPI_LOR, comm));
65974561e6c9SMatthew G. Knepley   if (hasJac && hasPrec) {
65984561e6c9SMatthew G. Knepley     PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));
65994561e6c9SMatthew G. Knepley     PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));
66004561e6c9SMatthew G. Knepley   }
66014561e6c9SMatthew G. Knepley }
66024561e6c9SMatthew G. Knepley   PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));
66034561e6c9SMatthew G. Knepley   PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY));
66044561e6c9SMatthew G. Knepley   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dmr, 0, 0, 0));
66054561e6c9SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
66064561e6c9SMatthew G. Knepley }
66074561e6c9SMatthew G. Knepley 
6608754e4fbaSMatthew G. Knepley /*@
6609754e4fbaSMatthew G. Knepley   DMPlexComputeJacobianHybridByKey - Compute the local Jacobian over hybrid cells for terms matching the input key
6610754e4fbaSMatthew G. Knepley 
6611754e4fbaSMatthew G. Knepley   Collective
6612754e4fbaSMatthew G. Knepley 
6613754e4fbaSMatthew G. Knepley   Input Parameters:
6614754e4fbaSMatthew G. Knepley + dm       - The output `DM`
6615754e4fbaSMatthew G. Knepley . key      - The `PetscFormKey` array (left cell, right cell, cohesive cell) indicating what should be integrated
6616754e4fbaSMatthew G. Knepley . cellIS   - The `IS` give a set of cells to integrate over
6617754e4fbaSMatthew G. Knepley . t        - The time
6618754e4fbaSMatthew G. Knepley . X_tShift - The multiplier for the Jacobian with respect to $X_t$
6619754e4fbaSMatthew G. Knepley . locX     - The local solution
6620754e4fbaSMatthew G. Knepley . locX_t   - The time derivative of the local solution, or `NULL` for time-independent problems
6621*2a8381b2SBarry Smith - ctx      - An optional application context, passed to the pointwise functions
6622754e4fbaSMatthew G. Knepley 
6623754e4fbaSMatthew G. Knepley   Output Parameters:
6624754e4fbaSMatthew G. Knepley + Jac  - The local Jacobian
6625754e4fbaSMatthew G. Knepley - JacP - The local Jacobian preconditioner
6626754e4fbaSMatthew G. Knepley 
6627754e4fbaSMatthew G. Knepley   Level: developer
6628754e4fbaSMatthew G. Knepley 
6629754e4fbaSMatthew G. Knepley .seealso: `DMPlexComputeResidualByKey()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `PetscFormKey`
6630754e4fbaSMatthew G. Knepley @*/
DMPlexComputeJacobianHybridByKey(DM dm,PetscFormKey key[],IS cellIS,PetscReal t,PetscReal X_tShift,Vec locX,Vec locX_t,Mat Jac,Mat JacP,PetscCtx ctx)6631*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeJacobianHybridByKey(DM dm, PetscFormKey key[], IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, PetscCtx ctx)
6632d71ae5a4SJacob Faibussowitsch {
66333e9753d6SMatthew G. Knepley   DM_Plex        *mesh          = (DM_Plex *)dm->data;
66343e9753d6SMatthew G. Knepley   const char     *name          = "Hybrid Jacobian";
6635148442b3SMatthew G. Knepley   DM              dmAux[3]      = {NULL, NULL, NULL};
6636148442b3SMatthew G. Knepley   DMLabel         ghostLabel    = NULL;
66373e9753d6SMatthew G. Knepley   DM              plex          = NULL;
66383e9753d6SMatthew G. Knepley   DM              plexA         = NULL;
6639148442b3SMatthew G. Knepley   PetscDS         ds            = NULL;
664007218a29SMatthew G. Knepley   PetscDS         dsIn          = NULL;
6641148442b3SMatthew G. Knepley   PetscDS         dsAux[3]      = {NULL, NULL, NULL};
6642148442b3SMatthew G. Knepley   Vec             locA[3]       = {NULL, NULL, NULL};
664307218a29SMatthew G. Knepley   DM              dmScale[3]    = {NULL, NULL, NULL};
664407218a29SMatthew G. Knepley   PetscDS         dsScale[3]    = {NULL, NULL, NULL};
664507218a29SMatthew G. Knepley   Vec             locS[3]       = {NULL, NULL, NULL};
66463e9753d6SMatthew G. Knepley   PetscSection    section       = NULL;
6647148442b3SMatthew G. Knepley   PetscSection    sectionAux[3] = {NULL, NULL, NULL};
66483e9753d6SMatthew G. Knepley   DMField         coordField    = NULL;
664907218a29SMatthew G. Knepley   PetscScalar    *a[3]          = {NULL, NULL, NULL};
665007218a29SMatthew G. Knepley   PetscScalar    *s[3]          = {NULL, NULL, NULL};
665107218a29SMatthew G. Knepley   PetscScalar    *u             = NULL, *u_t;
665207218a29SMatthew G. Knepley   PetscScalar    *elemMatNeg, *elemMatPos, *elemMatCoh;
665307218a29SMatthew G. Knepley   PetscScalar    *elemMatNegP, *elemMatPosP, *elemMatCohP;
6654e432b41dSStefano Zampini   PetscSection    globalSection;
6655989fa639SBrad Aagaard   IS              chunkISF, chunkISN;
66563e9753d6SMatthew G. Knepley   const PetscInt *cells;
6657989fa639SBrad Aagaard   PetscInt       *faces, *neighbors;
66583e9753d6SMatthew G. Knepley   PetscInt        cStart, cEnd, numCells;
66593e2b0218SMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ, totDim, totDimIn, totDimAux[3], totDimScale[3], numChunks, cellChunkSize, chunk;
66601690c2aeSBarry Smith   PetscInt        maxDegree   = PETSC_INT_MAX;
6661989fa639SBrad Aagaard   PetscQuadrature affineQuadF = NULL, *quadsF = NULL;
6662989fa639SBrad Aagaard   PetscFEGeom    *affineGeomF = NULL, **geomsF = NULL;
6663989fa639SBrad Aagaard   PetscQuadrature affineQuadN = NULL;
6664989fa639SBrad Aagaard   PetscFEGeom    *affineGeomN = NULL;
6665e432b41dSStefano Zampini   PetscBool       hasBdJac, hasBdPrec;
66663e9753d6SMatthew G. Knepley 
66673e9753d6SMatthew G. Knepley   PetscFunctionBegin;
66683cc88e6aSStefano Zampini   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
66693cc88e6aSStefano Zampini   if (!cellIS) goto end;
6670437e83fbSMatthew G. Knepley   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
6671437e83fbSMatthew G. Knepley   PetscCall(ISGetLocalSize(cellIS, &numCells));
66723cc88e6aSStefano Zampini   if (cStart >= cEnd) goto end;
66735fedec97SMatthew G. Knepley   if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) {
66745fedec97SMatthew G. Knepley     const char *name;
66759566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name));
667663a3b9bcSJacob 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);
66775fedec97SMatthew G. Knepley   }
66789566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
6679b98a7184SJames Wright   PetscCall(DMGetLocalSection(dm, &section));
66809566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
66819566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dm, "ghost", &ghostLabel));
668207218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds, &dsIn));
66839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
66849566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
668507218a29SMatthew G. Knepley   PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn));
66869566063dSJacob Faibussowitsch   PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac));
66879566063dSJacob Faibussowitsch   PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec));
66889566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2]));
6689148442b3SMatthew G. Knepley   if (locA[2]) {
66901059d808SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
66911059d808SMatthew G. Knepley 
66929566063dSJacob Faibussowitsch     PetscCall(VecGetDM(locA[2], &dmAux[2]));
66939566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA));
6694b98a7184SJames Wright     PetscCall(DMGetLocalSection(dmAux[2], &sectionAux[2]));
669507218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2], NULL));
66969566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2]));
6697148442b3SMatthew G. Knepley     {
6698148442b3SMatthew G. Knepley       const PetscInt *cone;
6699148442b3SMatthew G. Knepley       PetscInt        c;
6700148442b3SMatthew G. Knepley 
67011059d808SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
6702148442b3SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
6703148442b3SMatthew G. Knepley         const PetscInt *support;
6704148442b3SMatthew G. Knepley         PetscInt        ssize, s;
6705148442b3SMatthew G. Knepley 
67069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
67079566063dSJacob Faibussowitsch         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
67081059d808SMatthew 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);
67091059d808SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
67101059d808SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
67111059d808SMatthew 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);
67129566063dSJacob Faibussowitsch         PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c]));
67139566063dSJacob Faibussowitsch         if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c]));
6714ad540459SPierre Jolivet         else dmAux[c] = dmAux[2];
671507218a29SMatthew G. Knepley         PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c], NULL));
67169566063dSJacob Faibussowitsch         PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c]));
6717148442b3SMatthew G. Knepley       }
6718148442b3SMatthew G. Knepley     }
67193e9753d6SMatthew G. Knepley   }
672007218a29SMatthew G. Knepley   /* Handle mass matrix scaling
672107218a29SMatthew G. Knepley        The field in key[2] is the field to be scaled, and the scaling field is the first in the dsScale */
672207218a29SMatthew G. Knepley   PetscCall(DMGetAuxiliaryVec(dm, key[2].label, -key[2].value, key[2].part, &locS[2]));
672307218a29SMatthew G. Knepley   if (locS[2]) {
67243e2b0218SMatthew G. Knepley     const PetscInt cellStart = cells ? cells[cStart] : cStart;
672507218a29SMatthew G. Knepley     PetscInt       Nb, Nbs;
672607218a29SMatthew G. Knepley 
672707218a29SMatthew G. Knepley     PetscCall(VecGetDM(locS[2], &dmScale[2]));
672807218a29SMatthew G. Knepley     PetscCall(DMGetCellDS(dmScale[2], cells ? cells[cStart] : cStart, &dsScale[2], NULL));
67293e2b0218SMatthew G. Knepley     PetscCall(PetscDSGetTotalDimension(dsScale[2], &totDimScale[2]));
673007218a29SMatthew G. Knepley     // BRAD: This is not set correctly
673107218a29SMatthew G. Knepley     key[2].field = 2;
673207218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(ds, key[2].field, &Nb));
673307218a29SMatthew G. Knepley     PetscCall(PetscDSGetFieldSize(dsScale[2], 0, &Nbs));
673407218a29SMatthew 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);
67353e2b0218SMatthew G. Knepley     {
67363e2b0218SMatthew G. Knepley       const PetscInt *cone;
67373e2b0218SMatthew G. Knepley       PetscInt        c;
67383e2b0218SMatthew G. Knepley 
67393e2b0218SMatthew G. Knepley       locS[1] = locS[0] = locS[2];
67403e2b0218SMatthew G. Knepley       dmScale[1] = dmScale[0] = dmScale[2];
67413e2b0218SMatthew G. Knepley       PetscCall(DMPlexGetCone(dm, cellStart, &cone));
67423e2b0218SMatthew G. Knepley       for (c = 0; c < 2; ++c) {
67433e2b0218SMatthew G. Knepley         const PetscInt *support;
67443e2b0218SMatthew G. Knepley         PetscInt        ssize, s;
67453e2b0218SMatthew G. Knepley 
67463e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupport(dm, cone[c], &support));
67473e2b0218SMatthew G. Knepley         PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize));
67483e2b0218SMatthew 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);
67493e2b0218SMatthew G. Knepley         if (support[0] == cellStart) s = 1;
67503e2b0218SMatthew G. Knepley         else if (support[1] == cellStart) s = 0;
67513e2b0218SMatthew 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);
67523e2b0218SMatthew G. Knepley         PetscCall(DMGetCellDS(dmScale[c], support[s], &dsScale[c], NULL));
67533e2b0218SMatthew G. Knepley         PetscCall(PetscDSGetTotalDimension(dsScale[c], &totDimScale[c]));
67543e2b0218SMatthew G. Knepley       }
67553e2b0218SMatthew G. Knepley     }
675607218a29SMatthew G. Knepley   }
675707218a29SMatthew G. Knepley   /* 2: Setup geometric data */
67589566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
67599566063dSJacob Faibussowitsch   PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
67603e9753d6SMatthew G. Knepley   if (maxDegree > 1) {
67613e9753d6SMatthew G. Knepley     PetscInt f;
6762989fa639SBrad Aagaard     PetscCall(PetscCalloc2(Nf, &quadsF, Nf, &geomsF));
67633e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
67643e9753d6SMatthew G. Knepley       PetscFE fe;
67653e9753d6SMatthew G. Knepley 
67669566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
67673e9753d6SMatthew G. Knepley       if (fe) {
6768989fa639SBrad Aagaard         PetscCall(PetscFEGetQuadrature(fe, &quadsF[f]));
6769989fa639SBrad Aagaard         PetscCall(PetscObjectReference((PetscObject)quadsF[f]));
67703e9753d6SMatthew G. Knepley       }
67713e9753d6SMatthew G. Knepley     }
67723e9753d6SMatthew G. Knepley   }
677307218a29SMatthew G. Knepley   /* Loop over chunks */
67743e9753d6SMatthew G. Knepley   cellChunkSize = numCells;
67753e9753d6SMatthew G. Knepley   numChunks     = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize);
6776989fa639SBrad Aagaard   PetscCall(PetscCalloc2(2 * cellChunkSize, &faces, 2 * cellChunkSize, &neighbors));
6777989fa639SBrad Aagaard   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkISF));
6778989fa639SBrad Aagaard   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * cellChunkSize, neighbors, PETSC_USE_POINTER, &chunkISN));
677907218a29SMatthew G. Knepley   /* Extract field coefficients */
678007218a29SMatthew G. Knepley   /* NOTE This needs the end cap faces to have identical orientations */
678107218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
678207218a29SMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
67838bf0a22dSMatthew G. Knepley   PetscCall(DMPlexGetHybridFields(dm, dmScale, dsScale, cellIS, locS, PETSC_TRUE, s));
678407218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg));
678507218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos));
678607218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh));
678707218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP));
678807218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP));
678907218a29SMatthew G. Knepley   PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP));
67903e9753d6SMatthew G. Knepley   for (chunk = 0; chunk < numChunks; ++chunk) {
67913e9753d6SMatthew G. Knepley     PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c;
67923e9753d6SMatthew G. Knepley 
679307218a29SMatthew G. Knepley     if (hasBdJac) {
679407218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatNeg, cellChunkSize * totDim * totDim));
679507218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatPos, cellChunkSize * totDim * totDim));
679607218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatCoh, cellChunkSize * totDim * totDim));
679707218a29SMatthew G. Knepley     }
679807218a29SMatthew G. Knepley     if (hasBdPrec) {
679907218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatNegP, cellChunkSize * totDim * totDim));
680007218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatPosP, cellChunkSize * totDim * totDim));
680107218a29SMatthew G. Knepley       PetscCall(PetscArrayzero(elemMatCohP, cellChunkSize * totDim * totDim));
680207218a29SMatthew G. Knepley     }
68033e9753d6SMatthew G. Knepley     /* Get faces */
68043e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
68053e9753d6SMatthew G. Knepley       const PetscInt  cell = cells ? cells[c] : c;
6806989fa639SBrad Aagaard       const PetscInt *cone, *support;
68079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(plex, cell, &cone));
680807218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 0] = cone[0];
680907218a29SMatthew G. Knepley       faces[(c - cS) * 2 + 1] = cone[1];
6810989fa639SBrad Aagaard       PetscCall(DMPlexGetSupport(dm, cone[0], &support));
6811989fa639SBrad Aagaard       neighbors[(c - cS) * 2 + 0] = support[0] == cell ? support[1] : support[0];
6812989fa639SBrad Aagaard       PetscCall(DMPlexGetSupport(dm, cone[1], &support));
6813989fa639SBrad Aagaard       neighbors[(c - cS) * 2 + 1] = support[0] == cell ? support[1] : support[0];
68143e9753d6SMatthew G. Knepley     }
6815989fa639SBrad Aagaard     PetscCall(ISGeneralSetIndices(chunkISF, 2 * cellChunkSize, faces, PETSC_USE_POINTER));
6816989fa639SBrad Aagaard     PetscCall(ISGeneralSetIndices(chunkISN, 2 * cellChunkSize, neighbors, PETSC_USE_POINTER));
68173e9753d6SMatthew G. Knepley     if (maxDegree <= 1) {
6818989fa639SBrad Aagaard       if (!affineQuadF) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkISF, &affineQuadF));
6819989fa639SBrad Aagaard       if (affineQuadF) PetscCall(DMSNESGetFEGeom(coordField, chunkISF, affineQuadF, PETSC_FEGEOM_COHESIVE, &affineGeomF));
6820989fa639SBrad Aagaard       if (!affineQuadN) {
6821989fa639SBrad Aagaard         PetscInt dim;
6822989fa639SBrad Aagaard         PetscCall(PetscQuadratureGetData(affineQuadF, &dim, NULL, NULL, NULL, NULL));
6823989fa639SBrad Aagaard         PetscCall(DMFieldCreateDefaultFaceQuadrature(coordField, chunkISN, &affineQuadN));
6824989fa639SBrad Aagaard         PetscCall(PetscQuadratureSetData(affineQuadN, dim + 1, PETSC_DECIDE, PETSC_DECIDE, NULL, NULL));
6825989fa639SBrad Aagaard       }
6826989fa639SBrad Aagaard       if (affineQuadN) PetscCall(DMSNESGetFEGeom(coordField, chunkISN, affineQuadN, PETSC_FEGEOM_BASIC, &affineGeomN));
68273e9753d6SMatthew G. Knepley     } else {
68283e9753d6SMatthew G. Knepley       PetscInt f;
68293e9753d6SMatthew G. Knepley       for (f = 0; f < Nf; ++f) {
6830989fa639SBrad Aagaard         if (quadsF[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkISF, quadsF[f], PETSC_FEGEOM_COHESIVE, &geomsF[f]));
68313e9753d6SMatthew G. Knepley       }
68323e9753d6SMatthew G. Knepley     }
68333e9753d6SMatthew G. Knepley 
68343e9753d6SMatthew G. Knepley     for (fieldI = 0; fieldI < Nf; ++fieldI) {
68353e9753d6SMatthew G. Knepley       PetscFE         feI;
6836989fa639SBrad Aagaard       PetscFEGeom    *geomF      = affineGeomF ? affineGeomF : geomsF[fieldI];
6837989fa639SBrad Aagaard       PetscFEGeom    *chunkGeomF = NULL, *remGeomF = NULL;
6838989fa639SBrad Aagaard       PetscFEGeom    *geomN      = affineGeomN ? affineGeomN : geomsF[fieldI];
6839989fa639SBrad Aagaard       PetscFEGeom    *chunkGeomN = NULL, *remGeomN = NULL;
6840989fa639SBrad Aagaard       PetscQuadrature quadF = affineQuadF ? affineQuadF : quadsF[fieldI];
68413e9753d6SMatthew G. Knepley       PetscInt        numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb;
68425fedec97SMatthew G. Knepley       PetscBool       isCohesiveField;
68433e9753d6SMatthew G. Knepley 
68449566063dSJacob Faibussowitsch       PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
68453e9753d6SMatthew G. Knepley       if (!feI) continue;
68469566063dSJacob Faibussowitsch       PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches));
6847989fa639SBrad Aagaard       PetscCall(PetscQuadratureGetData(quadF, NULL, NULL, &Nq, NULL, NULL));
68489566063dSJacob Faibussowitsch       PetscCall(PetscFEGetDimension(feI, &Nb));
68493e9753d6SMatthew G. Knepley       blockSize = Nb;
68503e9753d6SMatthew G. Knepley       batchSize = numBlocks * blockSize;
68519566063dSJacob Faibussowitsch       PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches));
68523e9753d6SMatthew G. Knepley       numChunks = numCells / (numBatches * batchSize);
68533e9753d6SMatthew G. Knepley       Ne        = numChunks * numBatches * batchSize;
68543e9753d6SMatthew G. Knepley       Nr        = numCells % (numBatches * batchSize);
68553e9753d6SMatthew G. Knepley       offset    = numCells - Nr;
6856989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomF, 0, offset * 2, &chunkGeomF));
6857989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomF, offset * 2, numCells * 2, &remGeomF));
6858989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomN, 0, offset * 2, &chunkGeomN));
6859989fa639SBrad Aagaard       PetscCall(PetscFEGeomGetChunk(geomN, offset * 2, numCells * 2, &remGeomN));
68609566063dSJacob Faibussowitsch       PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField));
68613e9753d6SMatthew G. Knepley       for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
68623e9753d6SMatthew G. Knepley         PetscFE feJ;
68633e9753d6SMatthew G. Knepley 
68649566063dSJacob Faibussowitsch         PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
68653e9753d6SMatthew G. Knepley         if (!feJ) continue;
6866148442b3SMatthew G. Knepley         key[0].field = fieldI * Nf + fieldJ;
6867148442b3SMatthew G. Knepley         key[1].field = fieldI * Nf + fieldJ;
68685fedec97SMatthew G. Knepley         key[2].field = fieldI * Nf + fieldJ;
6869148442b3SMatthew G. Knepley         if (hasBdJac) {
6870989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNeg));
6871989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], PetscSafePointerPlusOffset(a[0], offset * totDimAux[0]), t, X_tShift, &elemMatNeg[offset * totDim * totDim]));
6872989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPos));
6873989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], PetscSafePointerPlusOffset(a[1], offset * totDimAux[1]), t, X_tShift, &elemMatPos[offset * totDim * totDim]));
6874148442b3SMatthew G. Knepley         }
6875148442b3SMatthew G. Knepley         if (hasBdPrec) {
6876989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatNegP));
6877989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatNegP[offset * totDim * totDim]));
6878989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatPosP));
6879989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatPosP[offset * totDim * totDim]));
6880148442b3SMatthew G. Knepley         }
68815fedec97SMatthew G. Knepley         if (hasBdJac) {
6882989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCoh));
6883989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], PetscSafePointerPlusOffset(a[2], offset * totDimAux[2]), t, X_tShift, &elemMatCoh[offset * totDim * totDim]));
6884148442b3SMatthew G. Knepley         }
68855fedec97SMatthew G. Knepley         if (hasBdPrec) {
6886989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeomF, chunkGeomN, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatCohP));
6887989fa639SBrad Aagaard           PetscCall(PetscFEIntegrateHybridJacobian(ds, dsIn, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeomF, remGeomN, &u[offset * totDimIn], PetscSafePointerPlusOffset(u_t, offset * totDimIn), dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatCohP[offset * totDim * totDim]));
68883e9753d6SMatthew G. Knepley         }
68893e9753d6SMatthew G. Knepley       }
6890989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomF, offset, numCells, &remGeomF));
6891989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomF, 0, offset, &chunkGeomF));
6892989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomN, offset, numCells, &remGeomN));
6893989fa639SBrad Aagaard       PetscCall(PetscFEGeomRestoreChunk(geomN, 0, offset, &chunkGeomN));
68943e9753d6SMatthew G. Knepley     }
68953e9753d6SMatthew G. Knepley     /* Insert values into matrix */
68963e9753d6SMatthew G. Knepley     for (c = cS; c < cE; ++c) {
68973e9753d6SMatthew G. Knepley       const PetscInt cell = cells ? cells[c] : c;
689807218a29SMatthew G. Knepley       const PetscInt cind = c - cS, coff = cind * totDim * totDim;
689907218a29SMatthew G. Knepley       PetscInt       i, j;
69003e9753d6SMatthew G. Knepley 
690107218a29SMatthew G. Knepley       /* Scale element values */
690207218a29SMatthew G. Knepley       if (locS[0]) {
69033e2b0218SMatthew G. Knepley         PetscInt  Nb, soff = cind * totDimScale[0], off = 0;
690407218a29SMatthew G. Knepley         PetscBool cohesive;
690507218a29SMatthew G. Knepley 
690607218a29SMatthew G. Knepley         for (fieldI = 0; fieldI < Nf; ++fieldI) {
690707218a29SMatthew G. Knepley           PetscCall(PetscDSGetFieldSize(ds, fieldI, &Nb));
690807218a29SMatthew G. Knepley           PetscCall(PetscDSGetCohesive(ds, fieldI, &cohesive));
690907218a29SMatthew G. Knepley 
691007218a29SMatthew G. Knepley           if (fieldI == key[2].field) {
691107218a29SMatthew G. Knepley             PetscCheck(cohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Scaling should not happen for face fields");
69128bf0a22dSMatthew G. Knepley             for (i = 0; i < Nb; ++i) {
691307218a29SMatthew 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];
69148bf0a22dSMatthew G. Knepley               if (hasBdPrec)
69158bf0a22dSMatthew 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];
69168bf0a22dSMatthew G. Knepley             }
691707218a29SMatthew G. Knepley             off += Nb;
691807218a29SMatthew G. Knepley           } else {
691907218a29SMatthew G. Knepley             const PetscInt N = cohesive ? Nb : Nb * 2;
692007218a29SMatthew G. Knepley 
69218bf0a22dSMatthew G. Knepley             for (i = 0; i < N; ++i) {
692207218a29SMatthew 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];
69238bf0a22dSMatthew G. Knepley               if (hasBdPrec)
69248bf0a22dSMatthew 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];
69258bf0a22dSMatthew G. Knepley             }
692607218a29SMatthew G. Knepley             off += N;
692707218a29SMatthew G. Knepley           }
692807218a29SMatthew G. Knepley         }
692907218a29SMatthew G. Knepley       } else {
693007218a29SMatthew G. Knepley         for (i = 0; i < totDim * totDim; ++i) elemMatCoh[coff + i] += elemMatNeg[coff + i] + elemMatPos[coff + i];
69318bf0a22dSMatthew G. Knepley         if (hasBdPrec)
69328bf0a22dSMatthew G. Knepley           for (i = 0; i < totDim * totDim; ++i) elemMatCohP[coff + i] += elemMatNegP[coff + i] + elemMatPosP[coff + i];
693307218a29SMatthew G. Knepley       }
69343e9753d6SMatthew G. Knepley       if (hasBdPrec) {
69353e9753d6SMatthew G. Knepley         if (hasBdJac) {
693607218a29SMatthew G. Knepley           if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim]));
6937e8e188d2SZach Atkins           PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, Jac, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES));
69383e9753d6SMatthew G. Knepley         }
693907218a29SMatthew G. Knepley         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCohP[cind * totDim * totDim]));
694007218a29SMatthew G. Knepley         PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatCohP[cind * totDim * totDim], ADD_VALUES));
69413e9753d6SMatthew G. Knepley       } else if (hasBdJac) {
694207218a29SMatthew G. Knepley         if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatCoh[cind * totDim * totDim]));
6943e8e188d2SZach Atkins         PetscCall(DMPlexMatSetClosure_Internal(plex, section, globalSection, mesh->useMatClPerm, JacP, cell, &elemMatCoh[cind * totDim * totDim], ADD_VALUES));
69443e9753d6SMatthew G. Knepley       }
69453e9753d6SMatthew G. Knepley     }
69463e9753d6SMatthew G. Knepley   }
69479566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2]));
694807218a29SMatthew G. Knepley   PetscCall(DMPlexRestoreHybridFields(dm, dmAux, dsAux, cellIS, locA, PETSC_TRUE, a));
694907218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNeg));
695007218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPos));
695107218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCoh));
695207218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatNegP));
695307218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatPosP));
695407218a29SMatthew G. Knepley   PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatCohP));
6955989fa639SBrad Aagaard   PetscCall(PetscFree2(faces, neighbors));
6956989fa639SBrad Aagaard   PetscCall(ISDestroy(&chunkISF));
6957989fa639SBrad Aagaard   PetscCall(ISDestroy(&chunkISN));
69589566063dSJacob Faibussowitsch   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
69593e9753d6SMatthew G. Knepley   if (maxDegree <= 1) {
6960989fa639SBrad Aagaard     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuadF, PETSC_FALSE, &affineGeomF));
6961989fa639SBrad Aagaard     PetscCall(PetscQuadratureDestroy(&affineQuadF));
6962989fa639SBrad Aagaard     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuadN, PETSC_FALSE, &affineGeomN));
6963989fa639SBrad Aagaard     PetscCall(PetscQuadratureDestroy(&affineQuadN));
69643e9753d6SMatthew G. Knepley   } else {
69653e9753d6SMatthew G. Knepley     PetscInt f;
69663e9753d6SMatthew G. Knepley     for (f = 0; f < Nf; ++f) {
6967989fa639SBrad Aagaard       if (geomsF) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quadsF[f], PETSC_FALSE, &geomsF[f]));
6968989fa639SBrad Aagaard       if (quadsF) PetscCall(PetscQuadratureDestroy(&quadsF[f]));
69693e9753d6SMatthew G. Knepley     }
6970989fa639SBrad Aagaard     PetscCall(PetscFree2(quadsF, geomsF));
69713e9753d6SMatthew G. Knepley   }
69729566063dSJacob Faibussowitsch   if (dmAux[2]) PetscCall(DMDestroy(&plexA));
69739566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
69743cc88e6aSStefano Zampini end:
69759566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
69763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
69773e9753d6SMatthew G. Knepley }
69788e3a2eefSMatthew G. Knepley 
6979754e4fbaSMatthew G. Knepley /*@
6980754e4fbaSMatthew G. Knepley   DMPlexComputeJacobianActionByKey - Compute the local Jacobian for terms matching the input key
6981754e4fbaSMatthew G. Knepley 
6982754e4fbaSMatthew G. Knepley   Collective
69838e3a2eefSMatthew G. Knepley 
69848e3a2eefSMatthew G. Knepley   Input Parameters:
6985754e4fbaSMatthew G. Knepley + dm       - The output `DM`
6986754e4fbaSMatthew G. Knepley . key      - The `PetscFormKey` indicating what should be integrated
6987754e4fbaSMatthew G. Knepley . cellIS   - The `IS` give a set of cells to integrate over
69888e3a2eefSMatthew G. Knepley . t        - The time
6989754e4fbaSMatthew G. Knepley . X_tShift - The multiplier for the Jacobian with respect to $X_t$
6990754e4fbaSMatthew G. Knepley . locX     - The local solution
6991754e4fbaSMatthew G. Knepley . locX_t   - The time derivative of the local solution, or `NULL` for time-independent problems
6992754e4fbaSMatthew G. Knepley . locY     - The local vector acted on by J
6993*2a8381b2SBarry Smith - ctx      - An optional application context, passed to the pointwise functions
69948e3a2eefSMatthew G. Knepley 
69958e3a2eefSMatthew G. Knepley   Output Parameter:
6996754e4fbaSMatthew G. Knepley . locF - The local residual F = J(X) Y
69978e3a2eefSMatthew G. Knepley 
6998754e4fbaSMatthew G. Knepley   Level: developer
6999754e4fbaSMatthew G. Knepley 
7000754e4fbaSMatthew G. Knepley .seealso: `DMPlexComputeResidualByKey()`, `DMPlexComputeJacobianByKey()`, `DMPlexComputeResidualHybridByKey()`, `DMPlexComputeJacobianHybridByKey()`, `PetscFormKey`
7001754e4fbaSMatthew G. Knepley @*/
DMPlexComputeJacobianActionByKey(DM dm,PetscFormKey key,IS cellIS,PetscReal t,PetscReal X_tShift,Vec locX,Vec locX_t,Vec locY,Vec locF,PetscCtx ctx)7002*2a8381b2SBarry Smith PetscErrorCode DMPlexComputeJacobianActionByKey(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Vec locY, Vec locF, PetscCtx ctx)
7003d71ae5a4SJacob Faibussowitsch {
70048e3a2eefSMatthew G. Knepley   DM_Plex        *mesh  = (DM_Plex *)dm->data;
70058e3a2eefSMatthew G. Knepley   const char     *name  = "Jacobian";
70068e3a2eefSMatthew G. Knepley   DM              dmAux = NULL, plex, plexAux = NULL;
70078e3a2eefSMatthew G. Knepley   DMEnclosureType encAux;
70088e3a2eefSMatthew G. Knepley   Vec             A;
70098e3a2eefSMatthew G. Knepley   DMField         coordField;
70108e3a2eefSMatthew G. Knepley   PetscDS         prob, probAux = NULL;
70118e3a2eefSMatthew G. Knepley   PetscQuadrature quad;
70128e3a2eefSMatthew G. Knepley   PetscSection    section, globalSection, sectionAux;
70138e3a2eefSMatthew G. Knepley   PetscScalar    *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z;
70148e3a2eefSMatthew G. Knepley   const PetscInt *cells;
70158e3a2eefSMatthew G. Knepley   PetscInt        Nf, fieldI, fieldJ;
70168e3a2eefSMatthew G. Knepley   PetscInt        totDim, totDimAux = 0, cStart, cEnd, numCells, c;
70178e3a2eefSMatthew G. Knepley   PetscBool       hasDyn;
70188e3a2eefSMatthew G. Knepley 
70198e3a2eefSMatthew G. Knepley   PetscFunctionBegin;
70209566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0));
70219566063dSJacob Faibussowitsch   PetscCall(DMConvert(dm, DMPLEX, &plex));
70229566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(cellIS, &numCells));
70239566063dSJacob Faibussowitsch   PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells));
70249566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(dm, &section));
70259566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dm, &globalSection));
702607218a29SMatthew G. Knepley   PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob, NULL));
70279566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(prob, &Nf));
70289566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(prob, &totDim));
70299566063dSJacob Faibussowitsch   PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn));
70308e3a2eefSMatthew G. Knepley   hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE;
70319566063dSJacob Faibussowitsch   PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A));
70328e3a2eefSMatthew G. Knepley   if (A) {
70339566063dSJacob Faibussowitsch     PetscCall(VecGetDM(A, &dmAux));
70349566063dSJacob Faibussowitsch     PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux));
70359566063dSJacob Faibussowitsch     PetscCall(DMConvert(dmAux, DMPLEX, &plexAux));
70369566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(plexAux, &sectionAux));
70379566063dSJacob Faibussowitsch     PetscCall(DMGetDS(dmAux, &probAux));
70389566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux));
70398e3a2eefSMatthew G. Knepley   }
7040754e4fbaSMatthew G. Knepley   PetscCall(VecSet(locF, 0.0));
7041754e4fbaSMatthew G. Knepley   PetscCall(PetscMalloc6(numCells * totDim, &u, (locX_t ? (size_t)numCells * totDim : 0), &u_t, numCells * totDim * totDim, &elemMat, (hasDyn ? (size_t)numCells * totDim * totDim : 0), &elemMatD, numCells * totDim, &y, totDim, &z));
70429566063dSJacob Faibussowitsch   if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a));
70439566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateField(dm, &coordField));
70448e3a2eefSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
70458e3a2eefSMatthew G. Knepley     const PetscInt cell = cells ? cells[c] : c;
70468e3a2eefSMatthew G. Knepley     const PetscInt cind = c - cStart;
70478e3a2eefSMatthew G. Knepley     PetscScalar   *x = NULL, *x_t = NULL;
70488e3a2eefSMatthew G. Knepley     PetscInt       i;
70498e3a2eefSMatthew G. Knepley 
7050754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x));
70518e3a2eefSMatthew G. Knepley     for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i];
7052754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x));
7053754e4fbaSMatthew G. Knepley     if (locX_t) {
7054754e4fbaSMatthew G. Knepley       PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t));
70558e3a2eefSMatthew G. Knepley       for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i];
7056754e4fbaSMatthew G. Knepley       PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t));
70578e3a2eefSMatthew G. Knepley     }
70588e3a2eefSMatthew G. Knepley     if (dmAux) {
70598e3a2eefSMatthew G. Knepley       PetscInt subcell;
70609566063dSJacob Faibussowitsch       PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell));
70619566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x));
70628e3a2eefSMatthew G. Knepley       for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i];
70639566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x));
70648e3a2eefSMatthew G. Knepley     }
7065754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecGetClosure(plex, section, locY, cell, NULL, &x));
70668e3a2eefSMatthew G. Knepley     for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i];
7067754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecRestoreClosure(plex, section, locY, cell, NULL, &x));
70688e3a2eefSMatthew G. Knepley   }
70699566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim));
70709566063dSJacob Faibussowitsch   if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim));
70718e3a2eefSMatthew G. Knepley   for (fieldI = 0; fieldI < Nf; ++fieldI) {
70728e3a2eefSMatthew G. Knepley     PetscFE  fe;
70738e3a2eefSMatthew G. Knepley     PetscInt Nb;
70748e3a2eefSMatthew G. Knepley     /* Conforming batches */
70758e3a2eefSMatthew G. Knepley     PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize;
70768e3a2eefSMatthew G. Knepley     /* Remainder */
70778e3a2eefSMatthew G. Knepley     PetscInt        Nr, offset, Nq;
70788e3a2eefSMatthew G. Knepley     PetscQuadrature qGeom = NULL;
70798e3a2eefSMatthew G. Knepley     PetscInt        maxDegree;
70808e3a2eefSMatthew G. Knepley     PetscFEGeom    *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL;
70818e3a2eefSMatthew G. Knepley 
70829566063dSJacob Faibussowitsch     PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe));
70839566063dSJacob Faibussowitsch     PetscCall(PetscFEGetQuadrature(fe, &quad));
70849566063dSJacob Faibussowitsch     PetscCall(PetscFEGetDimension(fe, &Nb));
70859566063dSJacob Faibussowitsch     PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches));
70869566063dSJacob Faibussowitsch     PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree));
70879566063dSJacob Faibussowitsch     if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom));
70888e3a2eefSMatthew G. Knepley     if (!qGeom) {
70899566063dSJacob Faibussowitsch       PetscCall(PetscFEGetQuadrature(fe, &qGeom));
70909566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)qGeom));
70918e3a2eefSMatthew G. Knepley     }
70929566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL));
7093ac9d17c7SMatthew G. Knepley     PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FEGEOM_BASIC, &cgeomFEM));
70948e3a2eefSMatthew G. Knepley     blockSize = Nb;
70958e3a2eefSMatthew G. Knepley     batchSize = numBlocks * blockSize;
70969566063dSJacob Faibussowitsch     PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches));
70978e3a2eefSMatthew G. Knepley     numChunks = numCells / (numBatches * batchSize);
70988e3a2eefSMatthew G. Knepley     Ne        = numChunks * numBatches * batchSize;
70998e3a2eefSMatthew G. Knepley     Nr        = numCells % (numBatches * batchSize);
71008e3a2eefSMatthew G. Knepley     offset    = numCells - Nr;
71019566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom));
71029566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom));
71038e3a2eefSMatthew G. Knepley     for (fieldJ = 0; fieldJ < Nf; ++fieldJ) {
71048e3a2eefSMatthew G. Knepley       key.field = fieldI * Nf + fieldJ;
71054561e6c9SMatthew G. Knepley       PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat));
71064561e6c9SMatthew G. Knepley       PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, PetscSafePointerPlusOffset(a, offset * totDimAux), t, X_tShift, &elemMat[offset * totDim * totDim]));
71078e3a2eefSMatthew G. Knepley       if (hasDyn) {
71084561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD));
71094561e6c9SMatthew G. Knepley         PetscCall(PetscFEIntegrateJacobian(prob, prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], PetscSafePointerPlusOffset(u_t, offset * totDim), probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim]));
71108e3a2eefSMatthew G. Knepley       }
71118e3a2eefSMatthew G. Knepley     }
71129566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom));
71139566063dSJacob Faibussowitsch     PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom));
71149566063dSJacob Faibussowitsch     PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM));
71159566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&qGeom));
71168e3a2eefSMatthew G. Knepley   }
71178e3a2eefSMatthew G. Knepley   if (hasDyn) {
71188e3a2eefSMatthew G. Knepley     for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c];
71198e3a2eefSMatthew G. Knepley   }
71208e3a2eefSMatthew G. Knepley   for (c = cStart; c < cEnd; ++c) {
71218e3a2eefSMatthew G. Knepley     const PetscInt     cell = cells ? cells[c] : c;
71228e3a2eefSMatthew G. Knepley     const PetscInt     cind = c - cStart;
71236497c311SBarry Smith     const PetscBLASInt one  = 1;
71246497c311SBarry Smith     PetscBLASInt       M;
71258e3a2eefSMatthew G. Knepley     const PetscScalar  a = 1.0, b = 0.0;
71268e3a2eefSMatthew G. Knepley 
71276497c311SBarry Smith     PetscCall(PetscBLASIntCast(totDim, &M));
7128792fecdfSBarry Smith     PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one));
71298e3a2eefSMatthew G. Knepley     if (mesh->printFEM > 1) {
71309566063dSJacob Faibussowitsch       PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim]));
71319566063dSJacob Faibussowitsch       PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim]));
71329566063dSJacob Faibussowitsch       PetscCall(DMPrintCellVector(c, "Z", totDim, z));
71338e3a2eefSMatthew G. Knepley     }
7134754e4fbaSMatthew G. Knepley     PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, z, ADD_VALUES));
71358e3a2eefSMatthew G. Knepley   }
71369566063dSJacob Faibussowitsch   PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z));
71378e3a2eefSMatthew G. Knepley   if (mesh->printFEM) {
7138754e4fbaSMatthew G. Knepley     PetscCall(PetscPrintf(PetscObjectComm((PetscObject)locF), "Z:\n"));
7139754e4fbaSMatthew G. Knepley     PetscCall(VecView(locF, NULL));
71408e3a2eefSMatthew G. Knepley   }
71411059d808SMatthew G. Knepley   PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells));
71429566063dSJacob Faibussowitsch   PetscCall(PetscFree(a));
71439566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plexAux));
71449566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&plex));
71459566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0));
71463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
71478e3a2eefSMatthew G. Knepley }
7148d52c2f21SMatthew G. Knepley 
f0_1(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])7149d52c2f21SMatthew G. Knepley static void f0_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
7150d52c2f21SMatthew G. Knepley {
7151d52c2f21SMatthew G. Knepley   f0[0] = u[0];
7152d52c2f21SMatthew G. Knepley }
7153d52c2f21SMatthew G. Knepley 
f0_x(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])7154d52c2f21SMatthew G. Knepley static void f0_x(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
7155d52c2f21SMatthew G. Knepley {
7156d52c2f21SMatthew G. Knepley   f0[0] = x[(int)PetscRealPart(constants[0])] * u[0];
7157d52c2f21SMatthew G. Knepley }
7158d52c2f21SMatthew G. Knepley 
f0_x2(PetscInt dim,PetscInt Nf,PetscInt NfAux,const PetscInt uOff[],const PetscInt uOff_x[],const PetscScalar u[],const PetscScalar u_t[],const PetscScalar u_x[],const PetscInt aOff[],const PetscInt aOff_x[],const PetscScalar a[],const PetscScalar a_t[],const PetscScalar a_x[],PetscReal t,const PetscReal x[],PetscInt numConstants,const PetscScalar constants[],PetscScalar f0[])7159d52c2f21SMatthew G. Knepley static void f0_x2(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[])
7160d52c2f21SMatthew G. Knepley {
7161d52c2f21SMatthew G. Knepley   PetscInt d;
7162d52c2f21SMatthew G. Knepley 
7163d52c2f21SMatthew G. Knepley   f0[0] = 0.0;
7164d52c2f21SMatthew G. Knepley   for (d = 0; d < dim; ++d) f0[0] += PetscSqr(x[d]) * u[0];
7165d52c2f21SMatthew G. Knepley }
7166d52c2f21SMatthew G. Knepley 
7167d52c2f21SMatthew G. Knepley /*@
7168d52c2f21SMatthew G. Knepley   DMPlexComputeMoments - Compute the first three moments for a field
7169d52c2f21SMatthew G. Knepley 
7170d52c2f21SMatthew G. Knepley   Noncollective
7171d52c2f21SMatthew G. Knepley 
7172d52c2f21SMatthew G. Knepley   Input Parameters:
7173d52c2f21SMatthew G. Knepley + dm - the `DMPLEX`
7174d52c2f21SMatthew G. Knepley - u  - the field
7175d52c2f21SMatthew G. Knepley 
7176d52c2f21SMatthew G. Knepley   Output Parameter:
7177d52c2f21SMatthew G. Knepley . moments - the field moments
7178d52c2f21SMatthew G. Knepley 
7179d52c2f21SMatthew G. Knepley   Level: intermediate
7180d52c2f21SMatthew G. Knepley 
7181d52c2f21SMatthew G. Knepley   Note:
718217314648SMatthew G. Knepley   The `moments` array should be of length cdim + 2, where cdim is the number of components for the coordinate field.
7183d52c2f21SMatthew G. Knepley 
7184d52c2f21SMatthew G. Knepley .seealso: `DM`, `DMPLEX`, `DMSwarmComputeMoments()`
7185d52c2f21SMatthew G. Knepley @*/
DMPlexComputeMoments(DM dm,Vec u,PetscReal moments[])7186d52c2f21SMatthew G. Knepley PetscErrorCode DMPlexComputeMoments(DM dm, Vec u, PetscReal moments[])
7187d52c2f21SMatthew G. Knepley {
7188d52c2f21SMatthew G. Knepley   PetscDS            ds;
7189d52c2f21SMatthew G. Knepley   PetscScalar        mom, constants[1];
7190d52c2f21SMatthew G. Knepley   const PetscScalar *oldConstants;
719117314648SMatthew G. Knepley   PetscInt           cdim, Nf, field = 0, Ncon;
7192d52c2f21SMatthew G. Knepley   MPI_Comm           comm;
7193*2a8381b2SBarry Smith   void              *ctx;
7194d52c2f21SMatthew G. Knepley 
7195d52c2f21SMatthew G. Knepley   PetscFunctionBeginUser;
7196d52c2f21SMatthew G. Knepley   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
719717314648SMatthew G. Knepley   PetscCall(DMGetCoordinateDim(dm, &cdim));
7198*2a8381b2SBarry Smith   PetscCall(DMGetApplicationContext(dm, &ctx));
7199d52c2f21SMatthew G. Knepley   PetscCall(DMGetDS(dm, &ds));
7200d52c2f21SMatthew G. Knepley   PetscCall(PetscDSGetNumFields(ds, &Nf));
7201d52c2f21SMatthew G. Knepley   PetscCall(PetscDSGetConstants(ds, &Ncon, &oldConstants));
7202d52c2f21SMatthew G. Knepley   PetscCheck(Nf == 1, comm, PETSC_ERR_ARG_WRONG, "We currently only support 1 field, not %" PetscInt_FMT, Nf);
7203d52c2f21SMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, field, &f0_1));
7204*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, ctx));
7205d52c2f21SMatthew G. Knepley   moments[0] = PetscRealPart(mom);
720617314648SMatthew G. Knepley   for (PetscInt c = 0; c < cdim; ++c) {
7207d52c2f21SMatthew G. Knepley     constants[0] = c;
720817314648SMatthew G. Knepley     PetscCall(PetscDSSetConstants(ds, 1, constants));
7209d52c2f21SMatthew G. Knepley     PetscCall(PetscDSSetObjective(ds, field, &f0_x));
7210*2a8381b2SBarry Smith     PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, ctx));
7211d52c2f21SMatthew G. Knepley     moments[c + 1] = PetscRealPart(mom);
7212d52c2f21SMatthew G. Knepley   }
7213d52c2f21SMatthew G. Knepley   PetscCall(PetscDSSetObjective(ds, field, &f0_x2));
7214*2a8381b2SBarry Smith   PetscCall(DMPlexComputeIntegralFEM(dm, u, &mom, ctx));
721517314648SMatthew G. Knepley   moments[cdim + 1] = PetscRealPart(mom);
7216d52c2f21SMatthew G. Knepley   PetscCall(PetscDSSetConstants(ds, Ncon, (PetscScalar *)oldConstants));
7217d52c2f21SMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
7218d52c2f21SMatthew G. Knepley }
7219