xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision dce8aeba1c9b69b19f651c53d8a6b674bd7e9cbd)
120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
220cf1dd8SToby Isaac #include <petscdmplex.h>
320cf1dd8SToby Isaac 
420cf1dd8SToby Isaac PetscClassId PETSCDUALSPACE_CLASSID = 0;
520cf1dd8SToby Isaac 
6ead873ccSMatthew G. Knepley PetscLogEvent PETSCDUALSPACE_SetUp;
7ead873ccSMatthew G. Knepley 
820cf1dd8SToby Isaac PetscFunctionList PetscDualSpaceList              = NULL;
920cf1dd8SToby Isaac PetscBool         PetscDualSpaceRegisterAllCalled = PETSC_FALSE;
1020cf1dd8SToby Isaac 
116f905325SMatthew G. Knepley /*
126f905325SMatthew G. Knepley   PetscDualSpaceLatticePointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to at most 'max'.
136f905325SMatthew G. Knepley                                                      Ordering is lexicographic with lowest index as least significant in ordering.
14b4457527SToby Isaac                                                      e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {0,2}.
156f905325SMatthew G. Knepley 
166f905325SMatthew G. Knepley   Input Parameters:
176f905325SMatthew G. Knepley + len - The length of the tuple
186f905325SMatthew G. Knepley . max - The maximum sum
196f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
206f905325SMatthew G. Knepley 
216f905325SMatthew G. Knepley   Output Parameter:
226f905325SMatthew G. Knepley . tup - A tuple of len integers whos sum is at most 'max'
236f905325SMatthew G. Knepley 
246f905325SMatthew G. Knepley   Level: developer
256f905325SMatthew G. Knepley 
26*dce8aebaSBarry Smith .seealso: `PetscDualSpaceType`, `PetscDualSpaceTensorPointLexicographic_Internal()`
276f905325SMatthew G. Knepley */
28d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceLatticePointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[])
29d71ae5a4SJacob Faibussowitsch {
306f905325SMatthew G. Knepley   PetscFunctionBegin;
316f905325SMatthew G. Knepley   while (len--) {
326f905325SMatthew G. Knepley     max -= tup[len];
336f905325SMatthew G. Knepley     if (!max) {
346f905325SMatthew G. Knepley       tup[len] = 0;
356f905325SMatthew G. Knepley       break;
366f905325SMatthew G. Knepley     }
376f905325SMatthew G. Knepley   }
386f905325SMatthew G. Knepley   tup[++len]++;
396f905325SMatthew G. Knepley   PetscFunctionReturn(0);
406f905325SMatthew G. Knepley }
416f905325SMatthew G. Knepley 
426f905325SMatthew G. Knepley /*
436f905325SMatthew G. Knepley   PetscDualSpaceTensorPointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max'.
446f905325SMatthew G. Knepley                                                     Ordering is lexicographic with lowest index as least significant in ordering.
456f905325SMatthew G. Knepley                                                     e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}.
466f905325SMatthew G. Knepley 
476f905325SMatthew G. Knepley   Input Parameters:
486f905325SMatthew G. Knepley + len - The length of the tuple
496f905325SMatthew G. Knepley . max - The maximum value
506f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
516f905325SMatthew G. Knepley 
526f905325SMatthew G. Knepley   Output Parameter:
536f905325SMatthew G. Knepley . tup - A tuple of len integers whos sum is at most 'max'
546f905325SMatthew G. Knepley 
556f905325SMatthew G. Knepley   Level: developer
566f905325SMatthew G. Knepley 
57*dce8aebaSBarry Smith .seealso: `PetscDualSpaceType`, `PetscDualSpaceLatticePointLexicographic_Internal()`
586f905325SMatthew G. Knepley */
59d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTensorPointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[])
60d71ae5a4SJacob Faibussowitsch {
616f905325SMatthew G. Knepley   PetscInt i;
626f905325SMatthew G. Knepley 
636f905325SMatthew G. Knepley   PetscFunctionBegin;
646f905325SMatthew G. Knepley   for (i = 0; i < len; i++) {
656f905325SMatthew G. Knepley     if (tup[i] < max) {
666f905325SMatthew G. Knepley       break;
676f905325SMatthew G. Knepley     } else {
686f905325SMatthew G. Knepley       tup[i] = 0;
696f905325SMatthew G. Knepley     }
706f905325SMatthew G. Knepley   }
716f905325SMatthew G. Knepley   tup[i]++;
726f905325SMatthew G. Knepley   PetscFunctionReturn(0);
736f905325SMatthew G. Knepley }
746f905325SMatthew G. Knepley 
7520cf1dd8SToby Isaac /*@C
76*dce8aebaSBarry Smith   PetscDualSpaceRegister - Adds a new `PetscDualSpaceType`
7720cf1dd8SToby Isaac 
7820cf1dd8SToby Isaac   Not Collective
7920cf1dd8SToby Isaac 
8020cf1dd8SToby Isaac   Input Parameters:
8120cf1dd8SToby Isaac + name        - The name of a new user-defined creation routine
8220cf1dd8SToby Isaac - create_func - The creation routine itself
8320cf1dd8SToby Isaac 
8420cf1dd8SToby Isaac   Sample usage:
8520cf1dd8SToby Isaac .vb
8620cf1dd8SToby Isaac     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
8720cf1dd8SToby Isaac .ve
8820cf1dd8SToby Isaac 
8920cf1dd8SToby Isaac   Then, your PetscDualSpace type can be chosen with the procedural interface via
9020cf1dd8SToby Isaac .vb
9120cf1dd8SToby Isaac     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
9220cf1dd8SToby Isaac     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
9320cf1dd8SToby Isaac .ve
9420cf1dd8SToby Isaac    or at runtime via the option
9520cf1dd8SToby Isaac .vb
9620cf1dd8SToby Isaac     -petscdualspace_type my_dual_space
9720cf1dd8SToby Isaac .ve
9820cf1dd8SToby Isaac 
9920cf1dd8SToby Isaac   Level: advanced
10020cf1dd8SToby Isaac 
101*dce8aebaSBarry Smith   Note:
102*dce8aebaSBarry Smith   `PetscDualSpaceRegister()` may be called multiple times to add several user-defined `PetscDualSpace`
10320cf1dd8SToby Isaac 
104*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceRegisterAll()`, `PetscDualSpaceRegisterDestroy()`
10520cf1dd8SToby Isaac @*/
106d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace))
107d71ae5a4SJacob Faibussowitsch {
10820cf1dd8SToby Isaac   PetscFunctionBegin;
1099566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PetscDualSpaceList, sname, function));
11020cf1dd8SToby Isaac   PetscFunctionReturn(0);
11120cf1dd8SToby Isaac }
11220cf1dd8SToby Isaac 
11320cf1dd8SToby Isaac /*@C
114*dce8aebaSBarry Smith   PetscDualSpaceSetType - Builds a particular `PetscDualSpace` based on its `PetscDualSpaceType`
11520cf1dd8SToby Isaac 
116d083f849SBarry Smith   Collective on sp
11720cf1dd8SToby Isaac 
11820cf1dd8SToby Isaac   Input Parameters:
119*dce8aebaSBarry Smith + sp   - The `PetscDualSpace` object
12020cf1dd8SToby Isaac - name - The kind of space
12120cf1dd8SToby Isaac 
12220cf1dd8SToby Isaac   Options Database Key:
12320cf1dd8SToby Isaac . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types
12420cf1dd8SToby Isaac 
12520cf1dd8SToby Isaac   Level: intermediate
12620cf1dd8SToby Isaac 
127*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceGetType()`, `PetscDualSpaceCreate()`
12820cf1dd8SToby Isaac @*/
129d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name)
130d71ae5a4SJacob Faibussowitsch {
13120cf1dd8SToby Isaac   PetscErrorCode (*r)(PetscDualSpace);
13220cf1dd8SToby Isaac   PetscBool match;
13320cf1dd8SToby Isaac 
13420cf1dd8SToby Isaac   PetscFunctionBegin;
13520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)sp, name, &match));
13720cf1dd8SToby Isaac   if (match) PetscFunctionReturn(0);
13820cf1dd8SToby Isaac 
1399566063dSJacob Faibussowitsch   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
1409566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PetscDualSpaceList, name, &r));
14128b400f6SJacob Faibussowitsch   PetscCheck(r, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name);
14220cf1dd8SToby Isaac 
143dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, destroy);
14420cf1dd8SToby Isaac   sp->ops->destroy = NULL;
145dbbe0bcdSBarry Smith 
1469566063dSJacob Faibussowitsch   PetscCall((*r)(sp));
1479566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)sp, name));
14820cf1dd8SToby Isaac   PetscFunctionReturn(0);
14920cf1dd8SToby Isaac }
15020cf1dd8SToby Isaac 
15120cf1dd8SToby Isaac /*@C
152*dce8aebaSBarry Smith   PetscDualSpaceGetType - Gets the `PetscDualSpaceType` name (as a string) from the object.
15320cf1dd8SToby Isaac 
15420cf1dd8SToby Isaac   Not Collective
15520cf1dd8SToby Isaac 
15620cf1dd8SToby Isaac   Input Parameter:
157*dce8aebaSBarry Smith . sp  - The `PetscDualSpace`
15820cf1dd8SToby Isaac 
15920cf1dd8SToby Isaac   Output Parameter:
160*dce8aebaSBarry Smith . name - The `PetscDualSpaceType` name
16120cf1dd8SToby Isaac 
16220cf1dd8SToby Isaac   Level: intermediate
16320cf1dd8SToby Isaac 
164*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceSetType()`, `PetscDualSpaceCreate()`
16520cf1dd8SToby Isaac @*/
166d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name)
167d71ae5a4SJacob Faibussowitsch {
16820cf1dd8SToby Isaac   PetscFunctionBegin;
16920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
17020cf1dd8SToby Isaac   PetscValidPointer(name, 2);
17148a46eb9SPierre Jolivet   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
17220cf1dd8SToby Isaac   *name = ((PetscObject)sp)->type_name;
17320cf1dd8SToby Isaac   PetscFunctionReturn(0);
17420cf1dd8SToby Isaac }
17520cf1dd8SToby Isaac 
176d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceView_ASCII(PetscDualSpace sp, PetscViewer v)
177d71ae5a4SJacob Faibussowitsch {
178221d6281SMatthew G. Knepley   PetscViewerFormat format;
179221d6281SMatthew G. Knepley   PetscInt          pdim, f;
180221d6281SMatthew G. Knepley 
181221d6281SMatthew G. Knepley   PetscFunctionBegin;
1829566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &pdim));
1839566063dSJacob Faibussowitsch   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sp, v));
1849566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(v));
185b4457527SToby Isaac   if (sp->k) {
18663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space for %" PetscInt_FMT "-forms %swith %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", PetscAbsInt(sp->k), sp->k < 0 ? "(stored in dual form) " : "", sp->Nc, pdim));
187b4457527SToby Isaac   } else {
18863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space with %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", sp->Nc, pdim));
189b4457527SToby Isaac   }
190dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, view, v);
1919566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(v, &format));
192221d6281SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(v));
194221d6281SMatthew G. Knepley     for (f = 0; f < pdim; ++f) {
19563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(v, "Dual basis vector %" PetscInt_FMT "\n", f));
1969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(v));
1979566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureView(sp->functional[f], v));
1989566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(v));
199221d6281SMatthew G. Knepley     }
2009566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(v));
201221d6281SMatthew G. Knepley   }
2029566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
203221d6281SMatthew G. Knepley   PetscFunctionReturn(0);
204221d6281SMatthew G. Knepley }
205221d6281SMatthew G. Knepley 
206fe2efc57SMark /*@C
207*dce8aebaSBarry Smith    PetscDualSpaceViewFromOptions - View a `PetscDualSpace` based on values in the options database
208fe2efc57SMark 
209*dce8aebaSBarry Smith    Collective on A
210fe2efc57SMark 
211fe2efc57SMark    Input Parameters:
212*dce8aebaSBarry Smith +  A - the `PetscDualSpace` object
213*dce8aebaSBarry Smith .  obj - Optional object, provides the options prefix
214*dce8aebaSBarry Smith -  name - command line option name
215fe2efc57SMark 
216fe2efc57SMark    Level: intermediate
217*dce8aebaSBarry Smith 
218db781477SPatrick Sanan .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()`
219fe2efc57SMark @*/
220d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PetscObject obj, const char name[])
221d71ae5a4SJacob Faibussowitsch {
222fe2efc57SMark   PetscFunctionBegin;
223fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
2249566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
225fe2efc57SMark   PetscFunctionReturn(0);
226fe2efc57SMark }
227fe2efc57SMark 
22820cf1dd8SToby Isaac /*@
229*dce8aebaSBarry Smith   PetscDualSpaceView - Views a `PetscDualSpace`
23020cf1dd8SToby Isaac 
231d083f849SBarry Smith   Collective on sp
23220cf1dd8SToby Isaac 
233d8d19677SJose E. Roman   Input Parameters:
234*dce8aebaSBarry Smith + sp - the `PetscDualSpace` object to view
23520cf1dd8SToby Isaac - v  - the viewer
23620cf1dd8SToby Isaac 
237a4ce7ad1SMatthew G. Knepley   Level: beginner
23820cf1dd8SToby Isaac 
239*dce8aebaSBarry Smith .seealso: `PetscViewer`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
24020cf1dd8SToby Isaac @*/
241d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
242d71ae5a4SJacob Faibussowitsch {
243d9bac1caSLisandro Dalcin   PetscBool iascii;
24420cf1dd8SToby Isaac 
24520cf1dd8SToby Isaac   PetscFunctionBegin;
24620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
247d9bac1caSLisandro Dalcin   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
2489566063dSJacob Faibussowitsch   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v));
2499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
2509566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v));
25120cf1dd8SToby Isaac   PetscFunctionReturn(0);
25220cf1dd8SToby Isaac }
25320cf1dd8SToby Isaac 
25420cf1dd8SToby Isaac /*@
255*dce8aebaSBarry Smith   PetscDualSpaceSetFromOptions - sets parameters in a `PetscDualSpace` from the options database
25620cf1dd8SToby Isaac 
257d083f849SBarry Smith   Collective on sp
25820cf1dd8SToby Isaac 
25920cf1dd8SToby Isaac   Input Parameter:
260*dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to set options for
26120cf1dd8SToby Isaac 
262*dce8aebaSBarry Smith   Options Database Keys:
2638f2aacc6SMatthew G. Knepley + -petscdualspace_order <order>      - the approximation order of the space
264fe36a153SMatthew G. Knepley . -petscdualspace_form_degree <deg>  - the form degree, say 0 for point evaluations, or 2 for area integrals
2658f2aacc6SMatthew G. Knepley . -petscdualspace_components <c>     - the number of components, say d for a vector field
2668f2aacc6SMatthew G. Knepley - -petscdualspace_refcell <celltype> - Reference cell type name
26720cf1dd8SToby Isaac 
268a4ce7ad1SMatthew G. Knepley   Level: intermediate
26920cf1dd8SToby Isaac 
270*dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()`
27120cf1dd8SToby Isaac @*/
272d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
273d71ae5a4SJacob Faibussowitsch {
2742df84da0SMatthew G. Knepley   DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE;
27520cf1dd8SToby Isaac   const char    *defaultType;
27620cf1dd8SToby Isaac   char           name[256];
277f783ec47SMatthew G. Knepley   PetscBool      flg;
27820cf1dd8SToby Isaac 
27920cf1dd8SToby Isaac   PetscFunctionBegin;
28020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
28120cf1dd8SToby Isaac   if (!((PetscObject)sp)->type_name) {
28220cf1dd8SToby Isaac     defaultType = PETSCDUALSPACELAGRANGE;
28320cf1dd8SToby Isaac   } else {
28420cf1dd8SToby Isaac     defaultType = ((PetscObject)sp)->type_name;
28520cf1dd8SToby Isaac   }
2869566063dSJacob Faibussowitsch   if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll());
28720cf1dd8SToby Isaac 
288d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sp);
2899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg));
29020cf1dd8SToby Isaac   if (flg) {
2919566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, name));
29220cf1dd8SToby Isaac   } else if (!((PetscObject)sp)->type_name) {
2939566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, defaultType));
29420cf1dd8SToby Isaac   }
2959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0));
2969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL));
2979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1));
298dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject);
2999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg));
300063ee4adSMatthew G. Knepley   if (flg) {
301063ee4adSMatthew G. Knepley     DM K;
302063ee4adSMatthew G. Knepley 
3039566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K));
3049566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetDM(sp, K));
3059566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&K));
306063ee4adSMatthew G. Knepley   }
307063ee4adSMatthew G. Knepley 
30820cf1dd8SToby Isaac   /* process any options handlers added with PetscObjectAddOptionsHandler() */
309dbbe0bcdSBarry Smith   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject));
310d0609cedSBarry Smith   PetscOptionsEnd();
311063ee4adSMatthew G. Knepley   sp->setfromoptionscalled = PETSC_TRUE;
31220cf1dd8SToby Isaac   PetscFunctionReturn(0);
31320cf1dd8SToby Isaac }
31420cf1dd8SToby Isaac 
31520cf1dd8SToby Isaac /*@
316*dce8aebaSBarry Smith   PetscDualSpaceSetUp - Construct a basis for a `PetscDualSpace`
31720cf1dd8SToby Isaac 
318d083f849SBarry Smith   Collective on sp
31920cf1dd8SToby Isaac 
32020cf1dd8SToby Isaac   Input Parameter:
321*dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to setup
32220cf1dd8SToby Isaac 
323a4ce7ad1SMatthew G. Knepley   Level: intermediate
32420cf1dd8SToby Isaac 
325*dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
32620cf1dd8SToby Isaac @*/
327d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
328d71ae5a4SJacob Faibussowitsch {
32920cf1dd8SToby Isaac   PetscFunctionBegin;
33020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
33120cf1dd8SToby Isaac   if (sp->setupcalled) PetscFunctionReturn(0);
3329566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
33320cf1dd8SToby Isaac   sp->setupcalled = PETSC_TRUE;
334dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setup);
3359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
3369566063dSJacob Faibussowitsch   if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view"));
33720cf1dd8SToby Isaac   PetscFunctionReturn(0);
33820cf1dd8SToby Isaac }
33920cf1dd8SToby Isaac 
340d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm)
341d71ae5a4SJacob Faibussowitsch {
342b4457527SToby Isaac   PetscInt pStart = -1, pEnd = -1, depth = -1;
343b4457527SToby Isaac 
344b4457527SToby Isaac   PetscFunctionBegin;
345b4457527SToby Isaac   if (!dm) PetscFunctionReturn(0);
3469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
348b4457527SToby Isaac 
349b4457527SToby Isaac   if (sp->pointSpaces) {
350b4457527SToby Isaac     PetscInt i;
351b4457527SToby Isaac 
35248a46eb9SPierre Jolivet     for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&(sp->pointSpaces[i])));
353b4457527SToby Isaac   }
3549566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->pointSpaces));
355b4457527SToby Isaac 
356b4457527SToby Isaac   if (sp->heightSpaces) {
357b4457527SToby Isaac     PetscInt i;
358b4457527SToby Isaac 
35948a46eb9SPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&(sp->heightSpaces[i])));
360b4457527SToby Isaac   }
3619566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
362b4457527SToby Isaac 
3639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&(sp->pointSection)));
3649566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
3659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intDofValues)));
3669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intNodeValues)));
3679566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->intMat)));
3689566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
3699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allDofValues)));
3709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allNodeValues)));
3719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->allMat)));
3729566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
373b4457527SToby Isaac   PetscFunctionReturn(0);
374b4457527SToby Isaac }
375b4457527SToby Isaac 
37620cf1dd8SToby Isaac /*@
377*dce8aebaSBarry Smith   PetscDualSpaceDestroy - Destroys a `PetscDualSpace` object
37820cf1dd8SToby Isaac 
379d083f849SBarry Smith   Collective on sp
38020cf1dd8SToby Isaac 
38120cf1dd8SToby Isaac   Input Parameter:
382*dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to destroy
38320cf1dd8SToby Isaac 
384a4ce7ad1SMatthew G. Knepley   Level: beginner
38520cf1dd8SToby Isaac 
386*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
38720cf1dd8SToby Isaac @*/
388d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
389d71ae5a4SJacob Faibussowitsch {
39020cf1dd8SToby Isaac   PetscInt dim, f;
391b4457527SToby Isaac   DM       dm;
39220cf1dd8SToby Isaac 
39320cf1dd8SToby Isaac   PetscFunctionBegin;
39420cf1dd8SToby Isaac   if (!*sp) PetscFunctionReturn(0);
39520cf1dd8SToby Isaac   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
39620cf1dd8SToby Isaac 
3979371c9d4SSatish Balay   if (--((PetscObject)(*sp))->refct > 0) {
3989371c9d4SSatish Balay     *sp = NULL;
3999371c9d4SSatish Balay     PetscFunctionReturn(0);
4009371c9d4SSatish Balay   }
40120cf1dd8SToby Isaac   ((PetscObject)(*sp))->refct = 0;
40220cf1dd8SToby Isaac 
4039566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
404b4457527SToby Isaac   dm = (*sp)->dm;
405b4457527SToby Isaac 
406dbbe0bcdSBarry Smith   PetscTryTypeMethod((*sp), destroy);
4079566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
408b4457527SToby Isaac 
40948a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
4109566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
4119566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4129566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
41320cf1dd8SToby Isaac   PetscFunctionReturn(0);
41420cf1dd8SToby Isaac }
41520cf1dd8SToby Isaac 
41620cf1dd8SToby Isaac /*@
417*dce8aebaSBarry Smith   PetscDualSpaceCreate - Creates an empty `PetscDualSpace` object. The type can then be set with `PetscDualSpaceSetType()`.
41820cf1dd8SToby Isaac 
419d083f849SBarry Smith   Collective
42020cf1dd8SToby Isaac 
42120cf1dd8SToby Isaac   Input Parameter:
422*dce8aebaSBarry Smith . comm - The communicator for the `PetscDualSpace` object
42320cf1dd8SToby Isaac 
42420cf1dd8SToby Isaac   Output Parameter:
425*dce8aebaSBarry Smith . sp - The `PetscDualSpace` object
42620cf1dd8SToby Isaac 
42720cf1dd8SToby Isaac   Level: beginner
42820cf1dd8SToby Isaac 
429*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
43020cf1dd8SToby Isaac @*/
431d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
432d71ae5a4SJacob Faibussowitsch {
43320cf1dd8SToby Isaac   PetscDualSpace s;
43420cf1dd8SToby Isaac 
43520cf1dd8SToby Isaac   PetscFunctionBegin;
43620cf1dd8SToby Isaac   PetscValidPointer(sp, 2);
4379566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
43820cf1dd8SToby Isaac   *sp = NULL;
4399566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
44020cf1dd8SToby Isaac 
4419566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
44220cf1dd8SToby Isaac 
44320cf1dd8SToby Isaac   s->order       = 0;
44420cf1dd8SToby Isaac   s->Nc          = 1;
4454bee2e38SMatthew G. Knepley   s->k           = 0;
446b4457527SToby Isaac   s->spdim       = -1;
447b4457527SToby Isaac   s->spintdim    = -1;
448b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
44920cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
45020cf1dd8SToby Isaac 
45120cf1dd8SToby Isaac   *sp = s;
45220cf1dd8SToby Isaac   PetscFunctionReturn(0);
45320cf1dd8SToby Isaac }
45420cf1dd8SToby Isaac 
45520cf1dd8SToby Isaac /*@
456*dce8aebaSBarry Smith   PetscDualSpaceDuplicate - Creates a duplicate `PetscDualSpace` object that is not setup.
45720cf1dd8SToby Isaac 
458d083f849SBarry Smith   Collective on sp
45920cf1dd8SToby Isaac 
46020cf1dd8SToby Isaac   Input Parameter:
461*dce8aebaSBarry Smith . sp - The original `PetscDualSpace`
46220cf1dd8SToby Isaac 
46320cf1dd8SToby Isaac   Output Parameter:
464*dce8aebaSBarry Smith . spNew - The duplicate `PetscDualSpace`
46520cf1dd8SToby Isaac 
46620cf1dd8SToby Isaac   Level: beginner
46720cf1dd8SToby Isaac 
468*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
46920cf1dd8SToby Isaac @*/
470d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
471d71ae5a4SJacob Faibussowitsch {
472b4457527SToby Isaac   DM                 dm;
473b4457527SToby Isaac   PetscDualSpaceType type;
474b4457527SToby Isaac   const char        *name;
47520cf1dd8SToby Isaac 
47620cf1dd8SToby Isaac   PetscFunctionBegin;
47720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
47820cf1dd8SToby Isaac   PetscValidPointer(spNew, 2);
4799566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4809566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)sp, &name));
4819566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*spNew, name));
4829566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4839566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4849566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4859566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
486b4457527SToby Isaac 
487b4457527SToby Isaac   (*spNew)->order   = sp->order;
488b4457527SToby Isaac   (*spNew)->k       = sp->k;
489b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
490b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
491dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
49220cf1dd8SToby Isaac   PetscFunctionReturn(0);
49320cf1dd8SToby Isaac }
49420cf1dd8SToby Isaac 
49520cf1dd8SToby Isaac /*@
496*dce8aebaSBarry Smith   PetscDualSpaceGetDM - Get the `DM` representing the reference cell of a `PetscDualSpace`
49720cf1dd8SToby Isaac 
49820cf1dd8SToby Isaac   Not collective
49920cf1dd8SToby Isaac 
50020cf1dd8SToby Isaac   Input Parameter:
501*dce8aebaSBarry Smith . sp - The `PetscDualSpace`
50220cf1dd8SToby Isaac 
50320cf1dd8SToby Isaac   Output Parameter:
504*dce8aebaSBarry Smith . dm - The reference cell, that is a `DM` that consists of a single cell
50520cf1dd8SToby Isaac 
50620cf1dd8SToby Isaac   Level: intermediate
50720cf1dd8SToby Isaac 
508*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
50920cf1dd8SToby Isaac @*/
510d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
511d71ae5a4SJacob Faibussowitsch {
51220cf1dd8SToby Isaac   PetscFunctionBegin;
51320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
51420cf1dd8SToby Isaac   PetscValidPointer(dm, 2);
51520cf1dd8SToby Isaac   *dm = sp->dm;
51620cf1dd8SToby Isaac   PetscFunctionReturn(0);
51720cf1dd8SToby Isaac }
51820cf1dd8SToby Isaac 
51920cf1dd8SToby Isaac /*@
520*dce8aebaSBarry Smith   PetscDualSpaceSetDM - Get the `DM` representing the reference cell
52120cf1dd8SToby Isaac 
52220cf1dd8SToby Isaac   Not collective
52320cf1dd8SToby Isaac 
52420cf1dd8SToby Isaac   Input Parameters:
525*dce8aebaSBarry Smith + sp - The `PetscDual`Space
52620cf1dd8SToby Isaac - dm - The reference cell
52720cf1dd8SToby Isaac 
52820cf1dd8SToby Isaac   Level: intermediate
52920cf1dd8SToby Isaac 
530*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `DM`, `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
53120cf1dd8SToby Isaac @*/
532d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
533d71ae5a4SJacob Faibussowitsch {
53420cf1dd8SToby Isaac   PetscFunctionBegin;
53520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
53620cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
53728b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5389566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
53948a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5409566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
54120cf1dd8SToby Isaac   sp->dm = dm;
54220cf1dd8SToby Isaac   PetscFunctionReturn(0);
54320cf1dd8SToby Isaac }
54420cf1dd8SToby Isaac 
54520cf1dd8SToby Isaac /*@
54620cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
54720cf1dd8SToby Isaac 
54820cf1dd8SToby Isaac   Not collective
54920cf1dd8SToby Isaac 
55020cf1dd8SToby Isaac   Input Parameter:
551*dce8aebaSBarry Smith . sp - The `PetscDualSpace`
55220cf1dd8SToby Isaac 
55320cf1dd8SToby Isaac   Output Parameter:
55420cf1dd8SToby Isaac . order - The order
55520cf1dd8SToby Isaac 
55620cf1dd8SToby Isaac   Level: intermediate
55720cf1dd8SToby Isaac 
558*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
55920cf1dd8SToby Isaac @*/
560d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
561d71ae5a4SJacob Faibussowitsch {
56220cf1dd8SToby Isaac   PetscFunctionBegin;
56320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
564dadcf809SJacob Faibussowitsch   PetscValidIntPointer(order, 2);
56520cf1dd8SToby Isaac   *order = sp->order;
56620cf1dd8SToby Isaac   PetscFunctionReturn(0);
56720cf1dd8SToby Isaac }
56820cf1dd8SToby Isaac 
56920cf1dd8SToby Isaac /*@
57020cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
57120cf1dd8SToby Isaac 
57220cf1dd8SToby Isaac   Not collective
57320cf1dd8SToby Isaac 
57420cf1dd8SToby Isaac   Input Parameters:
575*dce8aebaSBarry Smith + sp - The `PetscDualSpace`
57620cf1dd8SToby Isaac - order - The order
57720cf1dd8SToby Isaac 
57820cf1dd8SToby Isaac   Level: intermediate
57920cf1dd8SToby Isaac 
580*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
58120cf1dd8SToby Isaac @*/
582d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
583d71ae5a4SJacob Faibussowitsch {
58420cf1dd8SToby Isaac   PetscFunctionBegin;
58520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
58628b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
58720cf1dd8SToby Isaac   sp->order = order;
58820cf1dd8SToby Isaac   PetscFunctionReturn(0);
58920cf1dd8SToby Isaac }
59020cf1dd8SToby Isaac 
59120cf1dd8SToby Isaac /*@
59220cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
59320cf1dd8SToby Isaac 
59420cf1dd8SToby Isaac   Input Parameter:
595*dce8aebaSBarry Smith . sp - The `PetscDualSpace`
59620cf1dd8SToby Isaac 
59720cf1dd8SToby Isaac   Output Parameter:
59820cf1dd8SToby Isaac . Nc - The number of components
59920cf1dd8SToby Isaac 
60020cf1dd8SToby Isaac   Level: intermediate
60120cf1dd8SToby Isaac 
602*dce8aebaSBarry Smith   Note:
603*dce8aebaSBarry Smith   A vector space, for example, will have d components, where d is the spatial dimension
604*dce8aebaSBarry Smith 
605db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
60620cf1dd8SToby Isaac @*/
607d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
608d71ae5a4SJacob Faibussowitsch {
60920cf1dd8SToby Isaac   PetscFunctionBegin;
61020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
611dadcf809SJacob Faibussowitsch   PetscValidIntPointer(Nc, 2);
61220cf1dd8SToby Isaac   *Nc = sp->Nc;
61320cf1dd8SToby Isaac   PetscFunctionReturn(0);
61420cf1dd8SToby Isaac }
61520cf1dd8SToby Isaac 
61620cf1dd8SToby Isaac /*@
61720cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
61820cf1dd8SToby Isaac 
61920cf1dd8SToby Isaac   Input Parameters:
620*dce8aebaSBarry Smith + sp - The `PetscDualSpace`
62120cf1dd8SToby Isaac - order - The number of components
62220cf1dd8SToby Isaac 
62320cf1dd8SToby Isaac   Level: intermediate
62420cf1dd8SToby Isaac 
625db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
62620cf1dd8SToby Isaac @*/
627d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
628d71ae5a4SJacob Faibussowitsch {
62920cf1dd8SToby Isaac   PetscFunctionBegin;
63020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
63128b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
63220cf1dd8SToby Isaac   sp->Nc = Nc;
63320cf1dd8SToby Isaac   PetscFunctionReturn(0);
63420cf1dd8SToby Isaac }
63520cf1dd8SToby Isaac 
63620cf1dd8SToby Isaac /*@
63720cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
63820cf1dd8SToby Isaac 
63920cf1dd8SToby Isaac   Not collective
64020cf1dd8SToby Isaac 
64120cf1dd8SToby Isaac   Input Parameters:
642*dce8aebaSBarry Smith + sp - The `PetscDualSpace`
64320cf1dd8SToby Isaac - i  - The basis number
64420cf1dd8SToby Isaac 
64520cf1dd8SToby Isaac   Output Parameter:
64620cf1dd8SToby Isaac . functional - The basis functional
64720cf1dd8SToby Isaac 
64820cf1dd8SToby Isaac   Level: intermediate
64920cf1dd8SToby Isaac 
650*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
65120cf1dd8SToby Isaac @*/
652d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
653d71ae5a4SJacob Faibussowitsch {
65420cf1dd8SToby Isaac   PetscInt dim;
65520cf1dd8SToby Isaac 
65620cf1dd8SToby Isaac   PetscFunctionBegin;
65720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
65820cf1dd8SToby Isaac   PetscValidPointer(functional, 3);
6599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
66063a3b9bcSJacob Faibussowitsch   PetscCheck(!(i < 0) && !(i >= dim), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Functional index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", i, dim);
66120cf1dd8SToby Isaac   *functional = sp->functional[i];
66220cf1dd8SToby Isaac   PetscFunctionReturn(0);
66320cf1dd8SToby Isaac }
66420cf1dd8SToby Isaac 
66520cf1dd8SToby Isaac /*@
66620cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
66720cf1dd8SToby Isaac 
66820cf1dd8SToby Isaac   Not collective
66920cf1dd8SToby Isaac 
67020cf1dd8SToby Isaac   Input Parameter:
671*dce8aebaSBarry Smith . sp - The `PetscDualSpace`
67220cf1dd8SToby Isaac 
67320cf1dd8SToby Isaac   Output Parameter:
67420cf1dd8SToby Isaac . dim - The dimension
67520cf1dd8SToby Isaac 
67620cf1dd8SToby Isaac   Level: intermediate
67720cf1dd8SToby Isaac 
678*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
67920cf1dd8SToby Isaac @*/
680d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
681d71ae5a4SJacob Faibussowitsch {
68220cf1dd8SToby Isaac   PetscFunctionBegin;
68320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
684dadcf809SJacob Faibussowitsch   PetscValidIntPointer(dim, 2);
685b4457527SToby Isaac   if (sp->spdim < 0) {
686b4457527SToby Isaac     PetscSection section;
687b4457527SToby Isaac 
6889566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
689b4457527SToby Isaac     if (section) {
6909566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(section, &(sp->spdim)));
691b4457527SToby Isaac     } else sp->spdim = 0;
692b4457527SToby Isaac   }
693b4457527SToby Isaac   *dim = sp->spdim;
69420cf1dd8SToby Isaac   PetscFunctionReturn(0);
69520cf1dd8SToby Isaac }
69620cf1dd8SToby Isaac 
697b4457527SToby Isaac /*@
698b4457527SToby Isaac   PetscDualSpaceGetInteriorDimension - Get the interior dimension of the dual space, i.e. the number of basis functionals assigned to the interior of the reference domain
699b4457527SToby Isaac 
700b4457527SToby Isaac   Not collective
701b4457527SToby Isaac 
702b4457527SToby Isaac   Input Parameter:
703*dce8aebaSBarry Smith . sp - The `PetscDualSpace`
704b4457527SToby Isaac 
705b4457527SToby Isaac   Output Parameter:
706b4457527SToby Isaac . dim - The dimension
707b4457527SToby Isaac 
708b4457527SToby Isaac   Level: intermediate
709b4457527SToby Isaac 
710*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
711b4457527SToby Isaac @*/
712d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim)
713d71ae5a4SJacob Faibussowitsch {
714b4457527SToby Isaac   PetscFunctionBegin;
715b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
716dadcf809SJacob Faibussowitsch   PetscValidIntPointer(intdim, 2);
717b4457527SToby Isaac   if (sp->spintdim < 0) {
718b4457527SToby Isaac     PetscSection section;
719b4457527SToby Isaac 
7209566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
721b4457527SToby Isaac     if (section) {
7229566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstrainedStorageSize(section, &(sp->spintdim)));
723b4457527SToby Isaac     } else sp->spintdim = 0;
724b4457527SToby Isaac   }
725b4457527SToby Isaac   *intdim = sp->spintdim;
726b4457527SToby Isaac   PetscFunctionReturn(0);
727b4457527SToby Isaac }
728b4457527SToby Isaac 
729b4457527SToby Isaac /*@
730b4457527SToby Isaac    PetscDualSpaceGetUniform - Whether this dual space is uniform
731b4457527SToby Isaac 
732b4457527SToby Isaac    Not collective
733b4457527SToby Isaac 
734b4457527SToby Isaac    Input Parameters:
735b4457527SToby Isaac .  sp - A dual space
736b4457527SToby Isaac 
737b4457527SToby Isaac    Output Parameters:
738*dce8aebaSBarry Smith .  uniform - `PETSC_TRUE` if (a) the dual space is the same for each point in a stratum of the reference `DMPLEX`, and
739*dce8aebaSBarry Smith              (b) every symmetry of each point in the reference `DMPLEX` is also a symmetry of the point's dual space.
740b4457527SToby Isaac 
741b4457527SToby Isaac    Level: advanced
742b4457527SToby Isaac 
743*dce8aebaSBarry Smith    Note:
744*dce8aebaSBarry Smith    All of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
745b4457527SToby Isaac    with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
746b4457527SToby Isaac 
747*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
748b4457527SToby Isaac @*/
749d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform)
750d71ae5a4SJacob Faibussowitsch {
751b4457527SToby Isaac   PetscFunctionBegin;
752b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
753dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(uniform, 2);
754b4457527SToby Isaac   *uniform = sp->uniform;
755b4457527SToby Isaac   PetscFunctionReturn(0);
756b4457527SToby Isaac }
757b4457527SToby Isaac 
75820cf1dd8SToby Isaac /*@C
75920cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
76020cf1dd8SToby Isaac 
76120cf1dd8SToby Isaac   Not collective
76220cf1dd8SToby Isaac 
76320cf1dd8SToby Isaac   Input Parameter:
764*dce8aebaSBarry Smith . sp - The `PetscDualSpace`
76520cf1dd8SToby Isaac 
76620cf1dd8SToby Isaac   Output Parameter:
76720cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
76820cf1dd8SToby Isaac 
76920cf1dd8SToby Isaac   Level: intermediate
77020cf1dd8SToby Isaac 
771*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
77220cf1dd8SToby Isaac @*/
773d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof)
774d71ae5a4SJacob Faibussowitsch {
77520cf1dd8SToby Isaac   PetscFunctionBegin;
77620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
77720cf1dd8SToby Isaac   PetscValidPointer(numDof, 2);
77828b400f6SJacob Faibussowitsch   PetscCheck(sp->uniform, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "A non-uniform space does not have a fixed number of dofs for each height");
779b4457527SToby Isaac   if (!sp->numDof) {
780b4457527SToby Isaac     DM           dm;
781b4457527SToby Isaac     PetscInt     depth, d;
782b4457527SToby Isaac     PetscSection section;
783b4457527SToby Isaac 
7849566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
7859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
7869566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->numDof)));
7879566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
788b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
789b4457527SToby Isaac       PetscInt dStart, dEnd;
790b4457527SToby Isaac 
7919566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
792b4457527SToby Isaac       if (dEnd <= dStart) continue;
7939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, dStart, &(sp->numDof[d])));
794b4457527SToby Isaac     }
795b4457527SToby Isaac   }
796b4457527SToby Isaac   *numDof = sp->numDof;
79708401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
79820cf1dd8SToby Isaac   PetscFunctionReturn(0);
79920cf1dd8SToby Isaac }
80020cf1dd8SToby Isaac 
801b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
802d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection)
803d71ae5a4SJacob Faibussowitsch {
804b4457527SToby Isaac   DM           dm;
805b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
806b4457527SToby Isaac   PetscInt    *seen, *perm;
807b4457527SToby Isaac   PetscSection section;
808b4457527SToby Isaac 
809b4457527SToby Isaac   PetscFunctionBegin;
810b4457527SToby Isaac   dm = sp->dm;
8119566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
8129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8139566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8149566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
8159566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
8169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
818b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
819b4457527SToby Isaac     PetscInt  closureSize = -1, e;
820b4457527SToby Isaac     PetscInt *closure     = NULL;
821b4457527SToby Isaac 
822b4457527SToby Isaac     perm[count++]    = c;
823b4457527SToby Isaac     seen[c - pStart] = 1;
8249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
825b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
826b4457527SToby Isaac       PetscInt point = closure[2 * e];
827b4457527SToby Isaac 
828b4457527SToby Isaac       if (seen[point - pStart]) continue;
829b4457527SToby Isaac       perm[count++]        = point;
830b4457527SToby Isaac       seen[point - pStart] = 1;
831b4457527SToby Isaac     }
8329566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
833b4457527SToby Isaac   }
8341dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8359371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8369371c9d4SSatish Balay     if (perm[i] != i) break;
837b4457527SToby Isaac   if (i < pEnd - pStart) {
838b4457527SToby Isaac     IS permIS;
839b4457527SToby Isaac 
8409566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8419566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8429566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8439566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
844b4457527SToby Isaac   } else {
8459566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
846b4457527SToby Isaac   }
8479566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
848b4457527SToby Isaac   *topSection = section;
849b4457527SToby Isaac   PetscFunctionReturn(0);
850b4457527SToby Isaac }
851b4457527SToby Isaac 
852b4457527SToby Isaac /* mark boundary points and set up */
853d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section)
854d71ae5a4SJacob Faibussowitsch {
855b4457527SToby Isaac   DM       dm;
856b4457527SToby Isaac   DMLabel  boundary;
857b4457527SToby Isaac   PetscInt pStart, pEnd, p;
858b4457527SToby Isaac 
859b4457527SToby Isaac   PetscFunctionBegin;
860b4457527SToby Isaac   dm = sp->dm;
8619566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8629566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8639566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8649566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
866b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
867b4457527SToby Isaac     PetscInt bval;
868b4457527SToby Isaac 
8699566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
870b4457527SToby Isaac     if (bval == 1) {
871b4457527SToby Isaac       PetscInt dof;
872b4457527SToby Isaac 
8739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8749566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
875b4457527SToby Isaac     }
876b4457527SToby Isaac   }
8779566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8789566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
879b4457527SToby Isaac   PetscFunctionReturn(0);
880b4457527SToby Isaac }
881b4457527SToby Isaac 
882a4ce7ad1SMatthew G. Knepley /*@
883*dce8aebaSBarry Smith   PetscDualSpaceGetSection - Create a `PetscSection` over the reference cell with the layout from this space
884a4ce7ad1SMatthew G. Knepley 
885a4ce7ad1SMatthew G. Knepley   Collective on sp
886a4ce7ad1SMatthew G. Knepley 
887a4ce7ad1SMatthew G. Knepley   Input Parameters:
888*dce8aebaSBarry Smith . sp      - The `PetscDualSpace`
889a4ce7ad1SMatthew G. Knepley 
890a4ce7ad1SMatthew G. Knepley   Output Parameter:
891a4ce7ad1SMatthew G. Knepley . section - The section
892a4ce7ad1SMatthew G. Knepley 
893a4ce7ad1SMatthew G. Knepley   Level: advanced
894a4ce7ad1SMatthew G. Knepley 
895*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
896a4ce7ad1SMatthew G. Knepley @*/
897d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section)
898d71ae5a4SJacob Faibussowitsch {
899b4457527SToby Isaac   PetscInt pStart, pEnd, p;
900b4457527SToby Isaac 
901b4457527SToby Isaac   PetscFunctionBegin;
90278f1d139SRomain Beucher   if (!sp->dm) {
90378f1d139SRomain Beucher     *section = NULL;
90478f1d139SRomain Beucher     PetscFunctionReturn(0);
90578f1d139SRomain Beucher   }
906b4457527SToby Isaac   if (!sp->pointSection) {
907b4457527SToby Isaac     /* mark the boundary */
9089566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &(sp->pointSection)));
9099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
910b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
911b4457527SToby Isaac       PetscDualSpace psp;
912b4457527SToby Isaac 
9139566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
914b4457527SToby Isaac       if (psp) {
915b4457527SToby Isaac         PetscInt dof;
916b4457527SToby Isaac 
9179566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
9189566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
919b4457527SToby Isaac       }
920b4457527SToby Isaac     }
9219566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
922b4457527SToby Isaac   }
923b4457527SToby Isaac   *section = sp->pointSection;
924b4457527SToby Isaac   PetscFunctionReturn(0);
925b4457527SToby Isaac }
926b4457527SToby Isaac 
927b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
928b4457527SToby Isaac  * have one cell */
929d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd)
930d71ae5a4SJacob Faibussowitsch {
931b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
932b4457527SToby Isaac   PetscSection section;
933b4457527SToby Isaac   PetscInt     dim, s, k;
93420cf1dd8SToby Isaac   DM           dm;
93520cf1dd8SToby Isaac 
93620cf1dd8SToby Isaac   PetscFunctionBegin;
9379566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
9389566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9399566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
9409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
9419566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
942b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
943b4457527SToby Isaac     PetscReal      detJ, hdetJ;
944b4457527SToby Isaac     PetscDualSpace ssp;
945b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
946b4457527SToby Isaac     PetscInt       i, j;
947b4457527SToby Isaac     DM             sdm;
94820cf1dd8SToby Isaac 
9499566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
950b4457527SToby Isaac     if (!ssp) continue;
9519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
9529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
953b4457527SToby Isaac     /* get the first vertex of the reference cell */
9549566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
9559566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
9569566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
9579566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
958b4457527SToby Isaac     /* compactify Jacobian */
9599371c9d4SSatish Balay     for (i = 0; i < dim; i++)
9609371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
961b4457527SToby Isaac     for (f = 0; f < dof; f++) {
962b4457527SToby Isaac       PetscQuadrature fn;
96320cf1dd8SToby Isaac 
9649566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
9659566063dSJacob Faibussowitsch       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &(sp->functional[off + f])));
96620cf1dd8SToby Isaac     }
96720cf1dd8SToby Isaac   }
9689566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
96920cf1dd8SToby Isaac   PetscFunctionReturn(0);
97020cf1dd8SToby Isaac }
97120cf1dd8SToby Isaac 
97220cf1dd8SToby Isaac /*@C
97320cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
97420cf1dd8SToby Isaac 
97520cf1dd8SToby Isaac   Input Parameters:
976*dce8aebaSBarry Smith + sp      - The `PetscDualSpace` object
97720cf1dd8SToby Isaac . f       - The basis functional index
97820cf1dd8SToby Isaac . time    - The time
97920cf1dd8SToby Isaac . cgeom   - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian) (or evaluated at the coordinates of the functional)
98020cf1dd8SToby Isaac . numComp - The number of components for the function
98120cf1dd8SToby Isaac . func    - The input function
98220cf1dd8SToby Isaac - ctx     - A context for the function
98320cf1dd8SToby Isaac 
98420cf1dd8SToby Isaac   Output Parameter:
98520cf1dd8SToby Isaac . value   - numComp output values
98620cf1dd8SToby Isaac 
987*dce8aebaSBarry Smith   Calling Sequence of func:
988*dce8aebaSBarry Smith .vb
989*dce8aebaSBarry Smith   func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
990*dce8aebaSBarry Smith .ve
99120cf1dd8SToby Isaac 
992a4ce7ad1SMatthew G. Knepley   Level: beginner
99320cf1dd8SToby Isaac 
994*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
99520cf1dd8SToby Isaac @*/
996d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApply(PetscDualSpace sp, PetscInt f, PetscReal time, PetscFEGeom *cgeom, PetscInt numComp, PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, PetscScalar *value)
997d71ae5a4SJacob Faibussowitsch {
99820cf1dd8SToby Isaac   PetscFunctionBegin;
99920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
100020cf1dd8SToby Isaac   PetscValidPointer(cgeom, 4);
1001dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
1002dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
100320cf1dd8SToby Isaac   PetscFunctionReturn(0);
100420cf1dd8SToby Isaac }
100520cf1dd8SToby Isaac 
100620cf1dd8SToby Isaac /*@C
1007*dce8aebaSBarry Smith   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
100820cf1dd8SToby Isaac 
100920cf1dd8SToby Isaac   Input Parameters:
1010*dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1011*dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
101220cf1dd8SToby Isaac 
101320cf1dd8SToby Isaac   Output Parameter:
101420cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
101520cf1dd8SToby Isaac 
1016*dce8aebaSBarry Smith   Level: advanced
101720cf1dd8SToby Isaac 
1018*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
101920cf1dd8SToby Isaac @*/
1020d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1021d71ae5a4SJacob Faibussowitsch {
102220cf1dd8SToby Isaac   PetscFunctionBegin;
102320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1024dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
102520cf1dd8SToby Isaac   PetscFunctionReturn(0);
102620cf1dd8SToby Isaac }
102720cf1dd8SToby Isaac 
102820cf1dd8SToby Isaac /*@C
1029*dce8aebaSBarry Smith   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1030b4457527SToby Isaac 
1031b4457527SToby Isaac   Input Parameters:
1032*dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1033*dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1034b4457527SToby Isaac 
1035b4457527SToby Isaac   Output Parameter:
1036b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1037b4457527SToby Isaac 
1038*dce8aebaSBarry Smith   Level: advanced
1039b4457527SToby Isaac 
1040*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1041b4457527SToby Isaac @*/
1042d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1043d71ae5a4SJacob Faibussowitsch {
1044b4457527SToby Isaac   PetscFunctionBegin;
1045b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1046dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
1047b4457527SToby Isaac   PetscFunctionReturn(0);
1048b4457527SToby Isaac }
1049b4457527SToby Isaac 
1050b4457527SToby Isaac /*@C
105120cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
105220cf1dd8SToby Isaac 
105320cf1dd8SToby Isaac   Input Parameters:
1054*dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
105520cf1dd8SToby Isaac . f     - The basis functional index
105620cf1dd8SToby Isaac . time  - The time
105720cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
105820cf1dd8SToby Isaac . Nc    - The number of components for the function
105920cf1dd8SToby Isaac . func  - The input function
106020cf1dd8SToby Isaac - ctx   - A context for the function
106120cf1dd8SToby Isaac 
106220cf1dd8SToby Isaac   Output Parameter:
106320cf1dd8SToby Isaac . value   - The output value
106420cf1dd8SToby Isaac 
1065*dce8aebaSBarry Smith   Calling Sequence of func:
1066*dce8aebaSBarry Smith .vb
1067*dce8aebaSBarry Smith    func(PetscInt dim, PetscReal time, const PetscReal x[],PetscInt numComponents, PetscScalar values[], void *ctx)
1068*dce8aebaSBarry Smith .ve
106920cf1dd8SToby Isaac 
1070*dce8aebaSBarry Smith   Level: advanced
107120cf1dd8SToby Isaac 
1072*dce8aebaSBarry Smith   Note:
1073*dce8aebaSBarry Smith   The idea is to evaluate the functional as an integral $ n(f) = \int dx n(x) . f(x) $ where both n and f have Nc components.
107420cf1dd8SToby Isaac 
1075*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
107620cf1dd8SToby Isaac @*/
1077d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyDefault(PetscDualSpace sp, PetscInt f, PetscReal time, PetscFEGeom *cgeom, PetscInt Nc, PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, PetscScalar *value)
1078d71ae5a4SJacob Faibussowitsch {
107920cf1dd8SToby Isaac   DM               dm;
108020cf1dd8SToby Isaac   PetscQuadrature  n;
108120cf1dd8SToby Isaac   const PetscReal *points, *weights;
108220cf1dd8SToby Isaac   PetscReal        x[3];
108320cf1dd8SToby Isaac   PetscScalar     *val;
108420cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
108520cf1dd8SToby Isaac   PetscBool        isAffine;
108620cf1dd8SToby Isaac 
108720cf1dd8SToby Isaac   PetscFunctionBegin;
108820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1089dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
10909566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
10919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
10929566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
109363a3b9bcSJacob Faibussowitsch   PetscCheck(dim == cgeom->dim, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature spatial dimension %" PetscInt_FMT " != cell geometry dimension %" PetscInt_FMT, dim, cgeom->dim);
109463a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
10959566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
109620cf1dd8SToby Isaac   *value   = 0.0;
109720cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
109820cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
109920cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
110020cf1dd8SToby Isaac     if (isAffine) {
110120cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
11029566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
110320cf1dd8SToby Isaac     } else {
11049566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
110520cf1dd8SToby Isaac     }
1106ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
110720cf1dd8SToby Isaac   }
11089566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
110920cf1dd8SToby Isaac   PetscFunctionReturn(0);
111020cf1dd8SToby Isaac }
111120cf1dd8SToby Isaac 
111220cf1dd8SToby Isaac /*@C
1113*dce8aebaSBarry Smith   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
111420cf1dd8SToby Isaac 
111520cf1dd8SToby Isaac   Input Parameters:
1116*dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1117*dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
111820cf1dd8SToby Isaac 
111920cf1dd8SToby Isaac   Output Parameter:
112020cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
112120cf1dd8SToby Isaac 
1122*dce8aebaSBarry Smith   Level: advanced
112320cf1dd8SToby Isaac 
1124*dce8aebaSBarry Smith .seealso:  `PetscDualSpace`, `PetscDualSpaceCreate()`
112520cf1dd8SToby Isaac @*/
1126d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1127d71ae5a4SJacob Faibussowitsch {
1128b4457527SToby Isaac   Vec pointValues, dofValues;
1129b4457527SToby Isaac   Mat allMat;
113020cf1dd8SToby Isaac 
113120cf1dd8SToby Isaac   PetscFunctionBegin;
113220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
113320cf1dd8SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1134064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11359566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
113648a46eb9SPierre Jolivet   if (!(sp->allNodeValues)) PetscCall(MatCreateVecs(allMat, &(sp->allNodeValues), NULL));
1137b4457527SToby Isaac   pointValues = sp->allNodeValues;
113848a46eb9SPierre Jolivet   if (!(sp->allDofValues)) PetscCall(MatCreateVecs(allMat, NULL, &(sp->allDofValues)));
1139b4457527SToby Isaac   dofValues = sp->allDofValues;
11409566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11419566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11429566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
11439566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11449566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
1145b4457527SToby Isaac   PetscFunctionReturn(0);
114620cf1dd8SToby Isaac }
1147b4457527SToby Isaac 
1148b4457527SToby Isaac /*@C
1149*dce8aebaSBarry Smith   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1150b4457527SToby Isaac 
1151b4457527SToby Isaac   Input Parameters:
1152*dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1153*dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1154b4457527SToby Isaac 
1155b4457527SToby Isaac   Output Parameter:
1156b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1157b4457527SToby Isaac 
1158*dce8aebaSBarry Smith   Level: advanced
1159b4457527SToby Isaac 
1160*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1161b4457527SToby Isaac @*/
1162d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1163d71ae5a4SJacob Faibussowitsch {
1164b4457527SToby Isaac   Vec pointValues, dofValues;
1165b4457527SToby Isaac   Mat intMat;
1166b4457527SToby Isaac 
1167b4457527SToby Isaac   PetscFunctionBegin;
1168b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1169b4457527SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1170064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11719566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
117248a46eb9SPierre Jolivet   if (!(sp->intNodeValues)) PetscCall(MatCreateVecs(intMat, &(sp->intNodeValues), NULL));
1173b4457527SToby Isaac   pointValues = sp->intNodeValues;
117448a46eb9SPierre Jolivet   if (!(sp->intDofValues)) PetscCall(MatCreateVecs(intMat, NULL, &(sp->intDofValues)));
1175b4457527SToby Isaac   dofValues = sp->intDofValues;
11769566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11779566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11789566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
11799566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11809566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
118120cf1dd8SToby Isaac   PetscFunctionReturn(0);
118220cf1dd8SToby Isaac }
118320cf1dd8SToby Isaac 
1184a4ce7ad1SMatthew G. Knepley /*@
1185b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1186a4ce7ad1SMatthew G. Knepley 
1187a4ce7ad1SMatthew G. Knepley   Input Parameter:
1188a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1189a4ce7ad1SMatthew G. Knepley 
1190d8d19677SJose E. Roman   Output Parameters:
1191*dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1192*dce8aebaSBarry Smith - allMat - A `Mat` for the node-to-dof transformation
1193a4ce7ad1SMatthew G. Knepley 
1194a4ce7ad1SMatthew G. Knepley   Level: advanced
1195a4ce7ad1SMatthew G. Knepley 
1196*dce8aebaSBarry Smith .seealso: `PetscQuadrature`, `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`
1197a4ce7ad1SMatthew G. Knepley @*/
1198d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1199d71ae5a4SJacob Faibussowitsch {
120020cf1dd8SToby Isaac   PetscFunctionBegin;
120120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1202b4457527SToby Isaac   if (allNodes) PetscValidPointer(allNodes, 2);
1203b4457527SToby Isaac   if (allMat) PetscValidPointer(allMat, 3);
1204b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1205b4457527SToby Isaac     PetscQuadrature qpoints;
1206b4457527SToby Isaac     Mat             amat;
1207b4457527SToby Isaac 
1208dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
12099566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
12109566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->allMat)));
1211b4457527SToby Isaac     sp->allNodes = qpoints;
1212b4457527SToby Isaac     sp->allMat   = amat;
121320cf1dd8SToby Isaac   }
1214b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1215b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
121620cf1dd8SToby Isaac   PetscFunctionReturn(0);
121720cf1dd8SToby Isaac }
121820cf1dd8SToby Isaac 
1219a4ce7ad1SMatthew G. Knepley /*@
1220b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1221a4ce7ad1SMatthew G. Knepley 
1222a4ce7ad1SMatthew G. Knepley   Input Parameter:
1223a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1224a4ce7ad1SMatthew G. Knepley 
1225d8d19677SJose E. Roman   Output Parameters:
1226*dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1227*dce8aebaSBarry Smith - allMat - A `Mat` for the node-to-dof transformation
1228a4ce7ad1SMatthew G. Knepley 
1229a4ce7ad1SMatthew G. Knepley   Level: advanced
1230a4ce7ad1SMatthew G. Knepley 
1231*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`, `PetscQuadrature`
1232a4ce7ad1SMatthew G. Knepley @*/
1233d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1234d71ae5a4SJacob Faibussowitsch {
123520cf1dd8SToby Isaac   PetscInt        spdim;
123620cf1dd8SToby Isaac   PetscInt        numPoints, offset;
123720cf1dd8SToby Isaac   PetscReal      *points;
123820cf1dd8SToby Isaac   PetscInt        f, dim;
1239b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1240b4457527SToby Isaac   PetscInt        maxNumPoints;
124120cf1dd8SToby Isaac   PetscQuadrature q;
1242b4457527SToby Isaac   Mat             A;
124320cf1dd8SToby Isaac 
124420cf1dd8SToby Isaac   PetscFunctionBegin;
12459566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
12469566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
124720cf1dd8SToby Isaac   if (!spdim) {
12489566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12499566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
125020cf1dd8SToby Isaac   }
1251b4457527SToby Isaac   nrows = spdim;
12529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
12539566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1254b4457527SToby Isaac   maxNumPoints = numPoints;
125520cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
125620cf1dd8SToby Isaac     PetscInt Np;
125720cf1dd8SToby Isaac 
12589566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12599566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
126020cf1dd8SToby Isaac     numPoints += Np;
1261b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
126220cf1dd8SToby Isaac   }
1263b4457527SToby Isaac   ncols = numPoints * Nc;
12649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
12659566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
126620cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1267b4457527SToby Isaac     const PetscReal *p, *w;
126820cf1dd8SToby Isaac     PetscInt         Np, i;
1269b4457527SToby Isaac     PetscInt         fnc;
127020cf1dd8SToby Isaac 
12719566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12729566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
127308401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
1274ad540459SPierre Jolivet     for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i];
127548a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1276b4457527SToby Isaac     offset += Np;
1277b4457527SToby Isaac   }
12789566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
12799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
12809566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12819566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1282b4457527SToby Isaac   *allMat = A;
1283b4457527SToby Isaac   PetscFunctionReturn(0);
1284b4457527SToby Isaac }
1285b4457527SToby Isaac 
1286b4457527SToby Isaac /*@
1287b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1288b4457527SToby Isaac   this space, as well as the matrix that computes the degrees of freedom from the quadrature values.  Degrees of
1289*dce8aebaSBarry Smith   freedom are interior degrees of freedom if they belong (by `PetscDualSpaceGetSection()`) to interior points in the
1290*dce8aebaSBarry Smith   reference `DMPLEX`: complementary boundary degrees of freedom are marked as constrained in the section returned by
1291*dce8aebaSBarry Smith   `PetscDualSpaceGetSection()`).
1292b4457527SToby Isaac 
1293b4457527SToby Isaac   Input Parameter:
1294b4457527SToby Isaac . sp - The dualspace
1295b4457527SToby Isaac 
1296d8d19677SJose E. Roman   Output Parameters:
1297*dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1298b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1299*dce8aebaSBarry Smith              the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1300*dce8aebaSBarry Smith              npoints is the number of points in intNodes and nc is `PetscDualSpaceGetNumComponents()`.
1301b4457527SToby Isaac 
1302b4457527SToby Isaac   Level: advanced
1303b4457527SToby Isaac 
1304*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1305b4457527SToby Isaac @*/
1306d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1307d71ae5a4SJacob Faibussowitsch {
1308b4457527SToby Isaac   PetscFunctionBegin;
1309b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1310b4457527SToby Isaac   if (intNodes) PetscValidPointer(intNodes, 2);
1311b4457527SToby Isaac   if (intMat) PetscValidPointer(intMat, 3);
1312b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1313b4457527SToby Isaac     PetscQuadrature qpoints;
1314b4457527SToby Isaac     Mat             imat;
1315b4457527SToby Isaac 
1316dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
13179566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
13189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->intMat)));
1319b4457527SToby Isaac     sp->intNodes = qpoints;
1320b4457527SToby Isaac     sp->intMat   = imat;
1321b4457527SToby Isaac   }
1322b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1323b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
1324b4457527SToby Isaac   PetscFunctionReturn(0);
1325b4457527SToby Isaac }
1326b4457527SToby Isaac 
1327b4457527SToby Isaac /*@
1328b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1329b4457527SToby Isaac 
1330b4457527SToby Isaac   Input Parameter:
1331b4457527SToby Isaac . sp - The dualspace
1332b4457527SToby Isaac 
1333d8d19677SJose E. Roman   Output Parameters:
1334*dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1335b4457527SToby Isaac - intMat    - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1336*dce8aebaSBarry Smith               the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1337*dce8aebaSBarry Smith               npoints is the number of points in allNodes and nc is `PetscDualSpaceGetNumComponents()`.
1338b4457527SToby Isaac 
1339b4457527SToby Isaac   Level: advanced
1340b4457527SToby Isaac 
1341*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1342b4457527SToby Isaac @*/
1343d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1344d71ae5a4SJacob Faibussowitsch {
1345b4457527SToby Isaac   DM              dm;
1346b4457527SToby Isaac   PetscInt        spdim0;
1347b4457527SToby Isaac   PetscInt        Nc;
1348b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1349b4457527SToby Isaac   PetscSection    section;
1350b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1351b4457527SToby Isaac   PetscReal      *points;
1352b4457527SToby Isaac   PetscInt        dim;
1353b4457527SToby Isaac   PetscInt       *nnz;
1354b4457527SToby Isaac   PetscQuadrature q;
1355b4457527SToby Isaac   Mat             imat;
1356b4457527SToby Isaac 
1357b4457527SToby Isaac   PetscFunctionBegin;
1358b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
13609566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1361b4457527SToby Isaac   if (!spdim0) {
1362b4457527SToby Isaac     *intNodes = NULL;
1363b4457527SToby Isaac     *intMat   = NULL;
1364b4457527SToby Isaac     PetscFunctionReturn(0);
1365b4457527SToby Isaac   }
13669566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
13689566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
13699566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1371b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1372b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1373b4457527SToby Isaac 
13749566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1376b4457527SToby Isaac     if (!(dof - cdof)) continue;
13779566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1378b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1379b4457527SToby Isaac       PetscInt Np;
1380b4457527SToby Isaac 
13819566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
13829566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1383b4457527SToby Isaac       nnz[f] = Np * Nc;
1384b4457527SToby Isaac       numPoints += Np;
1385b4457527SToby Isaac     }
1386b4457527SToby Isaac   }
13879566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
13889566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
13899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1390b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1391b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1392b4457527SToby Isaac 
13939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1395b4457527SToby Isaac     if (!(dof - cdof)) continue;
13969566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1397b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1398b4457527SToby Isaac       const PetscReal *p;
1399b4457527SToby Isaac       const PetscReal *w;
1400b4457527SToby Isaac       PetscInt         Np, i;
1401b4457527SToby Isaac 
14029566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14039566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
1404ad540459SPierre Jolivet       for (i = 0; i < Np * dim; i++) points[offset + i] = p[i];
140548a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1406b4457527SToby Isaac       offset += Np * dim;
1407b4457527SToby Isaac       matoffset += Np * Nc;
1408b4457527SToby Isaac     }
1409b4457527SToby Isaac   }
14109566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
14119566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
14129566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
14139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1414b4457527SToby Isaac   *intMat = imat;
141520cf1dd8SToby Isaac   PetscFunctionReturn(0);
141620cf1dd8SToby Isaac }
141720cf1dd8SToby Isaac 
14184f9ab2b4SJed Brown /*@
1419*dce8aebaSBarry Smith   PetscDualSpaceEqual - Determine if two dual spaces are equivalent
14204f9ab2b4SJed Brown 
14214f9ab2b4SJed Brown   Input Parameters:
1422*dce8aebaSBarry Smith + A    - A `PetscDualSpace` object
1423*dce8aebaSBarry Smith - B    - Another `PetscDualSpace` object
14244f9ab2b4SJed Brown 
14254f9ab2b4SJed Brown   Output Parameter:
1426*dce8aebaSBarry Smith . equal - `PETSC_TRUE` if the dual spaces are equivalent
14274f9ab2b4SJed Brown 
14284f9ab2b4SJed Brown   Level: advanced
14294f9ab2b4SJed Brown 
1430*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
14314f9ab2b4SJed Brown @*/
1432d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal)
1433d71ae5a4SJacob Faibussowitsch {
14344f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
14354f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
14364f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
14374f9ab2b4SJed Brown   Mat             matA, matB;
14384f9ab2b4SJed Brown 
14394f9ab2b4SJed Brown   PetscFunctionBegin;
14404f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
14414f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
14424f9ab2b4SJed Brown   PetscValidBoolPointer(equal, 3);
14434f9ab2b4SJed Brown   *equal = PETSC_FALSE;
14449566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
14459566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
1446ad540459SPierre Jolivet   if (sizeB != sizeA) PetscFunctionReturn(0);
14479566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
14489566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
1449ad540459SPierre Jolivet   if (dimA != dimB) PetscFunctionReturn(0);
14504f9ab2b4SJed Brown 
14519566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
14529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
14534f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
1454ad540459SPierre Jolivet     if (dofA[d] != dofB[d]) PetscFunctionReturn(0);
14554f9ab2b4SJed Brown   }
14564f9ab2b4SJed Brown 
14579566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
14589566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
14594f9ab2b4SJed Brown   if (!quadA && !quadB) {
14604f9ab2b4SJed Brown     *equal = PETSC_TRUE;
14614f9ab2b4SJed Brown   } else if (quadA && quadB) {
14629566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
14634f9ab2b4SJed Brown     if (*equal == PETSC_FALSE) PetscFunctionReturn(0);
14644f9ab2b4SJed Brown     if (!matA && !matB) PetscFunctionReturn(0);
14659566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
14664f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
14674f9ab2b4SJed Brown   }
14684f9ab2b4SJed Brown   PetscFunctionReturn(0);
14694f9ab2b4SJed Brown }
14704f9ab2b4SJed Brown 
147120cf1dd8SToby Isaac /*@C
147220cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
147320cf1dd8SToby Isaac 
147420cf1dd8SToby Isaac   Input Parameters:
1475*dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
147620cf1dd8SToby Isaac . f     - The basis functional index
147720cf1dd8SToby Isaac . time  - The time
147820cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
147920cf1dd8SToby Isaac . Nc    - The number of components for the function
148020cf1dd8SToby Isaac . func  - The input function
148120cf1dd8SToby Isaac - ctx   - A context for the function
148220cf1dd8SToby Isaac 
148320cf1dd8SToby Isaac   Output Parameter:
148420cf1dd8SToby Isaac . value - The output value (scalar)
148520cf1dd8SToby Isaac 
1486*dce8aebaSBarry Smith   Calling Sequence of func:
1487*dce8aebaSBarry Smith .vb
1488*dce8aebaSBarry Smith   func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1489*dce8aebaSBarry Smith .ve
1490*dce8aebaSBarry Smith   Level: advanced
149120cf1dd8SToby Isaac 
1492*dce8aebaSBarry Smith   Note:
1493*dce8aebaSBarry Smith   The idea is to evaluate the functional as an integral $ n(f) = \int dx n(x) . f(x)$ where both n and f have Nc components.
149420cf1dd8SToby Isaac 
1495*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
149620cf1dd8SToby Isaac @*/
1497d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyFVM(PetscDualSpace sp, PetscInt f, PetscReal time, PetscFVCellGeom *cgeom, PetscInt Nc, PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, PetscScalar *value)
1498d71ae5a4SJacob Faibussowitsch {
149920cf1dd8SToby Isaac   DM               dm;
150020cf1dd8SToby Isaac   PetscQuadrature  n;
150120cf1dd8SToby Isaac   const PetscReal *points, *weights;
150220cf1dd8SToby Isaac   PetscScalar     *val;
150320cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
150420cf1dd8SToby Isaac 
150520cf1dd8SToby Isaac   PetscFunctionBegin;
150620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1507dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
15089566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
15099566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
15109566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
15119566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
151263a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
15139566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
151420cf1dd8SToby Isaac   *value = 0.;
151520cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
15169566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
1517ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
151820cf1dd8SToby Isaac   }
15199566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
152020cf1dd8SToby Isaac   PetscFunctionReturn(0);
152120cf1dd8SToby Isaac }
152220cf1dd8SToby Isaac 
152320cf1dd8SToby Isaac /*@
152420cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
152520cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
152620cf1dd8SToby Isaac 
152720cf1dd8SToby Isaac   Not collective
152820cf1dd8SToby Isaac 
152920cf1dd8SToby Isaac   Input Parameters:
1530*dce8aebaSBarry Smith + sp - the `PetscDualSpace` object
153120cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
153220cf1dd8SToby Isaac 
153320cf1dd8SToby Isaac   Output Parameter:
153420cf1dd8SToby Isaac . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
153520cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
153620cf1dd8SToby Isaac 
153720cf1dd8SToby Isaac   Level: advanced
153820cf1dd8SToby Isaac 
1539*dce8aebaSBarry Smith   Notes:
1540*dce8aebaSBarry Smith   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
1541*dce8aebaSBarry Smith   pointwise values are not defined on the element boundaries), or if the implementation of `PetscDualSpace` does not
1542*dce8aebaSBarry Smith   support extracting subspaces, then NULL is returned.
1543*dce8aebaSBarry Smith 
1544*dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1545*dce8aebaSBarry Smith 
1546*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSpaceGetHeightSubspace()`, `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`
154720cf1dd8SToby Isaac @*/
1548d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
1549d71ae5a4SJacob Faibussowitsch {
1550b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1551b4457527SToby Isaac   DM       dm;
155220cf1dd8SToby Isaac 
155320cf1dd8SToby Isaac   PetscFunctionBegin;
155420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1555064a246eSJacob Faibussowitsch   PetscValidPointer(subsp, 3);
155608401ef6SPierre Jolivet   PetscCheck((sp->uniform), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "A non-uniform dual space does not have a single dual space at each height");
155720cf1dd8SToby Isaac   *subsp = NULL;
1558b4457527SToby Isaac   dm     = sp->dm;
15599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
15601dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
15619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1562b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1563b4457527SToby Isaac     *subsp = sp;
1564b4457527SToby Isaac     PetscFunctionReturn(0);
1565b4457527SToby Isaac   }
1566b4457527SToby Isaac   if (!sp->heightSpaces) {
1567b4457527SToby Isaac     PetscInt h;
15689566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->heightSpaces)));
1569b4457527SToby Isaac 
1570b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1571b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
15729566063dSJacob Faibussowitsch       if (sp->ops->createheightsubspace) PetscCall((*sp->ops->createheightsubspace)(sp, height, &(sp->heightSpaces[h])));
1573b4457527SToby Isaac       else if (sp->pointSpaces) {
1574b4457527SToby Isaac         PetscInt hStart, hEnd;
1575b4457527SToby Isaac 
15769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1577b4457527SToby Isaac         if (hEnd > hStart) {
1578665f567fSMatthew G. Knepley           const char *name;
1579665f567fSMatthew G. Knepley 
15809566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)(sp->pointSpaces[hStart])));
1581665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
15829566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
15839566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1584665f567fSMatthew G. Knepley           }
1585b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1586b4457527SToby Isaac         }
1587b4457527SToby Isaac       }
1588b4457527SToby Isaac     }
1589b4457527SToby Isaac   }
1590b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
159120cf1dd8SToby Isaac   PetscFunctionReturn(0);
159220cf1dd8SToby Isaac }
159320cf1dd8SToby Isaac 
159420cf1dd8SToby Isaac /*@
159520cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
159620cf1dd8SToby Isaac 
159720cf1dd8SToby Isaac   Not collective
159820cf1dd8SToby Isaac 
159920cf1dd8SToby Isaac   Input Parameters:
1600*dce8aebaSBarry Smith + sp - the `PetscDualSpace` object
160120cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
160220cf1dd8SToby Isaac 
160320cf1dd8SToby Isaac   Output Parameters:
1604*dce8aebaSBarry Smith   bdsp - the subspace. The functionals in the subspace are with respect to the intrinsic geometry of the
160520cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
160620cf1dd8SToby Isaac 
160720cf1dd8SToby Isaac   Level: advanced
160820cf1dd8SToby Isaac 
1609*dce8aebaSBarry Smith   Notes:
1610*dce8aebaSBarry Smith   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
1611*dce8aebaSBarry Smith   defined on the element boundaries), or if the implementation of `PetscDualSpace` does not support extracting
1612*dce8aebaSBarry Smith   subspaces, then NULL is returned.
1613*dce8aebaSBarry Smith 
1614*dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1615*dce8aebaSBarry Smith 
1616*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetHeightSubspace()`
161720cf1dd8SToby Isaac @*/
1618d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1619d71ae5a4SJacob Faibussowitsch {
1620b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1621b4457527SToby Isaac   DM       dm;
162220cf1dd8SToby Isaac 
162320cf1dd8SToby Isaac   PetscFunctionBegin;
162420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1625064a246eSJacob Faibussowitsch   PetscValidPointer(bdsp, 3);
162620cf1dd8SToby Isaac   *bdsp = NULL;
1627b4457527SToby Isaac   dm    = sp->dm;
16289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16291dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
16309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1631b4457527SToby Isaac   if (point == cStart && cEnd == cStart + 1) { /* the dual space is only equivalent to the dual space on a cell if the reference mesh has just one cell */
1632b4457527SToby Isaac     *bdsp = sp;
1633b4457527SToby Isaac     PetscFunctionReturn(0);
1634b4457527SToby Isaac   }
1635b4457527SToby Isaac   if (!sp->pointSpaces) {
1636b4457527SToby Isaac     PetscInt p;
16379566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pEnd - pStart, &(sp->pointSpaces)));
163820cf1dd8SToby Isaac 
1639b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1640b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
16419566063dSJacob Faibussowitsch       if (sp->ops->createpointsubspace) PetscCall((*sp->ops->createpointsubspace)(sp, p + pStart, &(sp->pointSpaces[p])));
1642b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1643b4457527SToby Isaac         PetscInt dim, depth, height;
1644b4457527SToby Isaac         DMLabel  label;
1645b4457527SToby Isaac 
16469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
16479566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
16489566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
164920cf1dd8SToby Isaac         height = dim - depth;
16509566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &(sp->pointSpaces[p])));
16519566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
165220cf1dd8SToby Isaac       }
1653b4457527SToby Isaac     }
1654b4457527SToby Isaac   }
1655b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
165620cf1dd8SToby Isaac   PetscFunctionReturn(0);
165720cf1dd8SToby Isaac }
165820cf1dd8SToby Isaac 
16596f905325SMatthew G. Knepley /*@C
16606f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
16616f905325SMatthew G. Knepley 
16626f905325SMatthew G. Knepley   Not collective
16636f905325SMatthew G. Knepley 
16646f905325SMatthew G. Knepley   Input Parameter:
1665*dce8aebaSBarry Smith . sp - the `PetscDualSpace` object
16666f905325SMatthew G. Knepley 
16676f905325SMatthew G. Knepley   Output Parameters:
1668b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1669b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
16706f905325SMatthew G. Knepley 
16716f905325SMatthew G. Knepley   Level: developer
16726f905325SMatthew G. Knepley 
1673*dce8aebaSBarry Smith   Note:
1674*dce8aebaSBarry Smith   The permutation and flip arrays are organized in the following way
1675*dce8aebaSBarry Smith .vb
1676*dce8aebaSBarry Smith   perms[p][ornt][dof # on point] = new local dof #
1677*dce8aebaSBarry Smith   flips[p][ornt][dof # on point] = reversal or not
1678*dce8aebaSBarry Smith .ve
1679*dce8aebaSBarry Smith 
1680*dce8aebaSBarry Smith .seealso: `PetscDualSpace`
16816f905325SMatthew G. Knepley @*/
1682d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
1683d71ae5a4SJacob Faibussowitsch {
16846f905325SMatthew G. Knepley   PetscFunctionBegin;
16856f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16869371c9d4SSatish Balay   if (perms) {
16879371c9d4SSatish Balay     PetscValidPointer(perms, 2);
16889371c9d4SSatish Balay     *perms = NULL;
16899371c9d4SSatish Balay   }
16909371c9d4SSatish Balay   if (flips) {
16919371c9d4SSatish Balay     PetscValidPointer(flips, 3);
16929371c9d4SSatish Balay     *flips = NULL;
16939371c9d4SSatish Balay   }
16949566063dSJacob Faibussowitsch   if (sp->ops->getsymmetries) PetscCall((sp->ops->getsymmetries)(sp, perms, flips));
16956f905325SMatthew G. Knepley   PetscFunctionReturn(0);
16966f905325SMatthew G. Knepley }
16974bee2e38SMatthew G. Knepley 
16984bee2e38SMatthew G. Knepley /*@
1699b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1700b4457527SToby Isaac   dual space's functionals.
1701b4457527SToby Isaac 
1702b4457527SToby Isaac   Input Parameter:
1703*dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
1704b4457527SToby Isaac 
1705b4457527SToby Isaac   Output Parameter:
1706b4457527SToby Isaac . k   - The *signed* degree k of the k.  If k >= 0, this means that the degrees of freedom are k-forms, and are stored
1707b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1708b4457527SToby Isaac         the 1-form basis in 3-D is (dx, dy, dz), and the 2-form basis in 3-D is (dx wedge dy, dx wedge dz, dy wedge dz).
1709b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1710b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1711b4457527SToby Isaac         but are stored as 1-forms.
1712b4457527SToby Isaac 
1713b4457527SToby Isaac   Level: developer
1714b4457527SToby Isaac 
1715*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1716b4457527SToby Isaac @*/
1717d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k)
1718d71ae5a4SJacob Faibussowitsch {
1719b4457527SToby Isaac   PetscFunctionBeginHot;
1720b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1721dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1722b4457527SToby Isaac   *k = dsp->k;
1723b4457527SToby Isaac   PetscFunctionReturn(0);
1724b4457527SToby Isaac }
1725b4457527SToby Isaac 
1726b4457527SToby Isaac /*@
1727b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1728b4457527SToby Isaac   dual space's functionals.
1729b4457527SToby Isaac 
1730d8d19677SJose E. Roman   Input Parameters:
1731*dce8aebaSBarry Smith + dsp - The `PetscDualSpace`
1732b4457527SToby Isaac - k   - The *signed* degree k of the k.  If k >= 0, this means that the degrees of freedom are k-forms, and are stored
1733b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1734b4457527SToby Isaac         the 1-form basis in 3-D is (dx, dy, dz), and the 2-form basis in 3-D is (dx wedge dy, dx wedge dz, dy wedge dz).
1735b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1736b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1737b4457527SToby Isaac         but are stored as 1-forms.
1738b4457527SToby Isaac 
1739b4457527SToby Isaac   Level: developer
1740b4457527SToby Isaac 
1741*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1742b4457527SToby Isaac @*/
1743d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k)
1744d71ae5a4SJacob Faibussowitsch {
1745b4457527SToby Isaac   PetscInt dim;
1746b4457527SToby Isaac 
1747b4457527SToby Isaac   PetscFunctionBeginHot;
1748b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
174928b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1750b4457527SToby Isaac   dim = dsp->dm->dim;
17511dca8a05SBarry Smith   PetscCheck(k >= -dim && k <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported %" PetscInt_FMT "-form on %" PetscInt_FMT "-dimensional reference cell", PetscAbsInt(k), dim);
1752b4457527SToby Isaac   dsp->k = k;
1753b4457527SToby Isaac   PetscFunctionReturn(0);
1754b4457527SToby Isaac }
1755b4457527SToby Isaac 
1756b4457527SToby Isaac /*@
17574bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
17584bee2e38SMatthew G. Knepley 
17594bee2e38SMatthew G. Knepley   Input Parameter:
1760*dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
17614bee2e38SMatthew G. Knepley 
17624bee2e38SMatthew G. Knepley   Output Parameter:
17634bee2e38SMatthew G. Knepley . k   - The simplex dimension
17644bee2e38SMatthew G. Knepley 
1765a4ce7ad1SMatthew G. Knepley   Level: developer
17664bee2e38SMatthew G. Knepley 
1767*dce8aebaSBarry Smith   Note:
1768*dce8aebaSBarry Smith   Currently supported values are
1769*dce8aebaSBarry Smith .vb
1770*dce8aebaSBarry Smith   0: These are H_1 methods that only transform coordinates
1771*dce8aebaSBarry Smith   1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
1772*dce8aebaSBarry Smith   2: These are the same as 1
1773*dce8aebaSBarry Smith   3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
1774*dce8aebaSBarry Smith .ve
17754bee2e38SMatthew G. Knepley 
1776*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
17774bee2e38SMatthew G. Knepley @*/
1778d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k)
1779d71ae5a4SJacob Faibussowitsch {
1780b4457527SToby Isaac   PetscInt dim;
1781b4457527SToby Isaac 
17824bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
17834bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1784dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1785b4457527SToby Isaac   dim = dsp->dm->dim;
1786b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1787b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1788b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1789b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
17904bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
17914bee2e38SMatthew G. Knepley }
17924bee2e38SMatthew G. Knepley 
17934bee2e38SMatthew G. Knepley /*@C
17944bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
17954bee2e38SMatthew G. Knepley 
17964bee2e38SMatthew G. Knepley   Input Parameters:
1797*dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
17984bee2e38SMatthew G. Knepley . trans     - The type of transform
17994bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18004bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18014bee2e38SMatthew G. Knepley . Nv        - The number of function samples
18024bee2e38SMatthew G. Knepley . Nc        - The number of function components
18034bee2e38SMatthew G. Knepley - vals      - The function values
18044bee2e38SMatthew G. Knepley 
18054bee2e38SMatthew G. Knepley   Output Parameter:
18064bee2e38SMatthew G. Knepley . vals      - The transformed function values
18074bee2e38SMatthew G. Knepley 
1808a4ce7ad1SMatthew G. Knepley   Level: intermediate
18094bee2e38SMatthew G. Knepley 
1810*dce8aebaSBarry Smith   Note:
1811*dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18122edcad52SToby Isaac 
1813*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18144bee2e38SMatthew G. Knepley @*/
1815d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1816d71ae5a4SJacob Faibussowitsch {
1817b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1818b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
18194bee2e38SMatthew G. Knepley 
18204bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18214bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18224bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1823dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
1824b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
18252ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1826b4457527SToby Isaac   /* No change needed for 0-forms */
1827b4457527SToby Isaac   if (!dsp->k) PetscFunctionReturn(0);
18289566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1829b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
18309566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
18314bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1832b4457527SToby Isaac     switch (Nk) {
1833b4457527SToby Isaac     case 1:
1834b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
18354bee2e38SMatthew G. Knepley       break;
1836b4457527SToby Isaac     case 2:
1837b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
18384bee2e38SMatthew G. Knepley       break;
1839b4457527SToby Isaac     case 3:
1840b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1841b4457527SToby Isaac       break;
1842d71ae5a4SJacob Faibussowitsch     default:
1843d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1844b4457527SToby Isaac     }
18454bee2e38SMatthew G. Knepley   }
18464bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
18474bee2e38SMatthew G. Knepley }
1848b4457527SToby Isaac 
18494bee2e38SMatthew G. Knepley /*@C
18504bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
18514bee2e38SMatthew G. Knepley 
18524bee2e38SMatthew G. Knepley   Input Parameters:
1853*dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18544bee2e38SMatthew G. Knepley . trans     - The type of transform
18554bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18564bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18574bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
18584bee2e38SMatthew G. Knepley . Nc        - The number of function components
18594bee2e38SMatthew G. Knepley - vals      - The function gradient values
18604bee2e38SMatthew G. Knepley 
18614bee2e38SMatthew G. Knepley   Output Parameter:
1862f9244615SMatthew G. Knepley . vals      - The transformed function gradient values
18634bee2e38SMatthew G. Knepley 
1864a4ce7ad1SMatthew G. Knepley   Level: intermediate
18654bee2e38SMatthew G. Knepley 
1866*dce8aebaSBarry Smith   Note:
1867*dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18682edcad52SToby Isaac 
1869*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18704bee2e38SMatthew G. Knepley @*/
1871d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1872d71ae5a4SJacob Faibussowitsch {
187327f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
187427f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
18754bee2e38SMatthew G. Knepley 
18764bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18774bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18784bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1879dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
188027f02ce8SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
188163a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
188227f02ce8SMatthew G. Knepley #endif
18834bee2e38SMatthew G. Knepley   /* Transform gradient */
188427f02ce8SMatthew G. Knepley   if (dim == dE) {
18854bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
18864bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
18879371c9d4SSatish Balay         switch (dim) {
1888d71ae5a4SJacob Faibussowitsch         case 1:
1889d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim] *= fegeom->invJ[0];
1890d71ae5a4SJacob Faibussowitsch           break;
1891d71ae5a4SJacob Faibussowitsch         case 2:
1892d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1893d71ae5a4SJacob Faibussowitsch           break;
1894d71ae5a4SJacob Faibussowitsch         case 3:
1895d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1896d71ae5a4SJacob Faibussowitsch           break;
1897d71ae5a4SJacob Faibussowitsch         default:
1898d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18994bee2e38SMatthew G. Knepley         }
19004bee2e38SMatthew G. Knepley       }
19014bee2e38SMatthew G. Knepley     }
190227f02ce8SMatthew G. Knepley   } else {
190327f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1904ad540459SPierre Jolivet       for (c = 0; c < Nc; ++c) DMPlex_MultTransposeReal_Internal(fegeom->invJ, dim, dE, 1, &vals[(v * Nc + c) * dE], &vals[(v * Nc + c) * dE]);
190527f02ce8SMatthew G. Knepley     }
190627f02ce8SMatthew G. Knepley   }
19074bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
19084bee2e38SMatthew G. Knepley   if (Nc == 1 || Nc != dim) PetscFunctionReturn(0);
19094bee2e38SMatthew G. Knepley   switch (trans) {
1910d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
1911d71ae5a4SJacob Faibussowitsch     break;
19124bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
19134bee2e38SMatthew G. Knepley     if (isInverse) {
19144bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19154bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19169371c9d4SSatish Balay           switch (dim) {
1917d71ae5a4SJacob Faibussowitsch           case 2:
1918d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1919d71ae5a4SJacob Faibussowitsch             break;
1920d71ae5a4SJacob Faibussowitsch           case 3:
1921d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1922d71ae5a4SJacob Faibussowitsch             break;
1923d71ae5a4SJacob Faibussowitsch           default:
1924d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19254bee2e38SMatthew G. Knepley           }
19264bee2e38SMatthew G. Knepley         }
19274bee2e38SMatthew G. Knepley       }
19284bee2e38SMatthew G. Knepley     } else {
19294bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19304bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19319371c9d4SSatish Balay           switch (dim) {
1932d71ae5a4SJacob Faibussowitsch           case 2:
1933d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1934d71ae5a4SJacob Faibussowitsch             break;
1935d71ae5a4SJacob Faibussowitsch           case 3:
1936d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1937d71ae5a4SJacob Faibussowitsch             break;
1938d71ae5a4SJacob Faibussowitsch           default:
1939d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19404bee2e38SMatthew G. Knepley           }
19414bee2e38SMatthew G. Knepley         }
19424bee2e38SMatthew G. Knepley       }
19434bee2e38SMatthew G. Knepley     }
19444bee2e38SMatthew G. Knepley     break;
19454bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
19464bee2e38SMatthew G. Knepley     if (isInverse) {
19474bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19484bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19499371c9d4SSatish Balay           switch (dim) {
1950d71ae5a4SJacob Faibussowitsch           case 2:
1951d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1952d71ae5a4SJacob Faibussowitsch             break;
1953d71ae5a4SJacob Faibussowitsch           case 3:
1954d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1955d71ae5a4SJacob Faibussowitsch             break;
1956d71ae5a4SJacob Faibussowitsch           default:
1957d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19584bee2e38SMatthew G. Knepley           }
19594bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
19604bee2e38SMatthew G. Knepley         }
19614bee2e38SMatthew G. Knepley       }
19624bee2e38SMatthew G. Knepley     } else {
19634bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19644bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19659371c9d4SSatish Balay           switch (dim) {
1966d71ae5a4SJacob Faibussowitsch           case 2:
1967d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1968d71ae5a4SJacob Faibussowitsch             break;
1969d71ae5a4SJacob Faibussowitsch           case 3:
1970d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1971d71ae5a4SJacob Faibussowitsch             break;
1972d71ae5a4SJacob Faibussowitsch           default:
1973d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19744bee2e38SMatthew G. Knepley           }
19754bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
19764bee2e38SMatthew G. Knepley         }
19774bee2e38SMatthew G. Knepley       }
19784bee2e38SMatthew G. Knepley     }
19794bee2e38SMatthew G. Knepley     break;
19804bee2e38SMatthew G. Knepley   }
19814bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
19824bee2e38SMatthew G. Knepley }
19834bee2e38SMatthew G. Knepley 
19844bee2e38SMatthew G. Knepley /*@C
1985f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
1986f9244615SMatthew G. Knepley 
1987f9244615SMatthew G. Knepley   Input Parameters:
1988*dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
1989f9244615SMatthew G. Knepley . trans     - The type of transform
1990f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
1991f9244615SMatthew G. Knepley . fegeom    - The cell geometry
1992f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
1993f9244615SMatthew G. Knepley . Nc        - The number of function components
1994f9244615SMatthew G. Knepley - vals      - The function gradient values
1995f9244615SMatthew G. Knepley 
1996f9244615SMatthew G. Knepley   Output Parameter:
1997f9244615SMatthew G. Knepley . vals      - The transformed function Hessian values
1998f9244615SMatthew G. Knepley 
1999f9244615SMatthew G. Knepley   Level: intermediate
2000f9244615SMatthew G. Knepley 
2001*dce8aebaSBarry Smith   Note:
2002*dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2003f9244615SMatthew G. Knepley 
2004*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
2005f9244615SMatthew G. Knepley @*/
2006d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
2007d71ae5a4SJacob Faibussowitsch {
2008f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
2009f9244615SMatthew G. Knepley   PetscInt       v, c;
2010f9244615SMatthew G. Knepley 
2011f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2012f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2013f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
2014dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
2015f9244615SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
201663a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
2017f9244615SMatthew G. Knepley #endif
2018f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
2019f9244615SMatthew G. Knepley   if (dim == dE) {
2020f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2021f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
20229371c9d4SSatish Balay         switch (dim) {
2023d71ae5a4SJacob Faibussowitsch         case 1:
2024d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]);
2025d71ae5a4SJacob Faibussowitsch           break;
2026d71ae5a4SJacob Faibussowitsch         case 2:
2027d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2028d71ae5a4SJacob Faibussowitsch           break;
2029d71ae5a4SJacob Faibussowitsch         case 3:
2030d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2031d71ae5a4SJacob Faibussowitsch           break;
2032d71ae5a4SJacob Faibussowitsch         default:
2033d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
2034f9244615SMatthew G. Knepley         }
2035f9244615SMatthew G. Knepley       }
2036f9244615SMatthew G. Knepley     }
2037f9244615SMatthew G. Knepley   } else {
2038f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2039ad540459SPierre Jolivet       for (c = 0; c < Nc; ++c) DMPlex_PTAPReal_Internal(fegeom->invJ, dim, dE, &vals[(v * Nc + c) * dE * dE], &vals[(v * Nc + c) * dE * dE]);
2040f9244615SMatthew G. Knepley     }
2041f9244615SMatthew G. Knepley   }
2042f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
2043f9244615SMatthew G. Knepley   if (Nc == 1 || Nc != dim) PetscFunctionReturn(0);
2044f9244615SMatthew G. Knepley   switch (trans) {
2045d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
2046d71ae5a4SJacob Faibussowitsch     break;
2047d71ae5a4SJacob Faibussowitsch   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
2048d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2049d71ae5a4SJacob Faibussowitsch   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
2050d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2051f9244615SMatthew G. Knepley   }
2052f9244615SMatthew G. Knepley   PetscFunctionReturn(0);
2053f9244615SMatthew G. Knepley }
2054f9244615SMatthew G. Knepley 
2055f9244615SMatthew G. Knepley /*@C
20564bee2e38SMatthew G. Knepley   PetscDualSpacePullback - Transform the given functional so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method.
20574bee2e38SMatthew G. Knepley 
20584bee2e38SMatthew G. Knepley   Input Parameters:
2059*dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
20604bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
20614bee2e38SMatthew G. Knepley . Nq         - The number of function samples
20624bee2e38SMatthew G. Knepley . Nc         - The number of function components
20634bee2e38SMatthew G. Knepley - pointEval  - The function values
20644bee2e38SMatthew G. Knepley 
20654bee2e38SMatthew G. Knepley   Output Parameter:
20664bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
20674bee2e38SMatthew G. Knepley 
20684bee2e38SMatthew G. Knepley   Level: advanced
20694bee2e38SMatthew G. Knepley 
2070*dce8aebaSBarry Smith   Notes:
2071*dce8aebaSBarry Smith   Functions transform in a complementary way (pushforward) to functionals, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex.
20724bee2e38SMatthew G. Knepley 
2073*dce8aebaSBarry Smith   This only handles tranformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
20742edcad52SToby Isaac 
2075*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
20764bee2e38SMatthew G. Knepley @*/
2077d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2078d71ae5a4SJacob Faibussowitsch {
20794bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2080b4457527SToby Isaac   PetscInt                    k;
20814bee2e38SMatthew G. Knepley 
20824bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
20834bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20844bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2085dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
20864bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
20874bee2e38SMatthew G. Knepley      This determines their transformation properties. */
20889566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
20899371c9d4SSatish Balay   switch (k) {
2090d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2091d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2092d71ae5a4SJacob Faibussowitsch     break;
2093d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2094d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2095d71ae5a4SJacob Faibussowitsch     break;
2096b4457527SToby Isaac   case 2:
2097d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2098d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2099d71ae5a4SJacob Faibussowitsch     break;
2100d71ae5a4SJacob Faibussowitsch   default:
2101d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21024bee2e38SMatthew G. Knepley   }
21039566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
21044bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
21054bee2e38SMatthew G. Knepley }
21064bee2e38SMatthew G. Knepley 
21074bee2e38SMatthew G. Knepley /*@C
21084bee2e38SMatthew G. Knepley   PetscDualSpacePushforward - Transform the given function so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method.
21094bee2e38SMatthew G. Knepley 
21104bee2e38SMatthew G. Knepley   Input Parameters:
2111*dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
21124bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
21134bee2e38SMatthew G. Knepley . Nq         - The number of function samples
21144bee2e38SMatthew G. Knepley . Nc         - The number of function components
21154bee2e38SMatthew G. Knepley - pointEval  - The function values
21164bee2e38SMatthew G. Knepley 
21174bee2e38SMatthew G. Knepley   Output Parameter:
21184bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
21194bee2e38SMatthew G. Knepley 
21204bee2e38SMatthew G. Knepley   Level: advanced
21214bee2e38SMatthew G. Knepley 
2122*dce8aebaSBarry Smith   Notes:
2123*dce8aebaSBarry Smith   Functionals transform in a complementary way (pullback) to functions, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex.
21244bee2e38SMatthew G. Knepley 
2125*dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21262edcad52SToby Isaac 
2127*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21284bee2e38SMatthew G. Knepley @*/
2129d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2130d71ae5a4SJacob Faibussowitsch {
21314bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2132b4457527SToby Isaac   PetscInt                    k;
21334bee2e38SMatthew G. Knepley 
21344bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21354bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21364bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2137dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21384bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21394bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21409566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21419371c9d4SSatish Balay   switch (k) {
2142d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2143d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2144d71ae5a4SJacob Faibussowitsch     break;
2145d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2146d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2147d71ae5a4SJacob Faibussowitsch     break;
2148b4457527SToby Isaac   case 2:
2149d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2150d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2151d71ae5a4SJacob Faibussowitsch     break;
2152d71ae5a4SJacob Faibussowitsch   default:
2153d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21544bee2e38SMatthew G. Knepley   }
21559566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
21564bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
21574bee2e38SMatthew G. Knepley }
21584bee2e38SMatthew G. Knepley 
21594bee2e38SMatthew G. Knepley /*@C
21604bee2e38SMatthew G. Knepley   PetscDualSpacePushforwardGradient - Transform the given function gradient so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method.
21614bee2e38SMatthew G. Knepley 
21624bee2e38SMatthew G. Knepley   Input Parameters:
2163*dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
21644bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
21654bee2e38SMatthew G. Knepley . Nq         - The number of function gradient samples
21664bee2e38SMatthew G. Knepley . Nc         - The number of function components
21674bee2e38SMatthew G. Knepley - pointEval  - The function gradient values
21684bee2e38SMatthew G. Knepley 
21694bee2e38SMatthew G. Knepley   Output Parameter:
21704bee2e38SMatthew G. Knepley . pointEval  - The transformed function gradient values
21714bee2e38SMatthew G. Knepley 
21724bee2e38SMatthew G. Knepley   Level: advanced
21734bee2e38SMatthew G. Knepley 
2174*dce8aebaSBarry Smith   Notes:
2175*dce8aebaSBarry Smith   Functionals transform in a complementary way (pullback) to functions, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex.
21764bee2e38SMatthew G. Knepley 
2177*dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21782edcad52SToby Isaac 
2179*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2180dc0529c6SBarry Smith @*/
2181d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2182d71ae5a4SJacob Faibussowitsch {
21834bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2184b4457527SToby Isaac   PetscInt                    k;
21854bee2e38SMatthew G. Knepley 
21864bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21874bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21884bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2189dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21904bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21914bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21929566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21939371c9d4SSatish Balay   switch (k) {
2194d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2195d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2196d71ae5a4SJacob Faibussowitsch     break;
2197d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2198d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2199d71ae5a4SJacob Faibussowitsch     break;
2200b4457527SToby Isaac   case 2:
2201d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2202d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2203d71ae5a4SJacob Faibussowitsch     break;
2204d71ae5a4SJacob Faibussowitsch   default:
2205d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22064bee2e38SMatthew G. Knepley   }
22079566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22084bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
22094bee2e38SMatthew G. Knepley }
2210f9244615SMatthew G. Knepley 
2211f9244615SMatthew G. Knepley /*@C
2212f9244615SMatthew G. Knepley   PetscDualSpacePushforwardHessian - Transform the given function Hessian so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method.
2213f9244615SMatthew G. Knepley 
2214f9244615SMatthew G. Knepley   Input Parameters:
2215*dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
2216f9244615SMatthew G. Knepley . fegeom     - The geometry for this cell
2217f9244615SMatthew G. Knepley . Nq         - The number of function Hessian samples
2218f9244615SMatthew G. Knepley . Nc         - The number of function components
2219f9244615SMatthew G. Knepley - pointEval  - The function gradient values
2220f9244615SMatthew G. Knepley 
2221f9244615SMatthew G. Knepley   Output Parameter:
2222f9244615SMatthew G. Knepley . pointEval  - The transformed function Hessian values
2223f9244615SMatthew G. Knepley 
2224f9244615SMatthew G. Knepley   Level: advanced
2225f9244615SMatthew G. Knepley 
2226*dce8aebaSBarry Smith   Notes:
2227*dce8aebaSBarry Smith   Functionals transform in a complementary way (pullback) to functions, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex.
2228f9244615SMatthew G. Knepley 
2229*dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2230f9244615SMatthew G. Knepley 
2231*dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2232f9244615SMatthew G. Knepley @*/
2233d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2234d71ae5a4SJacob Faibussowitsch {
2235f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2236f9244615SMatthew G. Knepley   PetscInt                    k;
2237f9244615SMatthew G. Knepley 
2238f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2239f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2240f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2241dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
2242f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2243f9244615SMatthew G. Knepley      This determines their transformation properties. */
22449566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22459371c9d4SSatish Balay   switch (k) {
2246d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2247d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2248d71ae5a4SJacob Faibussowitsch     break;
2249d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2250d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2251d71ae5a4SJacob Faibussowitsch     break;
2252f9244615SMatthew G. Knepley   case 2:
2253d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2254d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2255d71ae5a4SJacob Faibussowitsch     break;
2256d71ae5a4SJacob Faibussowitsch   default:
2257d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2258f9244615SMatthew G. Knepley   }
22599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
2260f9244615SMatthew G. Knepley   PetscFunctionReturn(0);
2261f9244615SMatthew G. Knepley }
2262