xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision a9c5e6dee260bf8614e97178d3c9d0bd88ff54e9)
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:
22cfb853baSMatthew G. Knepley . 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:
53cfb853baSMatthew G. Knepley . 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:
8120cf1dd8SToby Isaac + name        - The name of a new user-defined creation routine
8220cf1dd8SToby Isaac - create_func - The creation routine itself
8320cf1dd8SToby Isaac 
8420cf1dd8SToby Isaac   Sample usage:
8520cf1dd8SToby Isaac .vb
8620cf1dd8SToby Isaac     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
8720cf1dd8SToby Isaac .ve
8820cf1dd8SToby Isaac 
8920cf1dd8SToby Isaac   Then, your PetscDualSpace type can be chosen with the procedural interface via
9020cf1dd8SToby Isaac .vb
9120cf1dd8SToby Isaac     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
9220cf1dd8SToby Isaac     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
9320cf1dd8SToby Isaac .ve
9420cf1dd8SToby Isaac    or at runtime via the option
9520cf1dd8SToby Isaac .vb
9620cf1dd8SToby Isaac     -petscdualspace_type my_dual_space
9720cf1dd8SToby Isaac .ve
9820cf1dd8SToby Isaac 
9920cf1dd8SToby Isaac   Level: advanced
10020cf1dd8SToby Isaac 
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 
116d083f849SBarry Smith   Collective on sp
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 
209dce8aebaSBarry Smith    Collective on A
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 
218db781477SPatrick Sanan .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()`
219fe2efc57SMark @*/
220d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PetscObject obj, const char name[])
221d71ae5a4SJacob Faibussowitsch {
222fe2efc57SMark   PetscFunctionBegin;
223fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
2249566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
2253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
226fe2efc57SMark }
227fe2efc57SMark 
22820cf1dd8SToby Isaac /*@
229dce8aebaSBarry Smith   PetscDualSpaceView - Views a `PetscDualSpace`
23020cf1dd8SToby Isaac 
231d083f849SBarry Smith   Collective on sp
23220cf1dd8SToby Isaac 
233d8d19677SJose E. Roman   Input Parameters:
234dce8aebaSBarry Smith + sp - the `PetscDualSpace` object to view
23520cf1dd8SToby Isaac - v  - the viewer
23620cf1dd8SToby Isaac 
237a4ce7ad1SMatthew G. Knepley   Level: beginner
23820cf1dd8SToby Isaac 
239dce8aebaSBarry Smith .seealso: `PetscViewer`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
24020cf1dd8SToby Isaac @*/
241d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
242d71ae5a4SJacob Faibussowitsch {
243d9bac1caSLisandro Dalcin   PetscBool iascii;
24420cf1dd8SToby Isaac 
24520cf1dd8SToby Isaac   PetscFunctionBegin;
24620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
247d9bac1caSLisandro Dalcin   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
2489566063dSJacob Faibussowitsch   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v));
2499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
2509566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v));
2513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25220cf1dd8SToby Isaac }
25320cf1dd8SToby Isaac 
25420cf1dd8SToby Isaac /*@
255dce8aebaSBarry Smith   PetscDualSpaceSetFromOptions - sets parameters in a `PetscDualSpace` from the options database
25620cf1dd8SToby Isaac 
257d083f849SBarry Smith   Collective on sp
25820cf1dd8SToby Isaac 
25920cf1dd8SToby Isaac   Input Parameter:
260dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to set options for
26120cf1dd8SToby Isaac 
262dce8aebaSBarry Smith   Options Database Keys:
2638f2aacc6SMatthew G. Knepley + -petscdualspace_order <order>      - the approximation order of the space
264fe36a153SMatthew G. Knepley . -petscdualspace_form_degree <deg>  - the form degree, say 0 for point evaluations, or 2 for area integrals
2658f2aacc6SMatthew G. Knepley . -petscdualspace_components <c>     - the number of components, say d for a vector field
266*a9c5e6deSMatthew G. Knepley . -petscdualspace_refcell <celltype> - Reference cell type name
267*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_continuity           - Flag for continuous element
268*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_tensor               - Flag for tensor dual space
269*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_trimmed              - Flag for trimmed dual space
270*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_type <nodetype> - Lagrange node location type
271*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_endpoints       - Flag for nodes that include endpoints
272*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_exponent        - Gauss-Jacobi weight function exponent
273*a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_use_moments          - Use moments (where appropriate) for functionals
274*a9c5e6deSMatthew G. Knepley - -petscdualspace_lagrange_moment_order <order> - Quadrature order for moment functionals
27520cf1dd8SToby Isaac 
276a4ce7ad1SMatthew G. Knepley   Level: intermediate
27720cf1dd8SToby Isaac 
278dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()`
27920cf1dd8SToby Isaac @*/
280d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
281d71ae5a4SJacob Faibussowitsch {
2822df84da0SMatthew G. Knepley   DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE;
28320cf1dd8SToby Isaac   const char    *defaultType;
28420cf1dd8SToby Isaac   char           name[256];
285f783ec47SMatthew G. Knepley   PetscBool      flg;
28620cf1dd8SToby Isaac 
28720cf1dd8SToby Isaac   PetscFunctionBegin;
28820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
28920cf1dd8SToby Isaac   if (!((PetscObject)sp)->type_name) {
29020cf1dd8SToby Isaac     defaultType = PETSCDUALSPACELAGRANGE;
29120cf1dd8SToby Isaac   } else {
29220cf1dd8SToby Isaac     defaultType = ((PetscObject)sp)->type_name;
29320cf1dd8SToby Isaac   }
2949566063dSJacob Faibussowitsch   if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll());
29520cf1dd8SToby Isaac 
296d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sp);
2979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg));
29820cf1dd8SToby Isaac   if (flg) {
2999566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, name));
30020cf1dd8SToby Isaac   } else if (!((PetscObject)sp)->type_name) {
3019566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, defaultType));
30220cf1dd8SToby Isaac   }
3039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0));
3049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL));
3059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1));
306dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject);
3079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg));
308063ee4adSMatthew G. Knepley   if (flg) {
309063ee4adSMatthew G. Knepley     DM K;
310063ee4adSMatthew G. Knepley 
3119566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K));
3129566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetDM(sp, K));
3139566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&K));
314063ee4adSMatthew G. Knepley   }
315063ee4adSMatthew G. Knepley 
31620cf1dd8SToby Isaac   /* process any options handlers added with PetscObjectAddOptionsHandler() */
317dbbe0bcdSBarry Smith   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject));
318d0609cedSBarry Smith   PetscOptionsEnd();
319063ee4adSMatthew G. Knepley   sp->setfromoptionscalled = PETSC_TRUE;
3203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32120cf1dd8SToby Isaac }
32220cf1dd8SToby Isaac 
32320cf1dd8SToby Isaac /*@
324dce8aebaSBarry Smith   PetscDualSpaceSetUp - Construct a basis for a `PetscDualSpace`
32520cf1dd8SToby Isaac 
326d083f849SBarry Smith   Collective on sp
32720cf1dd8SToby Isaac 
32820cf1dd8SToby Isaac   Input Parameter:
329dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to setup
33020cf1dd8SToby Isaac 
331a4ce7ad1SMatthew G. Knepley   Level: intermediate
33220cf1dd8SToby Isaac 
333dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
33420cf1dd8SToby Isaac @*/
335d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
336d71ae5a4SJacob Faibussowitsch {
33720cf1dd8SToby Isaac   PetscFunctionBegin;
33820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
3393ba16761SJacob Faibussowitsch   if (sp->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
3409566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
34120cf1dd8SToby Isaac   sp->setupcalled = PETSC_TRUE;
342dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setup);
3439566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
3449566063dSJacob Faibussowitsch   if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view"));
3453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34620cf1dd8SToby Isaac }
34720cf1dd8SToby Isaac 
348d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm)
349d71ae5a4SJacob Faibussowitsch {
350b4457527SToby Isaac   PetscInt pStart = -1, pEnd = -1, depth = -1;
351b4457527SToby Isaac 
352b4457527SToby Isaac   PetscFunctionBegin;
3533ba16761SJacob Faibussowitsch   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
3549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
356b4457527SToby Isaac 
357b4457527SToby Isaac   if (sp->pointSpaces) {
358b4457527SToby Isaac     PetscInt i;
359b4457527SToby Isaac 
36048a46eb9SPierre Jolivet     for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&(sp->pointSpaces[i])));
361b4457527SToby Isaac   }
3629566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->pointSpaces));
363b4457527SToby Isaac 
364b4457527SToby Isaac   if (sp->heightSpaces) {
365b4457527SToby Isaac     PetscInt i;
366b4457527SToby Isaac 
36748a46eb9SPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&(sp->heightSpaces[i])));
368b4457527SToby Isaac   }
3699566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
370b4457527SToby Isaac 
3719566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&(sp->pointSection)));
3729566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
3739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intDofValues)));
3749566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intNodeValues)));
3759566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->intMat)));
3769566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
3779566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allDofValues)));
3789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allNodeValues)));
3799566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->allMat)));
3809566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382b4457527SToby Isaac }
383b4457527SToby Isaac 
38420cf1dd8SToby Isaac /*@
385dce8aebaSBarry Smith   PetscDualSpaceDestroy - Destroys a `PetscDualSpace` object
38620cf1dd8SToby Isaac 
387d083f849SBarry Smith   Collective on sp
38820cf1dd8SToby Isaac 
38920cf1dd8SToby Isaac   Input Parameter:
390dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to destroy
39120cf1dd8SToby Isaac 
392a4ce7ad1SMatthew G. Knepley   Level: beginner
39320cf1dd8SToby Isaac 
394dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
39520cf1dd8SToby Isaac @*/
396d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
397d71ae5a4SJacob Faibussowitsch {
39820cf1dd8SToby Isaac   PetscInt dim, f;
399b4457527SToby Isaac   DM       dm;
40020cf1dd8SToby Isaac 
40120cf1dd8SToby Isaac   PetscFunctionBegin;
4023ba16761SJacob Faibussowitsch   if (!*sp) PetscFunctionReturn(PETSC_SUCCESS);
40320cf1dd8SToby Isaac   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
40420cf1dd8SToby Isaac 
4059371c9d4SSatish Balay   if (--((PetscObject)(*sp))->refct > 0) {
4069371c9d4SSatish Balay     *sp = NULL;
4073ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4089371c9d4SSatish Balay   }
40920cf1dd8SToby Isaac   ((PetscObject)(*sp))->refct = 0;
41020cf1dd8SToby Isaac 
4119566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
412b4457527SToby Isaac   dm = (*sp)->dm;
413b4457527SToby Isaac 
414dbbe0bcdSBarry Smith   PetscTryTypeMethod((*sp), destroy);
4159566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
416b4457527SToby Isaac 
41748a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
4189566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
4199566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4209566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
4213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42220cf1dd8SToby Isaac }
42320cf1dd8SToby Isaac 
42420cf1dd8SToby Isaac /*@
425dce8aebaSBarry Smith   PetscDualSpaceCreate - Creates an empty `PetscDualSpace` object. The type can then be set with `PetscDualSpaceSetType()`.
42620cf1dd8SToby Isaac 
427d083f849SBarry Smith   Collective
42820cf1dd8SToby Isaac 
42920cf1dd8SToby Isaac   Input Parameter:
430dce8aebaSBarry Smith . comm - The communicator for the `PetscDualSpace` object
43120cf1dd8SToby Isaac 
43220cf1dd8SToby Isaac   Output Parameter:
433dce8aebaSBarry Smith . sp - The `PetscDualSpace` object
43420cf1dd8SToby Isaac 
43520cf1dd8SToby Isaac   Level: beginner
43620cf1dd8SToby Isaac 
437dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
43820cf1dd8SToby Isaac @*/
439d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
440d71ae5a4SJacob Faibussowitsch {
44120cf1dd8SToby Isaac   PetscDualSpace s;
44220cf1dd8SToby Isaac 
44320cf1dd8SToby Isaac   PetscFunctionBegin;
44420cf1dd8SToby Isaac   PetscValidPointer(sp, 2);
4459566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
44620cf1dd8SToby Isaac   *sp = NULL;
4479566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
44820cf1dd8SToby Isaac 
4499566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
45020cf1dd8SToby Isaac 
45120cf1dd8SToby Isaac   s->order       = 0;
45220cf1dd8SToby Isaac   s->Nc          = 1;
4534bee2e38SMatthew G. Knepley   s->k           = 0;
454b4457527SToby Isaac   s->spdim       = -1;
455b4457527SToby Isaac   s->spintdim    = -1;
456b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
45720cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
45820cf1dd8SToby Isaac 
45920cf1dd8SToby Isaac   *sp = s;
4603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46120cf1dd8SToby Isaac }
46220cf1dd8SToby Isaac 
46320cf1dd8SToby Isaac /*@
464dce8aebaSBarry Smith   PetscDualSpaceDuplicate - Creates a duplicate `PetscDualSpace` object that is not setup.
46520cf1dd8SToby Isaac 
466d083f849SBarry Smith   Collective on sp
46720cf1dd8SToby Isaac 
46820cf1dd8SToby Isaac   Input Parameter:
469dce8aebaSBarry Smith . sp - The original `PetscDualSpace`
47020cf1dd8SToby Isaac 
47120cf1dd8SToby Isaac   Output Parameter:
472dce8aebaSBarry Smith . spNew - The duplicate `PetscDualSpace`
47320cf1dd8SToby Isaac 
47420cf1dd8SToby Isaac   Level: beginner
47520cf1dd8SToby Isaac 
476dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
47720cf1dd8SToby Isaac @*/
478d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
479d71ae5a4SJacob Faibussowitsch {
480b4457527SToby Isaac   DM                 dm;
481b4457527SToby Isaac   PetscDualSpaceType type;
482b4457527SToby Isaac   const char        *name;
48320cf1dd8SToby Isaac 
48420cf1dd8SToby Isaac   PetscFunctionBegin;
48520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
48620cf1dd8SToby Isaac   PetscValidPointer(spNew, 2);
4879566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4889566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)sp, &name));
4899566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*spNew, name));
4909566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4929566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4939566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
494b4457527SToby Isaac 
495b4457527SToby Isaac   (*spNew)->order   = sp->order;
496b4457527SToby Isaac   (*spNew)->k       = sp->k;
497b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
498b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
499dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
5003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50120cf1dd8SToby Isaac }
50220cf1dd8SToby Isaac 
50320cf1dd8SToby Isaac /*@
504dce8aebaSBarry Smith   PetscDualSpaceGetDM - Get the `DM` representing the reference cell of a `PetscDualSpace`
50520cf1dd8SToby Isaac 
50620cf1dd8SToby Isaac   Not collective
50720cf1dd8SToby Isaac 
50820cf1dd8SToby Isaac   Input Parameter:
509dce8aebaSBarry Smith . sp - The `PetscDualSpace`
51020cf1dd8SToby Isaac 
51120cf1dd8SToby Isaac   Output Parameter:
512dce8aebaSBarry Smith . dm - The reference cell, that is a `DM` that consists of a single cell
51320cf1dd8SToby Isaac 
51420cf1dd8SToby Isaac   Level: intermediate
51520cf1dd8SToby Isaac 
516dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
51720cf1dd8SToby Isaac @*/
518d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
519d71ae5a4SJacob Faibussowitsch {
52020cf1dd8SToby Isaac   PetscFunctionBegin;
52120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
52220cf1dd8SToby Isaac   PetscValidPointer(dm, 2);
52320cf1dd8SToby Isaac   *dm = sp->dm;
5243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52520cf1dd8SToby Isaac }
52620cf1dd8SToby Isaac 
52720cf1dd8SToby Isaac /*@
528dce8aebaSBarry Smith   PetscDualSpaceSetDM - Get the `DM` representing the reference cell
52920cf1dd8SToby Isaac 
53020cf1dd8SToby Isaac   Not collective
53120cf1dd8SToby Isaac 
53220cf1dd8SToby Isaac   Input Parameters:
533dce8aebaSBarry Smith + sp - The `PetscDual`Space
53420cf1dd8SToby Isaac - dm - The reference cell
53520cf1dd8SToby Isaac 
53620cf1dd8SToby Isaac   Level: intermediate
53720cf1dd8SToby Isaac 
538dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `DM`, `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
53920cf1dd8SToby Isaac @*/
540d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
541d71ae5a4SJacob Faibussowitsch {
54220cf1dd8SToby Isaac   PetscFunctionBegin;
54320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
54420cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
54528b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5469566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
54748a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5489566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
54920cf1dd8SToby Isaac   sp->dm = dm;
5503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55120cf1dd8SToby Isaac }
55220cf1dd8SToby Isaac 
55320cf1dd8SToby Isaac /*@
55420cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
55520cf1dd8SToby Isaac 
55620cf1dd8SToby Isaac   Not collective
55720cf1dd8SToby Isaac 
55820cf1dd8SToby Isaac   Input Parameter:
559dce8aebaSBarry Smith . sp - The `PetscDualSpace`
56020cf1dd8SToby Isaac 
56120cf1dd8SToby Isaac   Output Parameter:
56220cf1dd8SToby Isaac . order - The order
56320cf1dd8SToby Isaac 
56420cf1dd8SToby Isaac   Level: intermediate
56520cf1dd8SToby Isaac 
566dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
56720cf1dd8SToby Isaac @*/
568d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
569d71ae5a4SJacob Faibussowitsch {
57020cf1dd8SToby Isaac   PetscFunctionBegin;
57120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
572dadcf809SJacob Faibussowitsch   PetscValidIntPointer(order, 2);
57320cf1dd8SToby Isaac   *order = sp->order;
5743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57520cf1dd8SToby Isaac }
57620cf1dd8SToby Isaac 
57720cf1dd8SToby Isaac /*@
57820cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
57920cf1dd8SToby Isaac 
58020cf1dd8SToby Isaac   Not collective
58120cf1dd8SToby Isaac 
58220cf1dd8SToby Isaac   Input Parameters:
583dce8aebaSBarry Smith + sp - The `PetscDualSpace`
58420cf1dd8SToby Isaac - order - The order
58520cf1dd8SToby Isaac 
58620cf1dd8SToby Isaac   Level: intermediate
58720cf1dd8SToby Isaac 
588dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
58920cf1dd8SToby Isaac @*/
590d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
591d71ae5a4SJacob Faibussowitsch {
59220cf1dd8SToby Isaac   PetscFunctionBegin;
59320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
59428b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
59520cf1dd8SToby Isaac   sp->order = order;
5963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59720cf1dd8SToby Isaac }
59820cf1dd8SToby Isaac 
59920cf1dd8SToby Isaac /*@
60020cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
60120cf1dd8SToby Isaac 
60220cf1dd8SToby Isaac   Input Parameter:
603dce8aebaSBarry Smith . sp - The `PetscDualSpace`
60420cf1dd8SToby Isaac 
60520cf1dd8SToby Isaac   Output Parameter:
60620cf1dd8SToby Isaac . Nc - The number of components
60720cf1dd8SToby Isaac 
60820cf1dd8SToby Isaac   Level: intermediate
60920cf1dd8SToby Isaac 
610dce8aebaSBarry Smith   Note:
611dce8aebaSBarry Smith   A vector space, for example, will have d components, where d is the spatial dimension
612dce8aebaSBarry Smith 
613db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
61420cf1dd8SToby Isaac @*/
615d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
616d71ae5a4SJacob Faibussowitsch {
61720cf1dd8SToby Isaac   PetscFunctionBegin;
61820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
619dadcf809SJacob Faibussowitsch   PetscValidIntPointer(Nc, 2);
62020cf1dd8SToby Isaac   *Nc = sp->Nc;
6213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62220cf1dd8SToby Isaac }
62320cf1dd8SToby Isaac 
62420cf1dd8SToby Isaac /*@
62520cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
62620cf1dd8SToby Isaac 
62720cf1dd8SToby Isaac   Input Parameters:
628dce8aebaSBarry Smith + sp - The `PetscDualSpace`
62920cf1dd8SToby Isaac - order - The number of components
63020cf1dd8SToby Isaac 
63120cf1dd8SToby Isaac   Level: intermediate
63220cf1dd8SToby Isaac 
633db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
63420cf1dd8SToby Isaac @*/
635d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
636d71ae5a4SJacob Faibussowitsch {
63720cf1dd8SToby Isaac   PetscFunctionBegin;
63820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
63928b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
64020cf1dd8SToby Isaac   sp->Nc = Nc;
6413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64220cf1dd8SToby Isaac }
64320cf1dd8SToby Isaac 
64420cf1dd8SToby Isaac /*@
64520cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
64620cf1dd8SToby Isaac 
64720cf1dd8SToby Isaac   Not collective
64820cf1dd8SToby Isaac 
64920cf1dd8SToby Isaac   Input Parameters:
650dce8aebaSBarry Smith + sp - The `PetscDualSpace`
65120cf1dd8SToby Isaac - i  - The basis number
65220cf1dd8SToby Isaac 
65320cf1dd8SToby Isaac   Output Parameter:
65420cf1dd8SToby Isaac . functional - The basis functional
65520cf1dd8SToby Isaac 
65620cf1dd8SToby Isaac   Level: intermediate
65720cf1dd8SToby Isaac 
658dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
65920cf1dd8SToby Isaac @*/
660d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
661d71ae5a4SJacob Faibussowitsch {
66220cf1dd8SToby Isaac   PetscInt dim;
66320cf1dd8SToby Isaac 
66420cf1dd8SToby Isaac   PetscFunctionBegin;
66520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
66620cf1dd8SToby Isaac   PetscValidPointer(functional, 3);
6679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
66863a3b9bcSJacob 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);
66920cf1dd8SToby Isaac   *functional = sp->functional[i];
6703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
67120cf1dd8SToby Isaac }
67220cf1dd8SToby Isaac 
67320cf1dd8SToby Isaac /*@
67420cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
67520cf1dd8SToby Isaac 
67620cf1dd8SToby Isaac   Not collective
67720cf1dd8SToby Isaac 
67820cf1dd8SToby Isaac   Input Parameter:
679dce8aebaSBarry Smith . sp - The `PetscDualSpace`
68020cf1dd8SToby Isaac 
68120cf1dd8SToby Isaac   Output Parameter:
68220cf1dd8SToby Isaac . dim - The dimension
68320cf1dd8SToby Isaac 
68420cf1dd8SToby Isaac   Level: intermediate
68520cf1dd8SToby Isaac 
686dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
68720cf1dd8SToby Isaac @*/
688d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
689d71ae5a4SJacob Faibussowitsch {
69020cf1dd8SToby Isaac   PetscFunctionBegin;
69120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
692dadcf809SJacob Faibussowitsch   PetscValidIntPointer(dim, 2);
693b4457527SToby Isaac   if (sp->spdim < 0) {
694b4457527SToby Isaac     PetscSection section;
695b4457527SToby Isaac 
6969566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
697b4457527SToby Isaac     if (section) {
6989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(section, &(sp->spdim)));
699b4457527SToby Isaac     } else sp->spdim = 0;
700b4457527SToby Isaac   }
701b4457527SToby Isaac   *dim = sp->spdim;
7023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70320cf1dd8SToby Isaac }
70420cf1dd8SToby Isaac 
705b4457527SToby Isaac /*@
706b4457527SToby 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
707b4457527SToby Isaac 
708b4457527SToby Isaac   Not collective
709b4457527SToby Isaac 
710b4457527SToby Isaac   Input Parameter:
711dce8aebaSBarry Smith . sp - The `PetscDualSpace`
712b4457527SToby Isaac 
713b4457527SToby Isaac   Output Parameter:
714b4457527SToby Isaac . dim - The dimension
715b4457527SToby Isaac 
716b4457527SToby Isaac   Level: intermediate
717b4457527SToby Isaac 
718dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
719b4457527SToby Isaac @*/
720d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim)
721d71ae5a4SJacob Faibussowitsch {
722b4457527SToby Isaac   PetscFunctionBegin;
723b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
724dadcf809SJacob Faibussowitsch   PetscValidIntPointer(intdim, 2);
725b4457527SToby Isaac   if (sp->spintdim < 0) {
726b4457527SToby Isaac     PetscSection section;
727b4457527SToby Isaac 
7289566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
729b4457527SToby Isaac     if (section) {
7309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstrainedStorageSize(section, &(sp->spintdim)));
731b4457527SToby Isaac     } else sp->spintdim = 0;
732b4457527SToby Isaac   }
733b4457527SToby Isaac   *intdim = sp->spintdim;
7343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
735b4457527SToby Isaac }
736b4457527SToby Isaac 
737b4457527SToby Isaac /*@
738b4457527SToby Isaac    PetscDualSpaceGetUniform - Whether this dual space is uniform
739b4457527SToby Isaac 
740b4457527SToby Isaac    Not collective
741b4457527SToby Isaac 
742b4457527SToby Isaac    Input Parameters:
743b4457527SToby Isaac .  sp - A dual space
744b4457527SToby Isaac 
745b4457527SToby Isaac    Output Parameters:
746dce8aebaSBarry Smith .  uniform - `PETSC_TRUE` if (a) the dual space is the same for each point in a stratum of the reference `DMPLEX`, and
747dce8aebaSBarry Smith              (b) every symmetry of each point in the reference `DMPLEX` is also a symmetry of the point's dual space.
748b4457527SToby Isaac 
749b4457527SToby Isaac    Level: advanced
750b4457527SToby Isaac 
751dce8aebaSBarry Smith    Note:
752dce8aebaSBarry Smith    All of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
753b4457527SToby Isaac    with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
754b4457527SToby Isaac 
755dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
756b4457527SToby Isaac @*/
757d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform)
758d71ae5a4SJacob Faibussowitsch {
759b4457527SToby Isaac   PetscFunctionBegin;
760b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
761dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(uniform, 2);
762b4457527SToby Isaac   *uniform = sp->uniform;
7633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
764b4457527SToby Isaac }
765b4457527SToby Isaac 
76620cf1dd8SToby Isaac /*@C
76720cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
76820cf1dd8SToby Isaac 
76920cf1dd8SToby Isaac   Not collective
77020cf1dd8SToby Isaac 
77120cf1dd8SToby Isaac   Input Parameter:
772dce8aebaSBarry Smith . sp - The `PetscDualSpace`
77320cf1dd8SToby Isaac 
77420cf1dd8SToby Isaac   Output Parameter:
77520cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
77620cf1dd8SToby Isaac 
77720cf1dd8SToby Isaac   Level: intermediate
77820cf1dd8SToby Isaac 
779dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
78020cf1dd8SToby Isaac @*/
781d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof)
782d71ae5a4SJacob Faibussowitsch {
78320cf1dd8SToby Isaac   PetscFunctionBegin;
78420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
78520cf1dd8SToby Isaac   PetscValidPointer(numDof, 2);
78628b400f6SJacob 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");
787b4457527SToby Isaac   if (!sp->numDof) {
788b4457527SToby Isaac     DM           dm;
789b4457527SToby Isaac     PetscInt     depth, d;
790b4457527SToby Isaac     PetscSection section;
791b4457527SToby Isaac 
7929566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
7939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
7949566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->numDof)));
7959566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
796b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
797b4457527SToby Isaac       PetscInt dStart, dEnd;
798b4457527SToby Isaac 
7999566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
800b4457527SToby Isaac       if (dEnd <= dStart) continue;
8019566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, dStart, &(sp->numDof[d])));
802b4457527SToby Isaac     }
803b4457527SToby Isaac   }
804b4457527SToby Isaac   *numDof = sp->numDof;
80508401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
8063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
80720cf1dd8SToby Isaac }
80820cf1dd8SToby Isaac 
809b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
810d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection)
811d71ae5a4SJacob Faibussowitsch {
812b4457527SToby Isaac   DM           dm;
813b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
814b4457527SToby Isaac   PetscInt    *seen, *perm;
815b4457527SToby Isaac   PetscSection section;
816b4457527SToby Isaac 
817b4457527SToby Isaac   PetscFunctionBegin;
818b4457527SToby Isaac   dm = sp->dm;
8199566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
8209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8229566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
8239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
8249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
826b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
827b4457527SToby Isaac     PetscInt  closureSize = -1, e;
828b4457527SToby Isaac     PetscInt *closure     = NULL;
829b4457527SToby Isaac 
830b4457527SToby Isaac     perm[count++]    = c;
831b4457527SToby Isaac     seen[c - pStart] = 1;
8329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
833b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
834b4457527SToby Isaac       PetscInt point = closure[2 * e];
835b4457527SToby Isaac 
836b4457527SToby Isaac       if (seen[point - pStart]) continue;
837b4457527SToby Isaac       perm[count++]        = point;
838b4457527SToby Isaac       seen[point - pStart] = 1;
839b4457527SToby Isaac     }
8409566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
841b4457527SToby Isaac   }
8421dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8439371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8449371c9d4SSatish Balay     if (perm[i] != i) break;
845b4457527SToby Isaac   if (i < pEnd - pStart) {
846b4457527SToby Isaac     IS permIS;
847b4457527SToby Isaac 
8489566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8499566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8509566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8519566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
852b4457527SToby Isaac   } else {
8539566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
854b4457527SToby Isaac   }
8559566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
856b4457527SToby Isaac   *topSection = section;
8573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
858b4457527SToby Isaac }
859b4457527SToby Isaac 
860b4457527SToby Isaac /* mark boundary points and set up */
861d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section)
862d71ae5a4SJacob Faibussowitsch {
863b4457527SToby Isaac   DM       dm;
864b4457527SToby Isaac   DMLabel  boundary;
865b4457527SToby Isaac   PetscInt pStart, pEnd, p;
866b4457527SToby Isaac 
867b4457527SToby Isaac   PetscFunctionBegin;
868b4457527SToby Isaac   dm = sp->dm;
8699566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8709566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8719566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8729566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
874b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
875b4457527SToby Isaac     PetscInt bval;
876b4457527SToby Isaac 
8779566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
878b4457527SToby Isaac     if (bval == 1) {
879b4457527SToby Isaac       PetscInt dof;
880b4457527SToby Isaac 
8819566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8829566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
883b4457527SToby Isaac     }
884b4457527SToby Isaac   }
8859566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8869566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
888b4457527SToby Isaac }
889b4457527SToby Isaac 
890a4ce7ad1SMatthew G. Knepley /*@
891dce8aebaSBarry Smith   PetscDualSpaceGetSection - Create a `PetscSection` over the reference cell with the layout from this space
892a4ce7ad1SMatthew G. Knepley 
893a4ce7ad1SMatthew G. Knepley   Collective on sp
894a4ce7ad1SMatthew G. Knepley 
895a4ce7ad1SMatthew G. Knepley   Input Parameters:
896dce8aebaSBarry Smith . sp      - The `PetscDualSpace`
897a4ce7ad1SMatthew G. Knepley 
898a4ce7ad1SMatthew G. Knepley   Output Parameter:
899a4ce7ad1SMatthew G. Knepley . section - The section
900a4ce7ad1SMatthew G. Knepley 
901a4ce7ad1SMatthew G. Knepley   Level: advanced
902a4ce7ad1SMatthew G. Knepley 
903dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
904a4ce7ad1SMatthew G. Knepley @*/
905d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section)
906d71ae5a4SJacob Faibussowitsch {
907b4457527SToby Isaac   PetscInt pStart, pEnd, p;
908b4457527SToby Isaac 
909b4457527SToby Isaac   PetscFunctionBegin;
91078f1d139SRomain Beucher   if (!sp->dm) {
91178f1d139SRomain Beucher     *section = NULL;
9123ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
91378f1d139SRomain Beucher   }
914b4457527SToby Isaac   if (!sp->pointSection) {
915b4457527SToby Isaac     /* mark the boundary */
9169566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &(sp->pointSection)));
9179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
918b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
919b4457527SToby Isaac       PetscDualSpace psp;
920b4457527SToby Isaac 
9219566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
922b4457527SToby Isaac       if (psp) {
923b4457527SToby Isaac         PetscInt dof;
924b4457527SToby Isaac 
9259566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
9269566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
927b4457527SToby Isaac       }
928b4457527SToby Isaac     }
9299566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
930b4457527SToby Isaac   }
931b4457527SToby Isaac   *section = sp->pointSection;
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933b4457527SToby Isaac }
934b4457527SToby Isaac 
935b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
936b4457527SToby Isaac  * have one cell */
937d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd)
938d71ae5a4SJacob Faibussowitsch {
939b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
940b4457527SToby Isaac   PetscSection section;
941b4457527SToby Isaac   PetscInt     dim, s, k;
94220cf1dd8SToby Isaac   DM           dm;
94320cf1dd8SToby Isaac 
94420cf1dd8SToby Isaac   PetscFunctionBegin;
9459566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
9469566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9479566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
9489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
9499566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
950b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
951b4457527SToby Isaac     PetscReal      detJ, hdetJ;
952b4457527SToby Isaac     PetscDualSpace ssp;
953b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
954b4457527SToby Isaac     PetscInt       i, j;
955b4457527SToby Isaac     DM             sdm;
95620cf1dd8SToby Isaac 
9579566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
958b4457527SToby Isaac     if (!ssp) continue;
9599566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
9609566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
961b4457527SToby Isaac     /* get the first vertex of the reference cell */
9629566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
9639566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
9649566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
9659566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
966b4457527SToby Isaac     /* compactify Jacobian */
9679371c9d4SSatish Balay     for (i = 0; i < dim; i++)
9689371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
969b4457527SToby Isaac     for (f = 0; f < dof; f++) {
970b4457527SToby Isaac       PetscQuadrature fn;
97120cf1dd8SToby Isaac 
9729566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
9739566063dSJacob Faibussowitsch       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &(sp->functional[off + f])));
97420cf1dd8SToby Isaac     }
97520cf1dd8SToby Isaac   }
9769566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
9773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
97820cf1dd8SToby Isaac }
97920cf1dd8SToby Isaac 
98020cf1dd8SToby Isaac /*@C
98120cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
98220cf1dd8SToby Isaac 
98320cf1dd8SToby Isaac   Input Parameters:
984dce8aebaSBarry Smith + sp      - The `PetscDualSpace` object
98520cf1dd8SToby Isaac . f       - The basis functional index
98620cf1dd8SToby Isaac . time    - The time
98720cf1dd8SToby 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)
98820cf1dd8SToby Isaac . numComp - The number of components for the function
98920cf1dd8SToby Isaac . func    - The input function
99020cf1dd8SToby Isaac - ctx     - A context for the function
99120cf1dd8SToby Isaac 
99220cf1dd8SToby Isaac   Output Parameter:
99320cf1dd8SToby Isaac . value   - numComp output values
99420cf1dd8SToby Isaac 
995dce8aebaSBarry Smith   Calling Sequence of func:
996dce8aebaSBarry Smith .vb
997dce8aebaSBarry Smith   func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
998dce8aebaSBarry Smith .ve
99920cf1dd8SToby Isaac 
1000a4ce7ad1SMatthew G. Knepley   Level: beginner
100120cf1dd8SToby Isaac 
1002dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
100320cf1dd8SToby Isaac @*/
1004d71ae5a4SJacob 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)
1005d71ae5a4SJacob Faibussowitsch {
100620cf1dd8SToby Isaac   PetscFunctionBegin;
100720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
100820cf1dd8SToby Isaac   PetscValidPointer(cgeom, 4);
1009dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
1010dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
10113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
101220cf1dd8SToby Isaac }
101320cf1dd8SToby Isaac 
101420cf1dd8SToby Isaac /*@C
1015dce8aebaSBarry Smith   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
101620cf1dd8SToby Isaac 
101720cf1dd8SToby Isaac   Input Parameters:
1018dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1019dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
102020cf1dd8SToby Isaac 
102120cf1dd8SToby Isaac   Output Parameter:
102220cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
102320cf1dd8SToby Isaac 
1024dce8aebaSBarry Smith   Level: advanced
102520cf1dd8SToby Isaac 
1026dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
102720cf1dd8SToby Isaac @*/
1028d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1029d71ae5a4SJacob Faibussowitsch {
103020cf1dd8SToby Isaac   PetscFunctionBegin;
103120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1032dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
10333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103420cf1dd8SToby Isaac }
103520cf1dd8SToby Isaac 
103620cf1dd8SToby Isaac /*@C
1037dce8aebaSBarry Smith   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1038b4457527SToby Isaac 
1039b4457527SToby Isaac   Input Parameters:
1040dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1041dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1042b4457527SToby Isaac 
1043b4457527SToby Isaac   Output Parameter:
1044b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1045b4457527SToby Isaac 
1046dce8aebaSBarry Smith   Level: advanced
1047b4457527SToby Isaac 
1048dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1049b4457527SToby Isaac @*/
1050d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1051d71ae5a4SJacob Faibussowitsch {
1052b4457527SToby Isaac   PetscFunctionBegin;
1053b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1054dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
10553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1056b4457527SToby Isaac }
1057b4457527SToby Isaac 
1058b4457527SToby Isaac /*@C
105920cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
106020cf1dd8SToby Isaac 
106120cf1dd8SToby Isaac   Input Parameters:
1062dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
106320cf1dd8SToby Isaac . f     - The basis functional index
106420cf1dd8SToby Isaac . time  - The time
106520cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
106620cf1dd8SToby Isaac . Nc    - The number of components for the function
106720cf1dd8SToby Isaac . func  - The input function
106820cf1dd8SToby Isaac - ctx   - A context for the function
106920cf1dd8SToby Isaac 
107020cf1dd8SToby Isaac   Output Parameter:
107120cf1dd8SToby Isaac . value   - The output value
107220cf1dd8SToby Isaac 
1073dce8aebaSBarry Smith   Calling Sequence of func:
1074dce8aebaSBarry Smith .vb
1075dce8aebaSBarry Smith    func(PetscInt dim, PetscReal time, const PetscReal x[],PetscInt numComponents, PetscScalar values[], void *ctx)
1076dce8aebaSBarry Smith .ve
107720cf1dd8SToby Isaac 
1078dce8aebaSBarry Smith   Level: advanced
107920cf1dd8SToby Isaac 
1080dce8aebaSBarry Smith   Note:
1081dce8aebaSBarry 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.
108220cf1dd8SToby Isaac 
1083dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
108420cf1dd8SToby Isaac @*/
1085d71ae5a4SJacob 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)
1086d71ae5a4SJacob Faibussowitsch {
108720cf1dd8SToby Isaac   DM               dm;
108820cf1dd8SToby Isaac   PetscQuadrature  n;
108920cf1dd8SToby Isaac   const PetscReal *points, *weights;
109020cf1dd8SToby Isaac   PetscReal        x[3];
109120cf1dd8SToby Isaac   PetscScalar     *val;
109220cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
109320cf1dd8SToby Isaac   PetscBool        isAffine;
109420cf1dd8SToby Isaac 
109520cf1dd8SToby Isaac   PetscFunctionBegin;
109620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1097dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
10989566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
10999566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
11009566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
110163a3b9bcSJacob 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);
110263a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
11039566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
110420cf1dd8SToby Isaac   *value   = 0.0;
110520cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
110620cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
110720cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
110820cf1dd8SToby Isaac     if (isAffine) {
110920cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
11109566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
111120cf1dd8SToby Isaac     } else {
11129566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
111320cf1dd8SToby Isaac     }
1114ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
111520cf1dd8SToby Isaac   }
11169566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
11173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
111820cf1dd8SToby Isaac }
111920cf1dd8SToby Isaac 
112020cf1dd8SToby Isaac /*@C
1121dce8aebaSBarry Smith   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
112220cf1dd8SToby Isaac 
112320cf1dd8SToby Isaac   Input Parameters:
1124dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1125dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
112620cf1dd8SToby Isaac 
112720cf1dd8SToby Isaac   Output Parameter:
112820cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
112920cf1dd8SToby Isaac 
1130dce8aebaSBarry Smith   Level: advanced
113120cf1dd8SToby Isaac 
1132dce8aebaSBarry Smith .seealso:  `PetscDualSpace`, `PetscDualSpaceCreate()`
113320cf1dd8SToby Isaac @*/
1134d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1135d71ae5a4SJacob Faibussowitsch {
1136b4457527SToby Isaac   Vec pointValues, dofValues;
1137b4457527SToby Isaac   Mat allMat;
113820cf1dd8SToby Isaac 
113920cf1dd8SToby Isaac   PetscFunctionBegin;
114020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
114120cf1dd8SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1142064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11439566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
114448a46eb9SPierre Jolivet   if (!(sp->allNodeValues)) PetscCall(MatCreateVecs(allMat, &(sp->allNodeValues), NULL));
1145b4457527SToby Isaac   pointValues = sp->allNodeValues;
114648a46eb9SPierre Jolivet   if (!(sp->allDofValues)) PetscCall(MatCreateVecs(allMat, NULL, &(sp->allDofValues)));
1147b4457527SToby Isaac   dofValues = sp->allDofValues;
11489566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11499566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11509566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
11519566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11529566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
11533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
115420cf1dd8SToby Isaac }
1155b4457527SToby Isaac 
1156b4457527SToby Isaac /*@C
1157dce8aebaSBarry Smith   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1158b4457527SToby Isaac 
1159b4457527SToby Isaac   Input Parameters:
1160dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1161dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1162b4457527SToby Isaac 
1163b4457527SToby Isaac   Output Parameter:
1164b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1165b4457527SToby Isaac 
1166dce8aebaSBarry Smith   Level: advanced
1167b4457527SToby Isaac 
1168dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1169b4457527SToby Isaac @*/
1170d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1171d71ae5a4SJacob Faibussowitsch {
1172b4457527SToby Isaac   Vec pointValues, dofValues;
1173b4457527SToby Isaac   Mat intMat;
1174b4457527SToby Isaac 
1175b4457527SToby Isaac   PetscFunctionBegin;
1176b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1177b4457527SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1178064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11799566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
118048a46eb9SPierre Jolivet   if (!(sp->intNodeValues)) PetscCall(MatCreateVecs(intMat, &(sp->intNodeValues), NULL));
1181b4457527SToby Isaac   pointValues = sp->intNodeValues;
118248a46eb9SPierre Jolivet   if (!(sp->intDofValues)) PetscCall(MatCreateVecs(intMat, NULL, &(sp->intDofValues)));
1183b4457527SToby Isaac   dofValues = sp->intDofValues;
11849566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11859566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11869566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
11879566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11889566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
11893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
119020cf1dd8SToby Isaac }
119120cf1dd8SToby Isaac 
1192a4ce7ad1SMatthew G. Knepley /*@
1193b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1194a4ce7ad1SMatthew G. Knepley 
1195a4ce7ad1SMatthew G. Knepley   Input Parameter:
1196a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1197a4ce7ad1SMatthew G. Knepley 
1198d8d19677SJose E. Roman   Output Parameters:
1199dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1200dce8aebaSBarry Smith - allMat - A `Mat` for the node-to-dof transformation
1201a4ce7ad1SMatthew G. Knepley 
1202a4ce7ad1SMatthew G. Knepley   Level: advanced
1203a4ce7ad1SMatthew G. Knepley 
1204dce8aebaSBarry Smith .seealso: `PetscQuadrature`, `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`
1205a4ce7ad1SMatthew G. Knepley @*/
1206d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1207d71ae5a4SJacob Faibussowitsch {
120820cf1dd8SToby Isaac   PetscFunctionBegin;
120920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1210b4457527SToby Isaac   if (allNodes) PetscValidPointer(allNodes, 2);
1211b4457527SToby Isaac   if (allMat) PetscValidPointer(allMat, 3);
1212b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1213b4457527SToby Isaac     PetscQuadrature qpoints;
1214b4457527SToby Isaac     Mat             amat;
1215b4457527SToby Isaac 
1216dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
12179566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
12189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->allMat)));
1219b4457527SToby Isaac     sp->allNodes = qpoints;
1220b4457527SToby Isaac     sp->allMat   = amat;
122120cf1dd8SToby Isaac   }
1222b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1223b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
12243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122520cf1dd8SToby Isaac }
122620cf1dd8SToby Isaac 
1227a4ce7ad1SMatthew G. Knepley /*@
1228b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1229a4ce7ad1SMatthew G. Knepley 
1230a4ce7ad1SMatthew G. Knepley   Input Parameter:
1231a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1232a4ce7ad1SMatthew G. Knepley 
1233d8d19677SJose E. Roman   Output Parameters:
1234dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1235dce8aebaSBarry Smith - allMat - A `Mat` for the node-to-dof transformation
1236a4ce7ad1SMatthew G. Knepley 
1237a4ce7ad1SMatthew G. Knepley   Level: advanced
1238a4ce7ad1SMatthew G. Knepley 
1239dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`, `PetscQuadrature`
1240a4ce7ad1SMatthew G. Knepley @*/
1241d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1242d71ae5a4SJacob Faibussowitsch {
124320cf1dd8SToby Isaac   PetscInt        spdim;
124420cf1dd8SToby Isaac   PetscInt        numPoints, offset;
124520cf1dd8SToby Isaac   PetscReal      *points;
124620cf1dd8SToby Isaac   PetscInt        f, dim;
1247b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1248b4457527SToby Isaac   PetscInt        maxNumPoints;
124920cf1dd8SToby Isaac   PetscQuadrature q;
1250b4457527SToby Isaac   Mat             A;
125120cf1dd8SToby Isaac 
125220cf1dd8SToby Isaac   PetscFunctionBegin;
12539566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
12549566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
125520cf1dd8SToby Isaac   if (!spdim) {
12569566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12579566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
125820cf1dd8SToby Isaac   }
1259b4457527SToby Isaac   nrows = spdim;
12609566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
12619566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1262b4457527SToby Isaac   maxNumPoints = numPoints;
126320cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
126420cf1dd8SToby Isaac     PetscInt Np;
126520cf1dd8SToby Isaac 
12669566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12679566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
126820cf1dd8SToby Isaac     numPoints += Np;
1269b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
127020cf1dd8SToby Isaac   }
1271b4457527SToby Isaac   ncols = numPoints * Nc;
12729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
12739566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
127420cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1275b4457527SToby Isaac     const PetscReal *p, *w;
127620cf1dd8SToby Isaac     PetscInt         Np, i;
1277b4457527SToby Isaac     PetscInt         fnc;
127820cf1dd8SToby Isaac 
12799566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12809566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
128108401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
1282ad540459SPierre Jolivet     for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i];
128348a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1284b4457527SToby Isaac     offset += Np;
1285b4457527SToby Isaac   }
12869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
12879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
12889566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12899566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1290b4457527SToby Isaac   *allMat = A;
12913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1292b4457527SToby Isaac }
1293b4457527SToby Isaac 
1294b4457527SToby Isaac /*@
1295b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1296b4457527SToby Isaac   this space, as well as the matrix that computes the degrees of freedom from the quadrature values.  Degrees of
1297dce8aebaSBarry Smith   freedom are interior degrees of freedom if they belong (by `PetscDualSpaceGetSection()`) to interior points in the
1298dce8aebaSBarry Smith   reference `DMPLEX`: complementary boundary degrees of freedom are marked as constrained in the section returned by
1299dce8aebaSBarry Smith   `PetscDualSpaceGetSection()`).
1300b4457527SToby Isaac 
1301b4457527SToby Isaac   Input Parameter:
1302b4457527SToby Isaac . sp - The dualspace
1303b4457527SToby Isaac 
1304d8d19677SJose E. Roman   Output Parameters:
1305dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1306b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1307dce8aebaSBarry Smith              the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1308dce8aebaSBarry Smith              npoints is the number of points in intNodes and nc is `PetscDualSpaceGetNumComponents()`.
1309b4457527SToby Isaac 
1310b4457527SToby Isaac   Level: advanced
1311b4457527SToby Isaac 
1312dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1313b4457527SToby Isaac @*/
1314d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1315d71ae5a4SJacob Faibussowitsch {
1316b4457527SToby Isaac   PetscFunctionBegin;
1317b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1318b4457527SToby Isaac   if (intNodes) PetscValidPointer(intNodes, 2);
1319b4457527SToby Isaac   if (intMat) PetscValidPointer(intMat, 3);
1320b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1321b4457527SToby Isaac     PetscQuadrature qpoints;
1322b4457527SToby Isaac     Mat             imat;
1323b4457527SToby Isaac 
1324dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
13259566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
13269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->intMat)));
1327b4457527SToby Isaac     sp->intNodes = qpoints;
1328b4457527SToby Isaac     sp->intMat   = imat;
1329b4457527SToby Isaac   }
1330b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1331b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
13323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1333b4457527SToby Isaac }
1334b4457527SToby Isaac 
1335b4457527SToby Isaac /*@
1336b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1337b4457527SToby Isaac 
1338b4457527SToby Isaac   Input Parameter:
1339b4457527SToby Isaac . sp - The dualspace
1340b4457527SToby Isaac 
1341d8d19677SJose E. Roman   Output Parameters:
1342dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1343b4457527SToby Isaac - intMat    - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1344dce8aebaSBarry Smith               the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1345dce8aebaSBarry Smith               npoints is the number of points in allNodes and nc is `PetscDualSpaceGetNumComponents()`.
1346b4457527SToby Isaac 
1347b4457527SToby Isaac   Level: advanced
1348b4457527SToby Isaac 
1349dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1350b4457527SToby Isaac @*/
1351d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1352d71ae5a4SJacob Faibussowitsch {
1353b4457527SToby Isaac   DM              dm;
1354b4457527SToby Isaac   PetscInt        spdim0;
1355b4457527SToby Isaac   PetscInt        Nc;
1356b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1357b4457527SToby Isaac   PetscSection    section;
1358b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1359b4457527SToby Isaac   PetscReal      *points;
1360b4457527SToby Isaac   PetscInt        dim;
1361b4457527SToby Isaac   PetscInt       *nnz;
1362b4457527SToby Isaac   PetscQuadrature q;
1363b4457527SToby Isaac   Mat             imat;
1364b4457527SToby Isaac 
1365b4457527SToby Isaac   PetscFunctionBegin;
1366b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
13689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1369b4457527SToby Isaac   if (!spdim0) {
1370b4457527SToby Isaac     *intNodes = NULL;
1371b4457527SToby Isaac     *intMat   = NULL;
13723ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1373b4457527SToby Isaac   }
13749566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
13769566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
13779566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1379b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1380b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1381b4457527SToby Isaac 
13829566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13839566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1384b4457527SToby Isaac     if (!(dof - cdof)) continue;
13859566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1386b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1387b4457527SToby Isaac       PetscInt Np;
1388b4457527SToby Isaac 
13899566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
13909566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1391b4457527SToby Isaac       nnz[f] = Np * Nc;
1392b4457527SToby Isaac       numPoints += Np;
1393b4457527SToby Isaac     }
1394b4457527SToby Isaac   }
13959566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
13969566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
13979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1398b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1399b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1400b4457527SToby Isaac 
14019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
14029566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1403b4457527SToby Isaac     if (!(dof - cdof)) continue;
14049566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1405b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1406b4457527SToby Isaac       const PetscReal *p;
1407b4457527SToby Isaac       const PetscReal *w;
1408b4457527SToby Isaac       PetscInt         Np, i;
1409b4457527SToby Isaac 
14109566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14119566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
1412ad540459SPierre Jolivet       for (i = 0; i < Np * dim; i++) points[offset + i] = p[i];
141348a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1414b4457527SToby Isaac       offset += Np * dim;
1415b4457527SToby Isaac       matoffset += Np * Nc;
1416b4457527SToby Isaac     }
1417b4457527SToby Isaac   }
14189566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
14199566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
14209566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
14219566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1422b4457527SToby Isaac   *intMat = imat;
14233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
142420cf1dd8SToby Isaac }
142520cf1dd8SToby Isaac 
14264f9ab2b4SJed Brown /*@
1427dce8aebaSBarry Smith   PetscDualSpaceEqual - Determine if two dual spaces are equivalent
14284f9ab2b4SJed Brown 
14294f9ab2b4SJed Brown   Input Parameters:
1430dce8aebaSBarry Smith + A    - A `PetscDualSpace` object
1431dce8aebaSBarry Smith - B    - Another `PetscDualSpace` object
14324f9ab2b4SJed Brown 
14334f9ab2b4SJed Brown   Output Parameter:
1434dce8aebaSBarry Smith . equal - `PETSC_TRUE` if the dual spaces are equivalent
14354f9ab2b4SJed Brown 
14364f9ab2b4SJed Brown   Level: advanced
14374f9ab2b4SJed Brown 
1438dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
14394f9ab2b4SJed Brown @*/
1440d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal)
1441d71ae5a4SJacob Faibussowitsch {
14424f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
14434f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
14444f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
14454f9ab2b4SJed Brown   Mat             matA, matB;
14464f9ab2b4SJed Brown 
14474f9ab2b4SJed Brown   PetscFunctionBegin;
14484f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
14494f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
14504f9ab2b4SJed Brown   PetscValidBoolPointer(equal, 3);
14514f9ab2b4SJed Brown   *equal = PETSC_FALSE;
14529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
14539566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
14543ba16761SJacob Faibussowitsch   if (sizeB != sizeA) PetscFunctionReturn(PETSC_SUCCESS);
14559566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
14569566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
14573ba16761SJacob Faibussowitsch   if (dimA != dimB) PetscFunctionReturn(PETSC_SUCCESS);
14584f9ab2b4SJed Brown 
14599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
14609566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
14614f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
14623ba16761SJacob Faibussowitsch     if (dofA[d] != dofB[d]) PetscFunctionReturn(PETSC_SUCCESS);
14634f9ab2b4SJed Brown   }
14644f9ab2b4SJed Brown 
14659566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
14669566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
14674f9ab2b4SJed Brown   if (!quadA && !quadB) {
14684f9ab2b4SJed Brown     *equal = PETSC_TRUE;
14694f9ab2b4SJed Brown   } else if (quadA && quadB) {
14709566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
14713ba16761SJacob Faibussowitsch     if (*equal == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS);
14723ba16761SJacob Faibussowitsch     if (!matA && !matB) PetscFunctionReturn(PETSC_SUCCESS);
14739566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
14744f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
14754f9ab2b4SJed Brown   }
14763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14774f9ab2b4SJed Brown }
14784f9ab2b4SJed Brown 
147920cf1dd8SToby Isaac /*@C
148020cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
148120cf1dd8SToby Isaac 
148220cf1dd8SToby Isaac   Input Parameters:
1483dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
148420cf1dd8SToby Isaac . f     - The basis functional index
148520cf1dd8SToby Isaac . time  - The time
148620cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
148720cf1dd8SToby Isaac . Nc    - The number of components for the function
148820cf1dd8SToby Isaac . func  - The input function
148920cf1dd8SToby Isaac - ctx   - A context for the function
149020cf1dd8SToby Isaac 
149120cf1dd8SToby Isaac   Output Parameter:
149220cf1dd8SToby Isaac . value - The output value (scalar)
149320cf1dd8SToby Isaac 
1494dce8aebaSBarry Smith   Calling Sequence of func:
1495dce8aebaSBarry Smith .vb
1496dce8aebaSBarry Smith   func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1497dce8aebaSBarry Smith .ve
1498dce8aebaSBarry Smith   Level: advanced
149920cf1dd8SToby Isaac 
1500dce8aebaSBarry Smith   Note:
1501dce8aebaSBarry 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.
150220cf1dd8SToby Isaac 
1503dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
150420cf1dd8SToby Isaac @*/
1505d71ae5a4SJacob 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)
1506d71ae5a4SJacob Faibussowitsch {
150720cf1dd8SToby Isaac   DM               dm;
150820cf1dd8SToby Isaac   PetscQuadrature  n;
150920cf1dd8SToby Isaac   const PetscReal *points, *weights;
151020cf1dd8SToby Isaac   PetscScalar     *val;
151120cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
151220cf1dd8SToby Isaac 
151320cf1dd8SToby Isaac   PetscFunctionBegin;
151420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1515dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
15169566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
15179566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
15189566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
15199566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
152063a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
15219566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
152220cf1dd8SToby Isaac   *value = 0.;
152320cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
15249566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
1525ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
152620cf1dd8SToby Isaac   }
15279566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
15283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
152920cf1dd8SToby Isaac }
153020cf1dd8SToby Isaac 
153120cf1dd8SToby Isaac /*@
153220cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
153320cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
153420cf1dd8SToby Isaac 
153520cf1dd8SToby Isaac   Not collective
153620cf1dd8SToby Isaac 
153720cf1dd8SToby Isaac   Input Parameters:
1538dce8aebaSBarry Smith + sp - the `PetscDualSpace` object
153920cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
154020cf1dd8SToby Isaac 
154120cf1dd8SToby Isaac   Output Parameter:
154220cf1dd8SToby Isaac . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
154320cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
154420cf1dd8SToby Isaac 
154520cf1dd8SToby Isaac   Level: advanced
154620cf1dd8SToby Isaac 
1547dce8aebaSBarry Smith   Notes:
1548dce8aebaSBarry Smith   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
1549dce8aebaSBarry Smith   pointwise values are not defined on the element boundaries), or if the implementation of `PetscDualSpace` does not
1550dce8aebaSBarry Smith   support extracting subspaces, then NULL is returned.
1551dce8aebaSBarry Smith 
1552dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1553dce8aebaSBarry Smith 
1554dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSpaceGetHeightSubspace()`, `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`
155520cf1dd8SToby Isaac @*/
1556d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
1557d71ae5a4SJacob Faibussowitsch {
1558b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1559b4457527SToby Isaac   DM       dm;
156020cf1dd8SToby Isaac 
156120cf1dd8SToby Isaac   PetscFunctionBegin;
156220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1563064a246eSJacob Faibussowitsch   PetscValidPointer(subsp, 3);
156408401ef6SPierre 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");
156520cf1dd8SToby Isaac   *subsp = NULL;
1566b4457527SToby Isaac   dm     = sp->dm;
15679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
15681dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
15699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1570b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1571b4457527SToby Isaac     *subsp = sp;
15723ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1573b4457527SToby Isaac   }
1574b4457527SToby Isaac   if (!sp->heightSpaces) {
1575b4457527SToby Isaac     PetscInt h;
15769566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->heightSpaces)));
1577b4457527SToby Isaac 
1578b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1579b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
15809566063dSJacob Faibussowitsch       if (sp->ops->createheightsubspace) PetscCall((*sp->ops->createheightsubspace)(sp, height, &(sp->heightSpaces[h])));
1581b4457527SToby Isaac       else if (sp->pointSpaces) {
1582b4457527SToby Isaac         PetscInt hStart, hEnd;
1583b4457527SToby Isaac 
15849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1585b4457527SToby Isaac         if (hEnd > hStart) {
1586665f567fSMatthew G. Knepley           const char *name;
1587665f567fSMatthew G. Knepley 
15889566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)(sp->pointSpaces[hStart])));
1589665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
15909566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
15919566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1592665f567fSMatthew G. Knepley           }
1593b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1594b4457527SToby Isaac         }
1595b4457527SToby Isaac       }
1596b4457527SToby Isaac     }
1597b4457527SToby Isaac   }
1598b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
15993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
160020cf1dd8SToby Isaac }
160120cf1dd8SToby Isaac 
160220cf1dd8SToby Isaac /*@
160320cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
160420cf1dd8SToby Isaac 
160520cf1dd8SToby Isaac   Not collective
160620cf1dd8SToby Isaac 
160720cf1dd8SToby Isaac   Input Parameters:
1608dce8aebaSBarry Smith + sp - the `PetscDualSpace` object
160920cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
161020cf1dd8SToby Isaac 
161120cf1dd8SToby Isaac   Output Parameters:
1612dce8aebaSBarry Smith   bdsp - the subspace. The functionals in the subspace are with respect to the intrinsic geometry of the
161320cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
161420cf1dd8SToby Isaac 
161520cf1dd8SToby Isaac   Level: advanced
161620cf1dd8SToby Isaac 
1617dce8aebaSBarry Smith   Notes:
1618dce8aebaSBarry Smith   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
1619dce8aebaSBarry Smith   defined on the element boundaries), or if the implementation of `PetscDualSpace` does not support extracting
1620dce8aebaSBarry Smith   subspaces, then NULL is returned.
1621dce8aebaSBarry Smith 
1622dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1623dce8aebaSBarry Smith 
1624dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetHeightSubspace()`
162520cf1dd8SToby Isaac @*/
1626d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1627d71ae5a4SJacob Faibussowitsch {
1628b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1629b4457527SToby Isaac   DM       dm;
163020cf1dd8SToby Isaac 
163120cf1dd8SToby Isaac   PetscFunctionBegin;
163220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1633064a246eSJacob Faibussowitsch   PetscValidPointer(bdsp, 3);
163420cf1dd8SToby Isaac   *bdsp = NULL;
1635b4457527SToby Isaac   dm    = sp->dm;
16369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16371dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
16389566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1639b4457527SToby 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 */
1640b4457527SToby Isaac     *bdsp = sp;
16413ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1642b4457527SToby Isaac   }
1643b4457527SToby Isaac   if (!sp->pointSpaces) {
1644b4457527SToby Isaac     PetscInt p;
16459566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pEnd - pStart, &(sp->pointSpaces)));
164620cf1dd8SToby Isaac 
1647b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1648b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
16499566063dSJacob Faibussowitsch       if (sp->ops->createpointsubspace) PetscCall((*sp->ops->createpointsubspace)(sp, p + pStart, &(sp->pointSpaces[p])));
1650b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1651b4457527SToby Isaac         PetscInt dim, depth, height;
1652b4457527SToby Isaac         DMLabel  label;
1653b4457527SToby Isaac 
16549566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
16559566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
16569566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
165720cf1dd8SToby Isaac         height = dim - depth;
16589566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &(sp->pointSpaces[p])));
16599566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
166020cf1dd8SToby Isaac       }
1661b4457527SToby Isaac     }
1662b4457527SToby Isaac   }
1663b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
16643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
166520cf1dd8SToby Isaac }
166620cf1dd8SToby Isaac 
16676f905325SMatthew G. Knepley /*@C
16686f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
16696f905325SMatthew G. Knepley 
16706f905325SMatthew G. Knepley   Not collective
16716f905325SMatthew G. Knepley 
16726f905325SMatthew G. Knepley   Input Parameter:
1673dce8aebaSBarry Smith . sp - the `PetscDualSpace` object
16746f905325SMatthew G. Knepley 
16756f905325SMatthew G. Knepley   Output Parameters:
1676b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1677b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
16786f905325SMatthew G. Knepley 
16796f905325SMatthew G. Knepley   Level: developer
16806f905325SMatthew G. Knepley 
1681dce8aebaSBarry Smith   Note:
1682dce8aebaSBarry Smith   The permutation and flip arrays are organized in the following way
1683dce8aebaSBarry Smith .vb
1684dce8aebaSBarry Smith   perms[p][ornt][dof # on point] = new local dof #
1685dce8aebaSBarry Smith   flips[p][ornt][dof # on point] = reversal or not
1686dce8aebaSBarry Smith .ve
1687dce8aebaSBarry Smith 
1688dce8aebaSBarry Smith .seealso: `PetscDualSpace`
16896f905325SMatthew G. Knepley @*/
1690d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
1691d71ae5a4SJacob Faibussowitsch {
16926f905325SMatthew G. Knepley   PetscFunctionBegin;
16936f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16949371c9d4SSatish Balay   if (perms) {
16959371c9d4SSatish Balay     PetscValidPointer(perms, 2);
16969371c9d4SSatish Balay     *perms = NULL;
16979371c9d4SSatish Balay   }
16989371c9d4SSatish Balay   if (flips) {
16999371c9d4SSatish Balay     PetscValidPointer(flips, 3);
17009371c9d4SSatish Balay     *flips = NULL;
17019371c9d4SSatish Balay   }
17029566063dSJacob Faibussowitsch   if (sp->ops->getsymmetries) PetscCall((sp->ops->getsymmetries)(sp, perms, flips));
17033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17046f905325SMatthew G. Knepley }
17054bee2e38SMatthew G. Knepley 
17064bee2e38SMatthew G. Knepley /*@
1707b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1708b4457527SToby Isaac   dual space's functionals.
1709b4457527SToby Isaac 
1710b4457527SToby Isaac   Input Parameter:
1711dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
1712b4457527SToby Isaac 
1713b4457527SToby Isaac   Output Parameter:
1714b4457527SToby 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
1715b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1716b4457527SToby 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).
1717b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1718b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1719b4457527SToby Isaac         but are stored as 1-forms.
1720b4457527SToby Isaac 
1721b4457527SToby Isaac   Level: developer
1722b4457527SToby Isaac 
1723dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1724b4457527SToby Isaac @*/
1725d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k)
1726d71ae5a4SJacob Faibussowitsch {
1727b4457527SToby Isaac   PetscFunctionBeginHot;
1728b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1729dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1730b4457527SToby Isaac   *k = dsp->k;
17313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1732b4457527SToby Isaac }
1733b4457527SToby Isaac 
1734b4457527SToby Isaac /*@
1735b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1736b4457527SToby Isaac   dual space's functionals.
1737b4457527SToby Isaac 
1738d8d19677SJose E. Roman   Input Parameters:
1739dce8aebaSBarry Smith + dsp - The `PetscDualSpace`
1740b4457527SToby 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
1741b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1742b4457527SToby 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).
1743b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1744b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1745b4457527SToby Isaac         but are stored as 1-forms.
1746b4457527SToby Isaac 
1747b4457527SToby Isaac   Level: developer
1748b4457527SToby Isaac 
1749dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1750b4457527SToby Isaac @*/
1751d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k)
1752d71ae5a4SJacob Faibussowitsch {
1753b4457527SToby Isaac   PetscInt dim;
1754b4457527SToby Isaac 
1755b4457527SToby Isaac   PetscFunctionBeginHot;
1756b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
175728b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1758b4457527SToby Isaac   dim = dsp->dm->dim;
17591dca8a05SBarry 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);
1760b4457527SToby Isaac   dsp->k = k;
17613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1762b4457527SToby Isaac }
1763b4457527SToby Isaac 
1764b4457527SToby Isaac /*@
17654bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
17664bee2e38SMatthew G. Knepley 
17674bee2e38SMatthew G. Knepley   Input Parameter:
1768dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
17694bee2e38SMatthew G. Knepley 
17704bee2e38SMatthew G. Knepley   Output Parameter:
17714bee2e38SMatthew G. Knepley . k   - The simplex dimension
17724bee2e38SMatthew G. Knepley 
1773a4ce7ad1SMatthew G. Knepley   Level: developer
17744bee2e38SMatthew G. Knepley 
1775dce8aebaSBarry Smith   Note:
1776dce8aebaSBarry Smith   Currently supported values are
1777dce8aebaSBarry Smith .vb
1778dce8aebaSBarry Smith   0: These are H_1 methods that only transform coordinates
1779dce8aebaSBarry Smith   1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
1780dce8aebaSBarry Smith   2: These are the same as 1
1781dce8aebaSBarry Smith   3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
1782dce8aebaSBarry Smith .ve
17834bee2e38SMatthew G. Knepley 
1784dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
17854bee2e38SMatthew G. Knepley @*/
1786d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k)
1787d71ae5a4SJacob Faibussowitsch {
1788b4457527SToby Isaac   PetscInt dim;
1789b4457527SToby Isaac 
17904bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
17914bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1792dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1793b4457527SToby Isaac   dim = dsp->dm->dim;
1794b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1795b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1796b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1797b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
17983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17994bee2e38SMatthew G. Knepley }
18004bee2e38SMatthew G. Knepley 
18014bee2e38SMatthew G. Knepley /*@C
18024bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
18034bee2e38SMatthew G. Knepley 
18044bee2e38SMatthew G. Knepley   Input Parameters:
1805dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18064bee2e38SMatthew G. Knepley . trans     - The type of transform
18074bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18084bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18094bee2e38SMatthew G. Knepley . Nv        - The number of function samples
18104bee2e38SMatthew G. Knepley . Nc        - The number of function components
18114bee2e38SMatthew G. Knepley - vals      - The function values
18124bee2e38SMatthew G. Knepley 
18134bee2e38SMatthew G. Knepley   Output Parameter:
18144bee2e38SMatthew G. Knepley . vals      - The transformed function values
18154bee2e38SMatthew G. Knepley 
1816a4ce7ad1SMatthew G. Knepley   Level: intermediate
18174bee2e38SMatthew G. Knepley 
1818dce8aebaSBarry Smith   Note:
1819dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18202edcad52SToby Isaac 
1821dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18224bee2e38SMatthew G. Knepley @*/
1823d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1824d71ae5a4SJacob Faibussowitsch {
1825b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1826b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
18274bee2e38SMatthew G. Knepley 
18284bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18294bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18304bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1831dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
1832b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
18332ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1834b4457527SToby Isaac   /* No change needed for 0-forms */
18353ba16761SJacob Faibussowitsch   if (!dsp->k) PetscFunctionReturn(PETSC_SUCCESS);
18369566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1837b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
18389566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
18394bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1840b4457527SToby Isaac     switch (Nk) {
1841b4457527SToby Isaac     case 1:
1842b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
18434bee2e38SMatthew G. Knepley       break;
1844b4457527SToby Isaac     case 2:
1845b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
18464bee2e38SMatthew G. Knepley       break;
1847b4457527SToby Isaac     case 3:
1848b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1849b4457527SToby Isaac       break;
1850d71ae5a4SJacob Faibussowitsch     default:
1851d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1852b4457527SToby Isaac     }
18534bee2e38SMatthew G. Knepley   }
18543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18554bee2e38SMatthew G. Knepley }
1856b4457527SToby Isaac 
18574bee2e38SMatthew G. Knepley /*@C
18584bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
18594bee2e38SMatthew G. Knepley 
18604bee2e38SMatthew G. Knepley   Input Parameters:
1861dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18624bee2e38SMatthew G. Knepley . trans     - The type of transform
18634bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18644bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18654bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
18664bee2e38SMatthew G. Knepley . Nc        - The number of function components
18674bee2e38SMatthew G. Knepley - vals      - The function gradient values
18684bee2e38SMatthew G. Knepley 
18694bee2e38SMatthew G. Knepley   Output Parameter:
1870f9244615SMatthew G. Knepley . vals      - The transformed function gradient values
18714bee2e38SMatthew G. Knepley 
1872a4ce7ad1SMatthew G. Knepley   Level: intermediate
18734bee2e38SMatthew G. Knepley 
1874dce8aebaSBarry Smith   Note:
1875dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18762edcad52SToby Isaac 
1877dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18784bee2e38SMatthew G. Knepley @*/
1879d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1880d71ae5a4SJacob Faibussowitsch {
188127f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
188227f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
18834bee2e38SMatthew G. Knepley 
18844bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18854bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18864bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1887dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
188827f02ce8SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
188963a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
189027f02ce8SMatthew G. Knepley #endif
18914bee2e38SMatthew G. Knepley   /* Transform gradient */
189227f02ce8SMatthew G. Knepley   if (dim == dE) {
18934bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
18944bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
18959371c9d4SSatish Balay         switch (dim) {
1896d71ae5a4SJacob Faibussowitsch         case 1:
1897d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim] *= fegeom->invJ[0];
1898d71ae5a4SJacob Faibussowitsch           break;
1899d71ae5a4SJacob Faibussowitsch         case 2:
1900d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1901d71ae5a4SJacob Faibussowitsch           break;
1902d71ae5a4SJacob Faibussowitsch         case 3:
1903d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1904d71ae5a4SJacob Faibussowitsch           break;
1905d71ae5a4SJacob Faibussowitsch         default:
1906d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19074bee2e38SMatthew G. Knepley         }
19084bee2e38SMatthew G. Knepley       }
19094bee2e38SMatthew G. Knepley     }
191027f02ce8SMatthew G. Knepley   } else {
191127f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1912ad540459SPierre 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]);
191327f02ce8SMatthew G. Knepley     }
191427f02ce8SMatthew G. Knepley   }
19154bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
19163ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
19174bee2e38SMatthew G. Knepley   switch (trans) {
1918d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
1919d71ae5a4SJacob Faibussowitsch     break;
19204bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
19214bee2e38SMatthew G. Knepley     if (isInverse) {
19224bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19234bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19249371c9d4SSatish Balay           switch (dim) {
1925d71ae5a4SJacob Faibussowitsch           case 2:
1926d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1927d71ae5a4SJacob Faibussowitsch             break;
1928d71ae5a4SJacob Faibussowitsch           case 3:
1929d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1930d71ae5a4SJacob Faibussowitsch             break;
1931d71ae5a4SJacob Faibussowitsch           default:
1932d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19334bee2e38SMatthew G. Knepley           }
19344bee2e38SMatthew G. Knepley         }
19354bee2e38SMatthew G. Knepley       }
19364bee2e38SMatthew G. Knepley     } else {
19374bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19384bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19399371c9d4SSatish Balay           switch (dim) {
1940d71ae5a4SJacob Faibussowitsch           case 2:
1941d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1942d71ae5a4SJacob Faibussowitsch             break;
1943d71ae5a4SJacob Faibussowitsch           case 3:
1944d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1945d71ae5a4SJacob Faibussowitsch             break;
1946d71ae5a4SJacob Faibussowitsch           default:
1947d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19484bee2e38SMatthew G. Knepley           }
19494bee2e38SMatthew G. Knepley         }
19504bee2e38SMatthew G. Knepley       }
19514bee2e38SMatthew G. Knepley     }
19524bee2e38SMatthew G. Knepley     break;
19534bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
19544bee2e38SMatthew G. Knepley     if (isInverse) {
19554bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19564bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19579371c9d4SSatish Balay           switch (dim) {
1958d71ae5a4SJacob Faibussowitsch           case 2:
1959d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1960d71ae5a4SJacob Faibussowitsch             break;
1961d71ae5a4SJacob Faibussowitsch           case 3:
1962d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1963d71ae5a4SJacob Faibussowitsch             break;
1964d71ae5a4SJacob Faibussowitsch           default:
1965d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19664bee2e38SMatthew G. Knepley           }
19674bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
19684bee2e38SMatthew G. Knepley         }
19694bee2e38SMatthew G. Knepley       }
19704bee2e38SMatthew G. Knepley     } else {
19714bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19724bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19739371c9d4SSatish Balay           switch (dim) {
1974d71ae5a4SJacob Faibussowitsch           case 2:
1975d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1976d71ae5a4SJacob Faibussowitsch             break;
1977d71ae5a4SJacob Faibussowitsch           case 3:
1978d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1979d71ae5a4SJacob Faibussowitsch             break;
1980d71ae5a4SJacob Faibussowitsch           default:
1981d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19824bee2e38SMatthew G. Knepley           }
19834bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
19844bee2e38SMatthew G. Knepley         }
19854bee2e38SMatthew G. Knepley       }
19864bee2e38SMatthew G. Knepley     }
19874bee2e38SMatthew G. Knepley     break;
19884bee2e38SMatthew G. Knepley   }
19893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19904bee2e38SMatthew G. Knepley }
19914bee2e38SMatthew G. Knepley 
19924bee2e38SMatthew G. Knepley /*@C
1993f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
1994f9244615SMatthew G. Knepley 
1995f9244615SMatthew G. Knepley   Input Parameters:
1996dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
1997f9244615SMatthew G. Knepley . trans     - The type of transform
1998f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
1999f9244615SMatthew G. Knepley . fegeom    - The cell geometry
2000f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
2001f9244615SMatthew G. Knepley . Nc        - The number of function components
2002f9244615SMatthew G. Knepley - vals      - The function gradient values
2003f9244615SMatthew G. Knepley 
2004f9244615SMatthew G. Knepley   Output Parameter:
2005f9244615SMatthew G. Knepley . vals      - The transformed function Hessian values
2006f9244615SMatthew G. Knepley 
2007f9244615SMatthew G. Knepley   Level: intermediate
2008f9244615SMatthew G. Knepley 
2009dce8aebaSBarry Smith   Note:
2010dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2011f9244615SMatthew G. Knepley 
2012dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
2013f9244615SMatthew G. Knepley @*/
2014d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
2015d71ae5a4SJacob Faibussowitsch {
2016f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
2017f9244615SMatthew G. Knepley   PetscInt       v, c;
2018f9244615SMatthew G. Knepley 
2019f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2020f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2021f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
2022dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
2023f9244615SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
202463a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
2025f9244615SMatthew G. Knepley #endif
2026f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
2027f9244615SMatthew G. Knepley   if (dim == dE) {
2028f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2029f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
20309371c9d4SSatish Balay         switch (dim) {
2031d71ae5a4SJacob Faibussowitsch         case 1:
2032d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]);
2033d71ae5a4SJacob Faibussowitsch           break;
2034d71ae5a4SJacob Faibussowitsch         case 2:
2035d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2036d71ae5a4SJacob Faibussowitsch           break;
2037d71ae5a4SJacob Faibussowitsch         case 3:
2038d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2039d71ae5a4SJacob Faibussowitsch           break;
2040d71ae5a4SJacob Faibussowitsch         default:
2041d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
2042f9244615SMatthew G. Knepley         }
2043f9244615SMatthew G. Knepley       }
2044f9244615SMatthew G. Knepley     }
2045f9244615SMatthew G. Knepley   } else {
2046f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2047ad540459SPierre 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]);
2048f9244615SMatthew G. Knepley     }
2049f9244615SMatthew G. Knepley   }
2050f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
20513ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
2052f9244615SMatthew G. Knepley   switch (trans) {
2053d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
2054d71ae5a4SJacob Faibussowitsch     break;
2055d71ae5a4SJacob Faibussowitsch   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
2056d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2057d71ae5a4SJacob Faibussowitsch   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
2058d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2059f9244615SMatthew G. Knepley   }
20603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2061f9244615SMatthew G. Knepley }
2062f9244615SMatthew G. Knepley 
2063f9244615SMatthew G. Knepley /*@C
20644bee2e38SMatthew 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.
20654bee2e38SMatthew G. Knepley 
20664bee2e38SMatthew G. Knepley   Input Parameters:
2067dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
20684bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
20694bee2e38SMatthew G. Knepley . Nq         - The number of function samples
20704bee2e38SMatthew G. Knepley . Nc         - The number of function components
20714bee2e38SMatthew G. Knepley - pointEval  - The function values
20724bee2e38SMatthew G. Knepley 
20734bee2e38SMatthew G. Knepley   Output Parameter:
20744bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
20754bee2e38SMatthew G. Knepley 
20764bee2e38SMatthew G. Knepley   Level: advanced
20774bee2e38SMatthew G. Knepley 
2078dce8aebaSBarry Smith   Notes:
2079dce8aebaSBarry 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.
20804bee2e38SMatthew G. Knepley 
2081da81f932SPierre Jolivet   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
20822edcad52SToby Isaac 
2083dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
20844bee2e38SMatthew G. Knepley @*/
2085d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2086d71ae5a4SJacob Faibussowitsch {
20874bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2088b4457527SToby Isaac   PetscInt                    k;
20894bee2e38SMatthew G. Knepley 
20904bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
20914bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20924bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2093dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
20944bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
20954bee2e38SMatthew G. Knepley      This determines their transformation properties. */
20969566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
20979371c9d4SSatish Balay   switch (k) {
2098d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2099d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2100d71ae5a4SJacob Faibussowitsch     break;
2101d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2102d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2103d71ae5a4SJacob Faibussowitsch     break;
2104b4457527SToby Isaac   case 2:
2105d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2106d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2107d71ae5a4SJacob Faibussowitsch     break;
2108d71ae5a4SJacob Faibussowitsch   default:
2109d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21104bee2e38SMatthew G. Knepley   }
21119566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
21123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21134bee2e38SMatthew G. Knepley }
21144bee2e38SMatthew G. Knepley 
21154bee2e38SMatthew G. Knepley /*@C
21164bee2e38SMatthew 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.
21174bee2e38SMatthew G. Knepley 
21184bee2e38SMatthew G. Knepley   Input Parameters:
2119dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
21204bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
21214bee2e38SMatthew G. Knepley . Nq         - The number of function samples
21224bee2e38SMatthew G. Knepley . Nc         - The number of function components
21234bee2e38SMatthew G. Knepley - pointEval  - The function values
21244bee2e38SMatthew G. Knepley 
21254bee2e38SMatthew G. Knepley   Output Parameter:
21264bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
21274bee2e38SMatthew G. Knepley 
21284bee2e38SMatthew G. Knepley   Level: advanced
21294bee2e38SMatthew G. Knepley 
2130dce8aebaSBarry Smith   Notes:
2131dce8aebaSBarry 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.
21324bee2e38SMatthew G. Knepley 
2133dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21342edcad52SToby Isaac 
2135dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21364bee2e38SMatthew G. Knepley @*/
2137d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2138d71ae5a4SJacob Faibussowitsch {
21394bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2140b4457527SToby Isaac   PetscInt                    k;
21414bee2e38SMatthew G. Knepley 
21424bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21434bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21444bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2145dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21464bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21474bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21489566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21499371c9d4SSatish Balay   switch (k) {
2150d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2151d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2152d71ae5a4SJacob Faibussowitsch     break;
2153d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2154d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2155d71ae5a4SJacob Faibussowitsch     break;
2156b4457527SToby Isaac   case 2:
2157d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2158d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2159d71ae5a4SJacob Faibussowitsch     break;
2160d71ae5a4SJacob Faibussowitsch   default:
2161d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21624bee2e38SMatthew G. Knepley   }
21639566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
21643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21654bee2e38SMatthew G. Knepley }
21664bee2e38SMatthew G. Knepley 
21674bee2e38SMatthew G. Knepley /*@C
21684bee2e38SMatthew 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.
21694bee2e38SMatthew G. Knepley 
21704bee2e38SMatthew G. Knepley   Input Parameters:
2171dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
21724bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
21734bee2e38SMatthew G. Knepley . Nq         - The number of function gradient samples
21744bee2e38SMatthew G. Knepley . Nc         - The number of function components
21754bee2e38SMatthew G. Knepley - pointEval  - The function gradient values
21764bee2e38SMatthew G. Knepley 
21774bee2e38SMatthew G. Knepley   Output Parameter:
21784bee2e38SMatthew G. Knepley . pointEval  - The transformed function gradient values
21794bee2e38SMatthew G. Knepley 
21804bee2e38SMatthew G. Knepley   Level: advanced
21814bee2e38SMatthew G. Knepley 
2182dce8aebaSBarry Smith   Notes:
2183dce8aebaSBarry 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.
21844bee2e38SMatthew G. Knepley 
2185dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21862edcad52SToby Isaac 
2187dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2188dc0529c6SBarry Smith @*/
2189d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2190d71ae5a4SJacob Faibussowitsch {
21914bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2192b4457527SToby Isaac   PetscInt                    k;
21934bee2e38SMatthew G. Knepley 
21944bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21954bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21964bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2197dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21984bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21994bee2e38SMatthew G. Knepley      This determines their transformation properties. */
22009566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22019371c9d4SSatish Balay   switch (k) {
2202d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2203d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2204d71ae5a4SJacob Faibussowitsch     break;
2205d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2206d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2207d71ae5a4SJacob Faibussowitsch     break;
2208b4457527SToby Isaac   case 2:
2209d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2210d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2211d71ae5a4SJacob Faibussowitsch     break;
2212d71ae5a4SJacob Faibussowitsch   default:
2213d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22144bee2e38SMatthew G. Knepley   }
22159566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22174bee2e38SMatthew G. Knepley }
2218f9244615SMatthew G. Knepley 
2219f9244615SMatthew G. Knepley /*@C
2220f9244615SMatthew 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.
2221f9244615SMatthew G. Knepley 
2222f9244615SMatthew G. Knepley   Input Parameters:
2223dce8aebaSBarry Smith + dsp        - The `PetscDualSpace`
2224f9244615SMatthew G. Knepley . fegeom     - The geometry for this cell
2225f9244615SMatthew G. Knepley . Nq         - The number of function Hessian samples
2226f9244615SMatthew G. Knepley . Nc         - The number of function components
2227f9244615SMatthew G. Knepley - pointEval  - The function gradient values
2228f9244615SMatthew G. Knepley 
2229f9244615SMatthew G. Knepley   Output Parameter:
2230f9244615SMatthew G. Knepley . pointEval  - The transformed function Hessian values
2231f9244615SMatthew G. Knepley 
2232f9244615SMatthew G. Knepley   Level: advanced
2233f9244615SMatthew G. Knepley 
2234dce8aebaSBarry Smith   Notes:
2235dce8aebaSBarry 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.
2236f9244615SMatthew G. Knepley 
2237dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2238f9244615SMatthew G. Knepley 
2239dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2240f9244615SMatthew G. Knepley @*/
2241d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2242d71ae5a4SJacob Faibussowitsch {
2243f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2244f9244615SMatthew G. Knepley   PetscInt                    k;
2245f9244615SMatthew G. Knepley 
2246f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2247f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2248f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2249dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
2250f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2251f9244615SMatthew G. Knepley      This determines their transformation properties. */
22529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22539371c9d4SSatish Balay   switch (k) {
2254d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2255d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2256d71ae5a4SJacob Faibussowitsch     break;
2257d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2258d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2259d71ae5a4SJacob Faibussowitsch     break;
2260f9244615SMatthew G. Knepley   case 2:
2261d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2262d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2263d71ae5a4SJacob Faibussowitsch     break;
2264d71ae5a4SJacob Faibussowitsch   default:
2265d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2266f9244615SMatthew G. Knepley   }
22679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2269f9244615SMatthew G. Knepley }
2270