xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision 60225df5d8469840be2bf9c1f64795a92b19f3c2)
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 
84*60225df5SJacob 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);
17020cf1dd8SToby Isaac   PetscValidPointer(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));
185b4457527SToby Isaac   if (sp->k) {
18663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space for %" PetscInt_FMT "-forms %swith %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", PetscAbsInt(sp->k), sp->k < 0 ? "(stored in dual form) " : "", sp->Nc, pdim));
187b4457527SToby Isaac   } else {
18863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space with %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", sp->Nc, pdim));
189b4457527SToby Isaac   }
190dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, view, v);
1919566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(v, &format));
192221d6281SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(v));
194221d6281SMatthew G. Knepley     for (f = 0; f < pdim; ++f) {
19563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(v, "Dual basis vector %" PetscInt_FMT "\n", f));
1969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(v));
1979566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureView(sp->functional[f], v));
1989566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(v));
199221d6281SMatthew G. Knepley     }
2009566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(v));
201221d6281SMatthew G. Knepley   }
2029566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
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 
36348a46eb9SPierre 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 
37048a46eb9SPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&(sp->heightSpaces[i])));
371b4457527SToby Isaac   }
3729566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
373b4457527SToby Isaac 
3749566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&(sp->pointSection)));
3759566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
3769566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intDofValues)));
3779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intNodeValues)));
3789566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->intMat)));
3799566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
3809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allDofValues)));
3819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allNodeValues)));
3829566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->allMat)));
3839566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
3843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
385b4457527SToby Isaac }
386b4457527SToby Isaac 
38720cf1dd8SToby Isaac /*@
388dce8aebaSBarry Smith   PetscDualSpaceDestroy - Destroys a `PetscDualSpace` object
38920cf1dd8SToby Isaac 
39020f4b53cSBarry Smith   Collective
39120cf1dd8SToby Isaac 
39220cf1dd8SToby Isaac   Input Parameter:
393dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to destroy
39420cf1dd8SToby Isaac 
395a4ce7ad1SMatthew G. Knepley   Level: beginner
39620cf1dd8SToby Isaac 
397dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
39820cf1dd8SToby Isaac @*/
399d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
400d71ae5a4SJacob Faibussowitsch {
40120cf1dd8SToby Isaac   PetscInt dim, f;
402b4457527SToby Isaac   DM       dm;
40320cf1dd8SToby Isaac 
40420cf1dd8SToby Isaac   PetscFunctionBegin;
4053ba16761SJacob Faibussowitsch   if (!*sp) PetscFunctionReturn(PETSC_SUCCESS);
40620cf1dd8SToby Isaac   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
40720cf1dd8SToby Isaac 
4089371c9d4SSatish Balay   if (--((PetscObject)(*sp))->refct > 0) {
4099371c9d4SSatish Balay     *sp = NULL;
4103ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4119371c9d4SSatish Balay   }
41220cf1dd8SToby Isaac   ((PetscObject)(*sp))->refct = 0;
41320cf1dd8SToby Isaac 
4149566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
415b4457527SToby Isaac   dm = (*sp)->dm;
416b4457527SToby Isaac 
417dbbe0bcdSBarry Smith   PetscTryTypeMethod((*sp), destroy);
4189566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
419b4457527SToby Isaac 
42048a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
4219566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
4229566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4239566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
4243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42520cf1dd8SToby Isaac }
42620cf1dd8SToby Isaac 
42720cf1dd8SToby Isaac /*@
428dce8aebaSBarry Smith   PetscDualSpaceCreate - Creates an empty `PetscDualSpace` object. The type can then be set with `PetscDualSpaceSetType()`.
42920cf1dd8SToby Isaac 
430d083f849SBarry Smith   Collective
43120cf1dd8SToby Isaac 
43220cf1dd8SToby Isaac   Input Parameter:
433dce8aebaSBarry Smith . comm - The communicator for the `PetscDualSpace` object
43420cf1dd8SToby Isaac 
43520cf1dd8SToby Isaac   Output Parameter:
436dce8aebaSBarry Smith . sp - The `PetscDualSpace` object
43720cf1dd8SToby Isaac 
43820cf1dd8SToby Isaac   Level: beginner
43920cf1dd8SToby Isaac 
440dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
44120cf1dd8SToby Isaac @*/
442d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
443d71ae5a4SJacob Faibussowitsch {
44420cf1dd8SToby Isaac   PetscDualSpace s;
44520cf1dd8SToby Isaac 
44620cf1dd8SToby Isaac   PetscFunctionBegin;
44720cf1dd8SToby Isaac   PetscValidPointer(sp, 2);
4489566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
44920cf1dd8SToby Isaac   *sp = NULL;
4509566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
45120cf1dd8SToby Isaac 
4529566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
45320cf1dd8SToby Isaac 
45420cf1dd8SToby Isaac   s->order       = 0;
45520cf1dd8SToby Isaac   s->Nc          = 1;
4564bee2e38SMatthew G. Knepley   s->k           = 0;
457b4457527SToby Isaac   s->spdim       = -1;
458b4457527SToby Isaac   s->spintdim    = -1;
459b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
46020cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
46120cf1dd8SToby Isaac 
46220cf1dd8SToby Isaac   *sp = s;
4633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46420cf1dd8SToby Isaac }
46520cf1dd8SToby Isaac 
46620cf1dd8SToby Isaac /*@
467dce8aebaSBarry Smith   PetscDualSpaceDuplicate - Creates a duplicate `PetscDualSpace` object that is not setup.
46820cf1dd8SToby Isaac 
46920f4b53cSBarry Smith   Collective
47020cf1dd8SToby Isaac 
47120cf1dd8SToby Isaac   Input Parameter:
472dce8aebaSBarry Smith . sp - The original `PetscDualSpace`
47320cf1dd8SToby Isaac 
47420cf1dd8SToby Isaac   Output Parameter:
475dce8aebaSBarry Smith . spNew - The duplicate `PetscDualSpace`
47620cf1dd8SToby Isaac 
47720cf1dd8SToby Isaac   Level: beginner
47820cf1dd8SToby Isaac 
479dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
48020cf1dd8SToby Isaac @*/
481d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
482d71ae5a4SJacob Faibussowitsch {
483b4457527SToby Isaac   DM                 dm;
484b4457527SToby Isaac   PetscDualSpaceType type;
485b4457527SToby Isaac   const char        *name;
48620cf1dd8SToby Isaac 
48720cf1dd8SToby Isaac   PetscFunctionBegin;
48820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
48920cf1dd8SToby Isaac   PetscValidPointer(spNew, 2);
4909566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4919566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)sp, &name));
4929566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*spNew, name));
4939566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4949566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4959566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4969566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
497b4457527SToby Isaac 
498b4457527SToby Isaac   (*spNew)->order   = sp->order;
499b4457527SToby Isaac   (*spNew)->k       = sp->k;
500b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
501b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
502dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
5033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50420cf1dd8SToby Isaac }
50520cf1dd8SToby Isaac 
50620cf1dd8SToby Isaac /*@
507dce8aebaSBarry Smith   PetscDualSpaceGetDM - Get the `DM` representing the reference cell of a `PetscDualSpace`
50820cf1dd8SToby Isaac 
50920f4b53cSBarry Smith   Not Collective
51020cf1dd8SToby Isaac 
51120cf1dd8SToby Isaac   Input Parameter:
512dce8aebaSBarry Smith . sp - The `PetscDualSpace`
51320cf1dd8SToby Isaac 
51420cf1dd8SToby Isaac   Output Parameter:
515dce8aebaSBarry Smith . dm - The reference cell, that is a `DM` that consists of a single cell
51620cf1dd8SToby Isaac 
51720cf1dd8SToby Isaac   Level: intermediate
51820cf1dd8SToby Isaac 
519dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
52020cf1dd8SToby Isaac @*/
521d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
522d71ae5a4SJacob Faibussowitsch {
52320cf1dd8SToby Isaac   PetscFunctionBegin;
52420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
52520cf1dd8SToby Isaac   PetscValidPointer(dm, 2);
52620cf1dd8SToby Isaac   *dm = sp->dm;
5273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52820cf1dd8SToby Isaac }
52920cf1dd8SToby Isaac 
53020cf1dd8SToby Isaac /*@
531dce8aebaSBarry Smith   PetscDualSpaceSetDM - Get the `DM` representing the reference cell
53220cf1dd8SToby Isaac 
53320f4b53cSBarry Smith   Not Collective
53420cf1dd8SToby Isaac 
53520cf1dd8SToby Isaac   Input Parameters:
536dce8aebaSBarry Smith + sp - The `PetscDual`Space
53720cf1dd8SToby Isaac - dm - The reference cell
53820cf1dd8SToby Isaac 
53920cf1dd8SToby Isaac   Level: intermediate
54020cf1dd8SToby Isaac 
541dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `DM`, `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
54220cf1dd8SToby Isaac @*/
543d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
544d71ae5a4SJacob Faibussowitsch {
54520cf1dd8SToby Isaac   PetscFunctionBegin;
54620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
54720cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
54828b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5499566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
55048a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5519566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
55220cf1dd8SToby Isaac   sp->dm = dm;
5533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55420cf1dd8SToby Isaac }
55520cf1dd8SToby Isaac 
55620cf1dd8SToby Isaac /*@
55720cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
55820cf1dd8SToby Isaac 
55920f4b53cSBarry Smith   Not Collective
56020cf1dd8SToby Isaac 
56120cf1dd8SToby Isaac   Input Parameter:
562dce8aebaSBarry Smith . sp - The `PetscDualSpace`
56320cf1dd8SToby Isaac 
56420cf1dd8SToby Isaac   Output Parameter:
56520cf1dd8SToby Isaac . order - The order
56620cf1dd8SToby Isaac 
56720cf1dd8SToby Isaac   Level: intermediate
56820cf1dd8SToby Isaac 
569dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
57020cf1dd8SToby Isaac @*/
571d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
572d71ae5a4SJacob Faibussowitsch {
57320cf1dd8SToby Isaac   PetscFunctionBegin;
57420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
575dadcf809SJacob Faibussowitsch   PetscValidIntPointer(order, 2);
57620cf1dd8SToby Isaac   *order = sp->order;
5773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57820cf1dd8SToby Isaac }
57920cf1dd8SToby Isaac 
58020cf1dd8SToby Isaac /*@
58120cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
58220cf1dd8SToby Isaac 
58320f4b53cSBarry Smith   Not Collective
58420cf1dd8SToby Isaac 
58520cf1dd8SToby Isaac   Input Parameters:
586dce8aebaSBarry Smith + sp    - The `PetscDualSpace`
58720cf1dd8SToby Isaac - order - The order
58820cf1dd8SToby Isaac 
58920cf1dd8SToby Isaac   Level: intermediate
59020cf1dd8SToby Isaac 
591dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
59220cf1dd8SToby Isaac @*/
593d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
594d71ae5a4SJacob Faibussowitsch {
59520cf1dd8SToby Isaac   PetscFunctionBegin;
59620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
59728b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
59820cf1dd8SToby Isaac   sp->order = order;
5993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60020cf1dd8SToby Isaac }
60120cf1dd8SToby Isaac 
60220cf1dd8SToby Isaac /*@
60320cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
60420cf1dd8SToby Isaac 
60520cf1dd8SToby Isaac   Input Parameter:
606dce8aebaSBarry Smith . sp - The `PetscDualSpace`
60720cf1dd8SToby Isaac 
60820cf1dd8SToby Isaac   Output Parameter:
60920cf1dd8SToby Isaac . Nc - The number of components
61020cf1dd8SToby Isaac 
61120cf1dd8SToby Isaac   Level: intermediate
61220cf1dd8SToby Isaac 
613dce8aebaSBarry Smith   Note:
614dce8aebaSBarry Smith   A vector space, for example, will have d components, where d is the spatial dimension
615dce8aebaSBarry Smith 
616db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
61720cf1dd8SToby Isaac @*/
618d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
619d71ae5a4SJacob Faibussowitsch {
62020cf1dd8SToby Isaac   PetscFunctionBegin;
62120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
622dadcf809SJacob Faibussowitsch   PetscValidIntPointer(Nc, 2);
62320cf1dd8SToby Isaac   *Nc = sp->Nc;
6243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62520cf1dd8SToby Isaac }
62620cf1dd8SToby Isaac 
62720cf1dd8SToby Isaac /*@
62820cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
62920cf1dd8SToby Isaac 
63020cf1dd8SToby Isaac   Input Parameters:
631dce8aebaSBarry Smith + sp - The `PetscDualSpace`
632*60225df5SJacob Faibussowitsch - Nc - The number of components
63320cf1dd8SToby Isaac 
63420cf1dd8SToby Isaac   Level: intermediate
63520cf1dd8SToby Isaac 
636db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
63720cf1dd8SToby Isaac @*/
638d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
639d71ae5a4SJacob Faibussowitsch {
64020cf1dd8SToby Isaac   PetscFunctionBegin;
64120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
64228b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
64320cf1dd8SToby Isaac   sp->Nc = Nc;
6443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64520cf1dd8SToby Isaac }
64620cf1dd8SToby Isaac 
64720cf1dd8SToby Isaac /*@
64820cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
64920cf1dd8SToby Isaac 
65020f4b53cSBarry Smith   Not Collective
65120cf1dd8SToby Isaac 
65220cf1dd8SToby Isaac   Input Parameters:
653dce8aebaSBarry Smith + sp - The `PetscDualSpace`
65420cf1dd8SToby Isaac - i  - The basis number
65520cf1dd8SToby Isaac 
65620cf1dd8SToby Isaac   Output Parameter:
65720cf1dd8SToby Isaac . functional - The basis functional
65820cf1dd8SToby Isaac 
65920cf1dd8SToby Isaac   Level: intermediate
66020cf1dd8SToby Isaac 
661dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
66220cf1dd8SToby Isaac @*/
663d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
664d71ae5a4SJacob Faibussowitsch {
66520cf1dd8SToby Isaac   PetscInt dim;
66620cf1dd8SToby Isaac 
66720cf1dd8SToby Isaac   PetscFunctionBegin;
66820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
66920cf1dd8SToby Isaac   PetscValidPointer(functional, 3);
6709566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
67163a3b9bcSJacob 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);
67220cf1dd8SToby Isaac   *functional = sp->functional[i];
6733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
67420cf1dd8SToby Isaac }
67520cf1dd8SToby Isaac 
67620cf1dd8SToby Isaac /*@
67720cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
67820cf1dd8SToby Isaac 
67920f4b53cSBarry Smith   Not Collective
68020cf1dd8SToby Isaac 
68120cf1dd8SToby Isaac   Input Parameter:
682dce8aebaSBarry Smith . sp - The `PetscDualSpace`
68320cf1dd8SToby Isaac 
68420cf1dd8SToby Isaac   Output Parameter:
68520cf1dd8SToby Isaac . dim - The dimension
68620cf1dd8SToby Isaac 
68720cf1dd8SToby Isaac   Level: intermediate
68820cf1dd8SToby Isaac 
689dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
69020cf1dd8SToby Isaac @*/
691d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
692d71ae5a4SJacob Faibussowitsch {
69320cf1dd8SToby Isaac   PetscFunctionBegin;
69420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
695dadcf809SJacob Faibussowitsch   PetscValidIntPointer(dim, 2);
696b4457527SToby Isaac   if (sp->spdim < 0) {
697b4457527SToby Isaac     PetscSection section;
698b4457527SToby Isaac 
6999566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
700b4457527SToby Isaac     if (section) {
7019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(section, &(sp->spdim)));
702b4457527SToby Isaac     } else sp->spdim = 0;
703b4457527SToby Isaac   }
704b4457527SToby Isaac   *dim = sp->spdim;
7053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70620cf1dd8SToby Isaac }
70720cf1dd8SToby Isaac 
708b4457527SToby Isaac /*@
709b4457527SToby 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
710b4457527SToby Isaac 
71120f4b53cSBarry Smith   Not Collective
712b4457527SToby Isaac 
713b4457527SToby Isaac   Input Parameter:
714dce8aebaSBarry Smith . sp - The `PetscDualSpace`
715b4457527SToby Isaac 
716b4457527SToby Isaac   Output Parameter:
717*60225df5SJacob Faibussowitsch . intdim - The dimension
718b4457527SToby Isaac 
719b4457527SToby Isaac   Level: intermediate
720b4457527SToby Isaac 
721dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
722b4457527SToby Isaac @*/
723d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim)
724d71ae5a4SJacob Faibussowitsch {
725b4457527SToby Isaac   PetscFunctionBegin;
726b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
727dadcf809SJacob Faibussowitsch   PetscValidIntPointer(intdim, 2);
728b4457527SToby Isaac   if (sp->spintdim < 0) {
729b4457527SToby Isaac     PetscSection section;
730b4457527SToby Isaac 
7319566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
732b4457527SToby Isaac     if (section) {
7339566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstrainedStorageSize(section, &(sp->spintdim)));
734b4457527SToby Isaac     } else sp->spintdim = 0;
735b4457527SToby Isaac   }
736b4457527SToby Isaac   *intdim = sp->spintdim;
7373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
738b4457527SToby Isaac }
739b4457527SToby Isaac 
740b4457527SToby Isaac /*@
741b4457527SToby Isaac   PetscDualSpaceGetUniform - Whether this dual space is uniform
742b4457527SToby Isaac 
74320f4b53cSBarry Smith   Not Collective
744b4457527SToby Isaac 
7452fe279fdSBarry Smith   Input Parameter:
746b4457527SToby Isaac . sp - A dual space
747b4457527SToby Isaac 
7482fe279fdSBarry Smith   Output Parameter:
749dce8aebaSBarry Smith . uniform - `PETSC_TRUE` if (a) the dual space is the same for each point in a stratum of the reference `DMPLEX`, and
750dce8aebaSBarry Smith              (b) every symmetry of each point in the reference `DMPLEX` is also a symmetry of the point's dual space.
751b4457527SToby Isaac 
752b4457527SToby Isaac   Level: advanced
753b4457527SToby Isaac 
754dce8aebaSBarry Smith   Note:
755dce8aebaSBarry Smith   All of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
756b4457527SToby Isaac   with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
757b4457527SToby Isaac 
758dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
759b4457527SToby Isaac @*/
760d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform)
761d71ae5a4SJacob Faibussowitsch {
762b4457527SToby Isaac   PetscFunctionBegin;
763b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
764dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(uniform, 2);
765b4457527SToby Isaac   *uniform = sp->uniform;
7663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
767b4457527SToby Isaac }
768b4457527SToby Isaac 
76920cf1dd8SToby Isaac /*@C
77020cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
77120cf1dd8SToby Isaac 
77220f4b53cSBarry Smith   Not Collective
77320cf1dd8SToby Isaac 
77420cf1dd8SToby Isaac   Input Parameter:
775dce8aebaSBarry Smith . sp - The `PetscDualSpace`
77620cf1dd8SToby Isaac 
77720cf1dd8SToby Isaac   Output Parameter:
77820cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
77920cf1dd8SToby Isaac 
78020cf1dd8SToby Isaac   Level: intermediate
78120cf1dd8SToby Isaac 
782dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
78320cf1dd8SToby Isaac @*/
784d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof)
785d71ae5a4SJacob Faibussowitsch {
78620cf1dd8SToby Isaac   PetscFunctionBegin;
78720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
78820cf1dd8SToby Isaac   PetscValidPointer(numDof, 2);
78928b400f6SJacob 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");
790b4457527SToby Isaac   if (!sp->numDof) {
791b4457527SToby Isaac     DM           dm;
792b4457527SToby Isaac     PetscInt     depth, d;
793b4457527SToby Isaac     PetscSection section;
794b4457527SToby Isaac 
7959566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
7969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
7979566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->numDof)));
7989566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
799b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
800b4457527SToby Isaac       PetscInt dStart, dEnd;
801b4457527SToby Isaac 
8029566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
803b4457527SToby Isaac       if (dEnd <= dStart) continue;
8049566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, dStart, &(sp->numDof[d])));
805b4457527SToby Isaac     }
806b4457527SToby Isaac   }
807b4457527SToby Isaac   *numDof = sp->numDof;
80808401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
8093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81020cf1dd8SToby Isaac }
81120cf1dd8SToby Isaac 
812b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
813d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection)
814d71ae5a4SJacob Faibussowitsch {
815b4457527SToby Isaac   DM           dm;
816b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
817b4457527SToby Isaac   PetscInt    *seen, *perm;
818b4457527SToby Isaac   PetscSection section;
819b4457527SToby Isaac 
820b4457527SToby Isaac   PetscFunctionBegin;
821b4457527SToby Isaac   dm = sp->dm;
8229566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
8239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8249566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8259566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
8269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
8279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
829b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
830b4457527SToby Isaac     PetscInt  closureSize = -1, e;
831b4457527SToby Isaac     PetscInt *closure     = NULL;
832b4457527SToby Isaac 
833b4457527SToby Isaac     perm[count++]    = c;
834b4457527SToby Isaac     seen[c - pStart] = 1;
8359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
836b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
837b4457527SToby Isaac       PetscInt point = closure[2 * e];
838b4457527SToby Isaac 
839b4457527SToby Isaac       if (seen[point - pStart]) continue;
840b4457527SToby Isaac       perm[count++]        = point;
841b4457527SToby Isaac       seen[point - pStart] = 1;
842b4457527SToby Isaac     }
8439566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
844b4457527SToby Isaac   }
8451dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8469371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8479371c9d4SSatish Balay     if (perm[i] != i) break;
848b4457527SToby Isaac   if (i < pEnd - pStart) {
849b4457527SToby Isaac     IS permIS;
850b4457527SToby Isaac 
8519566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8529566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8539566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8549566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
855b4457527SToby Isaac   } else {
8569566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
857b4457527SToby Isaac   }
8589566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
859b4457527SToby Isaac   *topSection = section;
8603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
861b4457527SToby Isaac }
862b4457527SToby Isaac 
863b4457527SToby Isaac /* mark boundary points and set up */
864d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section)
865d71ae5a4SJacob Faibussowitsch {
866b4457527SToby Isaac   DM       dm;
867b4457527SToby Isaac   DMLabel  boundary;
868b4457527SToby Isaac   PetscInt pStart, pEnd, p;
869b4457527SToby Isaac 
870b4457527SToby Isaac   PetscFunctionBegin;
871b4457527SToby Isaac   dm = sp->dm;
8729566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8739566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8749566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8759566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
877b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
878b4457527SToby Isaac     PetscInt bval;
879b4457527SToby Isaac 
8809566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
881b4457527SToby Isaac     if (bval == 1) {
882b4457527SToby Isaac       PetscInt dof;
883b4457527SToby Isaac 
8849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8859566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
886b4457527SToby Isaac     }
887b4457527SToby Isaac   }
8889566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8899566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
891b4457527SToby Isaac }
892b4457527SToby Isaac 
893a4ce7ad1SMatthew G. Knepley /*@
894dce8aebaSBarry Smith   PetscDualSpaceGetSection - Create a `PetscSection` over the reference cell with the layout from this space
895a4ce7ad1SMatthew G. Knepley 
89620f4b53cSBarry Smith   Collective
897a4ce7ad1SMatthew G. Knepley 
8982fe279fdSBarry Smith   Input Parameter:
899dce8aebaSBarry Smith . sp - The `PetscDualSpace`
900a4ce7ad1SMatthew G. Knepley 
901a4ce7ad1SMatthew G. Knepley   Output Parameter:
902a4ce7ad1SMatthew G. Knepley . section - The section
903a4ce7ad1SMatthew G. Knepley 
904a4ce7ad1SMatthew G. Knepley   Level: advanced
905a4ce7ad1SMatthew G. Knepley 
906dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
907a4ce7ad1SMatthew G. Knepley @*/
908d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section)
909d71ae5a4SJacob Faibussowitsch {
910b4457527SToby Isaac   PetscInt pStart, pEnd, p;
911b4457527SToby Isaac 
912b4457527SToby Isaac   PetscFunctionBegin;
91378f1d139SRomain Beucher   if (!sp->dm) {
91478f1d139SRomain Beucher     *section = NULL;
9153ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
91678f1d139SRomain Beucher   }
917b4457527SToby Isaac   if (!sp->pointSection) {
918b4457527SToby Isaac     /* mark the boundary */
9199566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &(sp->pointSection)));
9209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
921b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
922b4457527SToby Isaac       PetscDualSpace psp;
923b4457527SToby Isaac 
9249566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
925b4457527SToby Isaac       if (psp) {
926b4457527SToby Isaac         PetscInt dof;
927b4457527SToby Isaac 
9289566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
9299566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
930b4457527SToby Isaac       }
931b4457527SToby Isaac     }
9329566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
933b4457527SToby Isaac   }
934b4457527SToby Isaac   *section = sp->pointSection;
9353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
936b4457527SToby Isaac }
937b4457527SToby Isaac 
938b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
939b4457527SToby Isaac  * have one cell */
940d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd)
941d71ae5a4SJacob Faibussowitsch {
942b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
943b4457527SToby Isaac   PetscSection section;
944b4457527SToby Isaac   PetscInt     dim, s, k;
94520cf1dd8SToby Isaac   DM           dm;
94620cf1dd8SToby Isaac 
94720cf1dd8SToby Isaac   PetscFunctionBegin;
9489566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
9499566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9509566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
9519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
9529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
953b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
954b4457527SToby Isaac     PetscReal      detJ, hdetJ;
955b4457527SToby Isaac     PetscDualSpace ssp;
956b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
957b4457527SToby Isaac     PetscInt       i, j;
958b4457527SToby Isaac     DM             sdm;
95920cf1dd8SToby Isaac 
9609566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
961b4457527SToby Isaac     if (!ssp) continue;
9629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
9639566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
964b4457527SToby Isaac     /* get the first vertex of the reference cell */
9659566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
9669566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
9679566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
9689566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
969b4457527SToby Isaac     /* compactify Jacobian */
9709371c9d4SSatish Balay     for (i = 0; i < dim; i++)
9719371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
972b4457527SToby Isaac     for (f = 0; f < dof; f++) {
973b4457527SToby Isaac       PetscQuadrature fn;
97420cf1dd8SToby Isaac 
9759566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
9769566063dSJacob Faibussowitsch       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &(sp->functional[off + f])));
97720cf1dd8SToby Isaac     }
97820cf1dd8SToby Isaac   }
9799566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
9803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98120cf1dd8SToby Isaac }
98220cf1dd8SToby Isaac 
98320cf1dd8SToby Isaac /*@C
98420cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
98520cf1dd8SToby Isaac 
98620cf1dd8SToby Isaac   Input Parameters:
987dce8aebaSBarry Smith + sp      - The `PetscDualSpace` object
98820cf1dd8SToby Isaac . f       - The basis functional index
98920cf1dd8SToby Isaac . time    - The time
99020cf1dd8SToby 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)
99120cf1dd8SToby Isaac . numComp - The number of components for the function
99220cf1dd8SToby Isaac . func    - The input function
99320cf1dd8SToby Isaac - ctx     - A context for the function
99420cf1dd8SToby Isaac 
99520cf1dd8SToby Isaac   Output Parameter:
99620cf1dd8SToby Isaac . value - numComp output values
99720cf1dd8SToby Isaac 
998*60225df5SJacob Faibussowitsch   Calling sequence:
999dce8aebaSBarry Smith .vb
100020f4b53cSBarry Smith   PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1001dce8aebaSBarry Smith .ve
100220cf1dd8SToby Isaac 
1003a4ce7ad1SMatthew G. Knepley   Level: beginner
100420cf1dd8SToby Isaac 
1005dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
100620cf1dd8SToby Isaac @*/
1007d71ae5a4SJacob 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)
1008d71ae5a4SJacob Faibussowitsch {
100920cf1dd8SToby Isaac   PetscFunctionBegin;
101020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
101120cf1dd8SToby Isaac   PetscValidPointer(cgeom, 4);
1012dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
1013dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
10143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
101520cf1dd8SToby Isaac }
101620cf1dd8SToby Isaac 
101720cf1dd8SToby Isaac /*@C
1018dce8aebaSBarry Smith   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
101920cf1dd8SToby Isaac 
102020cf1dd8SToby Isaac   Input Parameters:
1021dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1022dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
102320cf1dd8SToby Isaac 
102420cf1dd8SToby Isaac   Output Parameter:
102520cf1dd8SToby Isaac . spValue - The values of all dual space functionals
102620cf1dd8SToby Isaac 
1027dce8aebaSBarry Smith   Level: advanced
102820cf1dd8SToby Isaac 
1029dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
103020cf1dd8SToby Isaac @*/
1031d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1032d71ae5a4SJacob Faibussowitsch {
103320cf1dd8SToby Isaac   PetscFunctionBegin;
103420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1035dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
10363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103720cf1dd8SToby Isaac }
103820cf1dd8SToby Isaac 
103920cf1dd8SToby Isaac /*@C
1040dce8aebaSBarry Smith   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1041b4457527SToby Isaac 
1042b4457527SToby Isaac   Input Parameters:
1043dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1044dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1045b4457527SToby Isaac 
1046b4457527SToby Isaac   Output Parameter:
1047b4457527SToby Isaac . spValue - The values of interior dual space functionals
1048b4457527SToby Isaac 
1049dce8aebaSBarry Smith   Level: advanced
1050b4457527SToby Isaac 
1051dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1052b4457527SToby Isaac @*/
1053d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1054d71ae5a4SJacob Faibussowitsch {
1055b4457527SToby Isaac   PetscFunctionBegin;
1056b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1057dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
10583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1059b4457527SToby Isaac }
1060b4457527SToby Isaac 
1061b4457527SToby Isaac /*@C
106220cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
106320cf1dd8SToby Isaac 
106420cf1dd8SToby Isaac   Input Parameters:
1065dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
106620cf1dd8SToby Isaac . f     - The basis functional index
106720cf1dd8SToby Isaac . time  - The time
106820cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
106920cf1dd8SToby Isaac . Nc    - The number of components for the function
107020cf1dd8SToby Isaac . func  - The input function
107120cf1dd8SToby Isaac - ctx   - A context for the function
107220cf1dd8SToby Isaac 
107320cf1dd8SToby Isaac   Output Parameter:
107420cf1dd8SToby Isaac . value - The output value
107520cf1dd8SToby Isaac 
1076*60225df5SJacob Faibussowitsch   Calling sequence:
1077dce8aebaSBarry Smith .vb
107820f4b53cSBarry Smith    PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[],PetscInt numComponents, PetscScalar values[], void *ctx)
1079dce8aebaSBarry Smith .ve
108020cf1dd8SToby Isaac 
1081dce8aebaSBarry Smith   Level: advanced
108220cf1dd8SToby Isaac 
1083dce8aebaSBarry Smith   Note:
1084dce8aebaSBarry 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.
108520cf1dd8SToby Isaac 
1086dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
108720cf1dd8SToby Isaac @*/
1088d71ae5a4SJacob 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)
1089d71ae5a4SJacob Faibussowitsch {
109020cf1dd8SToby Isaac   DM               dm;
109120cf1dd8SToby Isaac   PetscQuadrature  n;
109220cf1dd8SToby Isaac   const PetscReal *points, *weights;
109320cf1dd8SToby Isaac   PetscReal        x[3];
109420cf1dd8SToby Isaac   PetscScalar     *val;
109520cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
109620cf1dd8SToby Isaac   PetscBool        isAffine;
109720cf1dd8SToby Isaac 
109820cf1dd8SToby Isaac   PetscFunctionBegin;
109920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1100dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
11019566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
11029566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
11039566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
110463a3b9bcSJacob 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);
110563a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
11069566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
110720cf1dd8SToby Isaac   *value   = 0.0;
110820cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
110920cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
111020cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
111120cf1dd8SToby Isaac     if (isAffine) {
111220cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
11139566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
111420cf1dd8SToby Isaac     } else {
11159566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
111620cf1dd8SToby Isaac     }
1117ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
111820cf1dd8SToby Isaac   }
11199566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
11203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
112120cf1dd8SToby Isaac }
112220cf1dd8SToby Isaac 
112320cf1dd8SToby Isaac /*@C
1124dce8aebaSBarry Smith   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
112520cf1dd8SToby Isaac 
112620cf1dd8SToby Isaac   Input Parameters:
1127dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1128dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
112920cf1dd8SToby Isaac 
113020cf1dd8SToby Isaac   Output Parameter:
113120cf1dd8SToby Isaac . spValue - The values of all dual space functionals
113220cf1dd8SToby Isaac 
1133dce8aebaSBarry Smith   Level: advanced
113420cf1dd8SToby Isaac 
1135dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
113620cf1dd8SToby Isaac @*/
1137d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1138d71ae5a4SJacob Faibussowitsch {
1139b4457527SToby Isaac   Vec pointValues, dofValues;
1140b4457527SToby Isaac   Mat allMat;
114120cf1dd8SToby Isaac 
114220cf1dd8SToby Isaac   PetscFunctionBegin;
114320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
114420cf1dd8SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1145064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11469566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
114748a46eb9SPierre Jolivet   if (!(sp->allNodeValues)) PetscCall(MatCreateVecs(allMat, &(sp->allNodeValues), NULL));
1148b4457527SToby Isaac   pointValues = sp->allNodeValues;
114948a46eb9SPierre Jolivet   if (!(sp->allDofValues)) PetscCall(MatCreateVecs(allMat, NULL, &(sp->allDofValues)));
1150b4457527SToby Isaac   dofValues = sp->allDofValues;
11519566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11529566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11539566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
11549566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11559566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
11563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
115720cf1dd8SToby Isaac }
1158b4457527SToby Isaac 
1159b4457527SToby Isaac /*@C
1160dce8aebaSBarry Smith   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1161b4457527SToby Isaac 
1162b4457527SToby Isaac   Input Parameters:
1163dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1164dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1165b4457527SToby Isaac 
1166b4457527SToby Isaac   Output Parameter:
1167b4457527SToby Isaac . spValue - The values of interior dual space functionals
1168b4457527SToby Isaac 
1169dce8aebaSBarry Smith   Level: advanced
1170b4457527SToby Isaac 
1171dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1172b4457527SToby Isaac @*/
1173d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1174d71ae5a4SJacob Faibussowitsch {
1175b4457527SToby Isaac   Vec pointValues, dofValues;
1176b4457527SToby Isaac   Mat intMat;
1177b4457527SToby Isaac 
1178b4457527SToby Isaac   PetscFunctionBegin;
1179b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1180b4457527SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1181064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11829566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
118348a46eb9SPierre Jolivet   if (!(sp->intNodeValues)) PetscCall(MatCreateVecs(intMat, &(sp->intNodeValues), NULL));
1184b4457527SToby Isaac   pointValues = sp->intNodeValues;
118548a46eb9SPierre Jolivet   if (!(sp->intDofValues)) PetscCall(MatCreateVecs(intMat, NULL, &(sp->intDofValues)));
1186b4457527SToby Isaac   dofValues = sp->intDofValues;
11879566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11889566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11899566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
11909566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11919566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
11923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
119320cf1dd8SToby Isaac }
119420cf1dd8SToby Isaac 
1195a4ce7ad1SMatthew G. Knepley /*@
1196b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1197a4ce7ad1SMatthew G. Knepley 
1198a4ce7ad1SMatthew G. Knepley   Input Parameter:
1199a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1200a4ce7ad1SMatthew G. Knepley 
1201d8d19677SJose E. Roman   Output Parameters:
1202dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1203dce8aebaSBarry Smith - allMat   - A `Mat` for the node-to-dof transformation
1204a4ce7ad1SMatthew G. Knepley 
1205a4ce7ad1SMatthew G. Knepley   Level: advanced
1206a4ce7ad1SMatthew G. Knepley 
1207dce8aebaSBarry Smith .seealso: `PetscQuadrature`, `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`
1208a4ce7ad1SMatthew G. Knepley @*/
1209d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1210d71ae5a4SJacob Faibussowitsch {
121120cf1dd8SToby Isaac   PetscFunctionBegin;
121220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1213b4457527SToby Isaac   if (allNodes) PetscValidPointer(allNodes, 2);
1214b4457527SToby Isaac   if (allMat) PetscValidPointer(allMat, 3);
1215b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1216b4457527SToby Isaac     PetscQuadrature qpoints;
1217b4457527SToby Isaac     Mat             amat;
1218b4457527SToby Isaac 
1219dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
12209566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
12219566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->allMat)));
1222b4457527SToby Isaac     sp->allNodes = qpoints;
1223b4457527SToby Isaac     sp->allMat   = amat;
122420cf1dd8SToby Isaac   }
1225b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1226b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
12273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122820cf1dd8SToby Isaac }
122920cf1dd8SToby Isaac 
1230a4ce7ad1SMatthew G. Knepley /*@
1231b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1232a4ce7ad1SMatthew G. Knepley 
1233a4ce7ad1SMatthew G. Knepley   Input Parameter:
1234a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1235a4ce7ad1SMatthew G. Knepley 
1236d8d19677SJose E. Roman   Output Parameters:
1237dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1238dce8aebaSBarry Smith - allMat   - A `Mat` for the node-to-dof transformation
1239a4ce7ad1SMatthew G. Knepley 
1240a4ce7ad1SMatthew G. Knepley   Level: advanced
1241a4ce7ad1SMatthew G. Knepley 
1242dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`, `PetscQuadrature`
1243a4ce7ad1SMatthew G. Knepley @*/
1244d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1245d71ae5a4SJacob Faibussowitsch {
124620cf1dd8SToby Isaac   PetscInt        spdim;
124720cf1dd8SToby Isaac   PetscInt        numPoints, offset;
124820cf1dd8SToby Isaac   PetscReal      *points;
124920cf1dd8SToby Isaac   PetscInt        f, dim;
1250b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1251b4457527SToby Isaac   PetscInt        maxNumPoints;
125220cf1dd8SToby Isaac   PetscQuadrature q;
1253b4457527SToby Isaac   Mat             A;
125420cf1dd8SToby Isaac 
125520cf1dd8SToby Isaac   PetscFunctionBegin;
12569566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
12579566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
125820cf1dd8SToby Isaac   if (!spdim) {
12599566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12609566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
126120cf1dd8SToby Isaac   }
1262b4457527SToby Isaac   nrows = spdim;
12639566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
12649566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1265b4457527SToby Isaac   maxNumPoints = numPoints;
126620cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
126720cf1dd8SToby Isaac     PetscInt Np;
126820cf1dd8SToby Isaac 
12699566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12709566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
127120cf1dd8SToby Isaac     numPoints += Np;
1272b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
127320cf1dd8SToby Isaac   }
1274b4457527SToby Isaac   ncols = numPoints * Nc;
12759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
12769566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
127720cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1278b4457527SToby Isaac     const PetscReal *p, *w;
127920cf1dd8SToby Isaac     PetscInt         Np, i;
1280b4457527SToby Isaac     PetscInt         fnc;
128120cf1dd8SToby Isaac 
12829566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12839566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
128408401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
1285ad540459SPierre Jolivet     for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i];
128648a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1287b4457527SToby Isaac     offset += Np;
1288b4457527SToby Isaac   }
12899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
12909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
12919566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12929566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1293b4457527SToby Isaac   *allMat = A;
12943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1295b4457527SToby Isaac }
1296b4457527SToby Isaac 
1297b4457527SToby Isaac /*@
1298b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1299b4457527SToby Isaac   this space, as well as the matrix that computes the degrees of freedom from the quadrature values.  Degrees of
1300dce8aebaSBarry Smith   freedom are interior degrees of freedom if they belong (by `PetscDualSpaceGetSection()`) to interior points in the
1301*60225df5SJacob Faibussowitsch 
1302*60225df5SJacob Faibussowitsch   References: complementary boundary degrees of freedom are marked as constrained in the section returned by
1303dce8aebaSBarry Smith   `PetscDualSpaceGetSection()`).
1304b4457527SToby Isaac 
1305b4457527SToby Isaac   Input Parameter:
1306b4457527SToby Isaac . sp - The dualspace
1307b4457527SToby Isaac 
1308d8d19677SJose E. Roman   Output Parameters:
1309dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1310b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1311dce8aebaSBarry Smith              the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1312dce8aebaSBarry Smith              npoints is the number of points in intNodes and nc is `PetscDualSpaceGetNumComponents()`.
1313b4457527SToby Isaac 
1314b4457527SToby Isaac   Level: advanced
1315b4457527SToby Isaac 
1316dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1317b4457527SToby Isaac @*/
1318d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1319d71ae5a4SJacob Faibussowitsch {
1320b4457527SToby Isaac   PetscFunctionBegin;
1321b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1322b4457527SToby Isaac   if (intNodes) PetscValidPointer(intNodes, 2);
1323b4457527SToby Isaac   if (intMat) PetscValidPointer(intMat, 3);
1324b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1325b4457527SToby Isaac     PetscQuadrature qpoints;
1326b4457527SToby Isaac     Mat             imat;
1327b4457527SToby Isaac 
1328dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
13299566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
13309566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->intMat)));
1331b4457527SToby Isaac     sp->intNodes = qpoints;
1332b4457527SToby Isaac     sp->intMat   = imat;
1333b4457527SToby Isaac   }
1334b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1335b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
13363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1337b4457527SToby Isaac }
1338b4457527SToby Isaac 
1339b4457527SToby Isaac /*@
1340b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1341b4457527SToby Isaac 
1342b4457527SToby Isaac   Input Parameter:
1343b4457527SToby Isaac . sp - The dualspace
1344b4457527SToby Isaac 
1345d8d19677SJose E. Roman   Output Parameters:
1346dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1347b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1348dce8aebaSBarry Smith               the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1349dce8aebaSBarry Smith               npoints is the number of points in allNodes and nc is `PetscDualSpaceGetNumComponents()`.
1350b4457527SToby Isaac 
1351b4457527SToby Isaac   Level: advanced
1352b4457527SToby Isaac 
1353dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1354b4457527SToby Isaac @*/
1355d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1356d71ae5a4SJacob Faibussowitsch {
1357b4457527SToby Isaac   DM              dm;
1358b4457527SToby Isaac   PetscInt        spdim0;
1359b4457527SToby Isaac   PetscInt        Nc;
1360b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1361b4457527SToby Isaac   PetscSection    section;
1362b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1363b4457527SToby Isaac   PetscReal      *points;
1364b4457527SToby Isaac   PetscInt        dim;
1365b4457527SToby Isaac   PetscInt       *nnz;
1366b4457527SToby Isaac   PetscQuadrature q;
1367b4457527SToby Isaac   Mat             imat;
1368b4457527SToby Isaac 
1369b4457527SToby Isaac   PetscFunctionBegin;
1370b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13719566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
13729566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1373b4457527SToby Isaac   if (!spdim0) {
1374b4457527SToby Isaac     *intNodes = NULL;
1375b4457527SToby Isaac     *intMat   = NULL;
13763ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1377b4457527SToby Isaac   }
13789566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
13809566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
13819566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1383b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1384b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1385b4457527SToby Isaac 
13869566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1388b4457527SToby Isaac     if (!(dof - cdof)) continue;
13899566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1390b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1391b4457527SToby Isaac       PetscInt Np;
1392b4457527SToby Isaac 
13939566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
13949566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1395b4457527SToby Isaac       nnz[f] = Np * Nc;
1396b4457527SToby Isaac       numPoints += Np;
1397b4457527SToby Isaac     }
1398b4457527SToby Isaac   }
13999566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
14009566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
14019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1402b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1403b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1404b4457527SToby Isaac 
14059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
14069566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1407b4457527SToby Isaac     if (!(dof - cdof)) continue;
14089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1409b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1410b4457527SToby Isaac       const PetscReal *p;
1411b4457527SToby Isaac       const PetscReal *w;
1412b4457527SToby Isaac       PetscInt         Np, i;
1413b4457527SToby Isaac 
14149566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14159566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
1416ad540459SPierre Jolivet       for (i = 0; i < Np * dim; i++) points[offset + i] = p[i];
141748a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1418b4457527SToby Isaac       offset += Np * dim;
1419b4457527SToby Isaac       matoffset += Np * Nc;
1420b4457527SToby Isaac     }
1421b4457527SToby Isaac   }
14229566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
14239566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
14249566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
14259566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1426b4457527SToby Isaac   *intMat = imat;
14273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
142820cf1dd8SToby Isaac }
142920cf1dd8SToby Isaac 
14304f9ab2b4SJed Brown /*@
1431dce8aebaSBarry Smith   PetscDualSpaceEqual - Determine if two dual spaces are equivalent
14324f9ab2b4SJed Brown 
14334f9ab2b4SJed Brown   Input Parameters:
1434dce8aebaSBarry Smith + A - A `PetscDualSpace` object
1435dce8aebaSBarry Smith - B - Another `PetscDualSpace` object
14364f9ab2b4SJed Brown 
14374f9ab2b4SJed Brown   Output Parameter:
1438dce8aebaSBarry Smith . equal - `PETSC_TRUE` if the dual spaces are equivalent
14394f9ab2b4SJed Brown 
14404f9ab2b4SJed Brown   Level: advanced
14414f9ab2b4SJed Brown 
1442dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
14434f9ab2b4SJed Brown @*/
1444d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal)
1445d71ae5a4SJacob Faibussowitsch {
14464f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
14474f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
14484f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
14494f9ab2b4SJed Brown   Mat             matA, matB;
14504f9ab2b4SJed Brown 
14514f9ab2b4SJed Brown   PetscFunctionBegin;
14524f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
14534f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
14544f9ab2b4SJed Brown   PetscValidBoolPointer(equal, 3);
14554f9ab2b4SJed Brown   *equal = PETSC_FALSE;
14569566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
14579566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
14583ba16761SJacob Faibussowitsch   if (sizeB != sizeA) PetscFunctionReturn(PETSC_SUCCESS);
14599566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
14609566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
14613ba16761SJacob Faibussowitsch   if (dimA != dimB) PetscFunctionReturn(PETSC_SUCCESS);
14624f9ab2b4SJed Brown 
14639566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
14649566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
14654f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
14663ba16761SJacob Faibussowitsch     if (dofA[d] != dofB[d]) PetscFunctionReturn(PETSC_SUCCESS);
14674f9ab2b4SJed Brown   }
14684f9ab2b4SJed Brown 
14699566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
14709566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
14714f9ab2b4SJed Brown   if (!quadA && !quadB) {
14724f9ab2b4SJed Brown     *equal = PETSC_TRUE;
14734f9ab2b4SJed Brown   } else if (quadA && quadB) {
14749566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
14753ba16761SJacob Faibussowitsch     if (*equal == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS);
14763ba16761SJacob Faibussowitsch     if (!matA && !matB) PetscFunctionReturn(PETSC_SUCCESS);
14779566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
14784f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
14794f9ab2b4SJed Brown   }
14803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14814f9ab2b4SJed Brown }
14824f9ab2b4SJed Brown 
148320cf1dd8SToby Isaac /*@C
148420cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
148520cf1dd8SToby Isaac 
148620cf1dd8SToby Isaac   Input Parameters:
1487dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
148820cf1dd8SToby Isaac . f     - The basis functional index
148920cf1dd8SToby Isaac . time  - The time
149020cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
149120cf1dd8SToby Isaac . Nc    - The number of components for the function
149220cf1dd8SToby Isaac . func  - The input function
149320cf1dd8SToby Isaac - ctx   - A context for the function
149420cf1dd8SToby Isaac 
149520cf1dd8SToby Isaac   Output Parameter:
149620cf1dd8SToby Isaac . value - The output value (scalar)
149720cf1dd8SToby Isaac 
1498*60225df5SJacob Faibussowitsch   Calling sequence:
1499dce8aebaSBarry Smith .vb
150020f4b53cSBarry Smith   PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1501dce8aebaSBarry Smith .ve
150220f4b53cSBarry Smith 
1503dce8aebaSBarry Smith   Level: advanced
150420cf1dd8SToby Isaac 
1505dce8aebaSBarry Smith   Note:
1506dce8aebaSBarry 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.
150720cf1dd8SToby Isaac 
1508dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
150920cf1dd8SToby Isaac @*/
1510d71ae5a4SJacob 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)
1511d71ae5a4SJacob Faibussowitsch {
151220cf1dd8SToby Isaac   DM               dm;
151320cf1dd8SToby Isaac   PetscQuadrature  n;
151420cf1dd8SToby Isaac   const PetscReal *points, *weights;
151520cf1dd8SToby Isaac   PetscScalar     *val;
151620cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
151720cf1dd8SToby Isaac 
151820cf1dd8SToby Isaac   PetscFunctionBegin;
151920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1520dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
15219566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
15229566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
15239566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
15249566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
152563a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
15269566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
152720cf1dd8SToby Isaac   *value = 0.;
152820cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
15299566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
1530ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
153120cf1dd8SToby Isaac   }
15329566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
15333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
153420cf1dd8SToby Isaac }
153520cf1dd8SToby Isaac 
153620cf1dd8SToby Isaac /*@
153720cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
153820cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
153920cf1dd8SToby Isaac 
154020f4b53cSBarry Smith   Not Collective
154120cf1dd8SToby Isaac 
154220cf1dd8SToby Isaac   Input Parameters:
1543dce8aebaSBarry Smith + sp     - the `PetscDualSpace` object
154420cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
154520cf1dd8SToby Isaac 
154620cf1dd8SToby Isaac   Output Parameter:
154720cf1dd8SToby Isaac . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
154820cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
154920cf1dd8SToby Isaac 
155020cf1dd8SToby Isaac   Level: advanced
155120cf1dd8SToby Isaac 
1552dce8aebaSBarry Smith   Notes:
1553dce8aebaSBarry Smith   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
1554dce8aebaSBarry Smith   pointwise values are not defined on the element boundaries), or if the implementation of `PetscDualSpace` does not
1555dce8aebaSBarry Smith   support extracting subspaces, then NULL is returned.
1556dce8aebaSBarry Smith 
1557dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1558dce8aebaSBarry Smith 
1559*60225df5SJacob Faibussowitsch .seealso: `PetscDualSpace`, `PetscSpaceGetHeightSubspace()`, `PetscDualSpaceGetPointSubspace()`
156020cf1dd8SToby Isaac @*/
1561d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
1562d71ae5a4SJacob Faibussowitsch {
1563b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1564b4457527SToby Isaac   DM       dm;
156520cf1dd8SToby Isaac 
156620cf1dd8SToby Isaac   PetscFunctionBegin;
156720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1568064a246eSJacob Faibussowitsch   PetscValidPointer(subsp, 3);
156908401ef6SPierre 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");
157020cf1dd8SToby Isaac   *subsp = NULL;
1571b4457527SToby Isaac   dm     = sp->dm;
15729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
15731dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
15749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1575b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1576b4457527SToby Isaac     *subsp = sp;
15773ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1578b4457527SToby Isaac   }
1579b4457527SToby Isaac   if (!sp->heightSpaces) {
1580b4457527SToby Isaac     PetscInt h;
15819566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->heightSpaces)));
1582b4457527SToby Isaac 
1583b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1584b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
15859566063dSJacob Faibussowitsch       if (sp->ops->createheightsubspace) PetscCall((*sp->ops->createheightsubspace)(sp, height, &(sp->heightSpaces[h])));
1586b4457527SToby Isaac       else if (sp->pointSpaces) {
1587b4457527SToby Isaac         PetscInt hStart, hEnd;
1588b4457527SToby Isaac 
15899566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1590b4457527SToby Isaac         if (hEnd > hStart) {
1591665f567fSMatthew G. Knepley           const char *name;
1592665f567fSMatthew G. Knepley 
15939566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)(sp->pointSpaces[hStart])));
1594665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
15959566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
15969566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1597665f567fSMatthew G. Knepley           }
1598b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1599b4457527SToby Isaac         }
1600b4457527SToby Isaac       }
1601b4457527SToby Isaac     }
1602b4457527SToby Isaac   }
1603b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
16043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160520cf1dd8SToby Isaac }
160620cf1dd8SToby Isaac 
160720cf1dd8SToby Isaac /*@
160820cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
160920cf1dd8SToby Isaac 
161020f4b53cSBarry Smith   Not Collective
161120cf1dd8SToby Isaac 
161220cf1dd8SToby Isaac   Input Parameters:
1613dce8aebaSBarry Smith + sp    - the `PetscDualSpace` object
161420cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
161520cf1dd8SToby Isaac 
161620cf1dd8SToby Isaac   Output Parameters:
1617dce8aebaSBarry Smith   bdsp - the subspace. The functionals in the subspace are with respect to the intrinsic geometry of the
161820cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
161920cf1dd8SToby Isaac 
162020cf1dd8SToby Isaac   Level: advanced
162120cf1dd8SToby Isaac 
1622dce8aebaSBarry Smith   Notes:
1623dce8aebaSBarry Smith   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
1624dce8aebaSBarry Smith   defined on the element boundaries), or if the implementation of `PetscDualSpace` does not support extracting
1625dce8aebaSBarry Smith   subspaces, then NULL is returned.
1626dce8aebaSBarry Smith 
1627dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1628dce8aebaSBarry Smith 
1629dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetHeightSubspace()`
163020cf1dd8SToby Isaac @*/
1631d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1632d71ae5a4SJacob Faibussowitsch {
1633b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1634b4457527SToby Isaac   DM       dm;
163520cf1dd8SToby Isaac 
163620cf1dd8SToby Isaac   PetscFunctionBegin;
163720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1638064a246eSJacob Faibussowitsch   PetscValidPointer(bdsp, 3);
163920cf1dd8SToby Isaac   *bdsp = NULL;
1640b4457527SToby Isaac   dm    = sp->dm;
16419566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16421dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
16439566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1644b4457527SToby 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 */
1645b4457527SToby Isaac     *bdsp = sp;
16463ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1647b4457527SToby Isaac   }
1648b4457527SToby Isaac   if (!sp->pointSpaces) {
1649b4457527SToby Isaac     PetscInt p;
16509566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pEnd - pStart, &(sp->pointSpaces)));
165120cf1dd8SToby Isaac 
1652b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1653b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
16549566063dSJacob Faibussowitsch       if (sp->ops->createpointsubspace) PetscCall((*sp->ops->createpointsubspace)(sp, p + pStart, &(sp->pointSpaces[p])));
1655b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1656b4457527SToby Isaac         PetscInt dim, depth, height;
1657b4457527SToby Isaac         DMLabel  label;
1658b4457527SToby Isaac 
16599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
16609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
16619566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
166220cf1dd8SToby Isaac         height = dim - depth;
16639566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &(sp->pointSpaces[p])));
16649566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
166520cf1dd8SToby Isaac       }
1666b4457527SToby Isaac     }
1667b4457527SToby Isaac   }
1668b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
16693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
167020cf1dd8SToby Isaac }
167120cf1dd8SToby Isaac 
16726f905325SMatthew G. Knepley /*@C
16736f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
16746f905325SMatthew G. Knepley 
167520f4b53cSBarry Smith   Not Collective
16766f905325SMatthew G. Knepley 
16776f905325SMatthew G. Knepley   Input Parameter:
1678dce8aebaSBarry Smith . sp - the `PetscDualSpace` object
16796f905325SMatthew G. Knepley 
16806f905325SMatthew G. Knepley   Output Parameters:
1681b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1682b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
16836f905325SMatthew G. Knepley 
16846f905325SMatthew G. Knepley   Level: developer
16856f905325SMatthew G. Knepley 
1686dce8aebaSBarry Smith   Note:
1687dce8aebaSBarry Smith   The permutation and flip arrays are organized in the following way
1688dce8aebaSBarry Smith .vb
1689dce8aebaSBarry Smith   perms[p][ornt][dof # on point] = new local dof #
1690dce8aebaSBarry Smith   flips[p][ornt][dof # on point] = reversal or not
1691dce8aebaSBarry Smith .ve
1692dce8aebaSBarry Smith 
1693dce8aebaSBarry Smith .seealso: `PetscDualSpace`
16946f905325SMatthew G. Knepley @*/
1695d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
1696d71ae5a4SJacob Faibussowitsch {
16976f905325SMatthew G. Knepley   PetscFunctionBegin;
16986f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16999371c9d4SSatish Balay   if (perms) {
17009371c9d4SSatish Balay     PetscValidPointer(perms, 2);
17019371c9d4SSatish Balay     *perms = NULL;
17029371c9d4SSatish Balay   }
17039371c9d4SSatish Balay   if (flips) {
17049371c9d4SSatish Balay     PetscValidPointer(flips, 3);
17059371c9d4SSatish Balay     *flips = NULL;
17069371c9d4SSatish Balay   }
17079566063dSJacob Faibussowitsch   if (sp->ops->getsymmetries) PetscCall((sp->ops->getsymmetries)(sp, perms, flips));
17083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17096f905325SMatthew G. Knepley }
17104bee2e38SMatthew G. Knepley 
17114bee2e38SMatthew G. Knepley /*@
1712b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1713b4457527SToby Isaac   dual space's functionals.
1714b4457527SToby Isaac 
1715b4457527SToby Isaac   Input Parameter:
1716dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
1717b4457527SToby Isaac 
1718b4457527SToby Isaac   Output Parameter:
1719b4457527SToby 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
1720b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1721b4457527SToby 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).
1722b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1723b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1724b4457527SToby Isaac         but are stored as 1-forms.
1725b4457527SToby Isaac 
1726b4457527SToby Isaac   Level: developer
1727b4457527SToby Isaac 
1728dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1729b4457527SToby Isaac @*/
1730d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k)
1731d71ae5a4SJacob Faibussowitsch {
1732b4457527SToby Isaac   PetscFunctionBeginHot;
1733b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1734dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1735b4457527SToby Isaac   *k = dsp->k;
17363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1737b4457527SToby Isaac }
1738b4457527SToby Isaac 
1739b4457527SToby Isaac /*@
1740b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1741b4457527SToby Isaac   dual space's functionals.
1742b4457527SToby Isaac 
1743d8d19677SJose E. Roman   Input Parameters:
1744dce8aebaSBarry Smith + dsp - The `PetscDualSpace`
1745b4457527SToby 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
1746b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1747b4457527SToby 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).
1748b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1749b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1750b4457527SToby Isaac         but are stored as 1-forms.
1751b4457527SToby Isaac 
1752b4457527SToby Isaac   Level: developer
1753b4457527SToby Isaac 
1754dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1755b4457527SToby Isaac @*/
1756d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k)
1757d71ae5a4SJacob Faibussowitsch {
1758b4457527SToby Isaac   PetscInt dim;
1759b4457527SToby Isaac 
1760b4457527SToby Isaac   PetscFunctionBeginHot;
1761b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
176228b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1763b4457527SToby Isaac   dim = dsp->dm->dim;
17641dca8a05SBarry Smith   PetscCheck(k >= -dim && k <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported %" PetscInt_FMT "-form on %" PetscInt_FMT "-dimensional reference cell", PetscAbsInt(k), dim);
1765b4457527SToby Isaac   dsp->k = k;
17663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1767b4457527SToby Isaac }
1768b4457527SToby Isaac 
1769b4457527SToby Isaac /*@
17704bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
17714bee2e38SMatthew G. Knepley 
17724bee2e38SMatthew G. Knepley   Input Parameter:
1773dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
17744bee2e38SMatthew G. Knepley 
17754bee2e38SMatthew G. Knepley   Output Parameter:
17764bee2e38SMatthew G. Knepley . k - The simplex dimension
17774bee2e38SMatthew G. Knepley 
1778a4ce7ad1SMatthew G. Knepley   Level: developer
17794bee2e38SMatthew G. Knepley 
1780dce8aebaSBarry Smith   Note:
1781dce8aebaSBarry Smith   Currently supported values are
1782dce8aebaSBarry Smith .vb
1783dce8aebaSBarry Smith   0: These are H_1 methods that only transform coordinates
1784dce8aebaSBarry Smith   1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
1785dce8aebaSBarry Smith   2: These are the same as 1
1786dce8aebaSBarry Smith   3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
1787dce8aebaSBarry Smith .ve
17884bee2e38SMatthew G. Knepley 
1789dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
17904bee2e38SMatthew G. Knepley @*/
1791d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k)
1792d71ae5a4SJacob Faibussowitsch {
1793b4457527SToby Isaac   PetscInt dim;
1794b4457527SToby Isaac 
17954bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
17964bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1797dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1798b4457527SToby Isaac   dim = dsp->dm->dim;
1799b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1800b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1801b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1802b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
18033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18044bee2e38SMatthew G. Knepley }
18054bee2e38SMatthew G. Knepley 
18064bee2e38SMatthew G. Knepley /*@C
18074bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
18084bee2e38SMatthew G. Knepley 
18094bee2e38SMatthew G. Knepley   Input Parameters:
1810dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18114bee2e38SMatthew G. Knepley . trans     - The type of transform
18124bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18134bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18144bee2e38SMatthew G. Knepley . Nv        - The number of function samples
18154bee2e38SMatthew G. Knepley . Nc        - The number of function components
18164bee2e38SMatthew G. Knepley - vals      - The function values
18174bee2e38SMatthew G. Knepley 
18184bee2e38SMatthew G. Knepley   Output Parameter:
18194bee2e38SMatthew G. Knepley . vals - The transformed function values
18204bee2e38SMatthew G. Knepley 
1821a4ce7ad1SMatthew G. Knepley   Level: intermediate
18224bee2e38SMatthew G. Knepley 
1823dce8aebaSBarry Smith   Note:
1824dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18252edcad52SToby Isaac 
1826dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18274bee2e38SMatthew G. Knepley @*/
1828d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1829d71ae5a4SJacob Faibussowitsch {
1830b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1831b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
18324bee2e38SMatthew G. Knepley 
18334bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18344bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18354bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1836dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
1837b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
18382ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1839b4457527SToby Isaac   /* No change needed for 0-forms */
18403ba16761SJacob Faibussowitsch   if (!dsp->k) PetscFunctionReturn(PETSC_SUCCESS);
18419566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1842b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
18439566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
18444bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1845b4457527SToby Isaac     switch (Nk) {
1846b4457527SToby Isaac     case 1:
1847b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
18484bee2e38SMatthew G. Knepley       break;
1849b4457527SToby Isaac     case 2:
1850b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
18514bee2e38SMatthew G. Knepley       break;
1852b4457527SToby Isaac     case 3:
1853b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1854b4457527SToby Isaac       break;
1855d71ae5a4SJacob Faibussowitsch     default:
1856d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1857b4457527SToby Isaac     }
18584bee2e38SMatthew G. Knepley   }
18593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18604bee2e38SMatthew G. Knepley }
1861b4457527SToby Isaac 
18624bee2e38SMatthew G. Knepley /*@C
18634bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
18644bee2e38SMatthew G. Knepley 
18654bee2e38SMatthew G. Knepley   Input Parameters:
1866dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18674bee2e38SMatthew G. Knepley . trans     - The type of transform
18684bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18694bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18704bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
18714bee2e38SMatthew G. Knepley . Nc        - The number of function components
18724bee2e38SMatthew G. Knepley - vals      - The function gradient values
18734bee2e38SMatthew G. Knepley 
18744bee2e38SMatthew G. Knepley   Output Parameter:
1875f9244615SMatthew G. Knepley . vals - The transformed function gradient values
18764bee2e38SMatthew G. Knepley 
1877a4ce7ad1SMatthew G. Knepley   Level: intermediate
18784bee2e38SMatthew G. Knepley 
1879dce8aebaSBarry Smith   Note:
1880dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18812edcad52SToby Isaac 
1882dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18834bee2e38SMatthew G. Knepley @*/
1884d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1885d71ae5a4SJacob Faibussowitsch {
188627f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
188727f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
18884bee2e38SMatthew G. Knepley 
18894bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18904bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18914bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1892dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
189327f02ce8SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
189463a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
189527f02ce8SMatthew G. Knepley #endif
18964bee2e38SMatthew G. Knepley   /* Transform gradient */
189727f02ce8SMatthew G. Knepley   if (dim == dE) {
18984bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
18994bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
19009371c9d4SSatish Balay         switch (dim) {
1901d71ae5a4SJacob Faibussowitsch         case 1:
1902d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim] *= fegeom->invJ[0];
1903d71ae5a4SJacob Faibussowitsch           break;
1904d71ae5a4SJacob Faibussowitsch         case 2:
1905d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1906d71ae5a4SJacob Faibussowitsch           break;
1907d71ae5a4SJacob Faibussowitsch         case 3:
1908d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1909d71ae5a4SJacob Faibussowitsch           break;
1910d71ae5a4SJacob Faibussowitsch         default:
1911d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19124bee2e38SMatthew G. Knepley         }
19134bee2e38SMatthew G. Knepley       }
19144bee2e38SMatthew G. Knepley     }
191527f02ce8SMatthew G. Knepley   } else {
191627f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1917ad540459SPierre 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]);
191827f02ce8SMatthew G. Knepley     }
191927f02ce8SMatthew G. Knepley   }
19204bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
19213ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
19224bee2e38SMatthew G. Knepley   switch (trans) {
1923d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
1924d71ae5a4SJacob Faibussowitsch     break;
19254bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
19264bee2e38SMatthew G. Knepley     if (isInverse) {
19274bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19284bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19299371c9d4SSatish Balay           switch (dim) {
1930d71ae5a4SJacob Faibussowitsch           case 2:
1931d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1932d71ae5a4SJacob Faibussowitsch             break;
1933d71ae5a4SJacob Faibussowitsch           case 3:
1934d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1935d71ae5a4SJacob Faibussowitsch             break;
1936d71ae5a4SJacob Faibussowitsch           default:
1937d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19384bee2e38SMatthew G. Knepley           }
19394bee2e38SMatthew G. Knepley         }
19404bee2e38SMatthew G. Knepley       }
19414bee2e38SMatthew G. Knepley     } else {
19424bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19434bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19449371c9d4SSatish Balay           switch (dim) {
1945d71ae5a4SJacob Faibussowitsch           case 2:
1946d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1947d71ae5a4SJacob Faibussowitsch             break;
1948d71ae5a4SJacob Faibussowitsch           case 3:
1949d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1950d71ae5a4SJacob Faibussowitsch             break;
1951d71ae5a4SJacob Faibussowitsch           default:
1952d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19534bee2e38SMatthew G. Knepley           }
19544bee2e38SMatthew G. Knepley         }
19554bee2e38SMatthew G. Knepley       }
19564bee2e38SMatthew G. Knepley     }
19574bee2e38SMatthew G. Knepley     break;
19584bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
19594bee2e38SMatthew G. Knepley     if (isInverse) {
19604bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19614bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19629371c9d4SSatish Balay           switch (dim) {
1963d71ae5a4SJacob Faibussowitsch           case 2:
1964d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1965d71ae5a4SJacob Faibussowitsch             break;
1966d71ae5a4SJacob Faibussowitsch           case 3:
1967d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1968d71ae5a4SJacob Faibussowitsch             break;
1969d71ae5a4SJacob Faibussowitsch           default:
1970d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19714bee2e38SMatthew G. Knepley           }
19724bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
19734bee2e38SMatthew G. Knepley         }
19744bee2e38SMatthew G. Knepley       }
19754bee2e38SMatthew G. Knepley     } else {
19764bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19774bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19789371c9d4SSatish Balay           switch (dim) {
1979d71ae5a4SJacob Faibussowitsch           case 2:
1980d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1981d71ae5a4SJacob Faibussowitsch             break;
1982d71ae5a4SJacob Faibussowitsch           case 3:
1983d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1984d71ae5a4SJacob Faibussowitsch             break;
1985d71ae5a4SJacob Faibussowitsch           default:
1986d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19874bee2e38SMatthew G. Knepley           }
19884bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
19894bee2e38SMatthew G. Knepley         }
19904bee2e38SMatthew G. Knepley       }
19914bee2e38SMatthew G. Knepley     }
19924bee2e38SMatthew G. Knepley     break;
19934bee2e38SMatthew G. Knepley   }
19943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19954bee2e38SMatthew G. Knepley }
19964bee2e38SMatthew G. Knepley 
19974bee2e38SMatthew G. Knepley /*@C
1998f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
1999f9244615SMatthew G. Knepley 
2000f9244615SMatthew G. Knepley   Input Parameters:
2001dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
2002f9244615SMatthew G. Knepley . trans     - The type of transform
2003f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
2004f9244615SMatthew G. Knepley . fegeom    - The cell geometry
2005f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
2006f9244615SMatthew G. Knepley . Nc        - The number of function components
2007f9244615SMatthew G. Knepley - vals      - The function gradient values
2008f9244615SMatthew G. Knepley 
2009f9244615SMatthew G. Knepley   Output Parameter:
2010f9244615SMatthew G. Knepley . vals - The transformed function Hessian values
2011f9244615SMatthew G. Knepley 
2012f9244615SMatthew G. Knepley   Level: intermediate
2013f9244615SMatthew G. Knepley 
2014dce8aebaSBarry Smith   Note:
2015dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2016f9244615SMatthew G. Knepley 
2017dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
2018f9244615SMatthew G. Knepley @*/
2019d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
2020d71ae5a4SJacob Faibussowitsch {
2021f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
2022f9244615SMatthew G. Knepley   PetscInt       v, c;
2023f9244615SMatthew G. Knepley 
2024f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2025f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2026f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
2027dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
2028f9244615SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
202963a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
2030f9244615SMatthew G. Knepley #endif
2031f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
2032f9244615SMatthew G. Knepley   if (dim == dE) {
2033f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2034f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
20359371c9d4SSatish Balay         switch (dim) {
2036d71ae5a4SJacob Faibussowitsch         case 1:
2037d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]);
2038d71ae5a4SJacob Faibussowitsch           break;
2039d71ae5a4SJacob Faibussowitsch         case 2:
2040d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2041d71ae5a4SJacob Faibussowitsch           break;
2042d71ae5a4SJacob Faibussowitsch         case 3:
2043d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2044d71ae5a4SJacob Faibussowitsch           break;
2045d71ae5a4SJacob Faibussowitsch         default:
2046d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
2047f9244615SMatthew G. Knepley         }
2048f9244615SMatthew G. Knepley       }
2049f9244615SMatthew G. Knepley     }
2050f9244615SMatthew G. Knepley   } else {
2051f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2052ad540459SPierre 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]);
2053f9244615SMatthew G. Knepley     }
2054f9244615SMatthew G. Knepley   }
2055f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
20563ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
2057f9244615SMatthew G. Knepley   switch (trans) {
2058d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
2059d71ae5a4SJacob Faibussowitsch     break;
2060d71ae5a4SJacob Faibussowitsch   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
2061d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2062d71ae5a4SJacob Faibussowitsch   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
2063d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2064f9244615SMatthew G. Knepley   }
20653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2066f9244615SMatthew G. Knepley }
2067f9244615SMatthew G. Knepley 
2068f9244615SMatthew G. Knepley /*@C
20694bee2e38SMatthew 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.
20704bee2e38SMatthew G. Knepley 
20714bee2e38SMatthew G. Knepley   Input Parameters:
2072dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
20734bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
20744bee2e38SMatthew G. Knepley . Nq        - The number of function samples
20754bee2e38SMatthew G. Knepley . Nc        - The number of function components
20764bee2e38SMatthew G. Knepley - pointEval - The function values
20774bee2e38SMatthew G. Knepley 
20784bee2e38SMatthew G. Knepley   Output Parameter:
20794bee2e38SMatthew G. Knepley . pointEval - The transformed function values
20804bee2e38SMatthew G. Knepley 
20814bee2e38SMatthew G. Knepley   Level: advanced
20824bee2e38SMatthew G. Knepley 
2083dce8aebaSBarry Smith   Notes:
2084dce8aebaSBarry 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.
20854bee2e38SMatthew G. Knepley 
2086da81f932SPierre Jolivet   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
20872edcad52SToby Isaac 
2088dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
20894bee2e38SMatthew G. Knepley @*/
2090d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2091d71ae5a4SJacob Faibussowitsch {
20924bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2093b4457527SToby Isaac   PetscInt                    k;
20944bee2e38SMatthew G. Knepley 
20954bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
20964bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20974bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2098dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
20994bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21004bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21019566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21029371c9d4SSatish Balay   switch (k) {
2103d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2104d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2105d71ae5a4SJacob Faibussowitsch     break;
2106d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2107d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2108d71ae5a4SJacob Faibussowitsch     break;
2109b4457527SToby Isaac   case 2:
2110d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2111d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2112d71ae5a4SJacob Faibussowitsch     break;
2113d71ae5a4SJacob Faibussowitsch   default:
2114d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21154bee2e38SMatthew G. Knepley   }
21169566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
21173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21184bee2e38SMatthew G. Knepley }
21194bee2e38SMatthew G. Knepley 
21204bee2e38SMatthew G. Knepley /*@C
21214bee2e38SMatthew 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.
21224bee2e38SMatthew G. Knepley 
21234bee2e38SMatthew G. Knepley   Input Parameters:
2124dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
21254bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
21264bee2e38SMatthew G. Knepley . Nq        - The number of function samples
21274bee2e38SMatthew G. Knepley . Nc        - The number of function components
21284bee2e38SMatthew G. Knepley - pointEval - The function values
21294bee2e38SMatthew G. Knepley 
21304bee2e38SMatthew G. Knepley   Output Parameter:
21314bee2e38SMatthew G. Knepley . pointEval - The transformed function values
21324bee2e38SMatthew G. Knepley 
21334bee2e38SMatthew G. Knepley   Level: advanced
21344bee2e38SMatthew G. Knepley 
2135dce8aebaSBarry Smith   Notes:
2136dce8aebaSBarry 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.
21374bee2e38SMatthew G. Knepley 
2138dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21392edcad52SToby Isaac 
2140dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21414bee2e38SMatthew G. Knepley @*/
2142d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2143d71ae5a4SJacob Faibussowitsch {
21444bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2145b4457527SToby Isaac   PetscInt                    k;
21464bee2e38SMatthew G. Knepley 
21474bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21484bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21494bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2150dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21514bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21524bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21539566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21549371c9d4SSatish Balay   switch (k) {
2155d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2156d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2157d71ae5a4SJacob Faibussowitsch     break;
2158d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2159d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2160d71ae5a4SJacob Faibussowitsch     break;
2161b4457527SToby Isaac   case 2:
2162d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2163d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2164d71ae5a4SJacob Faibussowitsch     break;
2165d71ae5a4SJacob Faibussowitsch   default:
2166d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21674bee2e38SMatthew G. Knepley   }
21689566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
21693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21704bee2e38SMatthew G. Knepley }
21714bee2e38SMatthew G. Knepley 
21724bee2e38SMatthew G. Knepley /*@C
21734bee2e38SMatthew 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.
21744bee2e38SMatthew G. Knepley 
21754bee2e38SMatthew G. Knepley   Input Parameters:
2176dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
21774bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
21784bee2e38SMatthew G. Knepley . Nq        - The number of function gradient samples
21794bee2e38SMatthew G. Knepley . Nc        - The number of function components
21804bee2e38SMatthew G. Knepley - pointEval - The function gradient values
21814bee2e38SMatthew G. Knepley 
21824bee2e38SMatthew G. Knepley   Output Parameter:
21834bee2e38SMatthew G. Knepley . pointEval - The transformed function gradient values
21844bee2e38SMatthew G. Knepley 
21854bee2e38SMatthew G. Knepley   Level: advanced
21864bee2e38SMatthew G. Knepley 
2187dce8aebaSBarry Smith   Notes:
2188dce8aebaSBarry 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.
21894bee2e38SMatthew G. Knepley 
2190dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21912edcad52SToby Isaac 
2192dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2193dc0529c6SBarry Smith @*/
2194d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2195d71ae5a4SJacob Faibussowitsch {
21964bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2197b4457527SToby Isaac   PetscInt                    k;
21984bee2e38SMatthew G. Knepley 
21994bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
22004bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
22014bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2202dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
22034bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
22044bee2e38SMatthew G. Knepley      This determines their transformation properties. */
22059566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22069371c9d4SSatish Balay   switch (k) {
2207d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2208d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2209d71ae5a4SJacob Faibussowitsch     break;
2210d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2211d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2212d71ae5a4SJacob Faibussowitsch     break;
2213b4457527SToby Isaac   case 2:
2214d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2215d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2216d71ae5a4SJacob Faibussowitsch     break;
2217d71ae5a4SJacob Faibussowitsch   default:
2218d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22194bee2e38SMatthew G. Knepley   }
22209566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22224bee2e38SMatthew G. Knepley }
2223f9244615SMatthew G. Knepley 
2224f9244615SMatthew G. Knepley /*@C
2225f9244615SMatthew 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.
2226f9244615SMatthew G. Knepley 
2227f9244615SMatthew G. Knepley   Input Parameters:
2228dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
2229f9244615SMatthew G. Knepley . fegeom    - The geometry for this cell
2230f9244615SMatthew G. Knepley . Nq        - The number of function Hessian samples
2231f9244615SMatthew G. Knepley . Nc        - The number of function components
2232f9244615SMatthew G. Knepley - pointEval - The function gradient values
2233f9244615SMatthew G. Knepley 
2234f9244615SMatthew G. Knepley   Output Parameter:
2235f9244615SMatthew G. Knepley . pointEval - The transformed function Hessian values
2236f9244615SMatthew G. Knepley 
2237f9244615SMatthew G. Knepley   Level: advanced
2238f9244615SMatthew G. Knepley 
2239dce8aebaSBarry Smith   Notes:
2240dce8aebaSBarry 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.
2241f9244615SMatthew G. Knepley 
2242dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2243f9244615SMatthew G. Knepley 
2244dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2245f9244615SMatthew G. Knepley @*/
2246d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2247d71ae5a4SJacob Faibussowitsch {
2248f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2249f9244615SMatthew G. Knepley   PetscInt                    k;
2250f9244615SMatthew G. Knepley 
2251f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2252f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2253f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2254dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
2255f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2256f9244615SMatthew G. Knepley      This determines their transformation properties. */
22579566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22589371c9d4SSatish Balay   switch (k) {
2259d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2260d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2261d71ae5a4SJacob Faibussowitsch     break;
2262d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2263d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2264d71ae5a4SJacob Faibussowitsch     break;
2265f9244615SMatthew G. Knepley   case 2:
2266d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2267d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2268d71ae5a4SJacob Faibussowitsch     break;
2269d71ae5a4SJacob Faibussowitsch   default:
2270d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2271f9244615SMatthew G. Knepley   }
22729566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2274f9244615SMatthew G. Knepley }
2275