xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision f13dfd9ea68e0ddeee984e65c377a1819eab8a8a)
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:
2220f4b53cSBarry Smith . tup - A tuple of `len` integers whose sum is at most `max`
236f905325SMatthew G. Knepley 
246f905325SMatthew G. Knepley   Level: developer
256f905325SMatthew G. Knepley 
26dce8aebaSBarry 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]++;
393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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:
5320f4b53cSBarry Smith . tup - A tuple of `len` integers whose entries are at most `max`
546f905325SMatthew G. Knepley 
556f905325SMatthew G. Knepley   Level: developer
566f905325SMatthew G. Knepley 
57dce8aebaSBarry 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]++;
723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
736f905325SMatthew G. Knepley }
746f905325SMatthew G. Knepley 
7520cf1dd8SToby Isaac /*@C
76dce8aebaSBarry Smith   PetscDualSpaceRegister - Adds a new `PetscDualSpaceType`
7720cf1dd8SToby Isaac 
7820cf1dd8SToby Isaac   Not Collective
7920cf1dd8SToby Isaac 
8020cf1dd8SToby Isaac   Input Parameters:
812fe279fdSBarry Smith + sname    - The name of a new user-defined creation routine
822fe279fdSBarry Smith - function - The creation routine
8320cf1dd8SToby Isaac 
8460225df5SJacob Faibussowitsch   Example 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 
101dce8aebaSBarry Smith   Note:
102dce8aebaSBarry Smith   `PetscDualSpaceRegister()` may be called multiple times to add several user-defined `PetscDualSpace`
10320cf1dd8SToby Isaac 
104dce8aebaSBarry 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));
1103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11120cf1dd8SToby Isaac }
11220cf1dd8SToby Isaac 
11320cf1dd8SToby Isaac /*@C
114dce8aebaSBarry Smith   PetscDualSpaceSetType - Builds a particular `PetscDualSpace` based on its `PetscDualSpaceType`
11520cf1dd8SToby Isaac 
11620f4b53cSBarry Smith   Collective
11720cf1dd8SToby Isaac 
11820cf1dd8SToby Isaac   Input Parameters:
119dce8aebaSBarry 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 
127dce8aebaSBarry 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));
1373ba16761SJacob Faibussowitsch   if (match) PetscFunctionReturn(PETSC_SUCCESS);
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));
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14920cf1dd8SToby Isaac }
15020cf1dd8SToby Isaac 
15120cf1dd8SToby Isaac /*@C
152dce8aebaSBarry Smith   PetscDualSpaceGetType - Gets the `PetscDualSpaceType` name (as a string) from the object.
15320cf1dd8SToby Isaac 
15420cf1dd8SToby Isaac   Not Collective
15520cf1dd8SToby Isaac 
15620cf1dd8SToby Isaac   Input Parameter:
157dce8aebaSBarry Smith . sp - The `PetscDualSpace`
15820cf1dd8SToby Isaac 
15920cf1dd8SToby Isaac   Output Parameter:
160dce8aebaSBarry Smith . name - The `PetscDualSpaceType` name
16120cf1dd8SToby Isaac 
16220cf1dd8SToby Isaac   Level: intermediate
16320cf1dd8SToby Isaac 
164dce8aebaSBarry 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);
1704f572ea9SToby Isaac   PetscAssertPointer(name, 2);
17148a46eb9SPierre Jolivet   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
17220cf1dd8SToby Isaac   *name = ((PetscObject)sp)->type_name;
1733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
1852dce792eSToby Isaac   if (sp->k != 0 && sp->k != PETSC_FORM_DEGREE_UNDEFINED) {
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));
2033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
204221d6281SMatthew G. Knepley }
205221d6281SMatthew G. Knepley 
206fe2efc57SMark /*@C
207dce8aebaSBarry Smith   PetscDualSpaceViewFromOptions - View a `PetscDualSpace` based on values in the options database
208fe2efc57SMark 
20920f4b53cSBarry Smith   Collective
210fe2efc57SMark 
211fe2efc57SMark   Input Parameters:
212dce8aebaSBarry Smith + A    - the `PetscDualSpace` object
213dce8aebaSBarry Smith . obj  - Optional object, provides the options prefix
214dce8aebaSBarry Smith - name - command line option name
215fe2efc57SMark 
216fe2efc57SMark   Level: intermediate
217dce8aebaSBarry Smith 
21820f4b53cSBarry Smith   Note:
21920f4b53cSBarry Smith   See `PetscObjectViewFromOptions()` for possible command line values
22020f4b53cSBarry Smith 
221db781477SPatrick Sanan .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()`
222fe2efc57SMark @*/
223d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PetscObject obj, const char name[])
224d71ae5a4SJacob Faibussowitsch {
225fe2efc57SMark   PetscFunctionBegin;
226fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
2279566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
2283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
229fe2efc57SMark }
230fe2efc57SMark 
23120cf1dd8SToby Isaac /*@
232dce8aebaSBarry Smith   PetscDualSpaceView - Views a `PetscDualSpace`
23320cf1dd8SToby Isaac 
23420f4b53cSBarry Smith   Collective
23520cf1dd8SToby Isaac 
236d8d19677SJose E. Roman   Input Parameters:
237dce8aebaSBarry Smith + sp - the `PetscDualSpace` object to view
23820cf1dd8SToby Isaac - v  - the viewer
23920cf1dd8SToby Isaac 
240a4ce7ad1SMatthew G. Knepley   Level: beginner
24120cf1dd8SToby Isaac 
242dce8aebaSBarry Smith .seealso: `PetscViewer`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
24320cf1dd8SToby Isaac @*/
244d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
245d71ae5a4SJacob Faibussowitsch {
246d9bac1caSLisandro Dalcin   PetscBool iascii;
24720cf1dd8SToby Isaac 
24820cf1dd8SToby Isaac   PetscFunctionBegin;
24920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
250d9bac1caSLisandro Dalcin   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
2519566063dSJacob Faibussowitsch   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v));
2529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
2539566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v));
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25520cf1dd8SToby Isaac }
25620cf1dd8SToby Isaac 
25720cf1dd8SToby Isaac /*@
258dce8aebaSBarry Smith   PetscDualSpaceSetFromOptions - sets parameters in a `PetscDualSpace` from the options database
25920cf1dd8SToby Isaac 
26020f4b53cSBarry Smith   Collective
26120cf1dd8SToby Isaac 
26220cf1dd8SToby Isaac   Input Parameter:
263dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to set options for
26420cf1dd8SToby Isaac 
265dce8aebaSBarry Smith   Options Database Keys:
2668f2aacc6SMatthew G. Knepley + -petscdualspace_order <order>                 - the approximation order of the space
267fe36a153SMatthew G. Knepley . -petscdualspace_form_degree <deg>             - the form degree, say 0 for point evaluations, or 2 for area integrals
2688f2aacc6SMatthew G. Knepley . -petscdualspace_components <c>                - the number of components, say d for a vector field
269a9c5e6deSMatthew G. Knepley . -petscdualspace_refcell <celltype>            - Reference cell type name
270a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_continuity           - Flag for continuous element
271a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_tensor               - Flag for tensor dual space
272a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_trimmed              - Flag for trimmed dual space
273a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_type <nodetype> - Lagrange node location type
274a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_endpoints       - Flag for nodes that include endpoints
275a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_exponent        - Gauss-Jacobi weight function exponent
276a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_use_moments          - Use moments (where appropriate) for functionals
277a9c5e6deSMatthew G. Knepley - -petscdualspace_lagrange_moment_order <order> - Quadrature order for moment functionals
27820cf1dd8SToby Isaac 
279a4ce7ad1SMatthew G. Knepley   Level: intermediate
28020cf1dd8SToby Isaac 
281dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()`
28220cf1dd8SToby Isaac @*/
283d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
284d71ae5a4SJacob Faibussowitsch {
2852df84da0SMatthew G. Knepley   DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE;
28620cf1dd8SToby Isaac   const char    *defaultType;
28720cf1dd8SToby Isaac   char           name[256];
288f783ec47SMatthew G. Knepley   PetscBool      flg;
28920cf1dd8SToby Isaac 
29020cf1dd8SToby Isaac   PetscFunctionBegin;
29120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
29220cf1dd8SToby Isaac   if (!((PetscObject)sp)->type_name) {
29320cf1dd8SToby Isaac     defaultType = PETSCDUALSPACELAGRANGE;
29420cf1dd8SToby Isaac   } else {
29520cf1dd8SToby Isaac     defaultType = ((PetscObject)sp)->type_name;
29620cf1dd8SToby Isaac   }
2979566063dSJacob Faibussowitsch   if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll());
29820cf1dd8SToby Isaac 
299d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sp);
3009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg));
30120cf1dd8SToby Isaac   if (flg) {
3029566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, name));
30320cf1dd8SToby Isaac   } else if (!((PetscObject)sp)->type_name) {
3049566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, defaultType));
30520cf1dd8SToby Isaac   }
3069566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0));
3079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL));
3089566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1));
309dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject);
3109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg));
311063ee4adSMatthew G. Knepley   if (flg) {
312063ee4adSMatthew G. Knepley     DM K;
313063ee4adSMatthew G. Knepley 
3149566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K));
3159566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetDM(sp, K));
3169566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&K));
317063ee4adSMatthew G. Knepley   }
318063ee4adSMatthew G. Knepley 
31920cf1dd8SToby Isaac   /* process any options handlers added with PetscObjectAddOptionsHandler() */
320dbbe0bcdSBarry Smith   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject));
321d0609cedSBarry Smith   PetscOptionsEnd();
322063ee4adSMatthew G. Knepley   sp->setfromoptionscalled = PETSC_TRUE;
3233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32420cf1dd8SToby Isaac }
32520cf1dd8SToby Isaac 
32620cf1dd8SToby Isaac /*@
327dce8aebaSBarry Smith   PetscDualSpaceSetUp - Construct a basis for a `PetscDualSpace`
32820cf1dd8SToby Isaac 
32920f4b53cSBarry Smith   Collective
33020cf1dd8SToby Isaac 
33120cf1dd8SToby Isaac   Input Parameter:
332dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to setup
33320cf1dd8SToby Isaac 
334a4ce7ad1SMatthew G. Knepley   Level: intermediate
33520cf1dd8SToby Isaac 
336dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
33720cf1dd8SToby Isaac @*/
338d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
339d71ae5a4SJacob Faibussowitsch {
34020cf1dd8SToby Isaac   PetscFunctionBegin;
34120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
3423ba16761SJacob Faibussowitsch   if (sp->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
3439566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
34420cf1dd8SToby Isaac   sp->setupcalled = PETSC_TRUE;
345dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setup);
3469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
3479566063dSJacob Faibussowitsch   if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view"));
3483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34920cf1dd8SToby Isaac }
35020cf1dd8SToby Isaac 
351d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm)
352d71ae5a4SJacob Faibussowitsch {
353b4457527SToby Isaac   PetscInt pStart = -1, pEnd = -1, depth = -1;
354b4457527SToby Isaac 
355b4457527SToby Isaac   PetscFunctionBegin;
3563ba16761SJacob Faibussowitsch   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
3579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
359b4457527SToby Isaac 
360b4457527SToby Isaac   if (sp->pointSpaces) {
361b4457527SToby Isaac     PetscInt i;
362b4457527SToby Isaac 
363f4f49eeaSPierre Jolivet     for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&sp->pointSpaces[i]));
364b4457527SToby Isaac   }
3659566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->pointSpaces));
366b4457527SToby Isaac 
367b4457527SToby Isaac   if (sp->heightSpaces) {
368b4457527SToby Isaac     PetscInt i;
369b4457527SToby Isaac 
370f4f49eeaSPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&sp->heightSpaces[i]));
371b4457527SToby Isaac   }
3729566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
373b4457527SToby Isaac 
374f4f49eeaSPierre Jolivet   PetscCall(PetscSectionDestroy(&sp->pointSection));
375f4f49eeaSPierre Jolivet   PetscCall(PetscSectionDestroy(&sp->intPointSection));
376f4f49eeaSPierre Jolivet   PetscCall(PetscQuadratureDestroy(&sp->intNodes));
377f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->intDofValues));
378f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->intNodeValues));
379f4f49eeaSPierre Jolivet   PetscCall(MatDestroy(&sp->intMat));
380f4f49eeaSPierre Jolivet   PetscCall(PetscQuadratureDestroy(&sp->allNodes));
381f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->allDofValues));
382f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->allNodeValues));
383f4f49eeaSPierre Jolivet   PetscCall(MatDestroy(&sp->allMat));
3849566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
3853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
386b4457527SToby Isaac }
387b4457527SToby Isaac 
38820cf1dd8SToby Isaac /*@
389dce8aebaSBarry Smith   PetscDualSpaceDestroy - Destroys a `PetscDualSpace` object
39020cf1dd8SToby Isaac 
39120f4b53cSBarry Smith   Collective
39220cf1dd8SToby Isaac 
39320cf1dd8SToby Isaac   Input Parameter:
394dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to destroy
39520cf1dd8SToby Isaac 
396a4ce7ad1SMatthew G. Knepley   Level: beginner
39720cf1dd8SToby Isaac 
398dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
39920cf1dd8SToby Isaac @*/
400d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
401d71ae5a4SJacob Faibussowitsch {
40220cf1dd8SToby Isaac   PetscInt dim, f;
403b4457527SToby Isaac   DM       dm;
40420cf1dd8SToby Isaac 
40520cf1dd8SToby Isaac   PetscFunctionBegin;
4063ba16761SJacob Faibussowitsch   if (!*sp) PetscFunctionReturn(PETSC_SUCCESS);
407f4f49eeaSPierre Jolivet   PetscValidHeaderSpecific(*sp, PETSCDUALSPACE_CLASSID, 1);
40820cf1dd8SToby Isaac 
409f4f49eeaSPierre Jolivet   if (--((PetscObject)*sp)->refct > 0) {
4109371c9d4SSatish Balay     *sp = NULL;
4113ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4129371c9d4SSatish Balay   }
413f4f49eeaSPierre Jolivet   ((PetscObject)*sp)->refct = 0;
41420cf1dd8SToby Isaac 
4159566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
416b4457527SToby Isaac   dm = (*sp)->dm;
417b4457527SToby Isaac 
418f4f49eeaSPierre Jolivet   PetscTryTypeMethod(*sp, destroy);
4199566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
420b4457527SToby Isaac 
42148a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
4239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4249566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
4253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42620cf1dd8SToby Isaac }
42720cf1dd8SToby Isaac 
42820cf1dd8SToby Isaac /*@
429dce8aebaSBarry Smith   PetscDualSpaceCreate - Creates an empty `PetscDualSpace` object. The type can then be set with `PetscDualSpaceSetType()`.
43020cf1dd8SToby Isaac 
431d083f849SBarry Smith   Collective
43220cf1dd8SToby Isaac 
43320cf1dd8SToby Isaac   Input Parameter:
434dce8aebaSBarry Smith . comm - The communicator for the `PetscDualSpace` object
43520cf1dd8SToby Isaac 
43620cf1dd8SToby Isaac   Output Parameter:
437dce8aebaSBarry Smith . sp - The `PetscDualSpace` object
43820cf1dd8SToby Isaac 
43920cf1dd8SToby Isaac   Level: beginner
44020cf1dd8SToby Isaac 
441dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
44220cf1dd8SToby Isaac @*/
443d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
444d71ae5a4SJacob Faibussowitsch {
44520cf1dd8SToby Isaac   PetscDualSpace s;
44620cf1dd8SToby Isaac 
44720cf1dd8SToby Isaac   PetscFunctionBegin;
4484f572ea9SToby Isaac   PetscAssertPointer(sp, 2);
4499566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
45020cf1dd8SToby Isaac   *sp = NULL;
4519566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
45220cf1dd8SToby Isaac 
4539566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
45420cf1dd8SToby Isaac 
45520cf1dd8SToby Isaac   s->order       = 0;
45620cf1dd8SToby Isaac   s->Nc          = 1;
4574bee2e38SMatthew G. Knepley   s->k           = 0;
458b4457527SToby Isaac   s->spdim       = -1;
459b4457527SToby Isaac   s->spintdim    = -1;
460b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
46120cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
46220cf1dd8SToby Isaac 
46320cf1dd8SToby Isaac   *sp = s;
4643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46520cf1dd8SToby Isaac }
46620cf1dd8SToby Isaac 
46720cf1dd8SToby Isaac /*@
468dce8aebaSBarry Smith   PetscDualSpaceDuplicate - Creates a duplicate `PetscDualSpace` object that is not setup.
46920cf1dd8SToby Isaac 
47020f4b53cSBarry Smith   Collective
47120cf1dd8SToby Isaac 
47220cf1dd8SToby Isaac   Input Parameter:
473dce8aebaSBarry Smith . sp - The original `PetscDualSpace`
47420cf1dd8SToby Isaac 
47520cf1dd8SToby Isaac   Output Parameter:
476dce8aebaSBarry Smith . spNew - The duplicate `PetscDualSpace`
47720cf1dd8SToby Isaac 
47820cf1dd8SToby Isaac   Level: beginner
47920cf1dd8SToby Isaac 
480dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
48120cf1dd8SToby Isaac @*/
482d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
483d71ae5a4SJacob Faibussowitsch {
484b4457527SToby Isaac   DM                 dm;
485b4457527SToby Isaac   PetscDualSpaceType type;
486b4457527SToby Isaac   const char        *name;
48720cf1dd8SToby Isaac 
48820cf1dd8SToby Isaac   PetscFunctionBegin;
48920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
4904f572ea9SToby Isaac   PetscAssertPointer(spNew, 2);
4919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4922dce792eSToby Isaac   name = ((PetscObject)sp)->name;
4932dce792eSToby Isaac   if (name) { PetscCall(PetscObjectSetName((PetscObject)*spNew, name)); }
4949566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4959566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4969566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4979566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
498b4457527SToby Isaac 
499b4457527SToby Isaac   (*spNew)->order   = sp->order;
500b4457527SToby Isaac   (*spNew)->k       = sp->k;
501b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
502b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
503dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
5043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50520cf1dd8SToby Isaac }
50620cf1dd8SToby Isaac 
50720cf1dd8SToby Isaac /*@
508dce8aebaSBarry Smith   PetscDualSpaceGetDM - Get the `DM` representing the reference cell of a `PetscDualSpace`
50920cf1dd8SToby Isaac 
51020f4b53cSBarry Smith   Not Collective
51120cf1dd8SToby Isaac 
51220cf1dd8SToby Isaac   Input Parameter:
513dce8aebaSBarry Smith . sp - The `PetscDualSpace`
51420cf1dd8SToby Isaac 
51520cf1dd8SToby Isaac   Output Parameter:
516dce8aebaSBarry Smith . dm - The reference cell, that is a `DM` that consists of a single cell
51720cf1dd8SToby Isaac 
51820cf1dd8SToby Isaac   Level: intermediate
51920cf1dd8SToby Isaac 
520dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
52120cf1dd8SToby Isaac @*/
522d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
523d71ae5a4SJacob Faibussowitsch {
52420cf1dd8SToby Isaac   PetscFunctionBegin;
52520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
5264f572ea9SToby Isaac   PetscAssertPointer(dm, 2);
52720cf1dd8SToby Isaac   *dm = sp->dm;
5283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52920cf1dd8SToby Isaac }
53020cf1dd8SToby Isaac 
53120cf1dd8SToby Isaac /*@
532dce8aebaSBarry Smith   PetscDualSpaceSetDM - Get the `DM` representing the reference cell
53320cf1dd8SToby Isaac 
53420f4b53cSBarry Smith   Not Collective
53520cf1dd8SToby Isaac 
53620cf1dd8SToby Isaac   Input Parameters:
537dce8aebaSBarry Smith + sp - The `PetscDual`Space
53820cf1dd8SToby Isaac - dm - The reference cell
53920cf1dd8SToby Isaac 
54020cf1dd8SToby Isaac   Level: intermediate
54120cf1dd8SToby Isaac 
542dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `DM`, `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
54320cf1dd8SToby Isaac @*/
544d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
545d71ae5a4SJacob Faibussowitsch {
54620cf1dd8SToby Isaac   PetscFunctionBegin;
54720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
54820cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
54928b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5509566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
55148a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5529566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
55320cf1dd8SToby Isaac   sp->dm = dm;
5543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55520cf1dd8SToby Isaac }
55620cf1dd8SToby Isaac 
55720cf1dd8SToby Isaac /*@
55820cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
55920cf1dd8SToby Isaac 
56020f4b53cSBarry Smith   Not Collective
56120cf1dd8SToby Isaac 
56220cf1dd8SToby Isaac   Input Parameter:
563dce8aebaSBarry Smith . sp - The `PetscDualSpace`
56420cf1dd8SToby Isaac 
56520cf1dd8SToby Isaac   Output Parameter:
56620cf1dd8SToby Isaac . order - The order
56720cf1dd8SToby Isaac 
56820cf1dd8SToby Isaac   Level: intermediate
56920cf1dd8SToby Isaac 
570dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
57120cf1dd8SToby Isaac @*/
572d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
573d71ae5a4SJacob Faibussowitsch {
57420cf1dd8SToby Isaac   PetscFunctionBegin;
57520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
5764f572ea9SToby Isaac   PetscAssertPointer(order, 2);
57720cf1dd8SToby Isaac   *order = sp->order;
5783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57920cf1dd8SToby Isaac }
58020cf1dd8SToby Isaac 
58120cf1dd8SToby Isaac /*@
58220cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
58320cf1dd8SToby Isaac 
58420f4b53cSBarry Smith   Not Collective
58520cf1dd8SToby Isaac 
58620cf1dd8SToby Isaac   Input Parameters:
587dce8aebaSBarry Smith + sp    - The `PetscDualSpace`
58820cf1dd8SToby Isaac - order - The order
58920cf1dd8SToby Isaac 
59020cf1dd8SToby Isaac   Level: intermediate
59120cf1dd8SToby Isaac 
592dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
59320cf1dd8SToby Isaac @*/
594d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
595d71ae5a4SJacob Faibussowitsch {
59620cf1dd8SToby Isaac   PetscFunctionBegin;
59720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
59828b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
59920cf1dd8SToby Isaac   sp->order = order;
6003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60120cf1dd8SToby Isaac }
60220cf1dd8SToby Isaac 
60320cf1dd8SToby Isaac /*@
60420cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
60520cf1dd8SToby Isaac 
60620cf1dd8SToby Isaac   Input Parameter:
607dce8aebaSBarry Smith . sp - The `PetscDualSpace`
60820cf1dd8SToby Isaac 
60920cf1dd8SToby Isaac   Output Parameter:
61020cf1dd8SToby Isaac . Nc - The number of components
61120cf1dd8SToby Isaac 
61220cf1dd8SToby Isaac   Level: intermediate
61320cf1dd8SToby Isaac 
614dce8aebaSBarry Smith   Note:
615dce8aebaSBarry Smith   A vector space, for example, will have d components, where d is the spatial dimension
616dce8aebaSBarry Smith 
617db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
61820cf1dd8SToby Isaac @*/
619d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
620d71ae5a4SJacob Faibussowitsch {
62120cf1dd8SToby Isaac   PetscFunctionBegin;
62220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
6234f572ea9SToby Isaac   PetscAssertPointer(Nc, 2);
62420cf1dd8SToby Isaac   *Nc = sp->Nc;
6253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62620cf1dd8SToby Isaac }
62720cf1dd8SToby Isaac 
62820cf1dd8SToby Isaac /*@
62920cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
63020cf1dd8SToby Isaac 
63120cf1dd8SToby Isaac   Input Parameters:
632dce8aebaSBarry Smith + sp - The `PetscDualSpace`
63360225df5SJacob Faibussowitsch - Nc - The number of components
63420cf1dd8SToby Isaac 
63520cf1dd8SToby Isaac   Level: intermediate
63620cf1dd8SToby Isaac 
637db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
63820cf1dd8SToby Isaac @*/
639d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
640d71ae5a4SJacob Faibussowitsch {
64120cf1dd8SToby Isaac   PetscFunctionBegin;
64220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
64328b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
64420cf1dd8SToby Isaac   sp->Nc = Nc;
6453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64620cf1dd8SToby Isaac }
64720cf1dd8SToby Isaac 
64820cf1dd8SToby Isaac /*@
64920cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
65020cf1dd8SToby Isaac 
65120f4b53cSBarry Smith   Not Collective
65220cf1dd8SToby Isaac 
65320cf1dd8SToby Isaac   Input Parameters:
654dce8aebaSBarry Smith + sp - The `PetscDualSpace`
65520cf1dd8SToby Isaac - i  - The basis number
65620cf1dd8SToby Isaac 
65720cf1dd8SToby Isaac   Output Parameter:
65820cf1dd8SToby Isaac . functional - The basis functional
65920cf1dd8SToby Isaac 
66020cf1dd8SToby Isaac   Level: intermediate
66120cf1dd8SToby Isaac 
662dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
66320cf1dd8SToby Isaac @*/
664d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
665d71ae5a4SJacob Faibussowitsch {
66620cf1dd8SToby Isaac   PetscInt dim;
66720cf1dd8SToby Isaac 
66820cf1dd8SToby Isaac   PetscFunctionBegin;
66920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
6704f572ea9SToby Isaac   PetscAssertPointer(functional, 3);
6719566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
67263a3b9bcSJacob 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);
67320cf1dd8SToby Isaac   *functional = sp->functional[i];
6743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
67520cf1dd8SToby Isaac }
67620cf1dd8SToby Isaac 
67720cf1dd8SToby Isaac /*@
67820cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
67920cf1dd8SToby Isaac 
68020f4b53cSBarry Smith   Not Collective
68120cf1dd8SToby Isaac 
68220cf1dd8SToby Isaac   Input Parameter:
683dce8aebaSBarry Smith . sp - The `PetscDualSpace`
68420cf1dd8SToby Isaac 
68520cf1dd8SToby Isaac   Output Parameter:
68620cf1dd8SToby Isaac . dim - The dimension
68720cf1dd8SToby Isaac 
68820cf1dd8SToby Isaac   Level: intermediate
68920cf1dd8SToby Isaac 
690dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
69120cf1dd8SToby Isaac @*/
692d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
693d71ae5a4SJacob Faibussowitsch {
69420cf1dd8SToby Isaac   PetscFunctionBegin;
69520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
6964f572ea9SToby Isaac   PetscAssertPointer(dim, 2);
697b4457527SToby Isaac   if (sp->spdim < 0) {
698b4457527SToby Isaac     PetscSection section;
699b4457527SToby Isaac 
7009566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
701b4457527SToby Isaac     if (section) {
702f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetStorageSize(section, &sp->spdim));
703b4457527SToby Isaac     } else sp->spdim = 0;
704b4457527SToby Isaac   }
705b4457527SToby Isaac   *dim = sp->spdim;
7063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70720cf1dd8SToby Isaac }
70820cf1dd8SToby Isaac 
709b4457527SToby Isaac /*@
710b4457527SToby 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
711b4457527SToby Isaac 
71220f4b53cSBarry Smith   Not Collective
713b4457527SToby Isaac 
714b4457527SToby Isaac   Input Parameter:
715dce8aebaSBarry Smith . sp - The `PetscDualSpace`
716b4457527SToby Isaac 
717b4457527SToby Isaac   Output Parameter:
71860225df5SJacob Faibussowitsch . intdim - The dimension
719b4457527SToby Isaac 
720b4457527SToby Isaac   Level: intermediate
721b4457527SToby Isaac 
722dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
723b4457527SToby Isaac @*/
724d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim)
725d71ae5a4SJacob Faibussowitsch {
726b4457527SToby Isaac   PetscFunctionBegin;
727b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7284f572ea9SToby Isaac   PetscAssertPointer(intdim, 2);
729b4457527SToby Isaac   if (sp->spintdim < 0) {
730b4457527SToby Isaac     PetscSection section;
731b4457527SToby Isaac 
7329566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
733b4457527SToby Isaac     if (section) {
734f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetConstrainedStorageSize(section, &sp->spintdim));
735b4457527SToby Isaac     } else sp->spintdim = 0;
736b4457527SToby Isaac   }
737b4457527SToby Isaac   *intdim = sp->spintdim;
7383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
739b4457527SToby Isaac }
740b4457527SToby Isaac 
741b4457527SToby Isaac /*@
742b4457527SToby Isaac   PetscDualSpaceGetUniform - Whether this dual space is uniform
743b4457527SToby Isaac 
74420f4b53cSBarry Smith   Not Collective
745b4457527SToby Isaac 
7462fe279fdSBarry Smith   Input Parameter:
747b4457527SToby Isaac . sp - A dual space
748b4457527SToby Isaac 
7492fe279fdSBarry Smith   Output Parameter:
750dce8aebaSBarry Smith . uniform - `PETSC_TRUE` if (a) the dual space is the same for each point in a stratum of the reference `DMPLEX`, and
751dce8aebaSBarry Smith              (b) every symmetry of each point in the reference `DMPLEX` is also a symmetry of the point's dual space.
752b4457527SToby Isaac 
753b4457527SToby Isaac   Level: advanced
754b4457527SToby Isaac 
755dce8aebaSBarry Smith   Note:
756dce8aebaSBarry Smith   All of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
757b4457527SToby Isaac   with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
758b4457527SToby Isaac 
759dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
760b4457527SToby Isaac @*/
761d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform)
762d71ae5a4SJacob Faibussowitsch {
763b4457527SToby Isaac   PetscFunctionBegin;
764b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7654f572ea9SToby Isaac   PetscAssertPointer(uniform, 2);
766b4457527SToby Isaac   *uniform = sp->uniform;
7673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
768b4457527SToby Isaac }
769b4457527SToby Isaac 
77020cf1dd8SToby Isaac /*@C
77120cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
77220cf1dd8SToby Isaac 
77320f4b53cSBarry Smith   Not Collective
77420cf1dd8SToby Isaac 
77520cf1dd8SToby Isaac   Input Parameter:
776dce8aebaSBarry Smith . sp - The `PetscDualSpace`
77720cf1dd8SToby Isaac 
77820cf1dd8SToby Isaac   Output Parameter:
77920cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
78020cf1dd8SToby Isaac 
78120cf1dd8SToby Isaac   Level: intermediate
78220cf1dd8SToby Isaac 
783*f13dfd9eSBarry Smith   Note:
784*f13dfd9eSBarry Smith   Do not free `numDof`
785*f13dfd9eSBarry Smith 
786dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
78720cf1dd8SToby Isaac @*/
788*f13dfd9eSBarry Smith PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt *numDof[])
789d71ae5a4SJacob Faibussowitsch {
79020cf1dd8SToby Isaac   PetscFunctionBegin;
79120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7924f572ea9SToby Isaac   PetscAssertPointer(numDof, 2);
79328b400f6SJacob 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");
794b4457527SToby Isaac   if (!sp->numDof) {
795b4457527SToby Isaac     DM           dm;
796b4457527SToby Isaac     PetscInt     depth, d;
797b4457527SToby Isaac     PetscSection section;
798b4457527SToby Isaac 
7999566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
8009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
801f4f49eeaSPierre Jolivet     PetscCall(PetscCalloc1(depth + 1, &sp->numDof));
8029566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
803b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
804b4457527SToby Isaac       PetscInt dStart, dEnd;
805b4457527SToby Isaac 
8069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
807b4457527SToby Isaac       if (dEnd <= dStart) continue;
808f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetDof(section, dStart, &sp->numDof[d]));
809b4457527SToby Isaac     }
810b4457527SToby Isaac   }
811b4457527SToby Isaac   *numDof = sp->numDof;
81208401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
8133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81420cf1dd8SToby Isaac }
81520cf1dd8SToby Isaac 
816b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
817d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection)
818d71ae5a4SJacob Faibussowitsch {
819b4457527SToby Isaac   DM           dm;
820b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
821b4457527SToby Isaac   PetscInt    *seen, *perm;
822b4457527SToby Isaac   PetscSection section;
823b4457527SToby Isaac 
824b4457527SToby Isaac   PetscFunctionBegin;
825b4457527SToby Isaac   dm = sp->dm;
8269566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
8279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8299566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
8309566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
8319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8329566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
833b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
834b4457527SToby Isaac     PetscInt  closureSize = -1, e;
835b4457527SToby Isaac     PetscInt *closure     = NULL;
836b4457527SToby Isaac 
837b4457527SToby Isaac     perm[count++]    = c;
838b4457527SToby Isaac     seen[c - pStart] = 1;
8399566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
840b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
841b4457527SToby Isaac       PetscInt point = closure[2 * e];
842b4457527SToby Isaac 
843b4457527SToby Isaac       if (seen[point - pStart]) continue;
844b4457527SToby Isaac       perm[count++]        = point;
845b4457527SToby Isaac       seen[point - pStart] = 1;
846b4457527SToby Isaac     }
8479566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
848b4457527SToby Isaac   }
8491dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8509371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8519371c9d4SSatish Balay     if (perm[i] != i) break;
852b4457527SToby Isaac   if (i < pEnd - pStart) {
853b4457527SToby Isaac     IS permIS;
854b4457527SToby Isaac 
8559566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8569566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8579566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8589566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
859b4457527SToby Isaac   } else {
8609566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
861b4457527SToby Isaac   }
8629566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
863b4457527SToby Isaac   *topSection = section;
8643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
865b4457527SToby Isaac }
866b4457527SToby Isaac 
867b4457527SToby Isaac /* mark boundary points and set up */
868d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section)
869d71ae5a4SJacob Faibussowitsch {
870b4457527SToby Isaac   DM       dm;
871b4457527SToby Isaac   DMLabel  boundary;
872b4457527SToby Isaac   PetscInt pStart, pEnd, p;
873b4457527SToby Isaac 
874b4457527SToby Isaac   PetscFunctionBegin;
875b4457527SToby Isaac   dm = sp->dm;
8769566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8779566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8789566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8799566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
881b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
882b4457527SToby Isaac     PetscInt bval;
883b4457527SToby Isaac 
8849566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
885b4457527SToby Isaac     if (bval == 1) {
886b4457527SToby Isaac       PetscInt dof;
887b4457527SToby Isaac 
8889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8899566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
890b4457527SToby Isaac     }
891b4457527SToby Isaac   }
8929566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
895b4457527SToby Isaac }
896b4457527SToby Isaac 
897a4ce7ad1SMatthew G. Knepley /*@
898dce8aebaSBarry Smith   PetscDualSpaceGetSection - Create a `PetscSection` over the reference cell with the layout from this space
899a4ce7ad1SMatthew G. Knepley 
90020f4b53cSBarry Smith   Collective
901a4ce7ad1SMatthew G. Knepley 
9022fe279fdSBarry Smith   Input Parameter:
903dce8aebaSBarry Smith . sp - The `PetscDualSpace`
904a4ce7ad1SMatthew G. Knepley 
905a4ce7ad1SMatthew G. Knepley   Output Parameter:
906a4ce7ad1SMatthew G. Knepley . section - The section
907a4ce7ad1SMatthew G. Knepley 
908a4ce7ad1SMatthew G. Knepley   Level: advanced
909a4ce7ad1SMatthew G. Knepley 
910dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
911a4ce7ad1SMatthew G. Knepley @*/
912d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section)
913d71ae5a4SJacob Faibussowitsch {
914b4457527SToby Isaac   PetscInt pStart, pEnd, p;
915b4457527SToby Isaac 
916b4457527SToby Isaac   PetscFunctionBegin;
91778f1d139SRomain Beucher   if (!sp->dm) {
91878f1d139SRomain Beucher     *section = NULL;
9193ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
92078f1d139SRomain Beucher   }
921b4457527SToby Isaac   if (!sp->pointSection) {
922b4457527SToby Isaac     /* mark the boundary */
923f4f49eeaSPierre Jolivet     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &sp->pointSection));
9249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
925b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
926b4457527SToby Isaac       PetscDualSpace psp;
927b4457527SToby Isaac 
9289566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
929b4457527SToby Isaac       if (psp) {
930b4457527SToby Isaac         PetscInt dof;
931b4457527SToby Isaac 
9329566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
9339566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
934b4457527SToby Isaac       }
935b4457527SToby Isaac     }
9369566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
937b4457527SToby Isaac   }
938b4457527SToby Isaac   *section = sp->pointSection;
9393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
940b4457527SToby Isaac }
941b4457527SToby Isaac 
9422dce792eSToby Isaac /*@
9432dce792eSToby Isaac   PetscDualSpaceGetInteriorSection - Create a `PetscSection` over the reference cell with the layout from this space
9442dce792eSToby Isaac   for interior degrees of freedom
9452dce792eSToby Isaac 
9462dce792eSToby Isaac   Collective
9472dce792eSToby Isaac 
9482dce792eSToby Isaac   Input Parameter:
9492dce792eSToby Isaac . sp - The `PetscDualSpace`
9502dce792eSToby Isaac 
9512dce792eSToby Isaac   Output Parameter:
9522dce792eSToby Isaac . section - The interior section
9532dce792eSToby Isaac 
9542dce792eSToby Isaac   Level: advanced
9552dce792eSToby Isaac 
9562dce792eSToby Isaac   Note:
9572dce792eSToby Isaac   Most reference domains have one cell, in which case the only cell will have
9582dce792eSToby Isaac   all of the interior degrees of freedom in the interior section.  But
9592dce792eSToby Isaac   for `PETSCDUALSPACEREFINED` there may be other mesh points in the interior,
9602dce792eSToby Isaac   and this section describes their layout.
9612dce792eSToby Isaac 
9622dce792eSToby Isaac .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
9632dce792eSToby Isaac @*/
9642dce792eSToby Isaac PetscErrorCode PetscDualSpaceGetInteriorSection(PetscDualSpace sp, PetscSection *section)
9652dce792eSToby Isaac {
9662dce792eSToby Isaac   PetscInt pStart, pEnd, p;
9672dce792eSToby Isaac 
9682dce792eSToby Isaac   PetscFunctionBegin;
9692dce792eSToby Isaac   if (!sp->dm) {
9702dce792eSToby Isaac     *section = NULL;
9712dce792eSToby Isaac     PetscFunctionReturn(PETSC_SUCCESS);
9722dce792eSToby Isaac   }
9732dce792eSToby Isaac   if (!sp->intPointSection) {
9742dce792eSToby Isaac     PetscSection full_section;
9752dce792eSToby Isaac 
9762dce792eSToby Isaac     PetscCall(PetscDualSpaceGetSection(sp, &full_section));
977f4f49eeaSPierre Jolivet     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &sp->intPointSection));
9782dce792eSToby Isaac     PetscCall(PetscSectionGetChart(full_section, &pStart, &pEnd));
9792dce792eSToby Isaac     for (p = pStart; p < pEnd; p++) {
9802dce792eSToby Isaac       PetscInt dof, cdof;
9812dce792eSToby Isaac 
9822dce792eSToby Isaac       PetscCall(PetscSectionGetDof(full_section, p, &dof));
9832dce792eSToby Isaac       PetscCall(PetscSectionGetConstraintDof(full_section, p, &cdof));
9842dce792eSToby Isaac       PetscCall(PetscSectionSetDof(sp->intPointSection, p, dof - cdof));
9852dce792eSToby Isaac     }
9862dce792eSToby Isaac     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->intPointSection));
9872dce792eSToby Isaac   }
9882dce792eSToby Isaac   *section = sp->intPointSection;
9892dce792eSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
9902dce792eSToby Isaac }
9912dce792eSToby Isaac 
992b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
993b4457527SToby Isaac  * have one cell */
994d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd)
995d71ae5a4SJacob Faibussowitsch {
996b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
997b4457527SToby Isaac   PetscSection section;
998b4457527SToby Isaac   PetscInt     dim, s, k;
99920cf1dd8SToby Isaac   DM           dm;
100020cf1dd8SToby Isaac 
100120cf1dd8SToby Isaac   PetscFunctionBegin;
10029566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
10039566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
10049566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
10059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
10069566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
1007b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
1008b4457527SToby Isaac     PetscReal      detJ, hdetJ;
1009b4457527SToby Isaac     PetscDualSpace ssp;
1010b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
1011b4457527SToby Isaac     PetscInt       i, j;
1012b4457527SToby Isaac     DM             sdm;
101320cf1dd8SToby Isaac 
10149566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
1015b4457527SToby Isaac     if (!ssp) continue;
10169566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
10179566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
1018b4457527SToby Isaac     /* get the first vertex of the reference cell */
10199566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
10209566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
10219566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
10229566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
1023b4457527SToby Isaac     /* compactify Jacobian */
10249371c9d4SSatish Balay     for (i = 0; i < dim; i++)
10259371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
1026b4457527SToby Isaac     for (f = 0; f < dof; f++) {
1027b4457527SToby Isaac       PetscQuadrature fn;
102820cf1dd8SToby Isaac 
10299566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
1030f4f49eeaSPierre Jolivet       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &sp->functional[off + f]));
103120cf1dd8SToby Isaac     }
103220cf1dd8SToby Isaac   }
10339566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
10343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103520cf1dd8SToby Isaac }
103620cf1dd8SToby Isaac 
103720cf1dd8SToby Isaac /*@C
103820cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
103920cf1dd8SToby Isaac 
104020cf1dd8SToby Isaac   Input Parameters:
1041dce8aebaSBarry Smith + sp      - The `PetscDualSpace` object
104220cf1dd8SToby Isaac . f       - The basis functional index
104320cf1dd8SToby Isaac . time    - The time
104420cf1dd8SToby 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)
104520cf1dd8SToby Isaac . numComp - The number of components for the function
104620cf1dd8SToby Isaac . func    - The input function
104720cf1dd8SToby Isaac - ctx     - A context for the function
104820cf1dd8SToby Isaac 
104920cf1dd8SToby Isaac   Output Parameter:
105020cf1dd8SToby Isaac . value - numComp output values
105120cf1dd8SToby Isaac 
105260225df5SJacob Faibussowitsch   Calling sequence:
1053dce8aebaSBarry Smith .vb
105420f4b53cSBarry Smith   PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1055dce8aebaSBarry Smith .ve
105620cf1dd8SToby Isaac 
1057a4ce7ad1SMatthew G. Knepley   Level: beginner
105820cf1dd8SToby Isaac 
1059dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
106020cf1dd8SToby Isaac @*/
1061d71ae5a4SJacob 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)
1062d71ae5a4SJacob Faibussowitsch {
106320cf1dd8SToby Isaac   PetscFunctionBegin;
106420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
10654f572ea9SToby Isaac   PetscAssertPointer(cgeom, 4);
10664f572ea9SToby Isaac   PetscAssertPointer(value, 8);
1067dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
10683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
106920cf1dd8SToby Isaac }
107020cf1dd8SToby Isaac 
107120cf1dd8SToby Isaac /*@C
1072dce8aebaSBarry Smith   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
107320cf1dd8SToby Isaac 
107420cf1dd8SToby Isaac   Input Parameters:
1075dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1076dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
107720cf1dd8SToby Isaac 
107820cf1dd8SToby Isaac   Output Parameter:
107920cf1dd8SToby Isaac . spValue - The values of all dual space functionals
108020cf1dd8SToby Isaac 
1081dce8aebaSBarry Smith   Level: advanced
108220cf1dd8SToby Isaac 
1083dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
108420cf1dd8SToby Isaac @*/
1085d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1086d71ae5a4SJacob Faibussowitsch {
108720cf1dd8SToby Isaac   PetscFunctionBegin;
108820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1089dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
10903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
109120cf1dd8SToby Isaac }
109220cf1dd8SToby Isaac 
109320cf1dd8SToby Isaac /*@C
1094dce8aebaSBarry Smith   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1095b4457527SToby Isaac 
1096b4457527SToby Isaac   Input Parameters:
1097dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1098dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1099b4457527SToby Isaac 
1100b4457527SToby Isaac   Output Parameter:
1101b4457527SToby Isaac . spValue - The values of interior dual space functionals
1102b4457527SToby Isaac 
1103dce8aebaSBarry Smith   Level: advanced
1104b4457527SToby Isaac 
1105dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1106b4457527SToby Isaac @*/
1107d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1108d71ae5a4SJacob Faibussowitsch {
1109b4457527SToby Isaac   PetscFunctionBegin;
1110b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1111dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
11123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1113b4457527SToby Isaac }
1114b4457527SToby Isaac 
1115b4457527SToby Isaac /*@C
111620cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
111720cf1dd8SToby Isaac 
111820cf1dd8SToby Isaac   Input Parameters:
1119dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
112020cf1dd8SToby Isaac . f     - The basis functional index
112120cf1dd8SToby Isaac . time  - The time
112220cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
112320cf1dd8SToby Isaac . Nc    - The number of components for the function
112420cf1dd8SToby Isaac . func  - The input function
112520cf1dd8SToby Isaac - ctx   - A context for the function
112620cf1dd8SToby Isaac 
112720cf1dd8SToby Isaac   Output Parameter:
112820cf1dd8SToby Isaac . value - The output value
112920cf1dd8SToby Isaac 
113060225df5SJacob Faibussowitsch   Calling sequence:
1131dce8aebaSBarry Smith .vb
113220f4b53cSBarry Smith    PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[],PetscInt numComponents, PetscScalar values[], void *ctx)
1133dce8aebaSBarry Smith .ve
113420cf1dd8SToby Isaac 
1135dce8aebaSBarry Smith   Level: advanced
113620cf1dd8SToby Isaac 
1137dce8aebaSBarry Smith   Note:
1138dce8aebaSBarry 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.
113920cf1dd8SToby Isaac 
1140dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
114120cf1dd8SToby Isaac @*/
1142d71ae5a4SJacob 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)
1143d71ae5a4SJacob Faibussowitsch {
114420cf1dd8SToby Isaac   DM               dm;
114520cf1dd8SToby Isaac   PetscQuadrature  n;
114620cf1dd8SToby Isaac   const PetscReal *points, *weights;
114720cf1dd8SToby Isaac   PetscReal        x[3];
114820cf1dd8SToby Isaac   PetscScalar     *val;
114920cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
115020cf1dd8SToby Isaac   PetscBool        isAffine;
115120cf1dd8SToby Isaac 
115220cf1dd8SToby Isaac   PetscFunctionBegin;
115320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
11544f572ea9SToby Isaac   PetscAssertPointer(value, 8);
11559566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
11569566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
11579566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
115863a3b9bcSJacob 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);
115963a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
11609566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
116120cf1dd8SToby Isaac   *value   = 0.0;
116220cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
116320cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
116420cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
116520cf1dd8SToby Isaac     if (isAffine) {
116620cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
11679566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
116820cf1dd8SToby Isaac     } else {
11699566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
117020cf1dd8SToby Isaac     }
1171ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
117220cf1dd8SToby Isaac   }
11739566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
11743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
117520cf1dd8SToby Isaac }
117620cf1dd8SToby Isaac 
117720cf1dd8SToby Isaac /*@C
1178dce8aebaSBarry Smith   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
117920cf1dd8SToby Isaac 
118020cf1dd8SToby Isaac   Input Parameters:
1181dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1182dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
118320cf1dd8SToby Isaac 
118420cf1dd8SToby Isaac   Output Parameter:
118520cf1dd8SToby Isaac . spValue - The values of all dual space functionals
118620cf1dd8SToby Isaac 
1187dce8aebaSBarry Smith   Level: advanced
118820cf1dd8SToby Isaac 
1189dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
119020cf1dd8SToby Isaac @*/
1191d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1192d71ae5a4SJacob Faibussowitsch {
1193b4457527SToby Isaac   Vec pointValues, dofValues;
1194b4457527SToby Isaac   Mat allMat;
119520cf1dd8SToby Isaac 
119620cf1dd8SToby Isaac   PetscFunctionBegin;
119720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
11984f572ea9SToby Isaac   PetscAssertPointer(pointEval, 2);
11994f572ea9SToby Isaac   PetscAssertPointer(spValue, 3);
12009566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
1201f4f49eeaSPierre Jolivet   if (!sp->allNodeValues) PetscCall(MatCreateVecs(allMat, &sp->allNodeValues, NULL));
1202b4457527SToby Isaac   pointValues = sp->allNodeValues;
1203f4f49eeaSPierre Jolivet   if (!sp->allDofValues) PetscCall(MatCreateVecs(allMat, NULL, &sp->allDofValues));
1204b4457527SToby Isaac   dofValues = sp->allDofValues;
12059566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
12069566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
12079566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
12089566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
12099566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
12103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
121120cf1dd8SToby Isaac }
1212b4457527SToby Isaac 
1213b4457527SToby Isaac /*@C
1214dce8aebaSBarry Smith   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1215b4457527SToby Isaac 
1216b4457527SToby Isaac   Input Parameters:
1217dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1218dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1219b4457527SToby Isaac 
1220b4457527SToby Isaac   Output Parameter:
1221b4457527SToby Isaac . spValue - The values of interior dual space functionals
1222b4457527SToby Isaac 
1223dce8aebaSBarry Smith   Level: advanced
1224b4457527SToby Isaac 
1225dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1226b4457527SToby Isaac @*/
1227d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1228d71ae5a4SJacob Faibussowitsch {
1229b4457527SToby Isaac   Vec pointValues, dofValues;
1230b4457527SToby Isaac   Mat intMat;
1231b4457527SToby Isaac 
1232b4457527SToby Isaac   PetscFunctionBegin;
1233b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
12344f572ea9SToby Isaac   PetscAssertPointer(pointEval, 2);
12354f572ea9SToby Isaac   PetscAssertPointer(spValue, 3);
12369566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
1237f4f49eeaSPierre Jolivet   if (!sp->intNodeValues) PetscCall(MatCreateVecs(intMat, &sp->intNodeValues, NULL));
1238b4457527SToby Isaac   pointValues = sp->intNodeValues;
1239f4f49eeaSPierre Jolivet   if (!sp->intDofValues) PetscCall(MatCreateVecs(intMat, NULL, &sp->intDofValues));
1240b4457527SToby Isaac   dofValues = sp->intDofValues;
12419566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
12429566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
12439566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
12449566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
12459566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
12463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
124720cf1dd8SToby Isaac }
124820cf1dd8SToby Isaac 
1249a4ce7ad1SMatthew G. Knepley /*@
1250b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1251a4ce7ad1SMatthew G. Knepley 
1252a4ce7ad1SMatthew G. Knepley   Input Parameter:
1253a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1254a4ce7ad1SMatthew G. Knepley 
1255d8d19677SJose E. Roman   Output Parameters:
1256dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1257dce8aebaSBarry Smith - allMat   - A `Mat` for the node-to-dof transformation
1258a4ce7ad1SMatthew G. Knepley 
1259a4ce7ad1SMatthew G. Knepley   Level: advanced
1260a4ce7ad1SMatthew G. Knepley 
1261dce8aebaSBarry Smith .seealso: `PetscQuadrature`, `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`
1262a4ce7ad1SMatthew G. Knepley @*/
1263d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1264d71ae5a4SJacob Faibussowitsch {
126520cf1dd8SToby Isaac   PetscFunctionBegin;
126620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
12674f572ea9SToby Isaac   if (allNodes) PetscAssertPointer(allNodes, 2);
12684f572ea9SToby Isaac   if (allMat) PetscAssertPointer(allMat, 3);
1269b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1270b4457527SToby Isaac     PetscQuadrature qpoints;
1271b4457527SToby Isaac     Mat             amat;
1272b4457527SToby Isaac 
1273dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
1274f4f49eeaSPierre Jolivet     PetscCall(PetscQuadratureDestroy(&sp->allNodes));
1275f4f49eeaSPierre Jolivet     PetscCall(MatDestroy(&sp->allMat));
1276b4457527SToby Isaac     sp->allNodes = qpoints;
1277b4457527SToby Isaac     sp->allMat   = amat;
127820cf1dd8SToby Isaac   }
1279b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1280b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
12813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128220cf1dd8SToby Isaac }
128320cf1dd8SToby Isaac 
1284a4ce7ad1SMatthew G. Knepley /*@
1285b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1286a4ce7ad1SMatthew G. Knepley 
1287a4ce7ad1SMatthew G. Knepley   Input Parameter:
1288a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1289a4ce7ad1SMatthew G. Knepley 
1290d8d19677SJose E. Roman   Output Parameters:
1291dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1292dce8aebaSBarry Smith - allMat   - A `Mat` for the node-to-dof transformation
1293a4ce7ad1SMatthew G. Knepley 
1294a4ce7ad1SMatthew G. Knepley   Level: advanced
1295a4ce7ad1SMatthew G. Knepley 
1296dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`, `PetscQuadrature`
1297a4ce7ad1SMatthew G. Knepley @*/
1298d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1299d71ae5a4SJacob Faibussowitsch {
130020cf1dd8SToby Isaac   PetscInt        spdim;
130120cf1dd8SToby Isaac   PetscInt        numPoints, offset;
130220cf1dd8SToby Isaac   PetscReal      *points;
130320cf1dd8SToby Isaac   PetscInt        f, dim;
1304b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1305b4457527SToby Isaac   PetscInt        maxNumPoints;
130620cf1dd8SToby Isaac   PetscQuadrature q;
1307b4457527SToby Isaac   Mat             A;
130820cf1dd8SToby Isaac 
130920cf1dd8SToby Isaac   PetscFunctionBegin;
13109566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13119566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
131220cf1dd8SToby Isaac   if (!spdim) {
13139566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
13149566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
131520cf1dd8SToby Isaac   }
1316b4457527SToby Isaac   nrows = spdim;
13179566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
13189566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1319b4457527SToby Isaac   maxNumPoints = numPoints;
132020cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
132120cf1dd8SToby Isaac     PetscInt Np;
132220cf1dd8SToby Isaac 
13239566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
13249566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
132520cf1dd8SToby Isaac     numPoints += Np;
1326b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
132720cf1dd8SToby Isaac   }
1328b4457527SToby Isaac   ncols = numPoints * Nc;
13299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
13309566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
133120cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1332b4457527SToby Isaac     const PetscReal *p, *w;
133320cf1dd8SToby Isaac     PetscInt         Np, i;
1334b4457527SToby Isaac     PetscInt         fnc;
133520cf1dd8SToby Isaac 
13369566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
13379566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
133808401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
1339ad540459SPierre Jolivet     for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i];
134048a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1341b4457527SToby Isaac     offset += Np;
1342b4457527SToby Isaac   }
13439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
13449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
13459566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
13469566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1347b4457527SToby Isaac   *allMat = A;
13483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1349b4457527SToby Isaac }
1350b4457527SToby Isaac 
1351b4457527SToby Isaac /*@
1352b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1353a4e35b19SJacob Faibussowitsch   this space, as well as the matrix that computes the degrees of freedom from the quadrature
1354a4e35b19SJacob Faibussowitsch   values.
1355b4457527SToby Isaac 
1356b4457527SToby Isaac   Input Parameter:
1357b4457527SToby Isaac . sp - The dualspace
1358b4457527SToby Isaac 
1359d8d19677SJose E. Roman   Output Parameters:
1360dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1361b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1362dce8aebaSBarry Smith              the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1363dce8aebaSBarry Smith              npoints is the number of points in intNodes and nc is `PetscDualSpaceGetNumComponents()`.
1364b4457527SToby Isaac 
1365b4457527SToby Isaac   Level: advanced
1366b4457527SToby Isaac 
1367a4e35b19SJacob Faibussowitsch   Notes:
1368a4e35b19SJacob Faibussowitsch   Degrees of freedom are interior degrees of freedom if they belong (by
1369a4e35b19SJacob Faibussowitsch   `PetscDualSpaceGetSection()`) to interior points in the references, complementary boundary
1370a4e35b19SJacob Faibussowitsch   degrees of freedom are marked as constrained in the section returned by
1371a4e35b19SJacob Faibussowitsch   `PetscDualSpaceGetSection()`).
1372a4e35b19SJacob Faibussowitsch 
1373dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1374b4457527SToby Isaac @*/
1375d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1376d71ae5a4SJacob Faibussowitsch {
1377b4457527SToby Isaac   PetscFunctionBegin;
1378b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13794f572ea9SToby Isaac   if (intNodes) PetscAssertPointer(intNodes, 2);
13804f572ea9SToby Isaac   if (intMat) PetscAssertPointer(intMat, 3);
1381b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1382b4457527SToby Isaac     PetscQuadrature qpoints;
1383b4457527SToby Isaac     Mat             imat;
1384b4457527SToby Isaac 
1385dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
1386f4f49eeaSPierre Jolivet     PetscCall(PetscQuadratureDestroy(&sp->intNodes));
1387f4f49eeaSPierre Jolivet     PetscCall(MatDestroy(&sp->intMat));
1388b4457527SToby Isaac     sp->intNodes = qpoints;
1389b4457527SToby Isaac     sp->intMat   = imat;
1390b4457527SToby Isaac   }
1391b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1392b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
13933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1394b4457527SToby Isaac }
1395b4457527SToby Isaac 
1396b4457527SToby Isaac /*@
1397b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1398b4457527SToby Isaac 
1399b4457527SToby Isaac   Input Parameter:
1400b4457527SToby Isaac . sp - The dualspace
1401b4457527SToby Isaac 
1402d8d19677SJose E. Roman   Output Parameters:
1403dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1404b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1405dce8aebaSBarry Smith               the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1406dce8aebaSBarry Smith               npoints is the number of points in allNodes and nc is `PetscDualSpaceGetNumComponents()`.
1407b4457527SToby Isaac 
1408b4457527SToby Isaac   Level: advanced
1409b4457527SToby Isaac 
1410dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1411b4457527SToby Isaac @*/
1412d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1413d71ae5a4SJacob Faibussowitsch {
1414b4457527SToby Isaac   DM              dm;
1415b4457527SToby Isaac   PetscInt        spdim0;
1416b4457527SToby Isaac   PetscInt        Nc;
1417b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1418b4457527SToby Isaac   PetscSection    section;
1419b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1420b4457527SToby Isaac   PetscReal      *points;
1421b4457527SToby Isaac   PetscInt        dim;
1422b4457527SToby Isaac   PetscInt       *nnz;
1423b4457527SToby Isaac   PetscQuadrature q;
1424b4457527SToby Isaac   Mat             imat;
1425b4457527SToby Isaac 
1426b4457527SToby Isaac   PetscFunctionBegin;
1427b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
14289566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
14299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1430b4457527SToby Isaac   if (!spdim0) {
1431b4457527SToby Isaac     *intNodes = NULL;
1432b4457527SToby Isaac     *intMat   = NULL;
14333ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1434b4457527SToby Isaac   }
14359566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
14369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
14379566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
14389566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1440b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1441b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1442b4457527SToby Isaac 
14439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
14449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1445b4457527SToby Isaac     if (!(dof - cdof)) continue;
14469566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1447b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1448b4457527SToby Isaac       PetscInt Np;
1449b4457527SToby Isaac 
14509566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14519566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1452b4457527SToby Isaac       nnz[f] = Np * Nc;
1453b4457527SToby Isaac       numPoints += Np;
1454b4457527SToby Isaac     }
1455b4457527SToby Isaac   }
14569566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
14579566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
14589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1459b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1460b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1461b4457527SToby Isaac 
14629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
14639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1464b4457527SToby Isaac     if (!(dof - cdof)) continue;
14659566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1466b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1467b4457527SToby Isaac       const PetscReal *p;
1468b4457527SToby Isaac       const PetscReal *w;
1469b4457527SToby Isaac       PetscInt         Np, i;
1470b4457527SToby Isaac 
14719566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14729566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
1473ad540459SPierre Jolivet       for (i = 0; i < Np * dim; i++) points[offset + i] = p[i];
147448a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1475b4457527SToby Isaac       offset += Np * dim;
1476b4457527SToby Isaac       matoffset += Np * Nc;
1477b4457527SToby Isaac     }
1478b4457527SToby Isaac   }
14799566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
14809566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
14819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
14829566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1483b4457527SToby Isaac   *intMat = imat;
14843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
148520cf1dd8SToby Isaac }
148620cf1dd8SToby Isaac 
14874f9ab2b4SJed Brown /*@
1488dce8aebaSBarry Smith   PetscDualSpaceEqual - Determine if two dual spaces are equivalent
14894f9ab2b4SJed Brown 
14904f9ab2b4SJed Brown   Input Parameters:
1491dce8aebaSBarry Smith + A - A `PetscDualSpace` object
1492dce8aebaSBarry Smith - B - Another `PetscDualSpace` object
14934f9ab2b4SJed Brown 
14944f9ab2b4SJed Brown   Output Parameter:
1495dce8aebaSBarry Smith . equal - `PETSC_TRUE` if the dual spaces are equivalent
14964f9ab2b4SJed Brown 
14974f9ab2b4SJed Brown   Level: advanced
14984f9ab2b4SJed Brown 
1499dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
15004f9ab2b4SJed Brown @*/
1501d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal)
1502d71ae5a4SJacob Faibussowitsch {
15034f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
15044f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
15054f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
15064f9ab2b4SJed Brown   Mat             matA, matB;
15074f9ab2b4SJed Brown 
15084f9ab2b4SJed Brown   PetscFunctionBegin;
15094f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
15104f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
15114f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
15124f9ab2b4SJed Brown   *equal = PETSC_FALSE;
15139566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
15149566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
15153ba16761SJacob Faibussowitsch   if (sizeB != sizeA) PetscFunctionReturn(PETSC_SUCCESS);
15169566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
15179566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
15183ba16761SJacob Faibussowitsch   if (dimA != dimB) PetscFunctionReturn(PETSC_SUCCESS);
15194f9ab2b4SJed Brown 
15209566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
15219566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
15224f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
15233ba16761SJacob Faibussowitsch     if (dofA[d] != dofB[d]) PetscFunctionReturn(PETSC_SUCCESS);
15244f9ab2b4SJed Brown   }
15254f9ab2b4SJed Brown 
15269566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
15279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
15284f9ab2b4SJed Brown   if (!quadA && !quadB) {
15294f9ab2b4SJed Brown     *equal = PETSC_TRUE;
15304f9ab2b4SJed Brown   } else if (quadA && quadB) {
15319566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
15323ba16761SJacob Faibussowitsch     if (*equal == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS);
15333ba16761SJacob Faibussowitsch     if (!matA && !matB) PetscFunctionReturn(PETSC_SUCCESS);
15349566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
15354f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
15364f9ab2b4SJed Brown   }
15373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15384f9ab2b4SJed Brown }
15394f9ab2b4SJed Brown 
154020cf1dd8SToby Isaac /*@C
154120cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
154220cf1dd8SToby Isaac 
154320cf1dd8SToby Isaac   Input Parameters:
1544dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
154520cf1dd8SToby Isaac . f     - The basis functional index
154620cf1dd8SToby Isaac . time  - The time
154720cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
154820cf1dd8SToby Isaac . Nc    - The number of components for the function
154920cf1dd8SToby Isaac . func  - The input function
155020cf1dd8SToby Isaac - ctx   - A context for the function
155120cf1dd8SToby Isaac 
155220cf1dd8SToby Isaac   Output Parameter:
155320cf1dd8SToby Isaac . value - The output value (scalar)
155420cf1dd8SToby Isaac 
155560225df5SJacob Faibussowitsch   Calling sequence:
1556dce8aebaSBarry Smith .vb
155720f4b53cSBarry Smith   PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1558dce8aebaSBarry Smith .ve
155920f4b53cSBarry Smith 
1560dce8aebaSBarry Smith   Level: advanced
156120cf1dd8SToby Isaac 
1562dce8aebaSBarry Smith   Note:
1563dce8aebaSBarry 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.
156420cf1dd8SToby Isaac 
1565dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
156620cf1dd8SToby Isaac @*/
1567d71ae5a4SJacob 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)
1568d71ae5a4SJacob Faibussowitsch {
156920cf1dd8SToby Isaac   DM               dm;
157020cf1dd8SToby Isaac   PetscQuadrature  n;
157120cf1dd8SToby Isaac   const PetscReal *points, *weights;
157220cf1dd8SToby Isaac   PetscScalar     *val;
157320cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
157420cf1dd8SToby Isaac 
157520cf1dd8SToby Isaac   PetscFunctionBegin;
157620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
15774f572ea9SToby Isaac   PetscAssertPointer(value, 8);
15789566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
15799566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
15809566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
15819566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
158263a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
15839566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
158420cf1dd8SToby Isaac   *value = 0.;
158520cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
15869566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
1587ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
158820cf1dd8SToby Isaac   }
15899566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
15903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159120cf1dd8SToby Isaac }
159220cf1dd8SToby Isaac 
159320cf1dd8SToby Isaac /*@
159420cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
159520cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
159620cf1dd8SToby Isaac 
159720f4b53cSBarry Smith   Not Collective
159820cf1dd8SToby Isaac 
159920cf1dd8SToby Isaac   Input Parameters:
1600dce8aebaSBarry Smith + sp     - the `PetscDualSpace` object
160120cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
160220cf1dd8SToby Isaac 
160320cf1dd8SToby Isaac   Output Parameter:
160420cf1dd8SToby Isaac . subsp - the subspace.  Note that 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 
1609dce8aebaSBarry Smith   Notes:
1610dce8aebaSBarry Smith   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
1611dce8aebaSBarry Smith   pointwise values are not defined on the element boundaries), or if the implementation of `PetscDualSpace` does not
1612dce8aebaSBarry Smith   support extracting subspaces, then NULL is returned.
1613dce8aebaSBarry Smith 
1614dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1615dce8aebaSBarry Smith 
161660225df5SJacob Faibussowitsch .seealso: `PetscDualSpace`, `PetscSpaceGetHeightSubspace()`, `PetscDualSpaceGetPointSubspace()`
161720cf1dd8SToby Isaac @*/
1618d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
1619d71ae5a4SJacob Faibussowitsch {
1620b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1621b4457527SToby Isaac   DM       dm;
162220cf1dd8SToby Isaac 
162320cf1dd8SToby Isaac   PetscFunctionBegin;
162420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16254f572ea9SToby Isaac   PetscAssertPointer(subsp, 3);
1626f4f49eeaSPierre 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");
162720cf1dd8SToby Isaac   *subsp = NULL;
1628b4457527SToby Isaac   dm     = sp->dm;
16299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
16301dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
16319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1632b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1633b4457527SToby Isaac     *subsp = sp;
16343ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1635b4457527SToby Isaac   }
1636b4457527SToby Isaac   if (!sp->heightSpaces) {
1637b4457527SToby Isaac     PetscInt h;
1638f4f49eeaSPierre Jolivet     PetscCall(PetscCalloc1(depth + 1, &sp->heightSpaces));
1639b4457527SToby Isaac 
1640b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1641b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
16429927e4dfSBarry Smith       if (sp->ops->createheightsubspace) PetscUseTypeMethod(sp, createheightsubspace, height, &sp->heightSpaces[h]);
1643b4457527SToby Isaac       else if (sp->pointSpaces) {
1644b4457527SToby Isaac         PetscInt hStart, hEnd;
1645b4457527SToby Isaac 
16469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1647b4457527SToby Isaac         if (hEnd > hStart) {
1648665f567fSMatthew G. Knepley           const char *name;
1649665f567fSMatthew G. Knepley 
1650f4f49eeaSPierre Jolivet           PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[hStart]));
1651665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
16529566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
16539566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1654665f567fSMatthew G. Knepley           }
1655b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1656b4457527SToby Isaac         }
1657b4457527SToby Isaac       }
1658b4457527SToby Isaac     }
1659b4457527SToby Isaac   }
1660b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
16613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
166220cf1dd8SToby Isaac }
166320cf1dd8SToby Isaac 
166420cf1dd8SToby Isaac /*@
166520cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
166620cf1dd8SToby Isaac 
166720f4b53cSBarry Smith   Not Collective
166820cf1dd8SToby Isaac 
166920cf1dd8SToby Isaac   Input Parameters:
1670dce8aebaSBarry Smith + sp    - the `PetscDualSpace` object
167120cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
167220cf1dd8SToby Isaac 
167320cf1dd8SToby Isaac   Output Parameters:
1674a4e35b19SJacob Faibussowitsch . bdsp - the subspace.
167520cf1dd8SToby Isaac 
167620cf1dd8SToby Isaac   Level: advanced
167720cf1dd8SToby Isaac 
1678dce8aebaSBarry Smith   Notes:
1679a4e35b19SJacob Faibussowitsch   The functionals in the subspace are with respect to the intrinsic geometry of the point,
1680a4e35b19SJacob Faibussowitsch   which will be of lesser dimension if height > 0.
1681a4e35b19SJacob Faibussowitsch 
1682dce8aebaSBarry Smith   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
1683dce8aebaSBarry Smith   defined on the element boundaries), or if the implementation of `PetscDualSpace` does not support extracting
1684a4e35b19SJacob Faibussowitsch   subspaces, then `NULL` is returned.
1685dce8aebaSBarry Smith 
1686dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1687dce8aebaSBarry Smith 
1688dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetHeightSubspace()`
168920cf1dd8SToby Isaac @*/
1690d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1691d71ae5a4SJacob Faibussowitsch {
1692b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1693b4457527SToby Isaac   DM       dm;
169420cf1dd8SToby Isaac 
169520cf1dd8SToby Isaac   PetscFunctionBegin;
169620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16974f572ea9SToby Isaac   PetscAssertPointer(bdsp, 3);
169820cf1dd8SToby Isaac   *bdsp = NULL;
1699b4457527SToby Isaac   dm    = sp->dm;
17009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17011dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
17029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1703b4457527SToby 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 */
1704b4457527SToby Isaac     *bdsp = sp;
17053ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1706b4457527SToby Isaac   }
1707b4457527SToby Isaac   if (!sp->pointSpaces) {
1708b4457527SToby Isaac     PetscInt p;
1709f4f49eeaSPierre Jolivet     PetscCall(PetscCalloc1(pEnd - pStart, &sp->pointSpaces));
171020cf1dd8SToby Isaac 
1711b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1712b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
17139927e4dfSBarry Smith       if (sp->ops->createpointsubspace) PetscUseTypeMethod(sp, createpointsubspace, p + pStart, &sp->pointSpaces[p]);
1714b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1715b4457527SToby Isaac         PetscInt dim, depth, height;
1716b4457527SToby Isaac         DMLabel  label;
1717b4457527SToby Isaac 
17189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
17199566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
17209566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
172120cf1dd8SToby Isaac         height = dim - depth;
1722f4f49eeaSPierre Jolivet         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &sp->pointSpaces[p]));
17239566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
172420cf1dd8SToby Isaac       }
1725b4457527SToby Isaac     }
1726b4457527SToby Isaac   }
1727b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
17283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172920cf1dd8SToby Isaac }
173020cf1dd8SToby Isaac 
17316f905325SMatthew G. Knepley /*@C
17326f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
17336f905325SMatthew G. Knepley 
173420f4b53cSBarry Smith   Not Collective
17356f905325SMatthew G. Knepley 
17366f905325SMatthew G. Knepley   Input Parameter:
1737dce8aebaSBarry Smith . sp - the `PetscDualSpace` object
17386f905325SMatthew G. Knepley 
17396f905325SMatthew G. Knepley   Output Parameters:
1740b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1741b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
17426f905325SMatthew G. Knepley 
17436f905325SMatthew G. Knepley   Level: developer
17446f905325SMatthew G. Knepley 
1745dce8aebaSBarry Smith   Note:
1746dce8aebaSBarry Smith   The permutation and flip arrays are organized in the following way
1747dce8aebaSBarry Smith .vb
1748dce8aebaSBarry Smith   perms[p][ornt][dof # on point] = new local dof #
1749dce8aebaSBarry Smith   flips[p][ornt][dof # on point] = reversal or not
1750dce8aebaSBarry Smith .ve
1751dce8aebaSBarry Smith 
1752dce8aebaSBarry Smith .seealso: `PetscDualSpace`
17536f905325SMatthew G. Knepley @*/
1754d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
1755d71ae5a4SJacob Faibussowitsch {
17566f905325SMatthew G. Knepley   PetscFunctionBegin;
17576f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
17589371c9d4SSatish Balay   if (perms) {
17594f572ea9SToby Isaac     PetscAssertPointer(perms, 2);
17609371c9d4SSatish Balay     *perms = NULL;
17619371c9d4SSatish Balay   }
17629371c9d4SSatish Balay   if (flips) {
17634f572ea9SToby Isaac     PetscAssertPointer(flips, 3);
17649371c9d4SSatish Balay     *flips = NULL;
17659371c9d4SSatish Balay   }
17669927e4dfSBarry Smith   PetscTryTypeMethod(sp, getsymmetries, perms, flips);
17673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17686f905325SMatthew G. Knepley }
17694bee2e38SMatthew G. Knepley 
17704bee2e38SMatthew G. Knepley /*@
1771b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1772b4457527SToby Isaac   dual space's functionals.
1773b4457527SToby Isaac 
1774b4457527SToby Isaac   Input Parameter:
1775dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
1776b4457527SToby Isaac 
1777b4457527SToby Isaac   Output Parameter:
1778b4457527SToby 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
1779b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1780b4457527SToby 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).
1781b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1782b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1783b4457527SToby Isaac         but are stored as 1-forms.
1784b4457527SToby Isaac 
1785b4457527SToby Isaac   Level: developer
1786b4457527SToby Isaac 
1787dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1788b4457527SToby Isaac @*/
1789d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k)
1790d71ae5a4SJacob Faibussowitsch {
1791b4457527SToby Isaac   PetscFunctionBeginHot;
1792b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
17934f572ea9SToby Isaac   PetscAssertPointer(k, 2);
1794b4457527SToby Isaac   *k = dsp->k;
17953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1796b4457527SToby Isaac }
1797b4457527SToby Isaac 
1798b4457527SToby Isaac /*@
1799b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1800b4457527SToby Isaac   dual space's functionals.
1801b4457527SToby Isaac 
1802d8d19677SJose E. Roman   Input Parameters:
1803dce8aebaSBarry Smith + dsp - The `PetscDualSpace`
1804b4457527SToby 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
1805b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1806b4457527SToby 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).
1807b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1808b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1809b4457527SToby Isaac         but are stored as 1-forms.
1810b4457527SToby Isaac 
1811b4457527SToby Isaac   Level: developer
1812b4457527SToby Isaac 
1813dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1814b4457527SToby Isaac @*/
1815d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k)
1816d71ae5a4SJacob Faibussowitsch {
1817b4457527SToby Isaac   PetscInt dim;
1818b4457527SToby Isaac 
1819b4457527SToby Isaac   PetscFunctionBeginHot;
1820b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
182128b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1822b4457527SToby Isaac   dim = dsp->dm->dim;
18232dce792eSToby Isaac   PetscCheck((k >= -dim && k <= dim) || k == PETSC_FORM_DEGREE_UNDEFINED, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported %" PetscInt_FMT "-form on %" PetscInt_FMT "-dimensional reference cell", PetscAbsInt(k), dim);
1824b4457527SToby Isaac   dsp->k = k;
18253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1826b4457527SToby Isaac }
1827b4457527SToby Isaac 
1828b4457527SToby Isaac /*@
18294bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
18304bee2e38SMatthew G. Knepley 
18314bee2e38SMatthew G. Knepley   Input Parameter:
1832dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
18334bee2e38SMatthew G. Knepley 
18344bee2e38SMatthew G. Knepley   Output Parameter:
18354bee2e38SMatthew G. Knepley . k - The simplex dimension
18364bee2e38SMatthew G. Knepley 
1837a4ce7ad1SMatthew G. Knepley   Level: developer
18384bee2e38SMatthew G. Knepley 
1839dce8aebaSBarry Smith   Note:
1840dce8aebaSBarry Smith   Currently supported values are
1841dce8aebaSBarry Smith .vb
1842dce8aebaSBarry Smith   0: These are H_1 methods that only transform coordinates
1843dce8aebaSBarry Smith   1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
1844dce8aebaSBarry Smith   2: These are the same as 1
1845dce8aebaSBarry Smith   3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
1846dce8aebaSBarry Smith .ve
18474bee2e38SMatthew G. Knepley 
1848dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
18494bee2e38SMatthew G. Knepley @*/
1850d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k)
1851d71ae5a4SJacob Faibussowitsch {
1852b4457527SToby Isaac   PetscInt dim;
1853b4457527SToby Isaac 
18544bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18554bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18564f572ea9SToby Isaac   PetscAssertPointer(k, 2);
1857b4457527SToby Isaac   dim = dsp->dm->dim;
1858b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1859b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1860b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1861b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
18623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18634bee2e38SMatthew G. Knepley }
18644bee2e38SMatthew G. Knepley 
18654bee2e38SMatthew G. Knepley /*@C
18664bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
18674bee2e38SMatthew G. Knepley 
18684bee2e38SMatthew G. Knepley   Input Parameters:
1869dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18704bee2e38SMatthew G. Knepley . trans     - The type of transform
18714bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18724bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18734bee2e38SMatthew G. Knepley . Nv        - The number of function samples
18744bee2e38SMatthew G. Knepley . Nc        - The number of function components
18754bee2e38SMatthew G. Knepley - vals      - The function values
18764bee2e38SMatthew G. Knepley 
18774bee2e38SMatthew G. Knepley   Output Parameter:
18784bee2e38SMatthew G. Knepley . vals - The transformed function values
18794bee2e38SMatthew G. Knepley 
1880a4ce7ad1SMatthew G. Knepley   Level: intermediate
18814bee2e38SMatthew G. Knepley 
1882dce8aebaSBarry Smith   Note:
1883dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18842edcad52SToby Isaac 
1885dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18864bee2e38SMatthew G. Knepley @*/
1887d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1888d71ae5a4SJacob Faibussowitsch {
1889b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1890b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
18914bee2e38SMatthew G. Knepley 
18924bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18934bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18944f572ea9SToby Isaac   PetscAssertPointer(fegeom, 4);
18954f572ea9SToby Isaac   PetscAssertPointer(vals, 7);
1896b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
18972ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1898b4457527SToby Isaac   /* No change needed for 0-forms */
18993ba16761SJacob Faibussowitsch   if (!dsp->k) PetscFunctionReturn(PETSC_SUCCESS);
19009566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1901b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
19029566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
19034bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1904b4457527SToby Isaac     switch (Nk) {
1905b4457527SToby Isaac     case 1:
1906b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
19074bee2e38SMatthew G. Knepley       break;
1908b4457527SToby Isaac     case 2:
1909b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
19104bee2e38SMatthew G. Knepley       break;
1911b4457527SToby Isaac     case 3:
1912b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1913b4457527SToby Isaac       break;
1914d71ae5a4SJacob Faibussowitsch     default:
1915d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1916b4457527SToby Isaac     }
19174bee2e38SMatthew G. Knepley   }
19183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19194bee2e38SMatthew G. Knepley }
1920b4457527SToby Isaac 
19214bee2e38SMatthew G. Knepley /*@C
19224bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
19234bee2e38SMatthew G. Knepley 
19244bee2e38SMatthew G. Knepley   Input Parameters:
1925dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
19264bee2e38SMatthew G. Knepley . trans     - The type of transform
19274bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
19284bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
19294bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
19304bee2e38SMatthew G. Knepley . Nc        - The number of function components
19314bee2e38SMatthew G. Knepley - vals      - The function gradient values
19324bee2e38SMatthew G. Knepley 
19334bee2e38SMatthew G. Knepley   Output Parameter:
1934f9244615SMatthew G. Knepley . vals - The transformed function gradient values
19354bee2e38SMatthew G. Knepley 
1936a4ce7ad1SMatthew G. Knepley   Level: intermediate
19374bee2e38SMatthew G. Knepley 
1938dce8aebaSBarry Smith   Note:
1939dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
19402edcad52SToby Isaac 
1941dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
19424bee2e38SMatthew G. Knepley @*/
1943d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1944d71ae5a4SJacob Faibussowitsch {
194527f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
194627f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
19474bee2e38SMatthew G. Knepley 
19484bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
19494bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
19504f572ea9SToby Isaac   PetscAssertPointer(fegeom, 4);
19514f572ea9SToby Isaac   PetscAssertPointer(vals, 7);
1952b498ca8aSPierre Jolivet   PetscAssert(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
19534bee2e38SMatthew G. Knepley   /* Transform gradient */
195427f02ce8SMatthew G. Knepley   if (dim == dE) {
19554bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
19564bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
19579371c9d4SSatish Balay         switch (dim) {
1958d71ae5a4SJacob Faibussowitsch         case 1:
1959d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim] *= fegeom->invJ[0];
1960d71ae5a4SJacob Faibussowitsch           break;
1961d71ae5a4SJacob Faibussowitsch         case 2:
1962d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1963d71ae5a4SJacob Faibussowitsch           break;
1964d71ae5a4SJacob Faibussowitsch         case 3:
1965d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1966d71ae5a4SJacob Faibussowitsch           break;
1967d71ae5a4SJacob Faibussowitsch         default:
1968d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19694bee2e38SMatthew G. Knepley         }
19704bee2e38SMatthew G. Knepley       }
19714bee2e38SMatthew G. Knepley     }
197227f02ce8SMatthew G. Knepley   } else {
197327f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1974ad540459SPierre 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]);
197527f02ce8SMatthew G. Knepley     }
197627f02ce8SMatthew G. Knepley   }
19774bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
19783ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
19794bee2e38SMatthew G. Knepley   switch (trans) {
1980d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
1981d71ae5a4SJacob Faibussowitsch     break;
19824bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
19834bee2e38SMatthew G. Knepley     if (isInverse) {
19844bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19854bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19869371c9d4SSatish Balay           switch (dim) {
1987d71ae5a4SJacob Faibussowitsch           case 2:
1988d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1989d71ae5a4SJacob Faibussowitsch             break;
1990d71ae5a4SJacob Faibussowitsch           case 3:
1991d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1992d71ae5a4SJacob Faibussowitsch             break;
1993d71ae5a4SJacob Faibussowitsch           default:
1994d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19954bee2e38SMatthew G. Knepley           }
19964bee2e38SMatthew G. Knepley         }
19974bee2e38SMatthew G. Knepley       }
19984bee2e38SMatthew G. Knepley     } else {
19994bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
20004bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
20019371c9d4SSatish Balay           switch (dim) {
2002d71ae5a4SJacob Faibussowitsch           case 2:
2003d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2004d71ae5a4SJacob Faibussowitsch             break;
2005d71ae5a4SJacob Faibussowitsch           case 3:
2006d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2007d71ae5a4SJacob Faibussowitsch             break;
2008d71ae5a4SJacob Faibussowitsch           default:
2009d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
20104bee2e38SMatthew G. Knepley           }
20114bee2e38SMatthew G. Knepley         }
20124bee2e38SMatthew G. Knepley       }
20134bee2e38SMatthew G. Knepley     }
20144bee2e38SMatthew G. Knepley     break;
20154bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
20164bee2e38SMatthew G. Knepley     if (isInverse) {
20174bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
20184bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
20199371c9d4SSatish Balay           switch (dim) {
2020d71ae5a4SJacob Faibussowitsch           case 2:
2021d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2022d71ae5a4SJacob Faibussowitsch             break;
2023d71ae5a4SJacob Faibussowitsch           case 3:
2024d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2025d71ae5a4SJacob Faibussowitsch             break;
2026d71ae5a4SJacob Faibussowitsch           default:
2027d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
20284bee2e38SMatthew G. Knepley           }
20294bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
20304bee2e38SMatthew G. Knepley         }
20314bee2e38SMatthew G. Knepley       }
20324bee2e38SMatthew G. Knepley     } else {
20334bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
20344bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
20359371c9d4SSatish Balay           switch (dim) {
2036d71ae5a4SJacob Faibussowitsch           case 2:
2037d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2038d71ae5a4SJacob Faibussowitsch             break;
2039d71ae5a4SJacob Faibussowitsch           case 3:
2040d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2041d71ae5a4SJacob Faibussowitsch             break;
2042d71ae5a4SJacob Faibussowitsch           default:
2043d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
20444bee2e38SMatthew G. Knepley           }
20454bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
20464bee2e38SMatthew G. Knepley         }
20474bee2e38SMatthew G. Knepley       }
20484bee2e38SMatthew G. Knepley     }
20494bee2e38SMatthew G. Knepley     break;
20504bee2e38SMatthew G. Knepley   }
20513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20524bee2e38SMatthew G. Knepley }
20534bee2e38SMatthew G. Knepley 
20544bee2e38SMatthew G. Knepley /*@C
2055f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
2056f9244615SMatthew G. Knepley 
2057f9244615SMatthew G. Knepley   Input Parameters:
2058dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
2059f9244615SMatthew G. Knepley . trans     - The type of transform
2060f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
2061f9244615SMatthew G. Knepley . fegeom    - The cell geometry
2062f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
2063f9244615SMatthew G. Knepley . Nc        - The number of function components
2064f9244615SMatthew G. Knepley - vals      - The function gradient values
2065f9244615SMatthew G. Knepley 
2066f9244615SMatthew G. Knepley   Output Parameter:
2067f9244615SMatthew G. Knepley . vals - The transformed function Hessian values
2068f9244615SMatthew G. Knepley 
2069f9244615SMatthew G. Knepley   Level: intermediate
2070f9244615SMatthew G. Knepley 
2071dce8aebaSBarry Smith   Note:
2072dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2073f9244615SMatthew G. Knepley 
2074dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
2075f9244615SMatthew G. Knepley @*/
2076d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
2077d71ae5a4SJacob Faibussowitsch {
2078f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
2079f9244615SMatthew G. Knepley   PetscInt       v, c;
2080f9244615SMatthew G. Knepley 
2081f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2082f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20834f572ea9SToby Isaac   PetscAssertPointer(fegeom, 4);
20844f572ea9SToby Isaac   PetscAssertPointer(vals, 7);
2085b498ca8aSPierre Jolivet   PetscAssert(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
2086f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
2087f9244615SMatthew G. Knepley   if (dim == dE) {
2088f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2089f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
20909371c9d4SSatish Balay         switch (dim) {
2091d71ae5a4SJacob Faibussowitsch         case 1:
2092d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]);
2093d71ae5a4SJacob Faibussowitsch           break;
2094d71ae5a4SJacob Faibussowitsch         case 2:
2095d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2096d71ae5a4SJacob Faibussowitsch           break;
2097d71ae5a4SJacob Faibussowitsch         case 3:
2098d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2099d71ae5a4SJacob Faibussowitsch           break;
2100d71ae5a4SJacob Faibussowitsch         default:
2101d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
2102f9244615SMatthew G. Knepley         }
2103f9244615SMatthew G. Knepley       }
2104f9244615SMatthew G. Knepley     }
2105f9244615SMatthew G. Knepley   } else {
2106f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2107ad540459SPierre 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]);
2108f9244615SMatthew G. Knepley     }
2109f9244615SMatthew G. Knepley   }
2110f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
21113ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
2112f9244615SMatthew G. Knepley   switch (trans) {
2113d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
2114d71ae5a4SJacob Faibussowitsch     break;
2115d71ae5a4SJacob Faibussowitsch   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
2116d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2117d71ae5a4SJacob Faibussowitsch   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
2118d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2119f9244615SMatthew G. Knepley   }
21203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2121f9244615SMatthew G. Knepley }
2122f9244615SMatthew G. Knepley 
2123f9244615SMatthew G. Knepley /*@C
21244bee2e38SMatthew 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.
21254bee2e38SMatthew G. Knepley 
21264bee2e38SMatthew G. Knepley   Input Parameters:
2127dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
21284bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
21294bee2e38SMatthew G. Knepley . Nq        - The number of function samples
21304bee2e38SMatthew G. Knepley . Nc        - The number of function components
21314bee2e38SMatthew G. Knepley - pointEval - The function values
21324bee2e38SMatthew G. Knepley 
21334bee2e38SMatthew G. Knepley   Output Parameter:
21344bee2e38SMatthew G. Knepley . pointEval - The transformed function values
21354bee2e38SMatthew G. Knepley 
21364bee2e38SMatthew G. Knepley   Level: advanced
21374bee2e38SMatthew G. Knepley 
2138dce8aebaSBarry Smith   Notes:
2139dce8aebaSBarry 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.
21404bee2e38SMatthew G. Knepley 
2141da81f932SPierre Jolivet   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21422edcad52SToby Isaac 
2143dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21444bee2e38SMatthew G. Knepley @*/
2145d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2146d71ae5a4SJacob Faibussowitsch {
21474bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2148b4457527SToby Isaac   PetscInt                    k;
21494bee2e38SMatthew G. Knepley 
21504bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21514bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21524f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
21534f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
21544bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21554bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21569566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21579371c9d4SSatish Balay   switch (k) {
2158d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2159d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2160d71ae5a4SJacob Faibussowitsch     break;
2161d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2162d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2163d71ae5a4SJacob Faibussowitsch     break;
2164b4457527SToby Isaac   case 2:
2165d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2166d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2167d71ae5a4SJacob Faibussowitsch     break;
2168d71ae5a4SJacob Faibussowitsch   default:
2169d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21704bee2e38SMatthew G. Knepley   }
21719566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
21723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21734bee2e38SMatthew G. Knepley }
21744bee2e38SMatthew G. Knepley 
21754bee2e38SMatthew G. Knepley /*@C
21764bee2e38SMatthew 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.
21774bee2e38SMatthew G. Knepley 
21784bee2e38SMatthew G. Knepley   Input Parameters:
2179dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
21804bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
21814bee2e38SMatthew G. Knepley . Nq        - The number of function samples
21824bee2e38SMatthew G. Knepley . Nc        - The number of function components
21834bee2e38SMatthew G. Knepley - pointEval - The function values
21844bee2e38SMatthew G. Knepley 
21854bee2e38SMatthew G. Knepley   Output Parameter:
21864bee2e38SMatthew G. Knepley . pointEval - The transformed function values
21874bee2e38SMatthew G. Knepley 
21884bee2e38SMatthew G. Knepley   Level: advanced
21894bee2e38SMatthew G. Knepley 
2190dce8aebaSBarry Smith   Notes:
2191dce8aebaSBarry 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.
21924bee2e38SMatthew G. Knepley 
2193dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21942edcad52SToby Isaac 
2195dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21964bee2e38SMatthew G. Knepley @*/
2197d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2198d71ae5a4SJacob Faibussowitsch {
21994bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2200b4457527SToby Isaac   PetscInt                    k;
22014bee2e38SMatthew G. Knepley 
22024bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
22034bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
22044f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
22054f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
22064bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
22074bee2e38SMatthew G. Knepley      This determines their transformation properties. */
22089566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22099371c9d4SSatish Balay   switch (k) {
2210d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2211d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2212d71ae5a4SJacob Faibussowitsch     break;
2213d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2214d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2215d71ae5a4SJacob Faibussowitsch     break;
2216b4457527SToby Isaac   case 2:
2217d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2218d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2219d71ae5a4SJacob Faibussowitsch     break;
2220d71ae5a4SJacob Faibussowitsch   default:
2221d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22224bee2e38SMatthew G. Knepley   }
22239566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22254bee2e38SMatthew G. Knepley }
22264bee2e38SMatthew G. Knepley 
22274bee2e38SMatthew G. Knepley /*@C
22284bee2e38SMatthew 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.
22294bee2e38SMatthew G. Knepley 
22304bee2e38SMatthew G. Knepley   Input Parameters:
2231dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
22324bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
22334bee2e38SMatthew G. Knepley . Nq        - The number of function gradient samples
22344bee2e38SMatthew G. Knepley . Nc        - The number of function components
22354bee2e38SMatthew G. Knepley - pointEval - The function gradient values
22364bee2e38SMatthew G. Knepley 
22374bee2e38SMatthew G. Knepley   Output Parameter:
22384bee2e38SMatthew G. Knepley . pointEval - The transformed function gradient values
22394bee2e38SMatthew G. Knepley 
22404bee2e38SMatthew G. Knepley   Level: advanced
22414bee2e38SMatthew G. Knepley 
2242dce8aebaSBarry Smith   Notes:
2243dce8aebaSBarry 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.
22444bee2e38SMatthew G. Knepley 
2245dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
22462edcad52SToby Isaac 
2247dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2248dc0529c6SBarry Smith @*/
2249d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2250d71ae5a4SJacob Faibussowitsch {
22514bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2252b4457527SToby Isaac   PetscInt                    k;
22534bee2e38SMatthew G. Knepley 
22544bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
22554bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
22564f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
22574f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
22584bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
22594bee2e38SMatthew G. Knepley      This determines their transformation properties. */
22609566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22619371c9d4SSatish Balay   switch (k) {
2262d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2263d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2264d71ae5a4SJacob Faibussowitsch     break;
2265d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2266d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2267d71ae5a4SJacob Faibussowitsch     break;
2268b4457527SToby Isaac   case 2:
2269d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2270d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2271d71ae5a4SJacob Faibussowitsch     break;
2272d71ae5a4SJacob Faibussowitsch   default:
2273d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22744bee2e38SMatthew G. Knepley   }
22759566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22774bee2e38SMatthew G. Knepley }
2278f9244615SMatthew G. Knepley 
2279f9244615SMatthew G. Knepley /*@C
2280f9244615SMatthew 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.
2281f9244615SMatthew G. Knepley 
2282f9244615SMatthew G. Knepley   Input Parameters:
2283dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
2284f9244615SMatthew G. Knepley . fegeom    - The geometry for this cell
2285f9244615SMatthew G. Knepley . Nq        - The number of function Hessian samples
2286f9244615SMatthew G. Knepley . Nc        - The number of function components
2287f9244615SMatthew G. Knepley - pointEval - The function gradient values
2288f9244615SMatthew G. Knepley 
2289f9244615SMatthew G. Knepley   Output Parameter:
2290f9244615SMatthew G. Knepley . pointEval - The transformed function Hessian values
2291f9244615SMatthew G. Knepley 
2292f9244615SMatthew G. Knepley   Level: advanced
2293f9244615SMatthew G. Knepley 
2294dce8aebaSBarry Smith   Notes:
2295dce8aebaSBarry 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.
2296f9244615SMatthew G. Knepley 
2297dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2298f9244615SMatthew G. Knepley 
2299dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2300f9244615SMatthew G. Knepley @*/
2301d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2302d71ae5a4SJacob Faibussowitsch {
2303f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2304f9244615SMatthew G. Knepley   PetscInt                    k;
2305f9244615SMatthew G. Knepley 
2306f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2307f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
23084f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
23094f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
2310f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2311f9244615SMatthew G. Knepley      This determines their transformation properties. */
23129566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
23139371c9d4SSatish Balay   switch (k) {
2314d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2315d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2316d71ae5a4SJacob Faibussowitsch     break;
2317d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2318d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2319d71ae5a4SJacob Faibussowitsch     break;
2320f9244615SMatthew G. Knepley   case 2:
2321d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2322d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2323d71ae5a4SJacob Faibussowitsch     break;
2324d71ae5a4SJacob Faibussowitsch   default:
2325d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2326f9244615SMatthew G. Knepley   }
23279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
23283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2329f9244615SMatthew G. Knepley }
2330