xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision bfe80ac4a46d58cb7760074b25f5e81b2f541d8a)
120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
220cf1dd8SToby Isaac #include <petscdmplex.h>
320cf1dd8SToby Isaac 
420cf1dd8SToby Isaac PetscClassId PETSCDUALSPACE_CLASSID = 0;
520cf1dd8SToby Isaac 
6ead873ccSMatthew G. Knepley PetscLogEvent PETSCDUALSPACE_SetUp;
7ead873ccSMatthew G. Knepley 
820cf1dd8SToby Isaac PetscFunctionList PetscDualSpaceList              = NULL;
920cf1dd8SToby Isaac PetscBool         PetscDualSpaceRegisterAllCalled = PETSC_FALSE;
1020cf1dd8SToby Isaac 
116f905325SMatthew G. Knepley /*
126f905325SMatthew G. Knepley   PetscDualSpaceLatticePointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to at most 'max'.
136f905325SMatthew G. Knepley                                                      Ordering is lexicographic with lowest index as least significant in ordering.
14b4457527SToby Isaac                                                      e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {0,2}.
156f905325SMatthew G. Knepley 
166f905325SMatthew G. Knepley   Input Parameters:
176f905325SMatthew G. Knepley + len - The length of the tuple
186f905325SMatthew G. Knepley . max - The maximum sum
196f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
206f905325SMatthew G. Knepley 
216f905325SMatthew G. Knepley   Output Parameter:
2220f4b53cSBarry Smith . tup - A tuple of `len` integers whose sum is at most `max`
236f905325SMatthew G. Knepley 
246f905325SMatthew G. Knepley   Level: developer
256f905325SMatthew G. Knepley 
26dce8aebaSBarry Smith .seealso: `PetscDualSpaceType`, `PetscDualSpaceTensorPointLexicographic_Internal()`
276f905325SMatthew G. Knepley */
28d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceLatticePointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[])
29d71ae5a4SJacob Faibussowitsch {
306f905325SMatthew G. Knepley   PetscFunctionBegin;
316f905325SMatthew G. Knepley   while (len--) {
326f905325SMatthew G. Knepley     max -= tup[len];
336f905325SMatthew G. Knepley     if (!max) {
346f905325SMatthew G. Knepley       tup[len] = 0;
356f905325SMatthew G. Knepley       break;
366f905325SMatthew G. Knepley     }
376f905325SMatthew G. Knepley   }
386f905325SMatthew G. Knepley   tup[++len]++;
393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
406f905325SMatthew G. Knepley }
416f905325SMatthew G. Knepley 
426f905325SMatthew G. Knepley /*
436f905325SMatthew G. Knepley   PetscDualSpaceTensorPointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max'.
446f905325SMatthew G. Knepley                                                     Ordering is lexicographic with lowest index as least significant in ordering.
456f905325SMatthew G. Knepley                                                     e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}.
466f905325SMatthew G. Knepley 
476f905325SMatthew G. Knepley   Input Parameters:
486f905325SMatthew G. Knepley + len - The length of the tuple
496f905325SMatthew G. Knepley . max - The maximum value
506f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
516f905325SMatthew G. Knepley 
526f905325SMatthew G. Knepley   Output Parameter:
5320f4b53cSBarry Smith . tup - A tuple of `len` integers whose entries are at most `max`
546f905325SMatthew G. Knepley 
556f905325SMatthew G. Knepley   Level: developer
566f905325SMatthew G. Knepley 
57dce8aebaSBarry Smith .seealso: `PetscDualSpaceType`, `PetscDualSpaceLatticePointLexicographic_Internal()`
586f905325SMatthew G. Knepley */
59d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTensorPointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[])
60d71ae5a4SJacob Faibussowitsch {
616f905325SMatthew G. Knepley   PetscInt i;
626f905325SMatthew G. Knepley 
636f905325SMatthew G. Knepley   PetscFunctionBegin;
646f905325SMatthew G. Knepley   for (i = 0; i < len; i++) {
656f905325SMatthew G. Knepley     if (tup[i] < max) {
666f905325SMatthew G. Knepley       break;
676f905325SMatthew G. Knepley     } else {
686f905325SMatthew G. Knepley       tup[i] = 0;
696f905325SMatthew G. Knepley     }
706f905325SMatthew G. Knepley   }
716f905325SMatthew G. Knepley   tup[i]++;
723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
736f905325SMatthew G. Knepley }
746f905325SMatthew G. Knepley 
7520cf1dd8SToby Isaac /*@C
76dce8aebaSBarry Smith   PetscDualSpaceRegister - Adds a new `PetscDualSpaceType`
7720cf1dd8SToby Isaac 
78cc4c1da9SBarry Smith   Not Collective, No Fortran Support
7920cf1dd8SToby Isaac 
8020cf1dd8SToby Isaac   Input Parameters:
812fe279fdSBarry Smith + sname    - The name of a new user-defined creation routine
822fe279fdSBarry Smith - function - The creation routine
8320cf1dd8SToby Isaac 
8460225df5SJacob Faibussowitsch   Example Usage:
8520cf1dd8SToby Isaac .vb
8620cf1dd8SToby Isaac     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
8720cf1dd8SToby Isaac .ve
8820cf1dd8SToby Isaac 
8920cf1dd8SToby Isaac   Then, your PetscDualSpace type can be chosen with the procedural interface via
9020cf1dd8SToby Isaac .vb
9120cf1dd8SToby Isaac     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
9220cf1dd8SToby Isaac     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
9320cf1dd8SToby Isaac .ve
9420cf1dd8SToby Isaac   or at runtime via the option
9520cf1dd8SToby Isaac .vb
9620cf1dd8SToby Isaac     -petscdualspace_type my_dual_space
9720cf1dd8SToby Isaac .ve
9820cf1dd8SToby Isaac 
9920cf1dd8SToby Isaac   Level: advanced
10020cf1dd8SToby Isaac 
101dce8aebaSBarry Smith   Note:
102dce8aebaSBarry Smith   `PetscDualSpaceRegister()` may be called multiple times to add several user-defined `PetscDualSpace`
10320cf1dd8SToby Isaac 
104dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceRegisterAll()`, `PetscDualSpaceRegisterDestroy()`
10520cf1dd8SToby Isaac @*/
106d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace))
107d71ae5a4SJacob Faibussowitsch {
10820cf1dd8SToby Isaac   PetscFunctionBegin;
1099566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PetscDualSpaceList, sname, function));
1103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11120cf1dd8SToby Isaac }
11220cf1dd8SToby Isaac 
11326a11704SBarry Smith /*@C
114dce8aebaSBarry Smith   PetscDualSpaceSetType - Builds a particular `PetscDualSpace` based on its `PetscDualSpaceType`
11520cf1dd8SToby Isaac 
11620f4b53cSBarry Smith   Collective
11720cf1dd8SToby Isaac 
11820cf1dd8SToby Isaac   Input Parameters:
119dce8aebaSBarry Smith + sp   - The `PetscDualSpace` object
12020cf1dd8SToby Isaac - name - The kind of space
12120cf1dd8SToby Isaac 
12220cf1dd8SToby Isaac   Options Database Key:
12320cf1dd8SToby Isaac . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types
12420cf1dd8SToby Isaac 
12520cf1dd8SToby Isaac   Level: intermediate
12620cf1dd8SToby Isaac 
127dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceGetType()`, `PetscDualSpaceCreate()`
12820cf1dd8SToby Isaac @*/
129d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name)
130d71ae5a4SJacob Faibussowitsch {
13120cf1dd8SToby Isaac   PetscErrorCode (*r)(PetscDualSpace);
13220cf1dd8SToby Isaac   PetscBool match;
13320cf1dd8SToby Isaac 
13420cf1dd8SToby Isaac   PetscFunctionBegin;
13520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1369566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)sp, name, &match));
1373ba16761SJacob Faibussowitsch   if (match) PetscFunctionReturn(PETSC_SUCCESS);
13820cf1dd8SToby Isaac 
1399566063dSJacob Faibussowitsch   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
1409566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PetscDualSpaceList, name, &r));
14128b400f6SJacob Faibussowitsch   PetscCheck(r, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name);
14220cf1dd8SToby Isaac 
143dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, destroy);
14420cf1dd8SToby Isaac   sp->ops->destroy = NULL;
145dbbe0bcdSBarry Smith 
1469566063dSJacob Faibussowitsch   PetscCall((*r)(sp));
1479566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)sp, name));
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14920cf1dd8SToby Isaac }
15020cf1dd8SToby Isaac 
15126a11704SBarry Smith /*@C
152dce8aebaSBarry Smith   PetscDualSpaceGetType - Gets the `PetscDualSpaceType` name (as a string) from the object.
15320cf1dd8SToby Isaac 
15420cf1dd8SToby Isaac   Not Collective
15520cf1dd8SToby Isaac 
15620cf1dd8SToby Isaac   Input Parameter:
157dce8aebaSBarry Smith . sp - The `PetscDualSpace`
15820cf1dd8SToby Isaac 
15920cf1dd8SToby Isaac   Output Parameter:
160dce8aebaSBarry Smith . name - The `PetscDualSpaceType` name
16120cf1dd8SToby Isaac 
16220cf1dd8SToby Isaac   Level: intermediate
16320cf1dd8SToby Isaac 
164dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceSetType()`, `PetscDualSpaceCreate()`
16520cf1dd8SToby Isaac @*/
166d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name)
167d71ae5a4SJacob Faibussowitsch {
16820cf1dd8SToby Isaac   PetscFunctionBegin;
16920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1704f572ea9SToby Isaac   PetscAssertPointer(name, 2);
17148a46eb9SPierre Jolivet   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
17220cf1dd8SToby Isaac   *name = ((PetscObject)sp)->type_name;
1733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17420cf1dd8SToby Isaac }
17520cf1dd8SToby Isaac 
176d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceView_ASCII(PetscDualSpace sp, PetscViewer v)
177d71ae5a4SJacob Faibussowitsch {
178221d6281SMatthew G. Knepley   PetscViewerFormat format;
179221d6281SMatthew G. Knepley   PetscInt          pdim, f;
180221d6281SMatthew G. Knepley 
181221d6281SMatthew G. Knepley   PetscFunctionBegin;
1829566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &pdim));
1839566063dSJacob Faibussowitsch   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sp, v));
1849566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(v));
1852dce792eSToby Isaac   if (sp->k != 0 && sp->k != PETSC_FORM_DEGREE_UNDEFINED) {
18663a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space for %" PetscInt_FMT "-forms %swith %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", PetscAbsInt(sp->k), sp->k < 0 ? "(stored in dual form) " : "", sp->Nc, pdim));
187b4457527SToby Isaac   } else {
18863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space with %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", sp->Nc, pdim));
189b4457527SToby Isaac   }
190dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, view, v);
1919566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(v, &format));
192221d6281SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1939566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(v));
194221d6281SMatthew G. Knepley     for (f = 0; f < pdim; ++f) {
19563a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(v, "Dual basis vector %" PetscInt_FMT "\n", f));
1969566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(v));
1979566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureView(sp->functional[f], v));
1989566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(v));
199221d6281SMatthew G. Knepley     }
2009566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(v));
201221d6281SMatthew G. Knepley   }
2029566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
2033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
204221d6281SMatthew G. Knepley }
205221d6281SMatthew G. Knepley 
20626a11704SBarry Smith /*@C
207dce8aebaSBarry Smith   PetscDualSpaceViewFromOptions - View a `PetscDualSpace` based on values in the options database
208fe2efc57SMark 
20920f4b53cSBarry Smith   Collective
210fe2efc57SMark 
211fe2efc57SMark   Input Parameters:
212dce8aebaSBarry Smith + A    - the `PetscDualSpace` object
213dce8aebaSBarry Smith . obj  - Optional object, provides the options prefix
214dce8aebaSBarry Smith - name - command line option name
215fe2efc57SMark 
216fe2efc57SMark   Level: intermediate
217dce8aebaSBarry Smith 
21820f4b53cSBarry Smith   Note:
21920f4b53cSBarry Smith   See `PetscObjectViewFromOptions()` for possible command line values
22020f4b53cSBarry Smith 
221db781477SPatrick Sanan .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()`
222fe2efc57SMark @*/
223ce78bad3SBarry Smith PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PeOp PetscObject obj, const char name[])
224d71ae5a4SJacob Faibussowitsch {
225fe2efc57SMark   PetscFunctionBegin;
226fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
2279566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
2283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
229fe2efc57SMark }
230fe2efc57SMark 
23126a11704SBarry Smith /*@C
232dce8aebaSBarry Smith   PetscDualSpaceView - Views a `PetscDualSpace`
23320cf1dd8SToby Isaac 
23420f4b53cSBarry Smith   Collective
23520cf1dd8SToby Isaac 
236d8d19677SJose E. Roman   Input Parameters:
237dce8aebaSBarry Smith + sp - the `PetscDualSpace` object to view
23820cf1dd8SToby Isaac - v  - the viewer
23920cf1dd8SToby Isaac 
240a4ce7ad1SMatthew G. Knepley   Level: beginner
24120cf1dd8SToby Isaac 
242dce8aebaSBarry Smith .seealso: `PetscViewer`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
24320cf1dd8SToby Isaac @*/
244d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
245d71ae5a4SJacob Faibussowitsch {
246d9bac1caSLisandro Dalcin   PetscBool iascii;
24720cf1dd8SToby Isaac 
24820cf1dd8SToby Isaac   PetscFunctionBegin;
24920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
250d9bac1caSLisandro Dalcin   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
2519566063dSJacob Faibussowitsch   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v));
2529566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
2539566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v));
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25520cf1dd8SToby Isaac }
25620cf1dd8SToby Isaac 
25726a11704SBarry Smith /*@C
258dce8aebaSBarry Smith   PetscDualSpaceSetFromOptions - sets parameters in a `PetscDualSpace` from the options database
25920cf1dd8SToby Isaac 
26020f4b53cSBarry Smith   Collective
26120cf1dd8SToby Isaac 
26220cf1dd8SToby Isaac   Input Parameter:
263dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to set options for
26420cf1dd8SToby Isaac 
265dce8aebaSBarry Smith   Options Database Keys:
2668f2aacc6SMatthew G. Knepley + -petscdualspace_order <order>                 - the approximation order of the space
267fe36a153SMatthew G. Knepley . -petscdualspace_form_degree <deg>             - the form degree, say 0 for point evaluations, or 2 for area integrals
2688f2aacc6SMatthew G. Knepley . -petscdualspace_components <c>                - the number of components, say d for a vector field
269a9c5e6deSMatthew G. Knepley . -petscdualspace_refcell <celltype>            - Reference cell type name
270a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_continuity           - Flag for continuous element
271a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_tensor               - Flag for tensor dual space
272a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_trimmed              - Flag for trimmed dual space
273a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_type <nodetype> - Lagrange node location type
274a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_endpoints       - Flag for nodes that include endpoints
275a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_node_exponent        - Gauss-Jacobi weight function exponent
276a9c5e6deSMatthew G. Knepley . -petscdualspace_lagrange_use_moments          - Use moments (where appropriate) for functionals
277a9c5e6deSMatthew G. Knepley - -petscdualspace_lagrange_moment_order <order> - Quadrature order for moment functionals
27820cf1dd8SToby Isaac 
279a4ce7ad1SMatthew G. Knepley   Level: intermediate
28020cf1dd8SToby Isaac 
281dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()`
28220cf1dd8SToby Isaac @*/
283d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
284d71ae5a4SJacob Faibussowitsch {
2852df84da0SMatthew G. Knepley   DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE;
28620cf1dd8SToby Isaac   const char    *defaultType;
28720cf1dd8SToby Isaac   char           name[256];
288f783ec47SMatthew G. Knepley   PetscBool      flg;
28920cf1dd8SToby Isaac 
29020cf1dd8SToby Isaac   PetscFunctionBegin;
29120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
29220cf1dd8SToby Isaac   if (!((PetscObject)sp)->type_name) {
29320cf1dd8SToby Isaac     defaultType = PETSCDUALSPACELAGRANGE;
29420cf1dd8SToby Isaac   } else {
29520cf1dd8SToby Isaac     defaultType = ((PetscObject)sp)->type_name;
29620cf1dd8SToby Isaac   }
2979566063dSJacob Faibussowitsch   if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll());
29820cf1dd8SToby Isaac 
299d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sp);
3009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg));
30120cf1dd8SToby Isaac   if (flg) {
3029566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, name));
30320cf1dd8SToby Isaac   } else if (!((PetscObject)sp)->type_name) {
3049566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, defaultType));
30520cf1dd8SToby Isaac   }
3069566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0));
3079566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL));
3089566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1));
309dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject);
3109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg));
311063ee4adSMatthew G. Knepley   if (flg) {
312063ee4adSMatthew G. Knepley     DM K;
313063ee4adSMatthew G. Knepley 
3149566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K));
3159566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetDM(sp, K));
3169566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&K));
317063ee4adSMatthew G. Knepley   }
318063ee4adSMatthew G. Knepley 
31920cf1dd8SToby Isaac   /* process any options handlers added with PetscObjectAddOptionsHandler() */
320dbbe0bcdSBarry Smith   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject));
321d0609cedSBarry Smith   PetscOptionsEnd();
322063ee4adSMatthew G. Knepley   sp->setfromoptionscalled = PETSC_TRUE;
3233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32420cf1dd8SToby Isaac }
32520cf1dd8SToby Isaac 
32626a11704SBarry Smith /*@C
327dce8aebaSBarry Smith   PetscDualSpaceSetUp - Construct a basis for a `PetscDualSpace`
32820cf1dd8SToby Isaac 
32920f4b53cSBarry Smith   Collective
33020cf1dd8SToby Isaac 
33120cf1dd8SToby Isaac   Input Parameter:
332dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to setup
33320cf1dd8SToby Isaac 
334a4ce7ad1SMatthew G. Knepley   Level: intermediate
33520cf1dd8SToby Isaac 
336dce8aebaSBarry Smith .seealso: `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
33720cf1dd8SToby Isaac @*/
338d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
339d71ae5a4SJacob Faibussowitsch {
34020cf1dd8SToby Isaac   PetscFunctionBegin;
34120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
3423ba16761SJacob Faibussowitsch   if (sp->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
3439566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
34420cf1dd8SToby Isaac   sp->setupcalled = PETSC_TRUE;
345dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setup);
3469566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
3479566063dSJacob Faibussowitsch   if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view"));
3483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34920cf1dd8SToby Isaac }
35020cf1dd8SToby Isaac 
351d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm)
352d71ae5a4SJacob Faibussowitsch {
353b4457527SToby Isaac   PetscInt pStart = -1, pEnd = -1, depth = -1;
354b4457527SToby Isaac 
355b4457527SToby Isaac   PetscFunctionBegin;
3563ba16761SJacob Faibussowitsch   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
3579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
359b4457527SToby Isaac 
360b4457527SToby Isaac   if (sp->pointSpaces) {
361b4457527SToby Isaac     PetscInt i;
362b4457527SToby Isaac 
363f4f49eeaSPierre Jolivet     for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&sp->pointSpaces[i]));
364b4457527SToby Isaac   }
3659566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->pointSpaces));
366b4457527SToby Isaac 
367b4457527SToby Isaac   if (sp->heightSpaces) {
368b4457527SToby Isaac     PetscInt i;
369b4457527SToby Isaac 
370f4f49eeaSPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&sp->heightSpaces[i]));
371b4457527SToby Isaac   }
3729566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
373b4457527SToby Isaac 
374f4f49eeaSPierre Jolivet   PetscCall(PetscSectionDestroy(&sp->pointSection));
375f4f49eeaSPierre Jolivet   PetscCall(PetscSectionDestroy(&sp->intPointSection));
376f4f49eeaSPierre Jolivet   PetscCall(PetscQuadratureDestroy(&sp->intNodes));
377f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->intDofValues));
378f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->intNodeValues));
379f4f49eeaSPierre Jolivet   PetscCall(MatDestroy(&sp->intMat));
380f4f49eeaSPierre Jolivet   PetscCall(PetscQuadratureDestroy(&sp->allNodes));
381f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->allDofValues));
382f4f49eeaSPierre Jolivet   PetscCall(VecDestroy(&sp->allNodeValues));
383f4f49eeaSPierre Jolivet   PetscCall(MatDestroy(&sp->allMat));
3849566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
3853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
386b4457527SToby Isaac }
387b4457527SToby Isaac 
38826a11704SBarry Smith /*@C
389dce8aebaSBarry Smith   PetscDualSpaceDestroy - Destroys a `PetscDualSpace` object
39020cf1dd8SToby Isaac 
39120f4b53cSBarry Smith   Collective
39220cf1dd8SToby Isaac 
39320cf1dd8SToby Isaac   Input Parameter:
394dce8aebaSBarry Smith . sp - the `PetscDualSpace` object to destroy
39520cf1dd8SToby Isaac 
396a4ce7ad1SMatthew G. Knepley   Level: beginner
39720cf1dd8SToby Isaac 
398dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
39920cf1dd8SToby Isaac @*/
400d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
401d71ae5a4SJacob Faibussowitsch {
40220cf1dd8SToby Isaac   PetscInt dim, f;
403b4457527SToby Isaac   DM       dm;
40420cf1dd8SToby Isaac 
40520cf1dd8SToby Isaac   PetscFunctionBegin;
4063ba16761SJacob Faibussowitsch   if (!*sp) PetscFunctionReturn(PETSC_SUCCESS);
407f4f49eeaSPierre Jolivet   PetscValidHeaderSpecific(*sp, PETSCDUALSPACE_CLASSID, 1);
40820cf1dd8SToby Isaac 
409f4f49eeaSPierre Jolivet   if (--((PetscObject)*sp)->refct > 0) {
4109371c9d4SSatish Balay     *sp = NULL;
4113ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
4129371c9d4SSatish Balay   }
413f4f49eeaSPierre Jolivet   ((PetscObject)*sp)->refct = 0;
41420cf1dd8SToby Isaac 
4159566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
416b4457527SToby Isaac   dm = (*sp)->dm;
417b4457527SToby Isaac 
418f4f49eeaSPierre Jolivet   PetscTryTypeMethod(*sp, destroy);
4199566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
420b4457527SToby Isaac 
42148a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
4239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4249566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
4253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42620cf1dd8SToby Isaac }
42720cf1dd8SToby Isaac 
42826a11704SBarry Smith /*@C
429dce8aebaSBarry Smith   PetscDualSpaceCreate - Creates an empty `PetscDualSpace` object. The type can then be set with `PetscDualSpaceSetType()`.
43020cf1dd8SToby Isaac 
431d083f849SBarry Smith   Collective
43220cf1dd8SToby Isaac 
43320cf1dd8SToby Isaac   Input Parameter:
434dce8aebaSBarry Smith . comm - The communicator for the `PetscDualSpace` object
43520cf1dd8SToby Isaac 
43620cf1dd8SToby Isaac   Output Parameter:
437dce8aebaSBarry Smith . sp - The `PetscDualSpace` object
43820cf1dd8SToby Isaac 
43920cf1dd8SToby Isaac   Level: beginner
44020cf1dd8SToby Isaac 
441dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
44220cf1dd8SToby Isaac @*/
443d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
444d71ae5a4SJacob Faibussowitsch {
44520cf1dd8SToby Isaac   PetscDualSpace s;
44620cf1dd8SToby Isaac 
44720cf1dd8SToby Isaac   PetscFunctionBegin;
4484f572ea9SToby Isaac   PetscAssertPointer(sp, 2);
4499566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
4509566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
45120cf1dd8SToby Isaac 
4529566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
45320cf1dd8SToby Isaac   s->order       = 0;
45420cf1dd8SToby Isaac   s->Nc          = 1;
4554bee2e38SMatthew G. Knepley   s->k           = 0;
456b4457527SToby Isaac   s->spdim       = -1;
457b4457527SToby Isaac   s->spintdim    = -1;
458b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
45920cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
46020cf1dd8SToby Isaac   *sp            = s;
4613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46220cf1dd8SToby Isaac }
46320cf1dd8SToby Isaac 
46426a11704SBarry Smith /*@C
465dce8aebaSBarry Smith   PetscDualSpaceDuplicate - Creates a duplicate `PetscDualSpace` object that is not setup.
46620cf1dd8SToby Isaac 
46720f4b53cSBarry Smith   Collective
46820cf1dd8SToby Isaac 
46920cf1dd8SToby Isaac   Input Parameter:
470dce8aebaSBarry Smith . sp - The original `PetscDualSpace`
47120cf1dd8SToby Isaac 
47220cf1dd8SToby Isaac   Output Parameter:
473dce8aebaSBarry Smith . spNew - The duplicate `PetscDualSpace`
47420cf1dd8SToby Isaac 
47520cf1dd8SToby Isaac   Level: beginner
47620cf1dd8SToby Isaac 
477dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
47820cf1dd8SToby Isaac @*/
479d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
480d71ae5a4SJacob Faibussowitsch {
481b4457527SToby Isaac   DM                 dm;
482b4457527SToby Isaac   PetscDualSpaceType type;
483b4457527SToby Isaac   const char        *name;
48420cf1dd8SToby Isaac 
48520cf1dd8SToby Isaac   PetscFunctionBegin;
48620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
4874f572ea9SToby Isaac   PetscAssertPointer(spNew, 2);
4889566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4892dce792eSToby Isaac   name = ((PetscObject)sp)->name;
4902dce792eSToby Isaac   if (name) { PetscCall(PetscObjectSetName((PetscObject)*spNew, name)); }
4919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4929566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4939566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4949566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
495b4457527SToby Isaac 
496b4457527SToby Isaac   (*spNew)->order   = sp->order;
497b4457527SToby Isaac   (*spNew)->k       = sp->k;
498b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
499b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
500dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
5013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50220cf1dd8SToby Isaac }
50320cf1dd8SToby Isaac 
50426a11704SBarry Smith /*@C
505dce8aebaSBarry Smith   PetscDualSpaceGetDM - Get the `DM` representing the reference cell of a `PetscDualSpace`
50620cf1dd8SToby Isaac 
50720f4b53cSBarry Smith   Not Collective
50820cf1dd8SToby Isaac 
50920cf1dd8SToby Isaac   Input Parameter:
510dce8aebaSBarry Smith . sp - The `PetscDualSpace`
51120cf1dd8SToby Isaac 
51220cf1dd8SToby Isaac   Output Parameter:
513dce8aebaSBarry Smith . dm - The reference cell, that is a `DM` that consists of a single cell
51420cf1dd8SToby Isaac 
51520cf1dd8SToby Isaac   Level: intermediate
51620cf1dd8SToby Isaac 
517dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
51820cf1dd8SToby Isaac @*/
519d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
520d71ae5a4SJacob Faibussowitsch {
52120cf1dd8SToby Isaac   PetscFunctionBegin;
52220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
5234f572ea9SToby Isaac   PetscAssertPointer(dm, 2);
52420cf1dd8SToby Isaac   *dm = sp->dm;
5253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52620cf1dd8SToby Isaac }
52720cf1dd8SToby Isaac 
52826a11704SBarry Smith /*@C
529dce8aebaSBarry Smith   PetscDualSpaceSetDM - Get the `DM` representing the reference cell
53020cf1dd8SToby Isaac 
53120f4b53cSBarry Smith   Not Collective
53220cf1dd8SToby Isaac 
53320cf1dd8SToby Isaac   Input Parameters:
534dce8aebaSBarry Smith + sp - The `PetscDual`Space
53520cf1dd8SToby Isaac - dm - The reference cell
53620cf1dd8SToby Isaac 
53720cf1dd8SToby Isaac   Level: intermediate
53820cf1dd8SToby Isaac 
539dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `DM`, `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
54020cf1dd8SToby Isaac @*/
541d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
542d71ae5a4SJacob Faibussowitsch {
54320cf1dd8SToby Isaac   PetscFunctionBegin;
54420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
54520cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
54628b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5479566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
54848a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5499566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
55020cf1dd8SToby Isaac   sp->dm = dm;
5513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55220cf1dd8SToby Isaac }
55320cf1dd8SToby Isaac 
55426a11704SBarry Smith /*@C
55520cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
55620cf1dd8SToby Isaac 
55720f4b53cSBarry Smith   Not Collective
55820cf1dd8SToby Isaac 
55920cf1dd8SToby Isaac   Input Parameter:
560dce8aebaSBarry Smith . sp - The `PetscDualSpace`
56120cf1dd8SToby Isaac 
56220cf1dd8SToby Isaac   Output Parameter:
56320cf1dd8SToby Isaac . order - The order
56420cf1dd8SToby Isaac 
56520cf1dd8SToby Isaac   Level: intermediate
56620cf1dd8SToby Isaac 
567dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
56820cf1dd8SToby Isaac @*/
569d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
570d71ae5a4SJacob Faibussowitsch {
57120cf1dd8SToby Isaac   PetscFunctionBegin;
57220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
5734f572ea9SToby Isaac   PetscAssertPointer(order, 2);
57420cf1dd8SToby Isaac   *order = sp->order;
5753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57620cf1dd8SToby Isaac }
57720cf1dd8SToby Isaac 
57826a11704SBarry Smith /*@C
57920cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
58020cf1dd8SToby Isaac 
58120f4b53cSBarry Smith   Not Collective
58220cf1dd8SToby Isaac 
58320cf1dd8SToby Isaac   Input Parameters:
584dce8aebaSBarry Smith + sp    - The `PetscDualSpace`
58520cf1dd8SToby Isaac - order - The order
58620cf1dd8SToby Isaac 
58720cf1dd8SToby Isaac   Level: intermediate
58820cf1dd8SToby Isaac 
589dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
59020cf1dd8SToby Isaac @*/
591d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
592d71ae5a4SJacob Faibussowitsch {
59320cf1dd8SToby Isaac   PetscFunctionBegin;
59420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
59528b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
59620cf1dd8SToby Isaac   sp->order = order;
5973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59820cf1dd8SToby Isaac }
59920cf1dd8SToby Isaac 
60026a11704SBarry Smith /*@C
60120cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
60220cf1dd8SToby Isaac 
60320cf1dd8SToby Isaac   Input Parameter:
604dce8aebaSBarry Smith . sp - The `PetscDualSpace`
60520cf1dd8SToby Isaac 
60620cf1dd8SToby Isaac   Output Parameter:
60720cf1dd8SToby Isaac . Nc - The number of components
60820cf1dd8SToby Isaac 
60920cf1dd8SToby Isaac   Level: intermediate
61020cf1dd8SToby Isaac 
611dce8aebaSBarry Smith   Note:
612dce8aebaSBarry Smith   A vector space, for example, will have d components, where d is the spatial dimension
613dce8aebaSBarry Smith 
614db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
61520cf1dd8SToby Isaac @*/
616d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
617d71ae5a4SJacob Faibussowitsch {
61820cf1dd8SToby Isaac   PetscFunctionBegin;
61920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
6204f572ea9SToby Isaac   PetscAssertPointer(Nc, 2);
62120cf1dd8SToby Isaac   *Nc = sp->Nc;
6223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
62320cf1dd8SToby Isaac }
62420cf1dd8SToby Isaac 
62526a11704SBarry Smith /*@C
62620cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
62720cf1dd8SToby Isaac 
62820cf1dd8SToby Isaac   Input Parameters:
629dce8aebaSBarry Smith + sp - The `PetscDualSpace`
63060225df5SJacob Faibussowitsch - Nc - The number of components
63120cf1dd8SToby Isaac 
63220cf1dd8SToby Isaac   Level: intermediate
63320cf1dd8SToby Isaac 
634db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
63520cf1dd8SToby Isaac @*/
636d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
637d71ae5a4SJacob Faibussowitsch {
63820cf1dd8SToby Isaac   PetscFunctionBegin;
63920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
64028b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
64120cf1dd8SToby Isaac   sp->Nc = Nc;
6423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
64320cf1dd8SToby Isaac }
64420cf1dd8SToby Isaac 
64526a11704SBarry Smith /*@C
64620cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
64720cf1dd8SToby Isaac 
64820f4b53cSBarry Smith   Not Collective
64920cf1dd8SToby Isaac 
65020cf1dd8SToby Isaac   Input Parameters:
651dce8aebaSBarry Smith + sp - The `PetscDualSpace`
65220cf1dd8SToby Isaac - i  - The basis number
65320cf1dd8SToby Isaac 
65420cf1dd8SToby Isaac   Output Parameter:
65520cf1dd8SToby Isaac . functional - The basis functional
65620cf1dd8SToby Isaac 
65720cf1dd8SToby Isaac   Level: intermediate
65820cf1dd8SToby Isaac 
659dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
66020cf1dd8SToby Isaac @*/
661d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
662d71ae5a4SJacob Faibussowitsch {
66320cf1dd8SToby Isaac   PetscInt dim;
66420cf1dd8SToby Isaac 
66520cf1dd8SToby Isaac   PetscFunctionBegin;
66620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
6674f572ea9SToby Isaac   PetscAssertPointer(functional, 3);
6689566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
66963a3b9bcSJacob 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);
67020cf1dd8SToby Isaac   *functional = sp->functional[i];
6713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
67220cf1dd8SToby Isaac }
67320cf1dd8SToby Isaac 
67426a11704SBarry Smith /*@C
67520cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
67620cf1dd8SToby Isaac 
67720f4b53cSBarry Smith   Not Collective
67820cf1dd8SToby Isaac 
67920cf1dd8SToby Isaac   Input Parameter:
680dce8aebaSBarry Smith . sp - The `PetscDualSpace`
68120cf1dd8SToby Isaac 
68220cf1dd8SToby Isaac   Output Parameter:
68320cf1dd8SToby Isaac . dim - The dimension
68420cf1dd8SToby Isaac 
68520cf1dd8SToby Isaac   Level: intermediate
68620cf1dd8SToby Isaac 
687dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
68820cf1dd8SToby Isaac @*/
689d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
690d71ae5a4SJacob Faibussowitsch {
69120cf1dd8SToby Isaac   PetscFunctionBegin;
69220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
6934f572ea9SToby Isaac   PetscAssertPointer(dim, 2);
694b4457527SToby Isaac   if (sp->spdim < 0) {
695b4457527SToby Isaac     PetscSection section;
696b4457527SToby Isaac 
6979566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
698b4457527SToby Isaac     if (section) {
699f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetStorageSize(section, &sp->spdim));
700b4457527SToby Isaac     } else sp->spdim = 0;
701b4457527SToby Isaac   }
702b4457527SToby Isaac   *dim = sp->spdim;
7033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70420cf1dd8SToby Isaac }
70520cf1dd8SToby Isaac 
70626a11704SBarry Smith /*@C
707b4457527SToby 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
708b4457527SToby Isaac 
70920f4b53cSBarry Smith   Not Collective
710b4457527SToby Isaac 
711b4457527SToby Isaac   Input Parameter:
712dce8aebaSBarry Smith . sp - The `PetscDualSpace`
713b4457527SToby Isaac 
714b4457527SToby Isaac   Output Parameter:
71560225df5SJacob Faibussowitsch . intdim - The dimension
716b4457527SToby Isaac 
717b4457527SToby Isaac   Level: intermediate
718b4457527SToby Isaac 
719dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
720b4457527SToby Isaac @*/
721d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim)
722d71ae5a4SJacob Faibussowitsch {
723b4457527SToby Isaac   PetscFunctionBegin;
724b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7254f572ea9SToby Isaac   PetscAssertPointer(intdim, 2);
726b4457527SToby Isaac   if (sp->spintdim < 0) {
727b4457527SToby Isaac     PetscSection section;
728b4457527SToby Isaac 
7299566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
730b4457527SToby Isaac     if (section) {
731f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetConstrainedStorageSize(section, &sp->spintdim));
732b4457527SToby Isaac     } else sp->spintdim = 0;
733b4457527SToby Isaac   }
734b4457527SToby Isaac   *intdim = sp->spintdim;
7353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
736b4457527SToby Isaac }
737b4457527SToby Isaac 
73826a11704SBarry Smith /*@C
739b4457527SToby Isaac   PetscDualSpaceGetUniform - Whether this dual space is uniform
740b4457527SToby Isaac 
74120f4b53cSBarry Smith   Not Collective
742b4457527SToby Isaac 
7432fe279fdSBarry Smith   Input Parameter:
744b4457527SToby Isaac . sp - A dual space
745b4457527SToby Isaac 
7462fe279fdSBarry Smith   Output Parameter:
747dce8aebaSBarry Smith . uniform - `PETSC_TRUE` if (a) the dual space is the same for each point in a stratum of the reference `DMPLEX`, and
748dce8aebaSBarry Smith              (b) every symmetry of each point in the reference `DMPLEX` is also a symmetry of the point's dual space.
749b4457527SToby Isaac 
750b4457527SToby Isaac   Level: advanced
751b4457527SToby Isaac 
752dce8aebaSBarry Smith   Note:
753dce8aebaSBarry Smith   All of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
754b4457527SToby Isaac   with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
755b4457527SToby Isaac 
756dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
757b4457527SToby Isaac @*/
758d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform)
759d71ae5a4SJacob Faibussowitsch {
760b4457527SToby Isaac   PetscFunctionBegin;
761b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7624f572ea9SToby Isaac   PetscAssertPointer(uniform, 2);
763b4457527SToby Isaac   *uniform = sp->uniform;
7643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
765b4457527SToby Isaac }
766b4457527SToby Isaac 
76726a11704SBarry Smith /*@CC
76820cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
76920cf1dd8SToby Isaac 
77020f4b53cSBarry Smith   Not Collective
77120cf1dd8SToby Isaac 
77220cf1dd8SToby Isaac   Input Parameter:
773dce8aebaSBarry Smith . sp - The `PetscDualSpace`
77420cf1dd8SToby Isaac 
77520cf1dd8SToby Isaac   Output Parameter:
77620cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
77720cf1dd8SToby Isaac 
77820cf1dd8SToby Isaac   Level: intermediate
77920cf1dd8SToby Isaac 
780f13dfd9eSBarry Smith   Note:
781f13dfd9eSBarry Smith   Do not free `numDof`
782f13dfd9eSBarry Smith 
783dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
78420cf1dd8SToby Isaac @*/
785f13dfd9eSBarry Smith PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt *numDof[])
786d71ae5a4SJacob Faibussowitsch {
78720cf1dd8SToby Isaac   PetscFunctionBegin;
78820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
7894f572ea9SToby Isaac   PetscAssertPointer(numDof, 2);
79028b400f6SJacob 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");
791b4457527SToby Isaac   if (!sp->numDof) {
792b4457527SToby Isaac     DM           dm;
793b4457527SToby Isaac     PetscInt     depth, d;
794b4457527SToby Isaac     PetscSection section;
795b4457527SToby Isaac 
7969566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
7979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
798f4f49eeaSPierre Jolivet     PetscCall(PetscCalloc1(depth + 1, &sp->numDof));
7999566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
800b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
801b4457527SToby Isaac       PetscInt dStart, dEnd;
802b4457527SToby Isaac 
8039566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
804b4457527SToby Isaac       if (dEnd <= dStart) continue;
805f4f49eeaSPierre Jolivet       PetscCall(PetscSectionGetDof(section, dStart, &sp->numDof[d]));
806b4457527SToby Isaac     }
807b4457527SToby Isaac   }
808b4457527SToby Isaac   *numDof = sp->numDof;
80908401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
8103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
81120cf1dd8SToby Isaac }
81220cf1dd8SToby Isaac 
813b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
814d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection)
815d71ae5a4SJacob Faibussowitsch {
816b4457527SToby Isaac   DM           dm;
817b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
818b4457527SToby Isaac   PetscInt    *seen, *perm;
819b4457527SToby Isaac   PetscSection section;
820b4457527SToby Isaac 
821b4457527SToby Isaac   PetscFunctionBegin;
822b4457527SToby Isaac   dm = sp->dm;
8239566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
8249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8259566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8269566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
8279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
8289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
830b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
831b4457527SToby Isaac     PetscInt  closureSize = -1, e;
832b4457527SToby Isaac     PetscInt *closure     = NULL;
833b4457527SToby Isaac 
834b4457527SToby Isaac     perm[count++]    = c;
835b4457527SToby Isaac     seen[c - pStart] = 1;
8369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
837b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
838b4457527SToby Isaac       PetscInt point = closure[2 * e];
839b4457527SToby Isaac 
840b4457527SToby Isaac       if (seen[point - pStart]) continue;
841b4457527SToby Isaac       perm[count++]        = point;
842b4457527SToby Isaac       seen[point - pStart] = 1;
843b4457527SToby Isaac     }
8449566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
845b4457527SToby Isaac   }
8461dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8479371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8489371c9d4SSatish Balay     if (perm[i] != i) break;
849b4457527SToby Isaac   if (i < pEnd - pStart) {
850b4457527SToby Isaac     IS permIS;
851b4457527SToby Isaac 
8529566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8539566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8549566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8559566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
856b4457527SToby Isaac   } else {
8579566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
858b4457527SToby Isaac   }
8599566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
860b4457527SToby Isaac   *topSection = section;
8613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
862b4457527SToby Isaac }
863b4457527SToby Isaac 
864b4457527SToby Isaac /* mark boundary points and set up */
865d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section)
866d71ae5a4SJacob Faibussowitsch {
867b4457527SToby Isaac   DM       dm;
868b4457527SToby Isaac   DMLabel  boundary;
869b4457527SToby Isaac   PetscInt pStart, pEnd, p;
870b4457527SToby Isaac 
871b4457527SToby Isaac   PetscFunctionBegin;
872b4457527SToby Isaac   dm = sp->dm;
8739566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8749566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8759566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8769566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
878b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
879b4457527SToby Isaac     PetscInt bval;
880b4457527SToby Isaac 
8819566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
882b4457527SToby Isaac     if (bval == 1) {
883b4457527SToby Isaac       PetscInt dof;
884b4457527SToby Isaac 
8859566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8869566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
887b4457527SToby Isaac     }
888b4457527SToby Isaac   }
8899566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8909566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
8913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
892b4457527SToby Isaac }
893b4457527SToby Isaac 
89426a11704SBarry Smith /*@C
895dce8aebaSBarry Smith   PetscDualSpaceGetSection - Create a `PetscSection` over the reference cell with the layout from this space
896a4ce7ad1SMatthew G. Knepley 
89720f4b53cSBarry Smith   Collective
898a4ce7ad1SMatthew G. Knepley 
8992fe279fdSBarry Smith   Input Parameter:
900dce8aebaSBarry Smith . sp - The `PetscDualSpace`
901a4ce7ad1SMatthew G. Knepley 
902a4ce7ad1SMatthew G. Knepley   Output Parameter:
903a4ce7ad1SMatthew G. Knepley . section - The section
904a4ce7ad1SMatthew G. Knepley 
905a4ce7ad1SMatthew G. Knepley   Level: advanced
906a4ce7ad1SMatthew G. Knepley 
907dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
908a4ce7ad1SMatthew G. Knepley @*/
909d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section)
910d71ae5a4SJacob Faibussowitsch {
911b4457527SToby Isaac   PetscInt pStart, pEnd, p;
912b4457527SToby Isaac 
913b4457527SToby Isaac   PetscFunctionBegin;
91478f1d139SRomain Beucher   if (!sp->dm) {
91578f1d139SRomain Beucher     *section = NULL;
9163ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
91778f1d139SRomain Beucher   }
918b4457527SToby Isaac   if (!sp->pointSection) {
919b4457527SToby Isaac     /* mark the boundary */
920f4f49eeaSPierre Jolivet     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &sp->pointSection));
9219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
922b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
923b4457527SToby Isaac       PetscDualSpace psp;
924b4457527SToby Isaac 
9259566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
926b4457527SToby Isaac       if (psp) {
927b4457527SToby Isaac         PetscInt dof;
928b4457527SToby Isaac 
9299566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
9309566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
931b4457527SToby Isaac       }
932b4457527SToby Isaac     }
9339566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
934b4457527SToby Isaac   }
935b4457527SToby Isaac   *section = sp->pointSection;
9363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
937b4457527SToby Isaac }
938b4457527SToby Isaac 
93926a11704SBarry Smith /*@C
9402dce792eSToby Isaac   PetscDualSpaceGetInteriorSection - Create a `PetscSection` over the reference cell with the layout from this space
9412dce792eSToby Isaac   for interior degrees of freedom
9422dce792eSToby Isaac 
9432dce792eSToby Isaac   Collective
9442dce792eSToby Isaac 
9452dce792eSToby Isaac   Input Parameter:
9462dce792eSToby Isaac . sp - The `PetscDualSpace`
9472dce792eSToby Isaac 
9482dce792eSToby Isaac   Output Parameter:
9492dce792eSToby Isaac . section - The interior section
9502dce792eSToby Isaac 
9512dce792eSToby Isaac   Level: advanced
9522dce792eSToby Isaac 
9532dce792eSToby Isaac   Note:
9542dce792eSToby Isaac   Most reference domains have one cell, in which case the only cell will have
9552dce792eSToby Isaac   all of the interior degrees of freedom in the interior section.  But
9562dce792eSToby Isaac   for `PETSCDUALSPACEREFINED` there may be other mesh points in the interior,
9572dce792eSToby Isaac   and this section describes their layout.
9582dce792eSToby Isaac 
9592dce792eSToby Isaac .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX`
9602dce792eSToby Isaac @*/
9612dce792eSToby Isaac PetscErrorCode PetscDualSpaceGetInteriorSection(PetscDualSpace sp, PetscSection *section)
9622dce792eSToby Isaac {
9632dce792eSToby Isaac   PetscInt pStart, pEnd, p;
9642dce792eSToby Isaac 
9652dce792eSToby Isaac   PetscFunctionBegin;
9662dce792eSToby Isaac   if (!sp->dm) {
9672dce792eSToby Isaac     *section = NULL;
9682dce792eSToby Isaac     PetscFunctionReturn(PETSC_SUCCESS);
9692dce792eSToby Isaac   }
9702dce792eSToby Isaac   if (!sp->intPointSection) {
9712dce792eSToby Isaac     PetscSection full_section;
9722dce792eSToby Isaac 
9732dce792eSToby Isaac     PetscCall(PetscDualSpaceGetSection(sp, &full_section));
974f4f49eeaSPierre Jolivet     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &sp->intPointSection));
9752dce792eSToby Isaac     PetscCall(PetscSectionGetChart(full_section, &pStart, &pEnd));
9762dce792eSToby Isaac     for (p = pStart; p < pEnd; p++) {
9772dce792eSToby Isaac       PetscInt dof, cdof;
9782dce792eSToby Isaac 
9792dce792eSToby Isaac       PetscCall(PetscSectionGetDof(full_section, p, &dof));
9802dce792eSToby Isaac       PetscCall(PetscSectionGetConstraintDof(full_section, p, &cdof));
9812dce792eSToby Isaac       PetscCall(PetscSectionSetDof(sp->intPointSection, p, dof - cdof));
9822dce792eSToby Isaac     }
9832dce792eSToby Isaac     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->intPointSection));
9842dce792eSToby Isaac   }
9852dce792eSToby Isaac   *section = sp->intPointSection;
9862dce792eSToby Isaac   PetscFunctionReturn(PETSC_SUCCESS);
9872dce792eSToby Isaac }
9882dce792eSToby Isaac 
989b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
990b4457527SToby Isaac  * have one cell */
991d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd)
992d71ae5a4SJacob Faibussowitsch {
993b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
994b4457527SToby Isaac   PetscSection section;
995b4457527SToby Isaac   PetscInt     dim, s, k;
99620cf1dd8SToby Isaac   DM           dm;
99720cf1dd8SToby Isaac 
99820cf1dd8SToby Isaac   PetscFunctionBegin;
9999566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
10009566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
10019566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
10029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
10039566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
1004b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
1005b4457527SToby Isaac     PetscReal      detJ, hdetJ;
1006b4457527SToby Isaac     PetscDualSpace ssp;
1007b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
1008b4457527SToby Isaac     PetscInt       i, j;
1009b4457527SToby Isaac     DM             sdm;
101020cf1dd8SToby Isaac 
10119566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
1012b4457527SToby Isaac     if (!ssp) continue;
10139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
10149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
1015b4457527SToby Isaac     /* get the first vertex of the reference cell */
10169566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
10179566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
10189566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
10199566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
1020b4457527SToby Isaac     /* compactify Jacobian */
10219371c9d4SSatish Balay     for (i = 0; i < dim; i++)
10229371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
1023b4457527SToby Isaac     for (f = 0; f < dof; f++) {
1024b4457527SToby Isaac       PetscQuadrature fn;
102520cf1dd8SToby Isaac 
10269566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
1027f4f49eeaSPierre Jolivet       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &sp->functional[off + f]));
102820cf1dd8SToby Isaac     }
102920cf1dd8SToby Isaac   }
10309566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
10313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
103220cf1dd8SToby Isaac }
103320cf1dd8SToby Isaac 
103420cf1dd8SToby Isaac /*@C
103520cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
103620cf1dd8SToby Isaac 
103720cf1dd8SToby Isaac   Input Parameters:
1038dce8aebaSBarry Smith + sp      - The `PetscDualSpace` object
103920cf1dd8SToby Isaac . f       - The basis functional index
104020cf1dd8SToby Isaac . time    - The time
104120cf1dd8SToby 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)
104220cf1dd8SToby Isaac . numComp - The number of components for the function
104320cf1dd8SToby Isaac . func    - The input function
104420cf1dd8SToby Isaac - ctx     - A context for the function
104520cf1dd8SToby Isaac 
104620cf1dd8SToby Isaac   Output Parameter:
104720cf1dd8SToby Isaac . value - numComp output values
104820cf1dd8SToby Isaac 
104960225df5SJacob Faibussowitsch   Calling sequence:
1050dce8aebaSBarry Smith .vb
105120f4b53cSBarry Smith   PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1052dce8aebaSBarry Smith .ve
105320cf1dd8SToby Isaac 
1054a4ce7ad1SMatthew G. Knepley   Level: beginner
105520cf1dd8SToby Isaac 
1056dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
105720cf1dd8SToby Isaac @*/
1058d71ae5a4SJacob 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)
1059d71ae5a4SJacob Faibussowitsch {
106020cf1dd8SToby Isaac   PetscFunctionBegin;
106120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
10624f572ea9SToby Isaac   PetscAssertPointer(cgeom, 4);
10634f572ea9SToby Isaac   PetscAssertPointer(value, 8);
1064dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
10653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
106620cf1dd8SToby Isaac }
106720cf1dd8SToby Isaac 
106826a11704SBarry Smith /*@C
1069dce8aebaSBarry Smith   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
107020cf1dd8SToby Isaac 
107120cf1dd8SToby Isaac   Input Parameters:
1072dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1073dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
107420cf1dd8SToby Isaac 
107520cf1dd8SToby Isaac   Output Parameter:
107620cf1dd8SToby Isaac . spValue - The values of all dual space functionals
107720cf1dd8SToby Isaac 
1078dce8aebaSBarry Smith   Level: advanced
107920cf1dd8SToby Isaac 
1080dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
108120cf1dd8SToby Isaac @*/
1082d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1083d71ae5a4SJacob Faibussowitsch {
108420cf1dd8SToby Isaac   PetscFunctionBegin;
108520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1086dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
10873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
108820cf1dd8SToby Isaac }
108920cf1dd8SToby Isaac 
109026a11704SBarry Smith /*@C
1091dce8aebaSBarry Smith   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1092b4457527SToby Isaac 
1093b4457527SToby Isaac   Input Parameters:
1094dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1095dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1096b4457527SToby Isaac 
1097b4457527SToby Isaac   Output Parameter:
1098b4457527SToby Isaac . spValue - The values of interior dual space functionals
1099b4457527SToby Isaac 
1100dce8aebaSBarry Smith   Level: advanced
1101b4457527SToby Isaac 
1102dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1103b4457527SToby Isaac @*/
1104d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1105d71ae5a4SJacob Faibussowitsch {
1106b4457527SToby Isaac   PetscFunctionBegin;
1107b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1108dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
11093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1110b4457527SToby Isaac }
1111b4457527SToby Isaac 
1112b4457527SToby Isaac /*@C
111320cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
111420cf1dd8SToby Isaac 
111520cf1dd8SToby Isaac   Input Parameters:
1116dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
111720cf1dd8SToby Isaac . f     - The basis functional index
111820cf1dd8SToby Isaac . time  - The time
111920cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
112020cf1dd8SToby Isaac . Nc    - The number of components for the function
112120cf1dd8SToby Isaac . func  - The input function
112220cf1dd8SToby Isaac - ctx   - A context for the function
112320cf1dd8SToby Isaac 
112420cf1dd8SToby Isaac   Output Parameter:
112520cf1dd8SToby Isaac . value - The output value
112620cf1dd8SToby Isaac 
112760225df5SJacob Faibussowitsch   Calling sequence:
1128dce8aebaSBarry Smith .vb
112920f4b53cSBarry Smith    PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[],PetscInt numComponents, PetscScalar values[], void *ctx)
1130dce8aebaSBarry Smith .ve
113120cf1dd8SToby Isaac 
1132dce8aebaSBarry Smith   Level: advanced
113320cf1dd8SToby Isaac 
1134dce8aebaSBarry Smith   Note:
1135dce8aebaSBarry 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.
113620cf1dd8SToby Isaac 
1137dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
113820cf1dd8SToby Isaac @*/
1139d71ae5a4SJacob 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)
1140d71ae5a4SJacob Faibussowitsch {
114120cf1dd8SToby Isaac   DM               dm;
114220cf1dd8SToby Isaac   PetscQuadrature  n;
114320cf1dd8SToby Isaac   const PetscReal *points, *weights;
114420cf1dd8SToby Isaac   PetscReal        x[3];
114520cf1dd8SToby Isaac   PetscScalar     *val;
114620cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
114720cf1dd8SToby Isaac   PetscBool        isAffine;
114820cf1dd8SToby Isaac 
114920cf1dd8SToby Isaac   PetscFunctionBegin;
115020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
11514f572ea9SToby Isaac   PetscAssertPointer(value, 8);
11529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
11539566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
11549566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
115563a3b9bcSJacob 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);
115663a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
11579566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
115820cf1dd8SToby Isaac   *value   = 0.0;
115920cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
116020cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
116120cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
116220cf1dd8SToby Isaac     if (isAffine) {
116320cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
11649566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
116520cf1dd8SToby Isaac     } else {
11669566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
116720cf1dd8SToby Isaac     }
1168ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
116920cf1dd8SToby Isaac   }
11709566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
11713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
117220cf1dd8SToby Isaac }
117320cf1dd8SToby Isaac 
117426a11704SBarry Smith /*@C
1175dce8aebaSBarry Smith   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()`
117620cf1dd8SToby Isaac 
117720cf1dd8SToby Isaac   Input Parameters:
1178dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1179dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()`
118020cf1dd8SToby Isaac 
118120cf1dd8SToby Isaac   Output Parameter:
118220cf1dd8SToby Isaac . spValue - The values of all dual space functionals
118320cf1dd8SToby Isaac 
1184dce8aebaSBarry Smith   Level: advanced
118520cf1dd8SToby Isaac 
1186dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
118720cf1dd8SToby Isaac @*/
1188d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1189d71ae5a4SJacob Faibussowitsch {
1190b4457527SToby Isaac   Vec pointValues, dofValues;
1191b4457527SToby Isaac   Mat allMat;
119220cf1dd8SToby Isaac 
119320cf1dd8SToby Isaac   PetscFunctionBegin;
119420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
11954f572ea9SToby Isaac   PetscAssertPointer(pointEval, 2);
11964f572ea9SToby Isaac   PetscAssertPointer(spValue, 3);
11979566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
1198f4f49eeaSPierre Jolivet   if (!sp->allNodeValues) PetscCall(MatCreateVecs(allMat, &sp->allNodeValues, NULL));
1199b4457527SToby Isaac   pointValues = sp->allNodeValues;
1200f4f49eeaSPierre Jolivet   if (!sp->allDofValues) PetscCall(MatCreateVecs(allMat, NULL, &sp->allDofValues));
1201b4457527SToby Isaac   dofValues = sp->allDofValues;
12029566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
12039566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
12049566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
12059566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
12069566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
12073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
120820cf1dd8SToby Isaac }
1209b4457527SToby Isaac 
121026a11704SBarry Smith /*@C
1211dce8aebaSBarry Smith   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1212b4457527SToby Isaac 
1213b4457527SToby Isaac   Input Parameters:
1214dce8aebaSBarry Smith + sp        - The `PetscDualSpace` object
1215dce8aebaSBarry Smith - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()`
1216b4457527SToby Isaac 
1217b4457527SToby Isaac   Output Parameter:
1218b4457527SToby Isaac . spValue - The values of interior dual space functionals
1219b4457527SToby Isaac 
1220dce8aebaSBarry Smith   Level: advanced
1221b4457527SToby Isaac 
1222dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
1223b4457527SToby Isaac @*/
1224d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1225d71ae5a4SJacob Faibussowitsch {
1226b4457527SToby Isaac   Vec pointValues, dofValues;
1227b4457527SToby Isaac   Mat intMat;
1228b4457527SToby Isaac 
1229b4457527SToby Isaac   PetscFunctionBegin;
1230b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
12314f572ea9SToby Isaac   PetscAssertPointer(pointEval, 2);
12324f572ea9SToby Isaac   PetscAssertPointer(spValue, 3);
12339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
1234f4f49eeaSPierre Jolivet   if (!sp->intNodeValues) PetscCall(MatCreateVecs(intMat, &sp->intNodeValues, NULL));
1235b4457527SToby Isaac   pointValues = sp->intNodeValues;
1236f4f49eeaSPierre Jolivet   if (!sp->intDofValues) PetscCall(MatCreateVecs(intMat, NULL, &sp->intDofValues));
1237b4457527SToby Isaac   dofValues = sp->intDofValues;
12389566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
12399566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
12409566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
12419566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
12429566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
12433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
124420cf1dd8SToby Isaac }
124520cf1dd8SToby Isaac 
124626a11704SBarry Smith /*@C
1247b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1248a4ce7ad1SMatthew G. Knepley 
1249a4ce7ad1SMatthew G. Knepley   Input Parameter:
1250a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1251a4ce7ad1SMatthew G. Knepley 
1252d8d19677SJose E. Roman   Output Parameters:
125326a11704SBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes, pass `NULL` if not needed
125426a11704SBarry Smith - allMat   - A `Mat` for the node-to-dof transformation, pass `NULL` if not needed
1255a4ce7ad1SMatthew G. Knepley 
1256a4ce7ad1SMatthew G. Knepley   Level: advanced
1257a4ce7ad1SMatthew G. Knepley 
1258dce8aebaSBarry Smith .seealso: `PetscQuadrature`, `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`
1259a4ce7ad1SMatthew G. Knepley @*/
1260ce78bad3SBarry Smith PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PeOp PetscQuadrature *allNodes, PeOp Mat *allMat)
1261d71ae5a4SJacob Faibussowitsch {
126220cf1dd8SToby Isaac   PetscFunctionBegin;
126320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
12644f572ea9SToby Isaac   if (allNodes) PetscAssertPointer(allNodes, 2);
12654f572ea9SToby Isaac   if (allMat) PetscAssertPointer(allMat, 3);
1266b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1267b4457527SToby Isaac     PetscQuadrature qpoints;
1268b4457527SToby Isaac     Mat             amat;
1269b4457527SToby Isaac 
1270dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
1271f4f49eeaSPierre Jolivet     PetscCall(PetscQuadratureDestroy(&sp->allNodes));
1272f4f49eeaSPierre Jolivet     PetscCall(MatDestroy(&sp->allMat));
1273b4457527SToby Isaac     sp->allNodes = qpoints;
1274b4457527SToby Isaac     sp->allMat   = amat;
127520cf1dd8SToby Isaac   }
1276b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1277b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
12783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
127920cf1dd8SToby Isaac }
128020cf1dd8SToby Isaac 
128126a11704SBarry Smith /*@C
1282b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1283a4ce7ad1SMatthew G. Knepley 
1284a4ce7ad1SMatthew G. Knepley   Input Parameter:
1285a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1286a4ce7ad1SMatthew G. Knepley 
1287d8d19677SJose E. Roman   Output Parameters:
1288dce8aebaSBarry Smith + allNodes - A `PetscQuadrature` object containing all evaluation nodes
1289dce8aebaSBarry Smith - allMat   - A `Mat` for the node-to-dof transformation
1290a4ce7ad1SMatthew G. Knepley 
1291a4ce7ad1SMatthew G. Knepley   Level: advanced
1292a4ce7ad1SMatthew G. Knepley 
1293dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`, `PetscQuadrature`
1294a4ce7ad1SMatthew G. Knepley @*/
1295d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1296d71ae5a4SJacob Faibussowitsch {
129720cf1dd8SToby Isaac   PetscInt        spdim;
129820cf1dd8SToby Isaac   PetscInt        numPoints, offset;
129920cf1dd8SToby Isaac   PetscReal      *points;
130020cf1dd8SToby Isaac   PetscInt        f, dim;
1301b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1302b4457527SToby Isaac   PetscInt        maxNumPoints;
130320cf1dd8SToby Isaac   PetscQuadrature q;
1304b4457527SToby Isaac   Mat             A;
130520cf1dd8SToby Isaac 
130620cf1dd8SToby Isaac   PetscFunctionBegin;
13079566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13089566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
130920cf1dd8SToby Isaac   if (!spdim) {
13109566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
13119566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
131220cf1dd8SToby Isaac   }
1313b4457527SToby Isaac   nrows = spdim;
13149566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
13159566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1316b4457527SToby Isaac   maxNumPoints = numPoints;
131720cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
131820cf1dd8SToby Isaac     PetscInt Np;
131920cf1dd8SToby Isaac 
13209566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
13219566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
132220cf1dd8SToby Isaac     numPoints += Np;
1323b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
132420cf1dd8SToby Isaac   }
1325b4457527SToby Isaac   ncols = numPoints * Nc;
13269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
13279566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
132820cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1329b4457527SToby Isaac     const PetscReal *p, *w;
133020cf1dd8SToby Isaac     PetscInt         Np, i;
1331b4457527SToby Isaac     PetscInt         fnc;
133220cf1dd8SToby Isaac 
13339566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
13349566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
133508401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
1336ad540459SPierre Jolivet     for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i];
133748a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1338b4457527SToby Isaac     offset += Np;
1339b4457527SToby Isaac   }
13409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
13419566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
13429566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
13439566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1344b4457527SToby Isaac   *allMat = A;
13453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1346b4457527SToby Isaac }
1347b4457527SToby Isaac 
134826a11704SBarry Smith /*@C
1349b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1350a4e35b19SJacob Faibussowitsch   this space, as well as the matrix that computes the degrees of freedom from the quadrature
1351a4e35b19SJacob Faibussowitsch   values.
1352b4457527SToby Isaac 
1353b4457527SToby Isaac   Input Parameter:
1354b4457527SToby Isaac . sp - The dualspace
1355b4457527SToby Isaac 
1356d8d19677SJose E. Roman   Output Parameters:
135726a11704SBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom,
135826a11704SBarry Smith              pass `NULL` if not needed
1359b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1360dce8aebaSBarry Smith              the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1361dce8aebaSBarry Smith              npoints is the number of points in intNodes and nc is `PetscDualSpaceGetNumComponents()`.
136226a11704SBarry Smith              Pass `NULL` if not needed
1363b4457527SToby Isaac 
1364b4457527SToby Isaac   Level: advanced
1365b4457527SToby Isaac 
1366a4e35b19SJacob Faibussowitsch   Notes:
1367a4e35b19SJacob Faibussowitsch   Degrees of freedom are interior degrees of freedom if they belong (by
1368a4e35b19SJacob Faibussowitsch   `PetscDualSpaceGetSection()`) to interior points in the references, complementary boundary
1369a4e35b19SJacob Faibussowitsch   degrees of freedom are marked as constrained in the section returned by
1370a4e35b19SJacob Faibussowitsch   `PetscDualSpaceGetSection()`).
1371a4e35b19SJacob Faibussowitsch 
1372dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1373b4457527SToby Isaac @*/
1374ce78bad3SBarry Smith PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PeOp PetscQuadrature *intNodes, PeOp Mat *intMat)
1375d71ae5a4SJacob Faibussowitsch {
1376b4457527SToby Isaac   PetscFunctionBegin;
1377b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13784f572ea9SToby Isaac   if (intNodes) PetscAssertPointer(intNodes, 2);
13794f572ea9SToby Isaac   if (intMat) PetscAssertPointer(intMat, 3);
1380b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1381b4457527SToby Isaac     PetscQuadrature qpoints;
1382b4457527SToby Isaac     Mat             imat;
1383b4457527SToby Isaac 
1384dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
1385f4f49eeaSPierre Jolivet     PetscCall(PetscQuadratureDestroy(&sp->intNodes));
1386f4f49eeaSPierre Jolivet     PetscCall(MatDestroy(&sp->intMat));
1387b4457527SToby Isaac     sp->intNodes = qpoints;
1388b4457527SToby Isaac     sp->intMat   = imat;
1389b4457527SToby Isaac   }
1390b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1391b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
13923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1393b4457527SToby Isaac }
1394b4457527SToby Isaac 
139526a11704SBarry Smith /*@C
1396b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1397b4457527SToby Isaac 
1398b4457527SToby Isaac   Input Parameter:
1399b4457527SToby Isaac . sp - The dualspace
1400b4457527SToby Isaac 
1401d8d19677SJose E. Roman   Output Parameters:
1402dce8aebaSBarry Smith + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom
1403b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1404dce8aebaSBarry Smith               the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section,
1405dce8aebaSBarry Smith               npoints is the number of points in allNodes and nc is `PetscDualSpaceGetNumComponents()`.
1406b4457527SToby Isaac 
1407b4457527SToby Isaac   Level: advanced
1408b4457527SToby Isaac 
1409dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1410b4457527SToby Isaac @*/
1411d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1412d71ae5a4SJacob Faibussowitsch {
1413b4457527SToby Isaac   DM              dm;
1414b4457527SToby Isaac   PetscInt        spdim0;
1415b4457527SToby Isaac   PetscInt        Nc;
1416b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1417b4457527SToby Isaac   PetscSection    section;
1418b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1419b4457527SToby Isaac   PetscReal      *points;
1420b4457527SToby Isaac   PetscInt        dim;
1421b4457527SToby Isaac   PetscInt       *nnz;
1422b4457527SToby Isaac   PetscQuadrature q;
1423b4457527SToby Isaac   Mat             imat;
1424b4457527SToby Isaac 
1425b4457527SToby Isaac   PetscFunctionBegin;
1426b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
14279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
14289566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1429b4457527SToby Isaac   if (!spdim0) {
1430b4457527SToby Isaac     *intNodes = NULL;
1431b4457527SToby Isaac     *intMat   = NULL;
14323ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1433b4457527SToby Isaac   }
14349566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
14359566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
14369566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
14379566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
14389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1439b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1440b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1441b4457527SToby Isaac 
14429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
14439566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1444b4457527SToby Isaac     if (!(dof - cdof)) continue;
14459566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1446b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1447b4457527SToby Isaac       PetscInt Np;
1448b4457527SToby Isaac 
14499566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14509566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1451b4457527SToby Isaac       nnz[f] = Np * Nc;
1452b4457527SToby Isaac       numPoints += Np;
1453b4457527SToby Isaac     }
1454b4457527SToby Isaac   }
14559566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
14569566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
14579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1458b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1459b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1460b4457527SToby Isaac 
14619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
14629566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1463b4457527SToby Isaac     if (!(dof - cdof)) continue;
14649566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1465b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1466b4457527SToby Isaac       const PetscReal *p;
1467b4457527SToby Isaac       const PetscReal *w;
1468b4457527SToby Isaac       PetscInt         Np, i;
1469b4457527SToby Isaac 
14709566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14719566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
1472ad540459SPierre Jolivet       for (i = 0; i < Np * dim; i++) points[offset + i] = p[i];
147348a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1474b4457527SToby Isaac       offset += Np * dim;
1475b4457527SToby Isaac       matoffset += Np * Nc;
1476b4457527SToby Isaac     }
1477b4457527SToby Isaac   }
14789566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
14799566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
14809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
14819566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1482b4457527SToby Isaac   *intMat = imat;
14833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
148420cf1dd8SToby Isaac }
148520cf1dd8SToby Isaac 
148626a11704SBarry Smith /*@C
1487dce8aebaSBarry Smith   PetscDualSpaceEqual - Determine if two dual spaces are equivalent
14884f9ab2b4SJed Brown 
14894f9ab2b4SJed Brown   Input Parameters:
1490dce8aebaSBarry Smith + A - A `PetscDualSpace` object
1491dce8aebaSBarry Smith - B - Another `PetscDualSpace` object
14924f9ab2b4SJed Brown 
14934f9ab2b4SJed Brown   Output Parameter:
1494dce8aebaSBarry Smith . equal - `PETSC_TRUE` if the dual spaces are equivalent
14954f9ab2b4SJed Brown 
14964f9ab2b4SJed Brown   Level: advanced
14974f9ab2b4SJed Brown 
1498dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
14994f9ab2b4SJed Brown @*/
1500d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal)
1501d71ae5a4SJacob Faibussowitsch {
15024f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
15034f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
15044f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
15054f9ab2b4SJed Brown   Mat             matA, matB;
15064f9ab2b4SJed Brown 
15074f9ab2b4SJed Brown   PetscFunctionBegin;
15084f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
15094f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
15104f572ea9SToby Isaac   PetscAssertPointer(equal, 3);
15114f9ab2b4SJed Brown   *equal = PETSC_FALSE;
15129566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
15139566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
15143ba16761SJacob Faibussowitsch   if (sizeB != sizeA) PetscFunctionReturn(PETSC_SUCCESS);
15159566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
15169566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
15173ba16761SJacob Faibussowitsch   if (dimA != dimB) PetscFunctionReturn(PETSC_SUCCESS);
15184f9ab2b4SJed Brown 
15199566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
15209566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
15214f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
15223ba16761SJacob Faibussowitsch     if (dofA[d] != dofB[d]) PetscFunctionReturn(PETSC_SUCCESS);
15234f9ab2b4SJed Brown   }
15244f9ab2b4SJed Brown 
15259566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
15269566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
15274f9ab2b4SJed Brown   if (!quadA && !quadB) {
15284f9ab2b4SJed Brown     *equal = PETSC_TRUE;
15294f9ab2b4SJed Brown   } else if (quadA && quadB) {
15309566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
15313ba16761SJacob Faibussowitsch     if (*equal == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS);
15323ba16761SJacob Faibussowitsch     if (!matA && !matB) PetscFunctionReturn(PETSC_SUCCESS);
15339566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
15344f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
15354f9ab2b4SJed Brown   }
15363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15374f9ab2b4SJed Brown }
15384f9ab2b4SJed Brown 
153920cf1dd8SToby Isaac /*@C
154020cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
154120cf1dd8SToby Isaac 
154220cf1dd8SToby Isaac   Input Parameters:
1543dce8aebaSBarry Smith + sp    - The `PetscDualSpace` object
154420cf1dd8SToby Isaac . f     - The basis functional index
154520cf1dd8SToby Isaac . time  - The time
154620cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
154720cf1dd8SToby Isaac . Nc    - The number of components for the function
154820cf1dd8SToby Isaac . func  - The input function
154920cf1dd8SToby Isaac - ctx   - A context for the function
155020cf1dd8SToby Isaac 
155120cf1dd8SToby Isaac   Output Parameter:
155220cf1dd8SToby Isaac . value - The output value (scalar)
155320cf1dd8SToby Isaac 
155460225df5SJacob Faibussowitsch   Calling sequence:
1555dce8aebaSBarry Smith .vb
155620f4b53cSBarry Smith   PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx)
1557dce8aebaSBarry Smith .ve
155820f4b53cSBarry Smith 
1559dce8aebaSBarry Smith   Level: advanced
156020cf1dd8SToby Isaac 
1561dce8aebaSBarry Smith   Note:
1562dce8aebaSBarry 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.
156320cf1dd8SToby Isaac 
1564dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`
156520cf1dd8SToby Isaac @*/
1566d71ae5a4SJacob 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)
1567d71ae5a4SJacob Faibussowitsch {
156820cf1dd8SToby Isaac   DM               dm;
156920cf1dd8SToby Isaac   PetscQuadrature  n;
157020cf1dd8SToby Isaac   const PetscReal *points, *weights;
157120cf1dd8SToby Isaac   PetscScalar     *val;
157220cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
157320cf1dd8SToby Isaac 
157420cf1dd8SToby Isaac   PetscFunctionBegin;
157520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
15764f572ea9SToby Isaac   PetscAssertPointer(value, 8);
15779566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
15789566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
15799566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
15809566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
158163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
15829566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
158320cf1dd8SToby Isaac   *value = 0.;
158420cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
15859566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
1586ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
158720cf1dd8SToby Isaac   }
15889566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
15893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
159020cf1dd8SToby Isaac }
159120cf1dd8SToby Isaac 
159226a11704SBarry Smith /*@C
159320cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
159420cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
159520cf1dd8SToby Isaac 
159620f4b53cSBarry Smith   Not Collective
159720cf1dd8SToby Isaac 
159820cf1dd8SToby Isaac   Input Parameters:
1599dce8aebaSBarry Smith + sp     - the `PetscDualSpace` object
160020cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
160120cf1dd8SToby Isaac 
160220cf1dd8SToby Isaac   Output Parameter:
160320cf1dd8SToby Isaac . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
160420cf1dd8SToby Isaac           point, which will be of lesser dimension if height > 0.
160520cf1dd8SToby Isaac 
160620cf1dd8SToby Isaac   Level: advanced
160720cf1dd8SToby Isaac 
1608dce8aebaSBarry Smith   Notes:
1609dce8aebaSBarry Smith   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
1610dce8aebaSBarry Smith   pointwise values are not defined on the element boundaries), or if the implementation of `PetscDualSpace` does not
161126a11704SBarry Smith   support extracting subspaces, then `NULL` is returned.
1612dce8aebaSBarry Smith 
1613dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1614dce8aebaSBarry Smith 
161560225df5SJacob Faibussowitsch .seealso: `PetscDualSpace`, `PetscSpaceGetHeightSubspace()`, `PetscDualSpaceGetPointSubspace()`
161620cf1dd8SToby Isaac @*/
1617d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
1618d71ae5a4SJacob Faibussowitsch {
1619b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1620b4457527SToby Isaac   DM       dm;
162120cf1dd8SToby Isaac 
162220cf1dd8SToby Isaac   PetscFunctionBegin;
162320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16244f572ea9SToby Isaac   PetscAssertPointer(subsp, 3);
1625f4f49eeaSPierre 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");
162620cf1dd8SToby Isaac   *subsp = NULL;
1627b4457527SToby Isaac   dm     = sp->dm;
16289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
16291dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
16309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1631b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1632b4457527SToby Isaac     *subsp = sp;
16333ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1634b4457527SToby Isaac   }
1635b4457527SToby Isaac   if (!sp->heightSpaces) {
1636b4457527SToby Isaac     PetscInt h;
1637f4f49eeaSPierre Jolivet     PetscCall(PetscCalloc1(depth + 1, &sp->heightSpaces));
1638b4457527SToby Isaac 
1639b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1640b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
16419927e4dfSBarry Smith       if (sp->ops->createheightsubspace) PetscUseTypeMethod(sp, createheightsubspace, height, &sp->heightSpaces[h]);
1642b4457527SToby Isaac       else if (sp->pointSpaces) {
1643b4457527SToby Isaac         PetscInt hStart, hEnd;
1644b4457527SToby Isaac 
16459566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1646b4457527SToby Isaac         if (hEnd > hStart) {
1647665f567fSMatthew G. Knepley           const char *name;
1648665f567fSMatthew G. Knepley 
1649f4f49eeaSPierre Jolivet           PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[hStart]));
1650665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
16519566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
16529566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1653665f567fSMatthew G. Knepley           }
1654b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1655b4457527SToby Isaac         }
1656b4457527SToby Isaac       }
1657b4457527SToby Isaac     }
1658b4457527SToby Isaac   }
1659b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
16603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
166120cf1dd8SToby Isaac }
166220cf1dd8SToby Isaac 
166326a11704SBarry Smith /*@C
166420cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
166520cf1dd8SToby Isaac 
166620f4b53cSBarry Smith   Not Collective
166720cf1dd8SToby Isaac 
166820cf1dd8SToby Isaac   Input Parameters:
1669dce8aebaSBarry Smith + sp    - the `PetscDualSpace` object
167020cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
167120cf1dd8SToby Isaac 
167226a11704SBarry Smith   Output Parameter:
1673a4e35b19SJacob Faibussowitsch . bdsp - the subspace.
167420cf1dd8SToby Isaac 
167520cf1dd8SToby Isaac   Level: advanced
167620cf1dd8SToby Isaac 
1677dce8aebaSBarry Smith   Notes:
1678a4e35b19SJacob Faibussowitsch   The functionals in the subspace are with respect to the intrinsic geometry of the point,
1679a4e35b19SJacob Faibussowitsch   which will be of lesser dimension if height > 0.
1680a4e35b19SJacob Faibussowitsch 
1681dce8aebaSBarry Smith   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
1682dce8aebaSBarry Smith   defined on the element boundaries), or if the implementation of `PetscDualSpace` does not support extracting
1683a4e35b19SJacob Faibussowitsch   subspaces, then `NULL` is returned.
1684dce8aebaSBarry Smith 
1685dce8aebaSBarry Smith   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1686dce8aebaSBarry Smith 
1687dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceGetHeightSubspace()`
168820cf1dd8SToby Isaac @*/
1689d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1690d71ae5a4SJacob Faibussowitsch {
1691b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1692b4457527SToby Isaac   DM       dm;
169320cf1dd8SToby Isaac 
169420cf1dd8SToby Isaac   PetscFunctionBegin;
169520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16964f572ea9SToby Isaac   PetscAssertPointer(bdsp, 3);
169720cf1dd8SToby Isaac   *bdsp = NULL;
1698b4457527SToby Isaac   dm    = sp->dm;
16999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
17001dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
17019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1702b4457527SToby 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 */
1703b4457527SToby Isaac     *bdsp = sp;
17043ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1705b4457527SToby Isaac   }
1706b4457527SToby Isaac   if (!sp->pointSpaces) {
1707b4457527SToby Isaac     PetscInt p;
1708f4f49eeaSPierre Jolivet     PetscCall(PetscCalloc1(pEnd - pStart, &sp->pointSpaces));
170920cf1dd8SToby Isaac 
1710b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1711b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
17129927e4dfSBarry Smith       if (sp->ops->createpointsubspace) PetscUseTypeMethod(sp, createpointsubspace, p + pStart, &sp->pointSpaces[p]);
1713b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1714b4457527SToby Isaac         PetscInt dim, depth, height;
1715b4457527SToby Isaac         DMLabel  label;
1716b4457527SToby Isaac 
17179566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
17189566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
17199566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
172020cf1dd8SToby Isaac         height = dim - depth;
1721f4f49eeaSPierre Jolivet         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &sp->pointSpaces[p]));
17229566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
172320cf1dd8SToby Isaac       }
1724b4457527SToby Isaac     }
1725b4457527SToby Isaac   }
1726b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
17273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
172820cf1dd8SToby Isaac }
172920cf1dd8SToby Isaac 
17306f905325SMatthew G. Knepley /*@C
17316f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
17326f905325SMatthew G. Knepley 
173320f4b53cSBarry Smith   Not Collective
17346f905325SMatthew G. Knepley 
17356f905325SMatthew G. Knepley   Input Parameter:
1736dce8aebaSBarry Smith . sp - the `PetscDualSpace` object
17376f905325SMatthew G. Knepley 
17386f905325SMatthew G. Knepley   Output Parameters:
1739b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1740b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
17416f905325SMatthew G. Knepley 
17426f905325SMatthew G. Knepley   Level: developer
17436f905325SMatthew G. Knepley 
1744dce8aebaSBarry Smith   Note:
1745dce8aebaSBarry Smith   The permutation and flip arrays are organized in the following way
1746dce8aebaSBarry Smith .vb
1747dce8aebaSBarry Smith   perms[p][ornt][dof # on point] = new local dof #
1748dce8aebaSBarry Smith   flips[p][ornt][dof # on point] = reversal or not
1749dce8aebaSBarry Smith .ve
1750dce8aebaSBarry Smith 
1751dce8aebaSBarry Smith .seealso: `PetscDualSpace`
17526f905325SMatthew G. Knepley @*/
1753d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
1754d71ae5a4SJacob Faibussowitsch {
17556f905325SMatthew G. Knepley   PetscFunctionBegin;
17566f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
17579371c9d4SSatish Balay   if (perms) {
17584f572ea9SToby Isaac     PetscAssertPointer(perms, 2);
17599371c9d4SSatish Balay     *perms = NULL;
17609371c9d4SSatish Balay   }
17619371c9d4SSatish Balay   if (flips) {
17624f572ea9SToby Isaac     PetscAssertPointer(flips, 3);
17639371c9d4SSatish Balay     *flips = NULL;
17649371c9d4SSatish Balay   }
17659927e4dfSBarry Smith   PetscTryTypeMethod(sp, getsymmetries, perms, flips);
17663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17676f905325SMatthew G. Knepley }
17684bee2e38SMatthew G. Knepley 
176926a11704SBarry Smith /*@C
1770b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1771b4457527SToby Isaac   dual space's functionals.
1772b4457527SToby Isaac 
1773b4457527SToby Isaac   Input Parameter:
1774dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
1775b4457527SToby Isaac 
1776b4457527SToby Isaac   Output Parameter:
1777b4457527SToby 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
1778b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1779b4457527SToby 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).
1780b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1781b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1782b4457527SToby Isaac         but are stored as 1-forms.
1783b4457527SToby Isaac 
1784b4457527SToby Isaac   Level: developer
1785b4457527SToby Isaac 
1786dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1787b4457527SToby Isaac @*/
1788d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k)
1789d71ae5a4SJacob Faibussowitsch {
1790b4457527SToby Isaac   PetscFunctionBeginHot;
1791b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
17924f572ea9SToby Isaac   PetscAssertPointer(k, 2);
1793b4457527SToby Isaac   *k = dsp->k;
17943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1795b4457527SToby Isaac }
1796b4457527SToby Isaac 
179726a11704SBarry Smith /*@C
1798b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1799b4457527SToby Isaac   dual space's functionals.
1800b4457527SToby Isaac 
1801d8d19677SJose E. Roman   Input Parameters:
1802dce8aebaSBarry Smith + dsp - The `PetscDualSpace`
1803b4457527SToby 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
1804b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1805b4457527SToby 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).
1806b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1807b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1808b4457527SToby Isaac         but are stored as 1-forms.
1809b4457527SToby Isaac 
1810b4457527SToby Isaac   Level: developer
1811b4457527SToby Isaac 
1812dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1813b4457527SToby Isaac @*/
1814d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k)
1815d71ae5a4SJacob Faibussowitsch {
1816b4457527SToby Isaac   PetscInt dim;
1817b4457527SToby Isaac 
1818b4457527SToby Isaac   PetscFunctionBeginHot;
1819b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
182028b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1821b4457527SToby Isaac   dim = dsp->dm->dim;
18222dce792eSToby Isaac   PetscCheck((k >= -dim && k <= dim) || k == PETSC_FORM_DEGREE_UNDEFINED, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported %" PetscInt_FMT "-form on %" PetscInt_FMT "-dimensional reference cell", PetscAbsInt(k), dim);
1823b4457527SToby Isaac   dsp->k = k;
18243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1825b4457527SToby Isaac }
1826b4457527SToby Isaac 
182726a11704SBarry Smith /*@C
18284bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
18294bee2e38SMatthew G. Knepley 
18304bee2e38SMatthew G. Knepley   Input Parameter:
1831dce8aebaSBarry Smith . dsp - The `PetscDualSpace`
18324bee2e38SMatthew G. Knepley 
18334bee2e38SMatthew G. Knepley   Output Parameter:
18344bee2e38SMatthew G. Knepley . k - The simplex dimension
18354bee2e38SMatthew G. Knepley 
1836a4ce7ad1SMatthew G. Knepley   Level: developer
18374bee2e38SMatthew G. Knepley 
1838dce8aebaSBarry Smith   Note:
1839dce8aebaSBarry Smith   Currently supported values are
1840dce8aebaSBarry Smith .vb
1841dce8aebaSBarry Smith   0: These are H_1 methods that only transform coordinates
1842dce8aebaSBarry Smith   1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
1843dce8aebaSBarry Smith   2: These are the same as 1
1844dce8aebaSBarry Smith   3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
1845dce8aebaSBarry Smith .ve
18464bee2e38SMatthew G. Knepley 
1847dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
18484bee2e38SMatthew G. Knepley @*/
1849d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k)
1850d71ae5a4SJacob Faibussowitsch {
1851b4457527SToby Isaac   PetscInt dim;
1852b4457527SToby Isaac 
18534bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18544bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18554f572ea9SToby Isaac   PetscAssertPointer(k, 2);
1856b4457527SToby Isaac   dim = dsp->dm->dim;
1857b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1858b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1859b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1860b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
18613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18624bee2e38SMatthew G. Knepley }
18634bee2e38SMatthew G. Knepley 
186426a11704SBarry Smith /*@C
18654bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
18664bee2e38SMatthew G. Knepley 
18674bee2e38SMatthew G. Knepley   Input Parameters:
1868dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
18694bee2e38SMatthew G. Knepley . trans     - The type of transform
18704bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18714bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18724bee2e38SMatthew G. Knepley . Nv        - The number of function samples
18734bee2e38SMatthew G. Knepley . Nc        - The number of function components
18744bee2e38SMatthew G. Knepley - vals      - The function values
18754bee2e38SMatthew G. Knepley 
18764bee2e38SMatthew G. Knepley   Output Parameter:
18774bee2e38SMatthew G. Knepley . vals - The transformed function values
18784bee2e38SMatthew G. Knepley 
1879a4ce7ad1SMatthew G. Knepley   Level: intermediate
18804bee2e38SMatthew G. Knepley 
1881dce8aebaSBarry Smith   Note:
1882dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18832edcad52SToby Isaac 
1884dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18854bee2e38SMatthew G. Knepley @*/
1886d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1887d71ae5a4SJacob Faibussowitsch {
1888b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1889b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
18904bee2e38SMatthew G. Knepley 
18914bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18924bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18934f572ea9SToby Isaac   PetscAssertPointer(fegeom, 4);
18944f572ea9SToby Isaac   PetscAssertPointer(vals, 7);
1895b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
18962ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1897b4457527SToby Isaac   /* No change needed for 0-forms */
18983ba16761SJacob Faibussowitsch   if (!dsp->k) PetscFunctionReturn(PETSC_SUCCESS);
18999566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1900b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
19019566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
19024bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1903b4457527SToby Isaac     switch (Nk) {
1904b4457527SToby Isaac     case 1:
1905b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
19064bee2e38SMatthew G. Knepley       break;
1907b4457527SToby Isaac     case 2:
1908b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
19094bee2e38SMatthew G. Knepley       break;
1910b4457527SToby Isaac     case 3:
1911b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1912b4457527SToby Isaac       break;
1913d71ae5a4SJacob Faibussowitsch     default:
1914d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1915b4457527SToby Isaac     }
19164bee2e38SMatthew G. Knepley   }
19173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19184bee2e38SMatthew G. Knepley }
1919b4457527SToby Isaac 
192026a11704SBarry Smith /*@C
19214bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
19224bee2e38SMatthew G. Knepley 
19234bee2e38SMatthew G. Knepley   Input Parameters:
1924dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
19254bee2e38SMatthew G. Knepley . trans     - The type of transform
19264bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
19274bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
19284bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
19294bee2e38SMatthew G. Knepley . Nc        - The number of function components
19304bee2e38SMatthew G. Knepley - vals      - The function gradient values
19314bee2e38SMatthew G. Knepley 
19324bee2e38SMatthew G. Knepley   Output Parameter:
1933f9244615SMatthew G. Knepley . vals - The transformed function gradient values
19344bee2e38SMatthew G. Knepley 
1935a4ce7ad1SMatthew G. Knepley   Level: intermediate
19364bee2e38SMatthew G. Knepley 
1937dce8aebaSBarry Smith   Note:
1938dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
19392edcad52SToby Isaac 
1940dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
19414bee2e38SMatthew G. Knepley @*/
1942d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1943d71ae5a4SJacob Faibussowitsch {
194427f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
194527f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
19464bee2e38SMatthew G. Knepley 
19474bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
19484bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
19494f572ea9SToby Isaac   PetscAssertPointer(fegeom, 4);
19504f572ea9SToby Isaac   PetscAssertPointer(vals, 7);
1951b498ca8aSPierre Jolivet   PetscAssert(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
19524bee2e38SMatthew G. Knepley   /* Transform gradient */
195327f02ce8SMatthew G. Knepley   if (dim == dE) {
19544bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
19554bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
19569371c9d4SSatish Balay         switch (dim) {
1957d71ae5a4SJacob Faibussowitsch         case 1:
1958d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim] *= fegeom->invJ[0];
1959d71ae5a4SJacob Faibussowitsch           break;
1960d71ae5a4SJacob Faibussowitsch         case 2:
1961d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1962d71ae5a4SJacob Faibussowitsch           break;
1963d71ae5a4SJacob Faibussowitsch         case 3:
1964d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1965d71ae5a4SJacob Faibussowitsch           break;
1966d71ae5a4SJacob Faibussowitsch         default:
1967d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19684bee2e38SMatthew G. Knepley         }
19694bee2e38SMatthew G. Knepley       }
19704bee2e38SMatthew G. Knepley     }
197127f02ce8SMatthew G. Knepley   } else {
197227f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1973ad540459SPierre 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]);
197427f02ce8SMatthew G. Knepley     }
197527f02ce8SMatthew G. Knepley   }
19764bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
19773ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
19784bee2e38SMatthew G. Knepley   switch (trans) {
1979d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
1980d71ae5a4SJacob Faibussowitsch     break;
19814bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
19824bee2e38SMatthew G. Knepley     if (isInverse) {
19834bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19844bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19859371c9d4SSatish Balay           switch (dim) {
1986d71ae5a4SJacob Faibussowitsch           case 2:
1987d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1988d71ae5a4SJacob Faibussowitsch             break;
1989d71ae5a4SJacob Faibussowitsch           case 3:
1990d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1991d71ae5a4SJacob Faibussowitsch             break;
1992d71ae5a4SJacob Faibussowitsch           default:
1993d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19944bee2e38SMatthew G. Knepley           }
19954bee2e38SMatthew G. Knepley         }
19964bee2e38SMatthew G. Knepley       }
19974bee2e38SMatthew G. Knepley     } else {
19984bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19994bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
20009371c9d4SSatish Balay           switch (dim) {
2001d71ae5a4SJacob Faibussowitsch           case 2:
2002d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2003d71ae5a4SJacob Faibussowitsch             break;
2004d71ae5a4SJacob Faibussowitsch           case 3:
2005d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2006d71ae5a4SJacob Faibussowitsch             break;
2007d71ae5a4SJacob Faibussowitsch           default:
2008d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
20094bee2e38SMatthew G. Knepley           }
20104bee2e38SMatthew G. Knepley         }
20114bee2e38SMatthew G. Knepley       }
20124bee2e38SMatthew G. Knepley     }
20134bee2e38SMatthew G. Knepley     break;
20144bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
20154bee2e38SMatthew G. Knepley     if (isInverse) {
20164bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
20174bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
20189371c9d4SSatish Balay           switch (dim) {
2019d71ae5a4SJacob Faibussowitsch           case 2:
2020d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2021d71ae5a4SJacob Faibussowitsch             break;
2022d71ae5a4SJacob Faibussowitsch           case 3:
2023d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2024d71ae5a4SJacob Faibussowitsch             break;
2025d71ae5a4SJacob Faibussowitsch           default:
2026d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
20274bee2e38SMatthew G. Knepley           }
20284bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
20294bee2e38SMatthew G. Knepley         }
20304bee2e38SMatthew G. Knepley       }
20314bee2e38SMatthew G. Knepley     } else {
20324bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
20334bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
20349371c9d4SSatish Balay           switch (dim) {
2035d71ae5a4SJacob Faibussowitsch           case 2:
2036d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2037d71ae5a4SJacob Faibussowitsch             break;
2038d71ae5a4SJacob Faibussowitsch           case 3:
2039d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
2040d71ae5a4SJacob Faibussowitsch             break;
2041d71ae5a4SJacob Faibussowitsch           default:
2042d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
20434bee2e38SMatthew G. Knepley           }
20444bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
20454bee2e38SMatthew G. Knepley         }
20464bee2e38SMatthew G. Knepley       }
20474bee2e38SMatthew G. Knepley     }
20484bee2e38SMatthew G. Knepley     break;
20494bee2e38SMatthew G. Knepley   }
20503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20514bee2e38SMatthew G. Knepley }
20524bee2e38SMatthew G. Knepley 
205326a11704SBarry Smith /*@C
2054f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
2055f9244615SMatthew G. Knepley 
2056f9244615SMatthew G. Knepley   Input Parameters:
2057dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
2058f9244615SMatthew G. Knepley . trans     - The type of transform
2059f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
2060f9244615SMatthew G. Knepley . fegeom    - The cell geometry
2061f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
2062f9244615SMatthew G. Knepley . Nc        - The number of function components
2063f9244615SMatthew G. Knepley - vals      - The function gradient values
2064f9244615SMatthew G. Knepley 
2065f9244615SMatthew G. Knepley   Output Parameter:
2066f9244615SMatthew G. Knepley . vals - The transformed function Hessian values
2067f9244615SMatthew G. Knepley 
2068f9244615SMatthew G. Knepley   Level: intermediate
2069f9244615SMatthew G. Knepley 
2070dce8aebaSBarry Smith   Note:
2071dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2072f9244615SMatthew G. Knepley 
2073dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
2074f9244615SMatthew G. Knepley @*/
2075d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
2076d71ae5a4SJacob Faibussowitsch {
2077f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
2078f9244615SMatthew G. Knepley   PetscInt       v, c;
2079f9244615SMatthew G. Knepley 
2080f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2081f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20824f572ea9SToby Isaac   PetscAssertPointer(fegeom, 4);
20834f572ea9SToby Isaac   PetscAssertPointer(vals, 7);
2084b498ca8aSPierre Jolivet   PetscAssert(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
2085f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
2086f9244615SMatthew G. Knepley   if (dim == dE) {
2087f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2088f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
20899371c9d4SSatish Balay         switch (dim) {
2090d71ae5a4SJacob Faibussowitsch         case 1:
2091d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]);
2092d71ae5a4SJacob Faibussowitsch           break;
2093d71ae5a4SJacob Faibussowitsch         case 2:
2094d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2095d71ae5a4SJacob Faibussowitsch           break;
2096d71ae5a4SJacob Faibussowitsch         case 3:
2097d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2098d71ae5a4SJacob Faibussowitsch           break;
2099d71ae5a4SJacob Faibussowitsch         default:
2100d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
2101f9244615SMatthew G. Knepley         }
2102f9244615SMatthew G. Knepley       }
2103f9244615SMatthew G. Knepley     }
2104f9244615SMatthew G. Knepley   } else {
2105f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2106ad540459SPierre 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]);
2107f9244615SMatthew G. Knepley     }
2108f9244615SMatthew G. Knepley   }
2109f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
21103ba16761SJacob Faibussowitsch   if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS);
2111f9244615SMatthew G. Knepley   switch (trans) {
2112d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
2113d71ae5a4SJacob Faibussowitsch     break;
2114d71ae5a4SJacob Faibussowitsch   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
2115d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2116d71ae5a4SJacob Faibussowitsch   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
2117d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2118f9244615SMatthew G. Knepley   }
21193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2120f9244615SMatthew G. Knepley }
2121f9244615SMatthew G. Knepley 
212226a11704SBarry Smith /*@C
21234bee2e38SMatthew 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.
21244bee2e38SMatthew G. Knepley 
21254bee2e38SMatthew G. Knepley   Input Parameters:
2126dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
21274bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
21284bee2e38SMatthew G. Knepley . Nq        - The number of function samples
21294bee2e38SMatthew G. Knepley . Nc        - The number of function components
21304bee2e38SMatthew G. Knepley - pointEval - The function values
21314bee2e38SMatthew G. Knepley 
21324bee2e38SMatthew G. Knepley   Output Parameter:
21334bee2e38SMatthew G. Knepley . pointEval - The transformed function values
21344bee2e38SMatthew G. Knepley 
21354bee2e38SMatthew G. Knepley   Level: advanced
21364bee2e38SMatthew G. Knepley 
2137dce8aebaSBarry Smith   Notes:
2138dce8aebaSBarry 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.
21394bee2e38SMatthew G. Knepley 
2140da81f932SPierre Jolivet   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21412edcad52SToby Isaac 
2142dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21434bee2e38SMatthew G. Knepley @*/
2144d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2145d71ae5a4SJacob Faibussowitsch {
21464bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2147b4457527SToby Isaac   PetscInt                    k;
21484bee2e38SMatthew G. Knepley 
21494bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21504bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21514f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
21524f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
21534bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21544bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21559566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21569371c9d4SSatish Balay   switch (k) {
2157d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2158d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2159d71ae5a4SJacob Faibussowitsch     break;
2160d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2161d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2162d71ae5a4SJacob Faibussowitsch     break;
2163b4457527SToby Isaac   case 2:
2164d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2165d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2166d71ae5a4SJacob Faibussowitsch     break;
2167d71ae5a4SJacob Faibussowitsch   default:
2168d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21694bee2e38SMatthew G. Knepley   }
21709566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
21713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21724bee2e38SMatthew G. Knepley }
21734bee2e38SMatthew G. Knepley 
217426a11704SBarry Smith /*@C
21754bee2e38SMatthew 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.
21764bee2e38SMatthew G. Knepley 
21774bee2e38SMatthew G. Knepley   Input Parameters:
2178dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
21794bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
21804bee2e38SMatthew G. Knepley . Nq        - The number of function samples
21814bee2e38SMatthew G. Knepley . Nc        - The number of function components
21824bee2e38SMatthew G. Knepley - pointEval - The function values
21834bee2e38SMatthew G. Knepley 
21844bee2e38SMatthew G. Knepley   Output Parameter:
21854bee2e38SMatthew G. Knepley . pointEval - The transformed function values
21864bee2e38SMatthew G. Knepley 
21874bee2e38SMatthew G. Knepley   Level: advanced
21884bee2e38SMatthew G. Knepley 
2189dce8aebaSBarry Smith   Notes:
2190dce8aebaSBarry 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.
21914bee2e38SMatthew G. Knepley 
2192dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21932edcad52SToby Isaac 
2194dce8aebaSBarry Smith .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21954bee2e38SMatthew G. Knepley @*/
2196d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2197d71ae5a4SJacob Faibussowitsch {
21984bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2199b4457527SToby Isaac   PetscInt                    k;
22004bee2e38SMatthew G. Knepley 
22014bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
22024bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
22034f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
22044f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
22054bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
22064bee2e38SMatthew G. Knepley      This determines their transformation properties. */
22079566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22089371c9d4SSatish Balay   switch (k) {
2209d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2210d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2211d71ae5a4SJacob Faibussowitsch     break;
2212d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2213d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2214d71ae5a4SJacob Faibussowitsch     break;
2215b4457527SToby Isaac   case 2:
2216d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2217d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2218d71ae5a4SJacob Faibussowitsch     break;
2219d71ae5a4SJacob Faibussowitsch   default:
2220d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22214bee2e38SMatthew G. Knepley   }
22229566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22244bee2e38SMatthew G. Knepley }
22254bee2e38SMatthew G. Knepley 
222626a11704SBarry Smith /*@C
22274bee2e38SMatthew 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.
22284bee2e38SMatthew G. Knepley 
22294bee2e38SMatthew G. Knepley   Input Parameters:
2230dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
22314bee2e38SMatthew G. Knepley . fegeom    - The geometry for this cell
22324bee2e38SMatthew G. Knepley . Nq        - The number of function gradient samples
22334bee2e38SMatthew G. Knepley . Nc        - The number of function components
22344bee2e38SMatthew G. Knepley - pointEval - The function gradient values
22354bee2e38SMatthew G. Knepley 
22364bee2e38SMatthew G. Knepley   Output Parameter:
22374bee2e38SMatthew G. Knepley . pointEval - The transformed function gradient values
22384bee2e38SMatthew G. Knepley 
22394bee2e38SMatthew G. Knepley   Level: advanced
22404bee2e38SMatthew G. Knepley 
2241dce8aebaSBarry Smith   Notes:
2242dce8aebaSBarry 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.
22434bee2e38SMatthew G. Knepley 
2244dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
22452edcad52SToby Isaac 
2246*bfe80ac4SPierre Jolivet .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2247dc0529c6SBarry Smith @*/
2248d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2249d71ae5a4SJacob Faibussowitsch {
22504bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2251b4457527SToby Isaac   PetscInt                    k;
22524bee2e38SMatthew G. Knepley 
22534bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
22544bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
22554f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
22564f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
22574bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
22584bee2e38SMatthew G. Knepley      This determines their transformation properties. */
22599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22609371c9d4SSatish Balay   switch (k) {
2261d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2262d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2263d71ae5a4SJacob Faibussowitsch     break;
2264d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2265d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2266d71ae5a4SJacob Faibussowitsch     break;
2267b4457527SToby Isaac   case 2:
2268d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2269d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2270d71ae5a4SJacob Faibussowitsch     break;
2271d71ae5a4SJacob Faibussowitsch   default:
2272d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
22734bee2e38SMatthew G. Knepley   }
22749566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
22753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22764bee2e38SMatthew G. Knepley }
2277f9244615SMatthew G. Knepley 
227826a11704SBarry Smith /*@C
2279f9244615SMatthew 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.
2280f9244615SMatthew G. Knepley 
2281f9244615SMatthew G. Knepley   Input Parameters:
2282dce8aebaSBarry Smith + dsp       - The `PetscDualSpace`
2283f9244615SMatthew G. Knepley . fegeom    - The geometry for this cell
2284f9244615SMatthew G. Knepley . Nq        - The number of function Hessian samples
2285f9244615SMatthew G. Knepley . Nc        - The number of function components
2286f9244615SMatthew G. Knepley - pointEval - The function gradient values
2287f9244615SMatthew G. Knepley 
2288f9244615SMatthew G. Knepley   Output Parameter:
2289f9244615SMatthew G. Knepley . pointEval - The transformed function Hessian values
2290f9244615SMatthew G. Knepley 
2291f9244615SMatthew G. Knepley   Level: advanced
2292f9244615SMatthew G. Knepley 
2293dce8aebaSBarry Smith   Notes:
2294dce8aebaSBarry 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.
2295f9244615SMatthew G. Knepley 
2296dce8aebaSBarry Smith   This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2297f9244615SMatthew G. Knepley 
2298*bfe80ac4SPierre Jolivet .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2299f9244615SMatthew G. Knepley @*/
2300d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2301d71ae5a4SJacob Faibussowitsch {
2302f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2303f9244615SMatthew G. Knepley   PetscInt                    k;
2304f9244615SMatthew G. Knepley 
2305f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2306f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
23074f572ea9SToby Isaac   PetscAssertPointer(fegeom, 2);
23084f572ea9SToby Isaac   PetscAssertPointer(pointEval, 5);
2309f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2310f9244615SMatthew G. Knepley      This determines their transformation properties. */
23119566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
23129371c9d4SSatish Balay   switch (k) {
2313d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2314d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2315d71ae5a4SJacob Faibussowitsch     break;
2316d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2317d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2318d71ae5a4SJacob Faibussowitsch     break;
2319f9244615SMatthew G. Knepley   case 2:
2320d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2321d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2322d71ae5a4SJacob Faibussowitsch     break;
2323d71ae5a4SJacob Faibussowitsch   default:
2324d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2325f9244615SMatthew G. Knepley   }
23269566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
23273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2328f9244615SMatthew G. Knepley }
2329