xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
220cf1dd8SToby Isaac #include <petscdmplex.h>
320cf1dd8SToby Isaac 
420cf1dd8SToby Isaac PetscClassId PETSCDUALSPACE_CLASSID = 0;
520cf1dd8SToby Isaac 
6ead873ccSMatthew G. Knepley PetscLogEvent PETSCDUALSPACE_SetUp;
7ead873ccSMatthew G. Knepley 
820cf1dd8SToby Isaac PetscFunctionList PetscDualSpaceList              = NULL;
920cf1dd8SToby Isaac PetscBool         PetscDualSpaceRegisterAllCalled = PETSC_FALSE;
1020cf1dd8SToby Isaac 
116f905325SMatthew G. Knepley /*
126f905325SMatthew G. Knepley   PetscDualSpaceLatticePointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to at most 'max'.
136f905325SMatthew G. Knepley                                                      Ordering is lexicographic with lowest index as least significant in ordering.
14b4457527SToby Isaac                                                      e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {0,2}.
156f905325SMatthew G. Knepley 
166f905325SMatthew G. Knepley   Input Parameters:
176f905325SMatthew G. Knepley + len - The length of the tuple
186f905325SMatthew G. Knepley . max - The maximum sum
196f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
206f905325SMatthew G. Knepley 
216f905325SMatthew G. Knepley   Output Parameter:
226f905325SMatthew G. Knepley . tup - A tuple of len integers whos sum is at most 'max'
236f905325SMatthew G. Knepley 
246f905325SMatthew G. Knepley   Level: developer
256f905325SMatthew G. Knepley 
26db781477SPatrick Sanan .seealso: `PetscDualSpaceTensorPointLexicographic_Internal()`
276f905325SMatthew G. Knepley */
28*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceLatticePointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[])
29*d71ae5a4SJacob Faibussowitsch {
306f905325SMatthew G. Knepley   PetscFunctionBegin;
316f905325SMatthew G. Knepley   while (len--) {
326f905325SMatthew G. Knepley     max -= tup[len];
336f905325SMatthew G. Knepley     if (!max) {
346f905325SMatthew G. Knepley       tup[len] = 0;
356f905325SMatthew G. Knepley       break;
366f905325SMatthew G. Knepley     }
376f905325SMatthew G. Knepley   }
386f905325SMatthew G. Knepley   tup[++len]++;
396f905325SMatthew G. Knepley   PetscFunctionReturn(0);
406f905325SMatthew G. Knepley }
416f905325SMatthew G. Knepley 
426f905325SMatthew G. Knepley /*
436f905325SMatthew G. Knepley   PetscDualSpaceTensorPointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max'.
446f905325SMatthew G. Knepley                                                     Ordering is lexicographic with lowest index as least significant in ordering.
456f905325SMatthew G. Knepley                                                     e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}.
466f905325SMatthew G. Knepley 
476f905325SMatthew G. Knepley   Input Parameters:
486f905325SMatthew G. Knepley + len - The length of the tuple
496f905325SMatthew G. Knepley . max - The maximum value
506f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
516f905325SMatthew G. Knepley 
526f905325SMatthew G. Knepley   Output Parameter:
536f905325SMatthew G. Knepley . tup - A tuple of len integers whos sum is at most 'max'
546f905325SMatthew G. Knepley 
556f905325SMatthew G. Knepley   Level: developer
566f905325SMatthew G. Knepley 
57db781477SPatrick Sanan .seealso: `PetscDualSpaceLatticePointLexicographic_Internal()`
586f905325SMatthew G. Knepley */
59*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTensorPointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[])
60*d71ae5a4SJacob Faibussowitsch {
616f905325SMatthew G. Knepley   PetscInt i;
626f905325SMatthew G. Knepley 
636f905325SMatthew G. Knepley   PetscFunctionBegin;
646f905325SMatthew G. Knepley   for (i = 0; i < len; i++) {
656f905325SMatthew G. Knepley     if (tup[i] < max) {
666f905325SMatthew G. Knepley       break;
676f905325SMatthew G. Knepley     } else {
686f905325SMatthew G. Knepley       tup[i] = 0;
696f905325SMatthew G. Knepley     }
706f905325SMatthew G. Knepley   }
716f905325SMatthew G. Knepley   tup[i]++;
726f905325SMatthew G. Knepley   PetscFunctionReturn(0);
736f905325SMatthew G. Knepley }
746f905325SMatthew G. Knepley 
7520cf1dd8SToby Isaac /*@C
7620cf1dd8SToby Isaac   PetscDualSpaceRegister - Adds a new PetscDualSpace implementation
7720cf1dd8SToby Isaac 
7820cf1dd8SToby Isaac   Not Collective
7920cf1dd8SToby Isaac 
8020cf1dd8SToby Isaac   Input Parameters:
8120cf1dd8SToby Isaac + name        - The name of a new user-defined creation routine
8220cf1dd8SToby Isaac - create_func - The creation routine itself
8320cf1dd8SToby Isaac 
8420cf1dd8SToby Isaac   Notes:
8520cf1dd8SToby Isaac   PetscDualSpaceRegister() may be called multiple times to add several user-defined PetscDualSpaces
8620cf1dd8SToby Isaac 
8720cf1dd8SToby Isaac   Sample usage:
8820cf1dd8SToby Isaac .vb
8920cf1dd8SToby Isaac     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
9020cf1dd8SToby Isaac .ve
9120cf1dd8SToby Isaac 
9220cf1dd8SToby Isaac   Then, your PetscDualSpace type can be chosen with the procedural interface via
9320cf1dd8SToby Isaac .vb
9420cf1dd8SToby Isaac     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
9520cf1dd8SToby Isaac     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
9620cf1dd8SToby Isaac .ve
9720cf1dd8SToby Isaac    or at runtime via the option
9820cf1dd8SToby Isaac .vb
9920cf1dd8SToby Isaac     -petscdualspace_type my_dual_space
10020cf1dd8SToby Isaac .ve
10120cf1dd8SToby Isaac 
10220cf1dd8SToby Isaac   Level: advanced
10320cf1dd8SToby Isaac 
104db781477SPatrick Sanan .seealso: `PetscDualSpaceRegisterAll()`, `PetscDualSpaceRegisterDestroy()`
10520cf1dd8SToby Isaac 
10620cf1dd8SToby Isaac @*/
107*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace))
108*d71ae5a4SJacob Faibussowitsch {
10920cf1dd8SToby Isaac   PetscFunctionBegin;
1109566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PetscDualSpaceList, sname, function));
11120cf1dd8SToby Isaac   PetscFunctionReturn(0);
11220cf1dd8SToby Isaac }
11320cf1dd8SToby Isaac 
11420cf1dd8SToby Isaac /*@C
11520cf1dd8SToby Isaac   PetscDualSpaceSetType - Builds a particular PetscDualSpace
11620cf1dd8SToby Isaac 
117d083f849SBarry Smith   Collective on sp
11820cf1dd8SToby Isaac 
11920cf1dd8SToby Isaac   Input Parameters:
12020cf1dd8SToby Isaac + sp   - The PetscDualSpace object
12120cf1dd8SToby Isaac - name - The kind of space
12220cf1dd8SToby Isaac 
12320cf1dd8SToby Isaac   Options Database Key:
12420cf1dd8SToby Isaac . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types
12520cf1dd8SToby Isaac 
12620cf1dd8SToby Isaac   Level: intermediate
12720cf1dd8SToby Isaac 
128db781477SPatrick Sanan .seealso: `PetscDualSpaceGetType()`, `PetscDualSpaceCreate()`
12920cf1dd8SToby Isaac @*/
130*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name)
131*d71ae5a4SJacob Faibussowitsch {
13220cf1dd8SToby Isaac   PetscErrorCode (*r)(PetscDualSpace);
13320cf1dd8SToby Isaac   PetscBool match;
13420cf1dd8SToby Isaac 
13520cf1dd8SToby Isaac   PetscFunctionBegin;
13620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1379566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)sp, name, &match));
13820cf1dd8SToby Isaac   if (match) PetscFunctionReturn(0);
13920cf1dd8SToby Isaac 
1409566063dSJacob Faibussowitsch   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
1419566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PetscDualSpaceList, name, &r));
14228b400f6SJacob Faibussowitsch   PetscCheck(r, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name);
14320cf1dd8SToby Isaac 
144dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, destroy);
14520cf1dd8SToby Isaac   sp->ops->destroy = NULL;
146dbbe0bcdSBarry Smith 
1479566063dSJacob Faibussowitsch   PetscCall((*r)(sp));
1489566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)sp, name));
14920cf1dd8SToby Isaac   PetscFunctionReturn(0);
15020cf1dd8SToby Isaac }
15120cf1dd8SToby Isaac 
15220cf1dd8SToby Isaac /*@C
15320cf1dd8SToby Isaac   PetscDualSpaceGetType - Gets the PetscDualSpace type name (as a string) from the object.
15420cf1dd8SToby Isaac 
15520cf1dd8SToby Isaac   Not Collective
15620cf1dd8SToby Isaac 
15720cf1dd8SToby Isaac   Input Parameter:
15820cf1dd8SToby Isaac . sp  - The PetscDualSpace
15920cf1dd8SToby Isaac 
16020cf1dd8SToby Isaac   Output Parameter:
16120cf1dd8SToby Isaac . name - The PetscDualSpace type name
16220cf1dd8SToby Isaac 
16320cf1dd8SToby Isaac   Level: intermediate
16420cf1dd8SToby Isaac 
165db781477SPatrick Sanan .seealso: `PetscDualSpaceSetType()`, `PetscDualSpaceCreate()`
16620cf1dd8SToby Isaac @*/
167*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name)
168*d71ae5a4SJacob Faibussowitsch {
16920cf1dd8SToby Isaac   PetscFunctionBegin;
17020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
17120cf1dd8SToby Isaac   PetscValidPointer(name, 2);
17248a46eb9SPierre Jolivet   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
17320cf1dd8SToby Isaac   *name = ((PetscObject)sp)->type_name;
17420cf1dd8SToby Isaac   PetscFunctionReturn(0);
17520cf1dd8SToby Isaac }
17620cf1dd8SToby Isaac 
177*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceView_ASCII(PetscDualSpace sp, PetscViewer v)
178*d71ae5a4SJacob Faibussowitsch {
179221d6281SMatthew G. Knepley   PetscViewerFormat format;
180221d6281SMatthew G. Knepley   PetscInt          pdim, f;
181221d6281SMatthew G. Knepley 
182221d6281SMatthew G. Knepley   PetscFunctionBegin;
1839566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &pdim));
1849566063dSJacob Faibussowitsch   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sp, v));
1859566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(v));
186b4457527SToby Isaac   if (sp->k) {
18763a3b9bcSJacob 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));
188b4457527SToby Isaac   } else {
18963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space with %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", sp->Nc, pdim));
190b4457527SToby Isaac   }
191dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, view, v);
1929566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(v, &format));
193221d6281SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1949566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(v));
195221d6281SMatthew G. Knepley     for (f = 0; f < pdim; ++f) {
19663a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(v, "Dual basis vector %" PetscInt_FMT "\n", f));
1979566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(v));
1989566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureView(sp->functional[f], v));
1999566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(v));
200221d6281SMatthew G. Knepley     }
2019566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(v));
202221d6281SMatthew G. Knepley   }
2039566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
204221d6281SMatthew G. Knepley   PetscFunctionReturn(0);
205221d6281SMatthew G. Knepley }
206221d6281SMatthew G. Knepley 
207fe2efc57SMark /*@C
208fe2efc57SMark    PetscDualSpaceViewFromOptions - View from Options
209fe2efc57SMark 
210fe2efc57SMark    Collective on PetscDualSpace
211fe2efc57SMark 
212fe2efc57SMark    Input Parameters:
213fe2efc57SMark +  A - the PetscDualSpace object
214736c3998SJose E. Roman .  obj - Optional object, proivides prefix
215736c3998SJose E. Roman -  name - command line option
216fe2efc57SMark 
217fe2efc57SMark    Level: intermediate
218db781477SPatrick Sanan .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()`
219fe2efc57SMark @*/
220*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PetscObject obj, const char name[])
221*d71ae5a4SJacob Faibussowitsch {
222fe2efc57SMark   PetscFunctionBegin;
223fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
2249566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
225fe2efc57SMark   PetscFunctionReturn(0);
226fe2efc57SMark }
227fe2efc57SMark 
22820cf1dd8SToby Isaac /*@
22920cf1dd8SToby Isaac   PetscDualSpaceView - Views a PetscDualSpace
23020cf1dd8SToby Isaac 
231d083f849SBarry Smith   Collective on sp
23220cf1dd8SToby Isaac 
233d8d19677SJose E. Roman   Input Parameters:
23420cf1dd8SToby Isaac + sp - the PetscDualSpace object to view
23520cf1dd8SToby Isaac - v  - the viewer
23620cf1dd8SToby Isaac 
237a4ce7ad1SMatthew G. Knepley   Level: beginner
23820cf1dd8SToby Isaac 
239db781477SPatrick Sanan .seealso `PetscDualSpaceDestroy()`, `PetscDualSpace`
24020cf1dd8SToby Isaac @*/
241*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
242*d71ae5a4SJacob Faibussowitsch {
243d9bac1caSLisandro Dalcin   PetscBool iascii;
24420cf1dd8SToby Isaac 
24520cf1dd8SToby Isaac   PetscFunctionBegin;
24620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
247d9bac1caSLisandro Dalcin   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
2489566063dSJacob Faibussowitsch   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v));
2499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
2509566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v));
25120cf1dd8SToby Isaac   PetscFunctionReturn(0);
25220cf1dd8SToby Isaac }
25320cf1dd8SToby Isaac 
25420cf1dd8SToby Isaac /*@
25520cf1dd8SToby Isaac   PetscDualSpaceSetFromOptions - sets parameters in a PetscDualSpace from the options database
25620cf1dd8SToby Isaac 
257d083f849SBarry Smith   Collective on sp
25820cf1dd8SToby Isaac 
25920cf1dd8SToby Isaac   Input Parameter:
26020cf1dd8SToby Isaac . sp - the PetscDualSpace object to set options for
26120cf1dd8SToby Isaac 
26220cf1dd8SToby Isaac   Options Database:
2638f2aacc6SMatthew G. Knepley + -petscdualspace_order <order>      - the approximation order of the space
264fe36a153SMatthew G. Knepley . -petscdualspace_form_degree <deg>  - the form degree, say 0 for point evaluations, or 2 for area integrals
2658f2aacc6SMatthew G. Knepley . -petscdualspace_components <c>     - the number of components, say d for a vector field
2668f2aacc6SMatthew G. Knepley - -petscdualspace_refcell <celltype> - Reference cell type name
26720cf1dd8SToby Isaac 
268a4ce7ad1SMatthew G. Knepley   Level: intermediate
26920cf1dd8SToby Isaac 
270db781477SPatrick Sanan .seealso `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()`
27120cf1dd8SToby Isaac @*/
272*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
273*d71ae5a4SJacob Faibussowitsch {
2742df84da0SMatthew G. Knepley   DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE;
27520cf1dd8SToby Isaac   const char    *defaultType;
27620cf1dd8SToby Isaac   char           name[256];
277f783ec47SMatthew G. Knepley   PetscBool      flg;
27820cf1dd8SToby Isaac 
27920cf1dd8SToby Isaac   PetscFunctionBegin;
28020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
28120cf1dd8SToby Isaac   if (!((PetscObject)sp)->type_name) {
28220cf1dd8SToby Isaac     defaultType = PETSCDUALSPACELAGRANGE;
28320cf1dd8SToby Isaac   } else {
28420cf1dd8SToby Isaac     defaultType = ((PetscObject)sp)->type_name;
28520cf1dd8SToby Isaac   }
2869566063dSJacob Faibussowitsch   if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll());
28720cf1dd8SToby Isaac 
288d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sp);
2899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg));
29020cf1dd8SToby Isaac   if (flg) {
2919566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, name));
29220cf1dd8SToby Isaac   } else if (!((PetscObject)sp)->type_name) {
2939566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, defaultType));
29420cf1dd8SToby Isaac   }
2959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0));
2969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL));
2979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1));
298dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject);
2999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg));
300063ee4adSMatthew G. Knepley   if (flg) {
301063ee4adSMatthew G. Knepley     DM K;
302063ee4adSMatthew G. Knepley 
3039566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K));
3049566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetDM(sp, K));
3059566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&K));
306063ee4adSMatthew G. Knepley   }
307063ee4adSMatthew G. Knepley 
30820cf1dd8SToby Isaac   /* process any options handlers added with PetscObjectAddOptionsHandler() */
309dbbe0bcdSBarry Smith   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject));
310d0609cedSBarry Smith   PetscOptionsEnd();
311063ee4adSMatthew G. Knepley   sp->setfromoptionscalled = PETSC_TRUE;
31220cf1dd8SToby Isaac   PetscFunctionReturn(0);
31320cf1dd8SToby Isaac }
31420cf1dd8SToby Isaac 
31520cf1dd8SToby Isaac /*@
31620cf1dd8SToby Isaac   PetscDualSpaceSetUp - Construct a basis for the PetscDualSpace
31720cf1dd8SToby Isaac 
318d083f849SBarry Smith   Collective on sp
31920cf1dd8SToby Isaac 
32020cf1dd8SToby Isaac   Input Parameter:
32120cf1dd8SToby Isaac . sp - the PetscDualSpace object to setup
32220cf1dd8SToby Isaac 
323a4ce7ad1SMatthew G. Knepley   Level: intermediate
32420cf1dd8SToby Isaac 
325db781477SPatrick Sanan .seealso `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
32620cf1dd8SToby Isaac @*/
327*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
328*d71ae5a4SJacob Faibussowitsch {
32920cf1dd8SToby Isaac   PetscFunctionBegin;
33020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
33120cf1dd8SToby Isaac   if (sp->setupcalled) PetscFunctionReturn(0);
3329566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
33320cf1dd8SToby Isaac   sp->setupcalled = PETSC_TRUE;
334dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setup);
3359566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
3369566063dSJacob Faibussowitsch   if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view"));
33720cf1dd8SToby Isaac   PetscFunctionReturn(0);
33820cf1dd8SToby Isaac }
33920cf1dd8SToby Isaac 
340*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm)
341*d71ae5a4SJacob Faibussowitsch {
342b4457527SToby Isaac   PetscInt pStart = -1, pEnd = -1, depth = -1;
343b4457527SToby Isaac 
344b4457527SToby Isaac   PetscFunctionBegin;
345b4457527SToby Isaac   if (!dm) PetscFunctionReturn(0);
3469566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
348b4457527SToby Isaac 
349b4457527SToby Isaac   if (sp->pointSpaces) {
350b4457527SToby Isaac     PetscInt i;
351b4457527SToby Isaac 
35248a46eb9SPierre Jolivet     for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&(sp->pointSpaces[i])));
353b4457527SToby Isaac   }
3549566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->pointSpaces));
355b4457527SToby Isaac 
356b4457527SToby Isaac   if (sp->heightSpaces) {
357b4457527SToby Isaac     PetscInt i;
358b4457527SToby Isaac 
35948a46eb9SPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&(sp->heightSpaces[i])));
360b4457527SToby Isaac   }
3619566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
362b4457527SToby Isaac 
3639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&(sp->pointSection)));
3649566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
3659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intDofValues)));
3669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intNodeValues)));
3679566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->intMat)));
3689566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
3699566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allDofValues)));
3709566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allNodeValues)));
3719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->allMat)));
3729566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
373b4457527SToby Isaac   PetscFunctionReturn(0);
374b4457527SToby Isaac }
375b4457527SToby Isaac 
37620cf1dd8SToby Isaac /*@
37720cf1dd8SToby Isaac   PetscDualSpaceDestroy - Destroys a PetscDualSpace object
37820cf1dd8SToby Isaac 
379d083f849SBarry Smith   Collective on sp
38020cf1dd8SToby Isaac 
38120cf1dd8SToby Isaac   Input Parameter:
38220cf1dd8SToby Isaac . sp - the PetscDualSpace object to destroy
38320cf1dd8SToby Isaac 
384a4ce7ad1SMatthew G. Knepley   Level: beginner
38520cf1dd8SToby Isaac 
386db781477SPatrick Sanan .seealso `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
38720cf1dd8SToby Isaac @*/
388*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
389*d71ae5a4SJacob Faibussowitsch {
39020cf1dd8SToby Isaac   PetscInt dim, f;
391b4457527SToby Isaac   DM       dm;
39220cf1dd8SToby Isaac 
39320cf1dd8SToby Isaac   PetscFunctionBegin;
39420cf1dd8SToby Isaac   if (!*sp) PetscFunctionReturn(0);
39520cf1dd8SToby Isaac   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
39620cf1dd8SToby Isaac 
3979371c9d4SSatish Balay   if (--((PetscObject)(*sp))->refct > 0) {
3989371c9d4SSatish Balay     *sp = NULL;
3999371c9d4SSatish Balay     PetscFunctionReturn(0);
4009371c9d4SSatish Balay   }
40120cf1dd8SToby Isaac   ((PetscObject)(*sp))->refct = 0;
40220cf1dd8SToby Isaac 
4039566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
404b4457527SToby Isaac   dm = (*sp)->dm;
405b4457527SToby Isaac 
406dbbe0bcdSBarry Smith   PetscTryTypeMethod((*sp), destroy);
4079566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
408b4457527SToby Isaac 
40948a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
4109566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
4119566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4129566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
41320cf1dd8SToby Isaac   PetscFunctionReturn(0);
41420cf1dd8SToby Isaac }
41520cf1dd8SToby Isaac 
41620cf1dd8SToby Isaac /*@
41720cf1dd8SToby Isaac   PetscDualSpaceCreate - Creates an empty PetscDualSpace object. The type can then be set with PetscDualSpaceSetType().
41820cf1dd8SToby Isaac 
419d083f849SBarry Smith   Collective
42020cf1dd8SToby Isaac 
42120cf1dd8SToby Isaac   Input Parameter:
42220cf1dd8SToby Isaac . comm - The communicator for the PetscDualSpace object
42320cf1dd8SToby Isaac 
42420cf1dd8SToby Isaac   Output Parameter:
42520cf1dd8SToby Isaac . sp - The PetscDualSpace object
42620cf1dd8SToby Isaac 
42720cf1dd8SToby Isaac   Level: beginner
42820cf1dd8SToby Isaac 
429db781477SPatrick Sanan .seealso: `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
43020cf1dd8SToby Isaac @*/
431*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
432*d71ae5a4SJacob Faibussowitsch {
43320cf1dd8SToby Isaac   PetscDualSpace s;
43420cf1dd8SToby Isaac 
43520cf1dd8SToby Isaac   PetscFunctionBegin;
43620cf1dd8SToby Isaac   PetscValidPointer(sp, 2);
4379566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
43820cf1dd8SToby Isaac   *sp = NULL;
4399566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
44020cf1dd8SToby Isaac 
4419566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
44220cf1dd8SToby Isaac 
44320cf1dd8SToby Isaac   s->order       = 0;
44420cf1dd8SToby Isaac   s->Nc          = 1;
4454bee2e38SMatthew G. Knepley   s->k           = 0;
446b4457527SToby Isaac   s->spdim       = -1;
447b4457527SToby Isaac   s->spintdim    = -1;
448b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
44920cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
45020cf1dd8SToby Isaac 
45120cf1dd8SToby Isaac   *sp = s;
45220cf1dd8SToby Isaac   PetscFunctionReturn(0);
45320cf1dd8SToby Isaac }
45420cf1dd8SToby Isaac 
45520cf1dd8SToby Isaac /*@
45620cf1dd8SToby Isaac   PetscDualSpaceDuplicate - Creates a duplicate PetscDualSpace object, however it is not setup.
45720cf1dd8SToby Isaac 
458d083f849SBarry Smith   Collective on sp
45920cf1dd8SToby Isaac 
46020cf1dd8SToby Isaac   Input Parameter:
46120cf1dd8SToby Isaac . sp - The original PetscDualSpace
46220cf1dd8SToby Isaac 
46320cf1dd8SToby Isaac   Output Parameter:
46420cf1dd8SToby Isaac . spNew - The duplicate PetscDualSpace
46520cf1dd8SToby Isaac 
46620cf1dd8SToby Isaac   Level: beginner
46720cf1dd8SToby Isaac 
468db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
46920cf1dd8SToby Isaac @*/
470*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
471*d71ae5a4SJacob Faibussowitsch {
472b4457527SToby Isaac   DM                 dm;
473b4457527SToby Isaac   PetscDualSpaceType type;
474b4457527SToby Isaac   const char        *name;
47520cf1dd8SToby Isaac 
47620cf1dd8SToby Isaac   PetscFunctionBegin;
47720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
47820cf1dd8SToby Isaac   PetscValidPointer(spNew, 2);
4799566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4809566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)sp, &name));
4819566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*spNew, name));
4829566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4839566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4849566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4859566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
486b4457527SToby Isaac 
487b4457527SToby Isaac   (*spNew)->order   = sp->order;
488b4457527SToby Isaac   (*spNew)->k       = sp->k;
489b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
490b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
491dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
49220cf1dd8SToby Isaac   PetscFunctionReturn(0);
49320cf1dd8SToby Isaac }
49420cf1dd8SToby Isaac 
49520cf1dd8SToby Isaac /*@
49620cf1dd8SToby Isaac   PetscDualSpaceGetDM - Get the DM representing the reference cell
49720cf1dd8SToby Isaac 
49820cf1dd8SToby Isaac   Not collective
49920cf1dd8SToby Isaac 
50020cf1dd8SToby Isaac   Input Parameter:
50120cf1dd8SToby Isaac . sp - The PetscDualSpace
50220cf1dd8SToby Isaac 
50320cf1dd8SToby Isaac   Output Parameter:
50420cf1dd8SToby Isaac . dm - The reference cell
50520cf1dd8SToby Isaac 
50620cf1dd8SToby Isaac   Level: intermediate
50720cf1dd8SToby Isaac 
508db781477SPatrick Sanan .seealso: `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
50920cf1dd8SToby Isaac @*/
510*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
511*d71ae5a4SJacob Faibussowitsch {
51220cf1dd8SToby Isaac   PetscFunctionBegin;
51320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
51420cf1dd8SToby Isaac   PetscValidPointer(dm, 2);
51520cf1dd8SToby Isaac   *dm = sp->dm;
51620cf1dd8SToby Isaac   PetscFunctionReturn(0);
51720cf1dd8SToby Isaac }
51820cf1dd8SToby Isaac 
51920cf1dd8SToby Isaac /*@
52020cf1dd8SToby Isaac   PetscDualSpaceSetDM - Get the DM representing the reference cell
52120cf1dd8SToby Isaac 
52220cf1dd8SToby Isaac   Not collective
52320cf1dd8SToby Isaac 
52420cf1dd8SToby Isaac   Input Parameters:
52520cf1dd8SToby Isaac + sp - The PetscDualSpace
52620cf1dd8SToby Isaac - dm - The reference cell
52720cf1dd8SToby Isaac 
52820cf1dd8SToby Isaac   Level: intermediate
52920cf1dd8SToby Isaac 
530db781477SPatrick Sanan .seealso: `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
53120cf1dd8SToby Isaac @*/
532*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
533*d71ae5a4SJacob Faibussowitsch {
53420cf1dd8SToby Isaac   PetscFunctionBegin;
53520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
53620cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
53728b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5389566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
53948a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5409566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
54120cf1dd8SToby Isaac   sp->dm = dm;
54220cf1dd8SToby Isaac   PetscFunctionReturn(0);
54320cf1dd8SToby Isaac }
54420cf1dd8SToby Isaac 
54520cf1dd8SToby Isaac /*@
54620cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
54720cf1dd8SToby Isaac 
54820cf1dd8SToby Isaac   Not collective
54920cf1dd8SToby Isaac 
55020cf1dd8SToby Isaac   Input Parameter:
55120cf1dd8SToby Isaac . sp - The PetscDualSpace
55220cf1dd8SToby Isaac 
55320cf1dd8SToby Isaac   Output Parameter:
55420cf1dd8SToby Isaac . order - The order
55520cf1dd8SToby Isaac 
55620cf1dd8SToby Isaac   Level: intermediate
55720cf1dd8SToby Isaac 
558db781477SPatrick Sanan .seealso: `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
55920cf1dd8SToby Isaac @*/
560*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
561*d71ae5a4SJacob Faibussowitsch {
56220cf1dd8SToby Isaac   PetscFunctionBegin;
56320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
564dadcf809SJacob Faibussowitsch   PetscValidIntPointer(order, 2);
56520cf1dd8SToby Isaac   *order = sp->order;
56620cf1dd8SToby Isaac   PetscFunctionReturn(0);
56720cf1dd8SToby Isaac }
56820cf1dd8SToby Isaac 
56920cf1dd8SToby Isaac /*@
57020cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
57120cf1dd8SToby Isaac 
57220cf1dd8SToby Isaac   Not collective
57320cf1dd8SToby Isaac 
57420cf1dd8SToby Isaac   Input Parameters:
57520cf1dd8SToby Isaac + sp - The PetscDualSpace
57620cf1dd8SToby Isaac - order - The order
57720cf1dd8SToby Isaac 
57820cf1dd8SToby Isaac   Level: intermediate
57920cf1dd8SToby Isaac 
580db781477SPatrick Sanan .seealso: `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
58120cf1dd8SToby Isaac @*/
582*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
583*d71ae5a4SJacob Faibussowitsch {
58420cf1dd8SToby Isaac   PetscFunctionBegin;
58520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
58628b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
58720cf1dd8SToby Isaac   sp->order = order;
58820cf1dd8SToby Isaac   PetscFunctionReturn(0);
58920cf1dd8SToby Isaac }
59020cf1dd8SToby Isaac 
59120cf1dd8SToby Isaac /*@
59220cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
59320cf1dd8SToby Isaac 
59420cf1dd8SToby Isaac   Input Parameter:
59520cf1dd8SToby Isaac . sp - The PetscDualSpace
59620cf1dd8SToby Isaac 
59720cf1dd8SToby Isaac   Output Parameter:
59820cf1dd8SToby Isaac . Nc - The number of components
59920cf1dd8SToby Isaac 
60020cf1dd8SToby Isaac   Note: A vector space, for example, will have d components, where d is the spatial dimension
60120cf1dd8SToby Isaac 
60220cf1dd8SToby Isaac   Level: intermediate
60320cf1dd8SToby Isaac 
604db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
60520cf1dd8SToby Isaac @*/
606*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
607*d71ae5a4SJacob Faibussowitsch {
60820cf1dd8SToby Isaac   PetscFunctionBegin;
60920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
610dadcf809SJacob Faibussowitsch   PetscValidIntPointer(Nc, 2);
61120cf1dd8SToby Isaac   *Nc = sp->Nc;
61220cf1dd8SToby Isaac   PetscFunctionReturn(0);
61320cf1dd8SToby Isaac }
61420cf1dd8SToby Isaac 
61520cf1dd8SToby Isaac /*@
61620cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
61720cf1dd8SToby Isaac 
61820cf1dd8SToby Isaac   Input Parameters:
61920cf1dd8SToby Isaac + sp - The PetscDualSpace
62020cf1dd8SToby Isaac - order - The number of components
62120cf1dd8SToby Isaac 
62220cf1dd8SToby Isaac   Level: intermediate
62320cf1dd8SToby Isaac 
624db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
62520cf1dd8SToby Isaac @*/
626*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
627*d71ae5a4SJacob Faibussowitsch {
62820cf1dd8SToby Isaac   PetscFunctionBegin;
62920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
63028b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
63120cf1dd8SToby Isaac   sp->Nc = Nc;
63220cf1dd8SToby Isaac   PetscFunctionReturn(0);
63320cf1dd8SToby Isaac }
63420cf1dd8SToby Isaac 
63520cf1dd8SToby Isaac /*@
63620cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
63720cf1dd8SToby Isaac 
63820cf1dd8SToby Isaac   Not collective
63920cf1dd8SToby Isaac 
64020cf1dd8SToby Isaac   Input Parameters:
64120cf1dd8SToby Isaac + sp - The PetscDualSpace
64220cf1dd8SToby Isaac - i  - The basis number
64320cf1dd8SToby Isaac 
64420cf1dd8SToby Isaac   Output Parameter:
64520cf1dd8SToby Isaac . functional - The basis functional
64620cf1dd8SToby Isaac 
64720cf1dd8SToby Isaac   Level: intermediate
64820cf1dd8SToby Isaac 
649db781477SPatrick Sanan .seealso: `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
65020cf1dd8SToby Isaac @*/
651*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
652*d71ae5a4SJacob Faibussowitsch {
65320cf1dd8SToby Isaac   PetscInt dim;
65420cf1dd8SToby Isaac 
65520cf1dd8SToby Isaac   PetscFunctionBegin;
65620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
65720cf1dd8SToby Isaac   PetscValidPointer(functional, 3);
6589566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
65963a3b9bcSJacob 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);
66020cf1dd8SToby Isaac   *functional = sp->functional[i];
66120cf1dd8SToby Isaac   PetscFunctionReturn(0);
66220cf1dd8SToby Isaac }
66320cf1dd8SToby Isaac 
66420cf1dd8SToby Isaac /*@
66520cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
66620cf1dd8SToby Isaac 
66720cf1dd8SToby Isaac   Not collective
66820cf1dd8SToby Isaac 
66920cf1dd8SToby Isaac   Input Parameter:
67020cf1dd8SToby Isaac . sp - The PetscDualSpace
67120cf1dd8SToby Isaac 
67220cf1dd8SToby Isaac   Output Parameter:
67320cf1dd8SToby Isaac . dim - The dimension
67420cf1dd8SToby Isaac 
67520cf1dd8SToby Isaac   Level: intermediate
67620cf1dd8SToby Isaac 
677db781477SPatrick Sanan .seealso: `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
67820cf1dd8SToby Isaac @*/
679*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
680*d71ae5a4SJacob Faibussowitsch {
68120cf1dd8SToby Isaac   PetscFunctionBegin;
68220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
683dadcf809SJacob Faibussowitsch   PetscValidIntPointer(dim, 2);
684b4457527SToby Isaac   if (sp->spdim < 0) {
685b4457527SToby Isaac     PetscSection section;
686b4457527SToby Isaac 
6879566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
688b4457527SToby Isaac     if (section) {
6899566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(section, &(sp->spdim)));
690b4457527SToby Isaac     } else sp->spdim = 0;
691b4457527SToby Isaac   }
692b4457527SToby Isaac   *dim = sp->spdim;
69320cf1dd8SToby Isaac   PetscFunctionReturn(0);
69420cf1dd8SToby Isaac }
69520cf1dd8SToby Isaac 
696b4457527SToby Isaac /*@
697b4457527SToby 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
698b4457527SToby Isaac 
699b4457527SToby Isaac   Not collective
700b4457527SToby Isaac 
701b4457527SToby Isaac   Input Parameter:
702b4457527SToby Isaac . sp - The PetscDualSpace
703b4457527SToby Isaac 
704b4457527SToby Isaac   Output Parameter:
705b4457527SToby Isaac . dim - The dimension
706b4457527SToby Isaac 
707b4457527SToby Isaac   Level: intermediate
708b4457527SToby Isaac 
709db781477SPatrick Sanan .seealso: `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
710b4457527SToby Isaac @*/
711*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim)
712*d71ae5a4SJacob Faibussowitsch {
713b4457527SToby Isaac   PetscFunctionBegin;
714b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
715dadcf809SJacob Faibussowitsch   PetscValidIntPointer(intdim, 2);
716b4457527SToby Isaac   if (sp->spintdim < 0) {
717b4457527SToby Isaac     PetscSection section;
718b4457527SToby Isaac 
7199566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
720b4457527SToby Isaac     if (section) {
7219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstrainedStorageSize(section, &(sp->spintdim)));
722b4457527SToby Isaac     } else sp->spintdim = 0;
723b4457527SToby Isaac   }
724b4457527SToby Isaac   *intdim = sp->spintdim;
725b4457527SToby Isaac   PetscFunctionReturn(0);
726b4457527SToby Isaac }
727b4457527SToby Isaac 
728b4457527SToby Isaac /*@
729b4457527SToby Isaac    PetscDualSpaceGetUniform - Whether this dual space is uniform
730b4457527SToby Isaac 
731b4457527SToby Isaac    Not collective
732b4457527SToby Isaac 
733b4457527SToby Isaac    Input Parameters:
734b4457527SToby Isaac .  sp - A dual space
735b4457527SToby Isaac 
736b4457527SToby Isaac    Output Parameters:
737b4457527SToby Isaac .  uniform - PETSC_TRUE if (a) the dual space is the same for each point in a stratum of the reference DMPlex, and
738b4457527SToby Isaac              (b) every symmetry of each point in the reference DMPlex is also a symmetry of the point's dual space.
739b4457527SToby Isaac 
740b4457527SToby Isaac    Level: advanced
741b4457527SToby Isaac 
742b4457527SToby Isaac    Note: all of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
743b4457527SToby Isaac    with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
744b4457527SToby Isaac 
745db781477SPatrick Sanan .seealso: `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
746b4457527SToby Isaac @*/
747*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform)
748*d71ae5a4SJacob Faibussowitsch {
749b4457527SToby Isaac   PetscFunctionBegin;
750b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
751dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(uniform, 2);
752b4457527SToby Isaac   *uniform = sp->uniform;
753b4457527SToby Isaac   PetscFunctionReturn(0);
754b4457527SToby Isaac }
755b4457527SToby Isaac 
75620cf1dd8SToby Isaac /*@C
75720cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
75820cf1dd8SToby Isaac 
75920cf1dd8SToby Isaac   Not collective
76020cf1dd8SToby Isaac 
76120cf1dd8SToby Isaac   Input Parameter:
76220cf1dd8SToby Isaac . sp - The PetscDualSpace
76320cf1dd8SToby Isaac 
76420cf1dd8SToby Isaac   Output Parameter:
76520cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
76620cf1dd8SToby Isaac 
76720cf1dd8SToby Isaac   Level: intermediate
76820cf1dd8SToby Isaac 
769db781477SPatrick Sanan .seealso: `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
77020cf1dd8SToby Isaac @*/
771*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof)
772*d71ae5a4SJacob Faibussowitsch {
77320cf1dd8SToby Isaac   PetscFunctionBegin;
77420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
77520cf1dd8SToby Isaac   PetscValidPointer(numDof, 2);
77628b400f6SJacob 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");
777b4457527SToby Isaac   if (!sp->numDof) {
778b4457527SToby Isaac     DM           dm;
779b4457527SToby Isaac     PetscInt     depth, d;
780b4457527SToby Isaac     PetscSection section;
781b4457527SToby Isaac 
7829566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
7839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
7849566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->numDof)));
7859566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
786b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
787b4457527SToby Isaac       PetscInt dStart, dEnd;
788b4457527SToby Isaac 
7899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
790b4457527SToby Isaac       if (dEnd <= dStart) continue;
7919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, dStart, &(sp->numDof[d])));
792b4457527SToby Isaac     }
793b4457527SToby Isaac   }
794b4457527SToby Isaac   *numDof = sp->numDof;
79508401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
79620cf1dd8SToby Isaac   PetscFunctionReturn(0);
79720cf1dd8SToby Isaac }
79820cf1dd8SToby Isaac 
799b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
800*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection)
801*d71ae5a4SJacob Faibussowitsch {
802b4457527SToby Isaac   DM           dm;
803b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
804b4457527SToby Isaac   PetscInt    *seen, *perm;
805b4457527SToby Isaac   PetscSection section;
806b4457527SToby Isaac 
807b4457527SToby Isaac   PetscFunctionBegin;
808b4457527SToby Isaac   dm = sp->dm;
8099566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
8109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8119566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
8129566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
8139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
8149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
8159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
816b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
817b4457527SToby Isaac     PetscInt  closureSize = -1, e;
818b4457527SToby Isaac     PetscInt *closure     = NULL;
819b4457527SToby Isaac 
820b4457527SToby Isaac     perm[count++]    = c;
821b4457527SToby Isaac     seen[c - pStart] = 1;
8229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
823b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
824b4457527SToby Isaac       PetscInt point = closure[2 * e];
825b4457527SToby Isaac 
826b4457527SToby Isaac       if (seen[point - pStart]) continue;
827b4457527SToby Isaac       perm[count++]        = point;
828b4457527SToby Isaac       seen[point - pStart] = 1;
829b4457527SToby Isaac     }
8309566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
831b4457527SToby Isaac   }
8321dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8339371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8349371c9d4SSatish Balay     if (perm[i] != i) break;
835b4457527SToby Isaac   if (i < pEnd - pStart) {
836b4457527SToby Isaac     IS permIS;
837b4457527SToby Isaac 
8389566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8399566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8409566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8419566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
842b4457527SToby Isaac   } else {
8439566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
844b4457527SToby Isaac   }
8459566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
846b4457527SToby Isaac   *topSection = section;
847b4457527SToby Isaac   PetscFunctionReturn(0);
848b4457527SToby Isaac }
849b4457527SToby Isaac 
850b4457527SToby Isaac /* mark boundary points and set up */
851*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section)
852*d71ae5a4SJacob Faibussowitsch {
853b4457527SToby Isaac   DM       dm;
854b4457527SToby Isaac   DMLabel  boundary;
855b4457527SToby Isaac   PetscInt pStart, pEnd, p;
856b4457527SToby Isaac 
857b4457527SToby Isaac   PetscFunctionBegin;
858b4457527SToby Isaac   dm = sp->dm;
8599566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8609566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8619566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8629566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
864b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
865b4457527SToby Isaac     PetscInt bval;
866b4457527SToby Isaac 
8679566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
868b4457527SToby Isaac     if (bval == 1) {
869b4457527SToby Isaac       PetscInt dof;
870b4457527SToby Isaac 
8719566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8729566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
873b4457527SToby Isaac     }
874b4457527SToby Isaac   }
8759566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8769566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
877b4457527SToby Isaac   PetscFunctionReturn(0);
878b4457527SToby Isaac }
879b4457527SToby Isaac 
880a4ce7ad1SMatthew G. Knepley /*@
881b4457527SToby Isaac   PetscDualSpaceGetSection - Create a PetscSection over the reference cell with the layout from this space
882a4ce7ad1SMatthew G. Knepley 
883a4ce7ad1SMatthew G. Knepley   Collective on sp
884a4ce7ad1SMatthew G. Knepley 
885a4ce7ad1SMatthew G. Knepley   Input Parameters:
886f0fc11ceSJed Brown . sp      - The PetscDualSpace
887a4ce7ad1SMatthew G. Knepley 
888a4ce7ad1SMatthew G. Knepley   Output Parameter:
889a4ce7ad1SMatthew G. Knepley . section - The section
890a4ce7ad1SMatthew G. Knepley 
891a4ce7ad1SMatthew G. Knepley   Level: advanced
892a4ce7ad1SMatthew G. Knepley 
893db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `DMPLEX`
894a4ce7ad1SMatthew G. Knepley @*/
895*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section)
896*d71ae5a4SJacob Faibussowitsch {
897b4457527SToby Isaac   PetscInt pStart, pEnd, p;
898b4457527SToby Isaac 
899b4457527SToby Isaac   PetscFunctionBegin;
90078f1d139SRomain Beucher   if (!sp->dm) {
90178f1d139SRomain Beucher     *section = NULL;
90278f1d139SRomain Beucher     PetscFunctionReturn(0);
90378f1d139SRomain Beucher   }
904b4457527SToby Isaac   if (!sp->pointSection) {
905b4457527SToby Isaac     /* mark the boundary */
9069566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &(sp->pointSection)));
9079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
908b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
909b4457527SToby Isaac       PetscDualSpace psp;
910b4457527SToby Isaac 
9119566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
912b4457527SToby Isaac       if (psp) {
913b4457527SToby Isaac         PetscInt dof;
914b4457527SToby Isaac 
9159566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
9169566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
917b4457527SToby Isaac       }
918b4457527SToby Isaac     }
9199566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
920b4457527SToby Isaac   }
921b4457527SToby Isaac   *section = sp->pointSection;
922b4457527SToby Isaac   PetscFunctionReturn(0);
923b4457527SToby Isaac }
924b4457527SToby Isaac 
925b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
926b4457527SToby Isaac  * have one cell */
927*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd)
928*d71ae5a4SJacob Faibussowitsch {
929b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
930b4457527SToby Isaac   PetscSection section;
931b4457527SToby Isaac   PetscInt     dim, s, k;
93220cf1dd8SToby Isaac   DM           dm;
93320cf1dd8SToby Isaac 
93420cf1dd8SToby Isaac   PetscFunctionBegin;
9359566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
9369566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9379566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
9389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
9399566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
940b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
941b4457527SToby Isaac     PetscReal      detJ, hdetJ;
942b4457527SToby Isaac     PetscDualSpace ssp;
943b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
944b4457527SToby Isaac     PetscInt       i, j;
945b4457527SToby Isaac     DM             sdm;
94620cf1dd8SToby Isaac 
9479566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
948b4457527SToby Isaac     if (!ssp) continue;
9499566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
9509566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
951b4457527SToby Isaac     /* get the first vertex of the reference cell */
9529566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
9539566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
9549566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
9559566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
956b4457527SToby Isaac     /* compactify Jacobian */
9579371c9d4SSatish Balay     for (i = 0; i < dim; i++)
9589371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
959b4457527SToby Isaac     for (f = 0; f < dof; f++) {
960b4457527SToby Isaac       PetscQuadrature fn;
96120cf1dd8SToby Isaac 
9629566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
9639566063dSJacob Faibussowitsch       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &(sp->functional[off + f])));
96420cf1dd8SToby Isaac     }
96520cf1dd8SToby Isaac   }
9669566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
96720cf1dd8SToby Isaac   PetscFunctionReturn(0);
96820cf1dd8SToby Isaac }
96920cf1dd8SToby Isaac 
97020cf1dd8SToby Isaac /*@C
97120cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
97220cf1dd8SToby Isaac 
97320cf1dd8SToby Isaac   Input Parameters:
97420cf1dd8SToby Isaac + sp      - The PetscDualSpace object
97520cf1dd8SToby Isaac . f       - The basis functional index
97620cf1dd8SToby Isaac . time    - The time
97720cf1dd8SToby 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)
97820cf1dd8SToby Isaac . numComp - The number of components for the function
97920cf1dd8SToby Isaac . func    - The input function
98020cf1dd8SToby Isaac - ctx     - A context for the function
98120cf1dd8SToby Isaac 
98220cf1dd8SToby Isaac   Output Parameter:
98320cf1dd8SToby Isaac . value   - numComp output values
98420cf1dd8SToby Isaac 
98520cf1dd8SToby Isaac   Note: The calling sequence for the callback func is given by:
98620cf1dd8SToby Isaac 
98720cf1dd8SToby Isaac $ func(PetscInt dim, PetscReal time, const PetscReal x[],
98820cf1dd8SToby Isaac $      PetscInt numComponents, PetscScalar values[], void *ctx)
98920cf1dd8SToby Isaac 
990a4ce7ad1SMatthew G. Knepley   Level: beginner
99120cf1dd8SToby Isaac 
992db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
99320cf1dd8SToby Isaac @*/
994*d71ae5a4SJacob 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)
995*d71ae5a4SJacob Faibussowitsch {
99620cf1dd8SToby Isaac   PetscFunctionBegin;
99720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
99820cf1dd8SToby Isaac   PetscValidPointer(cgeom, 4);
999dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
1000dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
100120cf1dd8SToby Isaac   PetscFunctionReturn(0);
100220cf1dd8SToby Isaac }
100320cf1dd8SToby Isaac 
100420cf1dd8SToby Isaac /*@C
1005b4457527SToby Isaac   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllData()
100620cf1dd8SToby Isaac 
100720cf1dd8SToby Isaac   Input Parameters:
100820cf1dd8SToby Isaac + sp        - The PetscDualSpace object
1009b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllData()
101020cf1dd8SToby Isaac 
101120cf1dd8SToby Isaac   Output Parameter:
101220cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
101320cf1dd8SToby Isaac 
1014a4ce7ad1SMatthew G. Knepley   Level: beginner
101520cf1dd8SToby Isaac 
1016db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
101720cf1dd8SToby Isaac @*/
1018*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1019*d71ae5a4SJacob Faibussowitsch {
102020cf1dd8SToby Isaac   PetscFunctionBegin;
102120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1022dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
102320cf1dd8SToby Isaac   PetscFunctionReturn(0);
102420cf1dd8SToby Isaac }
102520cf1dd8SToby Isaac 
102620cf1dd8SToby Isaac /*@C
1027b4457527SToby Isaac   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetInteriorData()
1028b4457527SToby Isaac 
1029b4457527SToby Isaac   Input Parameters:
1030b4457527SToby Isaac + sp        - The PetscDualSpace object
1031b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetInteriorData()
1032b4457527SToby Isaac 
1033b4457527SToby Isaac   Output Parameter:
1034b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1035b4457527SToby Isaac 
1036b4457527SToby Isaac   Level: beginner
1037b4457527SToby Isaac 
1038db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1039b4457527SToby Isaac @*/
1040*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1041*d71ae5a4SJacob Faibussowitsch {
1042b4457527SToby Isaac   PetscFunctionBegin;
1043b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1044dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
1045b4457527SToby Isaac   PetscFunctionReturn(0);
1046b4457527SToby Isaac }
1047b4457527SToby Isaac 
1048b4457527SToby Isaac /*@C
104920cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
105020cf1dd8SToby Isaac 
105120cf1dd8SToby Isaac   Input Parameters:
105220cf1dd8SToby Isaac + sp    - The PetscDualSpace object
105320cf1dd8SToby Isaac . f     - The basis functional index
105420cf1dd8SToby Isaac . time  - The time
105520cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
105620cf1dd8SToby Isaac . Nc    - The number of components for the function
105720cf1dd8SToby Isaac . func  - The input function
105820cf1dd8SToby Isaac - ctx   - A context for the function
105920cf1dd8SToby Isaac 
106020cf1dd8SToby Isaac   Output Parameter:
106120cf1dd8SToby Isaac . value   - The output value
106220cf1dd8SToby Isaac 
106320cf1dd8SToby Isaac   Note: The calling sequence for the callback func is given by:
106420cf1dd8SToby Isaac 
106520cf1dd8SToby Isaac $ func(PetscInt dim, PetscReal time, const PetscReal x[],
106620cf1dd8SToby Isaac $      PetscInt numComponents, PetscScalar values[], void *ctx)
106720cf1dd8SToby Isaac 
106820cf1dd8SToby Isaac and the idea is to evaluate the functional as an integral
106920cf1dd8SToby Isaac 
107020cf1dd8SToby Isaac $ n(f) = int dx n(x) . f(x)
107120cf1dd8SToby Isaac 
107220cf1dd8SToby Isaac where both n and f have Nc components.
107320cf1dd8SToby Isaac 
1074a4ce7ad1SMatthew G. Knepley   Level: beginner
107520cf1dd8SToby Isaac 
1076db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
107720cf1dd8SToby Isaac @*/
1078*d71ae5a4SJacob 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)
1079*d71ae5a4SJacob Faibussowitsch {
108020cf1dd8SToby Isaac   DM               dm;
108120cf1dd8SToby Isaac   PetscQuadrature  n;
108220cf1dd8SToby Isaac   const PetscReal *points, *weights;
108320cf1dd8SToby Isaac   PetscReal        x[3];
108420cf1dd8SToby Isaac   PetscScalar     *val;
108520cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
108620cf1dd8SToby Isaac   PetscBool        isAffine;
108720cf1dd8SToby Isaac 
108820cf1dd8SToby Isaac   PetscFunctionBegin;
108920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1090dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
10919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
10929566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
10939566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
109463a3b9bcSJacob 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);
109563a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
10969566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
109720cf1dd8SToby Isaac   *value   = 0.0;
109820cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
109920cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
110020cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
110120cf1dd8SToby Isaac     if (isAffine) {
110220cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
11039566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
110420cf1dd8SToby Isaac     } else {
11059566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
110620cf1dd8SToby Isaac     }
1107ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
110820cf1dd8SToby Isaac   }
11099566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
111020cf1dd8SToby Isaac   PetscFunctionReturn(0);
111120cf1dd8SToby Isaac }
111220cf1dd8SToby Isaac 
111320cf1dd8SToby Isaac /*@C
1114b4457527SToby Isaac   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllData()
111520cf1dd8SToby Isaac 
111620cf1dd8SToby Isaac   Input Parameters:
111720cf1dd8SToby Isaac + sp        - The PetscDualSpace object
1118b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllData()
111920cf1dd8SToby Isaac 
112020cf1dd8SToby Isaac   Output Parameter:
112120cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
112220cf1dd8SToby Isaac 
1123a4ce7ad1SMatthew G. Knepley   Level: beginner
112420cf1dd8SToby Isaac 
1125db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
112620cf1dd8SToby Isaac @*/
1127*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1128*d71ae5a4SJacob Faibussowitsch {
1129b4457527SToby Isaac   Vec pointValues, dofValues;
1130b4457527SToby Isaac   Mat allMat;
113120cf1dd8SToby Isaac 
113220cf1dd8SToby Isaac   PetscFunctionBegin;
113320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
113420cf1dd8SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1135064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11369566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
113748a46eb9SPierre Jolivet   if (!(sp->allNodeValues)) PetscCall(MatCreateVecs(allMat, &(sp->allNodeValues), NULL));
1138b4457527SToby Isaac   pointValues = sp->allNodeValues;
113948a46eb9SPierre Jolivet   if (!(sp->allDofValues)) PetscCall(MatCreateVecs(allMat, NULL, &(sp->allDofValues)));
1140b4457527SToby Isaac   dofValues = sp->allDofValues;
11419566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11429566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11439566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
11449566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11459566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
1146b4457527SToby Isaac   PetscFunctionReturn(0);
114720cf1dd8SToby Isaac }
1148b4457527SToby Isaac 
1149b4457527SToby Isaac /*@C
1150b4457527SToby Isaac   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetInteriorData()
1151b4457527SToby Isaac 
1152b4457527SToby Isaac   Input Parameters:
1153b4457527SToby Isaac + sp        - The PetscDualSpace object
1154b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetInteriorData()
1155b4457527SToby Isaac 
1156b4457527SToby Isaac   Output Parameter:
1157b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1158b4457527SToby Isaac 
1159b4457527SToby Isaac   Level: beginner
1160b4457527SToby Isaac 
1161db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1162b4457527SToby Isaac @*/
1163*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
1164*d71ae5a4SJacob Faibussowitsch {
1165b4457527SToby Isaac   Vec pointValues, dofValues;
1166b4457527SToby Isaac   Mat intMat;
1167b4457527SToby Isaac 
1168b4457527SToby Isaac   PetscFunctionBegin;
1169b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1170b4457527SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1171064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11729566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
117348a46eb9SPierre Jolivet   if (!(sp->intNodeValues)) PetscCall(MatCreateVecs(intMat, &(sp->intNodeValues), NULL));
1174b4457527SToby Isaac   pointValues = sp->intNodeValues;
117548a46eb9SPierre Jolivet   if (!(sp->intDofValues)) PetscCall(MatCreateVecs(intMat, NULL, &(sp->intDofValues)));
1176b4457527SToby Isaac   dofValues = sp->intDofValues;
11779566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11789566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11799566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
11809566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11819566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
118220cf1dd8SToby Isaac   PetscFunctionReturn(0);
118320cf1dd8SToby Isaac }
118420cf1dd8SToby Isaac 
1185a4ce7ad1SMatthew G. Knepley /*@
1186b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1187a4ce7ad1SMatthew G. Knepley 
1188a4ce7ad1SMatthew G. Knepley   Input Parameter:
1189a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1190a4ce7ad1SMatthew G. Knepley 
1191d8d19677SJose E. Roman   Output Parameters:
1192b4457527SToby Isaac + allNodes - A PetscQuadrature object containing all evaluation nodes
1193b4457527SToby Isaac - allMat - A Mat for the node-to-dof transformation
1194a4ce7ad1SMatthew G. Knepley 
1195a4ce7ad1SMatthew G. Knepley   Level: advanced
1196a4ce7ad1SMatthew G. Knepley 
1197db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1198a4ce7ad1SMatthew G. Knepley @*/
1199*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1200*d71ae5a4SJacob Faibussowitsch {
120120cf1dd8SToby Isaac   PetscFunctionBegin;
120220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1203b4457527SToby Isaac   if (allNodes) PetscValidPointer(allNodes, 2);
1204b4457527SToby Isaac   if (allMat) PetscValidPointer(allMat, 3);
1205b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1206b4457527SToby Isaac     PetscQuadrature qpoints;
1207b4457527SToby Isaac     Mat             amat;
1208b4457527SToby Isaac 
1209dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
12109566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
12119566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->allMat)));
1212b4457527SToby Isaac     sp->allNodes = qpoints;
1213b4457527SToby Isaac     sp->allMat   = amat;
121420cf1dd8SToby Isaac   }
1215b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1216b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
121720cf1dd8SToby Isaac   PetscFunctionReturn(0);
121820cf1dd8SToby Isaac }
121920cf1dd8SToby Isaac 
1220a4ce7ad1SMatthew G. Knepley /*@
1221b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1222a4ce7ad1SMatthew G. Knepley 
1223a4ce7ad1SMatthew G. Knepley   Input Parameter:
1224a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1225a4ce7ad1SMatthew G. Knepley 
1226d8d19677SJose E. Roman   Output Parameters:
1227b4457527SToby Isaac + allNodes - A PetscQuadrature object containing all evaluation nodes
1228b4457527SToby Isaac - allMat - A Mat for the node-to-dof transformation
1229a4ce7ad1SMatthew G. Knepley 
1230a4ce7ad1SMatthew G. Knepley   Level: advanced
1231a4ce7ad1SMatthew G. Knepley 
1232db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1233a4ce7ad1SMatthew G. Knepley @*/
1234*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat)
1235*d71ae5a4SJacob Faibussowitsch {
123620cf1dd8SToby Isaac   PetscInt        spdim;
123720cf1dd8SToby Isaac   PetscInt        numPoints, offset;
123820cf1dd8SToby Isaac   PetscReal      *points;
123920cf1dd8SToby Isaac   PetscInt        f, dim;
1240b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1241b4457527SToby Isaac   PetscInt        maxNumPoints;
124220cf1dd8SToby Isaac   PetscQuadrature q;
1243b4457527SToby Isaac   Mat             A;
124420cf1dd8SToby Isaac 
124520cf1dd8SToby Isaac   PetscFunctionBegin;
12469566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
12479566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
124820cf1dd8SToby Isaac   if (!spdim) {
12499566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12509566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
125120cf1dd8SToby Isaac   }
1252b4457527SToby Isaac   nrows = spdim;
12539566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
12549566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1255b4457527SToby Isaac   maxNumPoints = numPoints;
125620cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
125720cf1dd8SToby Isaac     PetscInt Np;
125820cf1dd8SToby Isaac 
12599566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12609566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
126120cf1dd8SToby Isaac     numPoints += Np;
1262b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
126320cf1dd8SToby Isaac   }
1264b4457527SToby Isaac   ncols = numPoints * Nc;
12659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
12669566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
126720cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1268b4457527SToby Isaac     const PetscReal *p, *w;
126920cf1dd8SToby Isaac     PetscInt         Np, i;
1270b4457527SToby Isaac     PetscInt         fnc;
127120cf1dd8SToby Isaac 
12729566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12739566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
127408401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
1275ad540459SPierre Jolivet     for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i];
127648a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1277b4457527SToby Isaac     offset += Np;
1278b4457527SToby Isaac   }
12799566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
12809566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
12819566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12829566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1283b4457527SToby Isaac   *allMat = A;
1284b4457527SToby Isaac   PetscFunctionReturn(0);
1285b4457527SToby Isaac }
1286b4457527SToby Isaac 
1287b4457527SToby Isaac /*@
1288b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1289b4457527SToby Isaac   this space, as well as the matrix that computes the degrees of freedom from the quadrature values.  Degrees of
1290b4457527SToby Isaac   freedom are interior degrees of freedom if they belong (by PetscDualSpaceGetSection()) to interior points in the
1291b4457527SToby Isaac   reference DMPlex: complementary boundary degrees of freedom are marked as constrained in the section returned by
1292b4457527SToby Isaac   PetscDualSpaceGetSection()).
1293b4457527SToby Isaac 
1294b4457527SToby Isaac   Input Parameter:
1295b4457527SToby Isaac . sp - The dualspace
1296b4457527SToby Isaac 
1297d8d19677SJose E. Roman   Output Parameters:
1298b4457527SToby Isaac + intNodes - A PetscQuadrature object containing all evaluation points needed to evaluate interior degrees of freedom
1299b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1300b4457527SToby Isaac              the size of the constrained layout (PetscSectionGetConstrainStorageSize()) of the dual space section,
1301b4457527SToby Isaac              npoints is the number of points in intNodes and nc is PetscDualSpaceGetNumComponents().
1302b4457527SToby Isaac 
1303b4457527SToby Isaac   Level: advanced
1304b4457527SToby Isaac 
1305db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1306b4457527SToby Isaac @*/
1307*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1308*d71ae5a4SJacob Faibussowitsch {
1309b4457527SToby Isaac   PetscFunctionBegin;
1310b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1311b4457527SToby Isaac   if (intNodes) PetscValidPointer(intNodes, 2);
1312b4457527SToby Isaac   if (intMat) PetscValidPointer(intMat, 3);
1313b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1314b4457527SToby Isaac     PetscQuadrature qpoints;
1315b4457527SToby Isaac     Mat             imat;
1316b4457527SToby Isaac 
1317dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
13189566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
13199566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->intMat)));
1320b4457527SToby Isaac     sp->intNodes = qpoints;
1321b4457527SToby Isaac     sp->intMat   = imat;
1322b4457527SToby Isaac   }
1323b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1324b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
1325b4457527SToby Isaac   PetscFunctionReturn(0);
1326b4457527SToby Isaac }
1327b4457527SToby Isaac 
1328b4457527SToby Isaac /*@
1329b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1330b4457527SToby Isaac 
1331b4457527SToby Isaac   Input Parameter:
1332b4457527SToby Isaac . sp - The dualspace
1333b4457527SToby Isaac 
1334d8d19677SJose E. Roman   Output Parameters:
1335b4457527SToby Isaac + intNodes - A PetscQuadrature object containing all evaluation points needed to evaluate interior degrees of freedom
1336b4457527SToby Isaac - intMat    - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1337b4457527SToby Isaac               the size of the constrained layout (PetscSectionGetConstrainStorageSize()) of the dual space section,
1338b4457527SToby Isaac               npoints is the number of points in allNodes and nc is PetscDualSpaceGetNumComponents().
1339b4457527SToby Isaac 
1340b4457527SToby Isaac   Level: advanced
1341b4457527SToby Isaac 
1342db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1343b4457527SToby Isaac @*/
1344*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat)
1345*d71ae5a4SJacob Faibussowitsch {
1346b4457527SToby Isaac   DM              dm;
1347b4457527SToby Isaac   PetscInt        spdim0;
1348b4457527SToby Isaac   PetscInt        Nc;
1349b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1350b4457527SToby Isaac   PetscSection    section;
1351b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1352b4457527SToby Isaac   PetscReal      *points;
1353b4457527SToby Isaac   PetscInt        dim;
1354b4457527SToby Isaac   PetscInt       *nnz;
1355b4457527SToby Isaac   PetscQuadrature q;
1356b4457527SToby Isaac   Mat             imat;
1357b4457527SToby Isaac 
1358b4457527SToby Isaac   PetscFunctionBegin;
1359b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13609566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
13619566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1362b4457527SToby Isaac   if (!spdim0) {
1363b4457527SToby Isaac     *intNodes = NULL;
1364b4457527SToby Isaac     *intMat   = NULL;
1365b4457527SToby Isaac     PetscFunctionReturn(0);
1366b4457527SToby Isaac   }
13679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13689566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
13699566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
13709566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13719566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1372b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1373b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1374b4457527SToby Isaac 
13759566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13769566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1377b4457527SToby Isaac     if (!(dof - cdof)) continue;
13789566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1379b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1380b4457527SToby Isaac       PetscInt Np;
1381b4457527SToby Isaac 
13829566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
13839566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1384b4457527SToby Isaac       nnz[f] = Np * Nc;
1385b4457527SToby Isaac       numPoints += Np;
1386b4457527SToby Isaac     }
1387b4457527SToby Isaac   }
13889566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
13899566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
13909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1391b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1392b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1393b4457527SToby Isaac 
13949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1396b4457527SToby Isaac     if (!(dof - cdof)) continue;
13979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1398b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1399b4457527SToby Isaac       const PetscReal *p;
1400b4457527SToby Isaac       const PetscReal *w;
1401b4457527SToby Isaac       PetscInt         Np, i;
1402b4457527SToby Isaac 
14039566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
14049566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
1405ad540459SPierre Jolivet       for (i = 0; i < Np * dim; i++) points[offset + i] = p[i];
140648a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1407b4457527SToby Isaac       offset += Np * dim;
1408b4457527SToby Isaac       matoffset += Np * Nc;
1409b4457527SToby Isaac     }
1410b4457527SToby Isaac   }
14119566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
14129566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
14139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
14149566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1415b4457527SToby Isaac   *intMat = imat;
141620cf1dd8SToby Isaac   PetscFunctionReturn(0);
141720cf1dd8SToby Isaac }
141820cf1dd8SToby Isaac 
14194f9ab2b4SJed Brown /*@
14204f9ab2b4SJed Brown   PetscDualSpaceEqual - Determine if a dual space is equivalent
14214f9ab2b4SJed Brown 
14224f9ab2b4SJed Brown   Input Parameters:
14234f9ab2b4SJed Brown + A    - A PetscDualSpace object
14244f9ab2b4SJed Brown - B    - Another PetscDualSpace object
14254f9ab2b4SJed Brown 
14264f9ab2b4SJed Brown   Output Parameter:
14274f9ab2b4SJed Brown . equal - PETSC_TRUE if the dual spaces are equivalent
14284f9ab2b4SJed Brown 
14294f9ab2b4SJed Brown   Level: advanced
14304f9ab2b4SJed Brown 
1431db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
14324f9ab2b4SJed Brown @*/
1433*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal)
1434*d71ae5a4SJacob Faibussowitsch {
14354f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
14364f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
14374f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
14384f9ab2b4SJed Brown   Mat             matA, matB;
14394f9ab2b4SJed Brown 
14404f9ab2b4SJed Brown   PetscFunctionBegin;
14414f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
14424f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
14434f9ab2b4SJed Brown   PetscValidBoolPointer(equal, 3);
14444f9ab2b4SJed Brown   *equal = PETSC_FALSE;
14459566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
14469566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
1447ad540459SPierre Jolivet   if (sizeB != sizeA) PetscFunctionReturn(0);
14489566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
14499566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
1450ad540459SPierre Jolivet   if (dimA != dimB) PetscFunctionReturn(0);
14514f9ab2b4SJed Brown 
14529566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
14539566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
14544f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
1455ad540459SPierre Jolivet     if (dofA[d] != dofB[d]) PetscFunctionReturn(0);
14564f9ab2b4SJed Brown   }
14574f9ab2b4SJed Brown 
14589566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
14599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
14604f9ab2b4SJed Brown   if (!quadA && !quadB) {
14614f9ab2b4SJed Brown     *equal = PETSC_TRUE;
14624f9ab2b4SJed Brown   } else if (quadA && quadB) {
14639566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
14644f9ab2b4SJed Brown     if (*equal == PETSC_FALSE) PetscFunctionReturn(0);
14654f9ab2b4SJed Brown     if (!matA && !matB) PetscFunctionReturn(0);
14669566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
14674f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
14684f9ab2b4SJed Brown   }
14694f9ab2b4SJed Brown   PetscFunctionReturn(0);
14704f9ab2b4SJed Brown }
14714f9ab2b4SJed Brown 
147220cf1dd8SToby Isaac /*@C
147320cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
147420cf1dd8SToby Isaac 
147520cf1dd8SToby Isaac   Input Parameters:
147620cf1dd8SToby Isaac + sp    - The PetscDualSpace object
147720cf1dd8SToby Isaac . f     - The basis functional index
147820cf1dd8SToby Isaac . time  - The time
147920cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
148020cf1dd8SToby Isaac . Nc    - The number of components for the function
148120cf1dd8SToby Isaac . func  - The input function
148220cf1dd8SToby Isaac - ctx   - A context for the function
148320cf1dd8SToby Isaac 
148420cf1dd8SToby Isaac   Output Parameter:
148520cf1dd8SToby Isaac . value - The output value (scalar)
148620cf1dd8SToby Isaac 
148720cf1dd8SToby Isaac   Note: The calling sequence for the callback func is given by:
148820cf1dd8SToby Isaac 
148920cf1dd8SToby Isaac $ func(PetscInt dim, PetscReal time, const PetscReal x[],
149020cf1dd8SToby Isaac $      PetscInt numComponents, PetscScalar values[], void *ctx)
149120cf1dd8SToby Isaac 
149220cf1dd8SToby Isaac and the idea is to evaluate the functional as an integral
149320cf1dd8SToby Isaac 
149420cf1dd8SToby Isaac $ n(f) = int dx n(x) . f(x)
149520cf1dd8SToby Isaac 
149620cf1dd8SToby Isaac where both n and f have Nc components.
149720cf1dd8SToby Isaac 
1498a4ce7ad1SMatthew G. Knepley   Level: beginner
149920cf1dd8SToby Isaac 
1500db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
150120cf1dd8SToby Isaac @*/
1502*d71ae5a4SJacob 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)
1503*d71ae5a4SJacob Faibussowitsch {
150420cf1dd8SToby Isaac   DM               dm;
150520cf1dd8SToby Isaac   PetscQuadrature  n;
150620cf1dd8SToby Isaac   const PetscReal *points, *weights;
150720cf1dd8SToby Isaac   PetscScalar     *val;
150820cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
150920cf1dd8SToby Isaac 
151020cf1dd8SToby Isaac   PetscFunctionBegin;
151120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1512dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
15139566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
15149566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
15159566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
15169566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
151763a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
15189566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
151920cf1dd8SToby Isaac   *value = 0.;
152020cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
15219566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
1522ad540459SPierre Jolivet     for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c];
152320cf1dd8SToby Isaac   }
15249566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
152520cf1dd8SToby Isaac   PetscFunctionReturn(0);
152620cf1dd8SToby Isaac }
152720cf1dd8SToby Isaac 
152820cf1dd8SToby Isaac /*@
152920cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
153020cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
153120cf1dd8SToby Isaac 
153220cf1dd8SToby Isaac   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
153320cf1dd8SToby Isaac   pointwise values are not defined on the element boundaries), or if the implementation of PetscDualSpace does not
153420cf1dd8SToby Isaac   support extracting subspaces, then NULL is returned.
153520cf1dd8SToby Isaac 
153620cf1dd8SToby Isaac   This does not increment the reference count on the returned dual space, and the user should not destroy it.
153720cf1dd8SToby Isaac 
153820cf1dd8SToby Isaac   Not collective
153920cf1dd8SToby Isaac 
154020cf1dd8SToby Isaac   Input Parameters:
154120cf1dd8SToby Isaac + sp - the PetscDualSpace object
154220cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
154320cf1dd8SToby Isaac 
154420cf1dd8SToby Isaac   Output Parameter:
154520cf1dd8SToby Isaac . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
154620cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
154720cf1dd8SToby Isaac 
154820cf1dd8SToby Isaac   Level: advanced
154920cf1dd8SToby Isaac 
1550db781477SPatrick Sanan .seealso: `PetscSpaceGetHeightSubspace()`, `PetscDualSpace`
155120cf1dd8SToby Isaac @*/
1552*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
1553*d71ae5a4SJacob Faibussowitsch {
1554b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1555b4457527SToby Isaac   DM       dm;
155620cf1dd8SToby Isaac 
155720cf1dd8SToby Isaac   PetscFunctionBegin;
155820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1559064a246eSJacob Faibussowitsch   PetscValidPointer(subsp, 3);
156008401ef6SPierre 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");
156120cf1dd8SToby Isaac   *subsp = NULL;
1562b4457527SToby Isaac   dm     = sp->dm;
15639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
15641dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
15659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1566b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1567b4457527SToby Isaac     *subsp = sp;
1568b4457527SToby Isaac     PetscFunctionReturn(0);
1569b4457527SToby Isaac   }
1570b4457527SToby Isaac   if (!sp->heightSpaces) {
1571b4457527SToby Isaac     PetscInt h;
15729566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->heightSpaces)));
1573b4457527SToby Isaac 
1574b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1575b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
15769566063dSJacob Faibussowitsch       if (sp->ops->createheightsubspace) PetscCall((*sp->ops->createheightsubspace)(sp, height, &(sp->heightSpaces[h])));
1577b4457527SToby Isaac       else if (sp->pointSpaces) {
1578b4457527SToby Isaac         PetscInt hStart, hEnd;
1579b4457527SToby Isaac 
15809566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1581b4457527SToby Isaac         if (hEnd > hStart) {
1582665f567fSMatthew G. Knepley           const char *name;
1583665f567fSMatthew G. Knepley 
15849566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)(sp->pointSpaces[hStart])));
1585665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
15869566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
15879566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1588665f567fSMatthew G. Knepley           }
1589b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1590b4457527SToby Isaac         }
1591b4457527SToby Isaac       }
1592b4457527SToby Isaac     }
1593b4457527SToby Isaac   }
1594b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
159520cf1dd8SToby Isaac   PetscFunctionReturn(0);
159620cf1dd8SToby Isaac }
159720cf1dd8SToby Isaac 
159820cf1dd8SToby Isaac /*@
159920cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
160020cf1dd8SToby Isaac 
160120cf1dd8SToby Isaac   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
160220cf1dd8SToby Isaac   defined on the element boundaries), or if the implementation of PetscDualSpace does not support extracting
160320cf1dd8SToby Isaac   subspaces, then NULL is returned.
160420cf1dd8SToby Isaac 
160520cf1dd8SToby Isaac   This does not increment the reference count on the returned dual space, and the user should not destroy it.
160620cf1dd8SToby Isaac 
160720cf1dd8SToby Isaac   Not collective
160820cf1dd8SToby Isaac 
160920cf1dd8SToby Isaac   Input Parameters:
161020cf1dd8SToby Isaac + sp - the PetscDualSpace object
161120cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
161220cf1dd8SToby Isaac 
161320cf1dd8SToby Isaac   Output Parameters:
161420cf1dd8SToby Isaac   bdsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
161520cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
161620cf1dd8SToby Isaac 
161720cf1dd8SToby Isaac   Level: advanced
161820cf1dd8SToby Isaac 
1619db781477SPatrick Sanan .seealso: `PetscDualSpace`
162020cf1dd8SToby Isaac @*/
1621*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1622*d71ae5a4SJacob Faibussowitsch {
1623b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1624b4457527SToby Isaac   DM       dm;
162520cf1dd8SToby Isaac 
162620cf1dd8SToby Isaac   PetscFunctionBegin;
162720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1628064a246eSJacob Faibussowitsch   PetscValidPointer(bdsp, 3);
162920cf1dd8SToby Isaac   *bdsp = NULL;
1630b4457527SToby Isaac   dm    = sp->dm;
16319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
16321dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
16339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1634b4457527SToby 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 */
1635b4457527SToby Isaac     *bdsp = sp;
1636b4457527SToby Isaac     PetscFunctionReturn(0);
1637b4457527SToby Isaac   }
1638b4457527SToby Isaac   if (!sp->pointSpaces) {
1639b4457527SToby Isaac     PetscInt p;
16409566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pEnd - pStart, &(sp->pointSpaces)));
164120cf1dd8SToby Isaac 
1642b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1643b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
16449566063dSJacob Faibussowitsch       if (sp->ops->createpointsubspace) PetscCall((*sp->ops->createpointsubspace)(sp, p + pStart, &(sp->pointSpaces[p])));
1645b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1646b4457527SToby Isaac         PetscInt dim, depth, height;
1647b4457527SToby Isaac         DMLabel  label;
1648b4457527SToby Isaac 
16499566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
16509566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
16519566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
165220cf1dd8SToby Isaac         height = dim - depth;
16539566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &(sp->pointSpaces[p])));
16549566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
165520cf1dd8SToby Isaac       }
1656b4457527SToby Isaac     }
1657b4457527SToby Isaac   }
1658b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
165920cf1dd8SToby Isaac   PetscFunctionReturn(0);
166020cf1dd8SToby Isaac }
166120cf1dd8SToby Isaac 
16626f905325SMatthew G. Knepley /*@C
16636f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
16646f905325SMatthew G. Knepley 
16656f905325SMatthew G. Knepley   Not collective
16666f905325SMatthew G. Knepley 
16676f905325SMatthew G. Knepley   Input Parameter:
16686f905325SMatthew G. Knepley . sp - the PetscDualSpace object
16696f905325SMatthew G. Knepley 
16706f905325SMatthew G. Knepley   Output Parameters:
1671b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1672b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
16736f905325SMatthew G. Knepley 
16746f905325SMatthew G. Knepley   Note: The permutation and flip arrays are organized in the following way
16756f905325SMatthew G. Knepley $ perms[p][ornt][dof # on point] = new local dof #
16766f905325SMatthew G. Knepley $ flips[p][ornt][dof # on point] = reversal or not
16776f905325SMatthew G. Knepley 
16786f905325SMatthew G. Knepley   Level: developer
16796f905325SMatthew G. Knepley 
16806f905325SMatthew G. Knepley @*/
1681*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips)
1682*d71ae5a4SJacob Faibussowitsch {
16836f905325SMatthew G. Knepley   PetscFunctionBegin;
16846f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16859371c9d4SSatish Balay   if (perms) {
16869371c9d4SSatish Balay     PetscValidPointer(perms, 2);
16879371c9d4SSatish Balay     *perms = NULL;
16889371c9d4SSatish Balay   }
16899371c9d4SSatish Balay   if (flips) {
16909371c9d4SSatish Balay     PetscValidPointer(flips, 3);
16919371c9d4SSatish Balay     *flips = NULL;
16929371c9d4SSatish Balay   }
16939566063dSJacob Faibussowitsch   if (sp->ops->getsymmetries) PetscCall((sp->ops->getsymmetries)(sp, perms, flips));
16946f905325SMatthew G. Knepley   PetscFunctionReturn(0);
16956f905325SMatthew G. Knepley }
16964bee2e38SMatthew G. Knepley 
16974bee2e38SMatthew G. Knepley /*@
1698b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1699b4457527SToby Isaac   dual space's functionals.
1700b4457527SToby Isaac 
1701b4457527SToby Isaac   Input Parameter:
1702b4457527SToby Isaac . dsp - The PetscDualSpace
1703b4457527SToby Isaac 
1704b4457527SToby Isaac   Output Parameter:
1705b4457527SToby 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
1706b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1707b4457527SToby 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).
1708b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1709b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1710b4457527SToby Isaac         but are stored as 1-forms.
1711b4457527SToby Isaac 
1712b4457527SToby Isaac   Level: developer
1713b4457527SToby Isaac 
1714db781477SPatrick Sanan .seealso: `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1715b4457527SToby Isaac @*/
1716*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k)
1717*d71ae5a4SJacob Faibussowitsch {
1718b4457527SToby Isaac   PetscFunctionBeginHot;
1719b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1720dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1721b4457527SToby Isaac   *k = dsp->k;
1722b4457527SToby Isaac   PetscFunctionReturn(0);
1723b4457527SToby Isaac }
1724b4457527SToby Isaac 
1725b4457527SToby Isaac /*@
1726b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1727b4457527SToby Isaac   dual space's functionals.
1728b4457527SToby Isaac 
1729d8d19677SJose E. Roman   Input Parameters:
1730b4457527SToby Isaac + dsp - The PetscDualSpace
1731b4457527SToby 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
1732b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1733b4457527SToby 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).
1734b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1735b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1736b4457527SToby Isaac         but are stored as 1-forms.
1737b4457527SToby Isaac 
1738b4457527SToby Isaac   Level: developer
1739b4457527SToby Isaac 
1740db781477SPatrick Sanan .seealso: `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1741b4457527SToby Isaac @*/
1742*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k)
1743*d71ae5a4SJacob Faibussowitsch {
1744b4457527SToby Isaac   PetscInt dim;
1745b4457527SToby Isaac 
1746b4457527SToby Isaac   PetscFunctionBeginHot;
1747b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
174828b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1749b4457527SToby Isaac   dim = dsp->dm->dim;
17501dca8a05SBarry Smith   PetscCheck(k >= -dim && k <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported %" PetscInt_FMT "-form on %" PetscInt_FMT "-dimensional reference cell", PetscAbsInt(k), dim);
1751b4457527SToby Isaac   dsp->k = k;
1752b4457527SToby Isaac   PetscFunctionReturn(0);
1753b4457527SToby Isaac }
1754b4457527SToby Isaac 
1755b4457527SToby Isaac /*@
17564bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
17574bee2e38SMatthew G. Knepley 
17584bee2e38SMatthew G. Knepley   Input Parameter:
17594bee2e38SMatthew G. Knepley . dsp - The PetscDualSpace
17604bee2e38SMatthew G. Knepley 
17614bee2e38SMatthew G. Knepley   Output Parameter:
17624bee2e38SMatthew G. Knepley . k   - The simplex dimension
17634bee2e38SMatthew G. Knepley 
1764a4ce7ad1SMatthew G. Knepley   Level: developer
17654bee2e38SMatthew G. Knepley 
17664bee2e38SMatthew G. Knepley   Note: Currently supported values are
17674bee2e38SMatthew G. Knepley $ 0: These are H_1 methods that only transform coordinates
17684bee2e38SMatthew G. Knepley $ 1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
17694bee2e38SMatthew G. Knepley $ 2: These are the same as 1
17704bee2e38SMatthew G. Knepley $ 3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
17714bee2e38SMatthew G. Knepley 
1772db781477SPatrick Sanan .seealso: `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
17734bee2e38SMatthew G. Knepley @*/
1774*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k)
1775*d71ae5a4SJacob Faibussowitsch {
1776b4457527SToby Isaac   PetscInt dim;
1777b4457527SToby Isaac 
17784bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
17794bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1780dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1781b4457527SToby Isaac   dim = dsp->dm->dim;
1782b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1783b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1784b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1785b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
17864bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
17874bee2e38SMatthew G. Knepley }
17884bee2e38SMatthew G. Knepley 
17894bee2e38SMatthew G. Knepley /*@C
17904bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
17914bee2e38SMatthew G. Knepley 
17924bee2e38SMatthew G. Knepley   Input Parameters:
17934bee2e38SMatthew G. Knepley + dsp       - The PetscDualSpace
17944bee2e38SMatthew G. Knepley . trans     - The type of transform
17954bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
17964bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
17974bee2e38SMatthew G. Knepley . Nv        - The number of function samples
17984bee2e38SMatthew G. Knepley . Nc        - The number of function components
17994bee2e38SMatthew G. Knepley - vals      - The function values
18004bee2e38SMatthew G. Knepley 
18014bee2e38SMatthew G. Knepley   Output Parameter:
18024bee2e38SMatthew G. Knepley . vals      - The transformed function values
18034bee2e38SMatthew G. Knepley 
1804a4ce7ad1SMatthew G. Knepley   Level: intermediate
18054bee2e38SMatthew G. Knepley 
1806f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18072edcad52SToby Isaac 
1808db781477SPatrick Sanan .seealso: `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18094bee2e38SMatthew G. Knepley @*/
1810*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1811*d71ae5a4SJacob Faibussowitsch {
1812b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1813b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
18144bee2e38SMatthew G. Knepley 
18154bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18164bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18174bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1818dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
1819b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
18202ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1821b4457527SToby Isaac   /* No change needed for 0-forms */
1822b4457527SToby Isaac   if (!dsp->k) PetscFunctionReturn(0);
18239566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1824b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
18259566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
18264bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1827b4457527SToby Isaac     switch (Nk) {
1828b4457527SToby Isaac     case 1:
1829b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
18304bee2e38SMatthew G. Knepley       break;
1831b4457527SToby Isaac     case 2:
1832b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
18334bee2e38SMatthew G. Knepley       break;
1834b4457527SToby Isaac     case 3:
1835b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1836b4457527SToby Isaac       break;
1837*d71ae5a4SJacob Faibussowitsch     default:
1838*d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1839b4457527SToby Isaac     }
18404bee2e38SMatthew G. Knepley   }
18414bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
18424bee2e38SMatthew G. Knepley }
1843b4457527SToby Isaac 
18444bee2e38SMatthew G. Knepley /*@C
18454bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
18464bee2e38SMatthew G. Knepley 
18474bee2e38SMatthew G. Knepley   Input Parameters:
18484bee2e38SMatthew G. Knepley + dsp       - The PetscDualSpace
18494bee2e38SMatthew G. Knepley . trans     - The type of transform
18504bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18514bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18524bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
18534bee2e38SMatthew G. Knepley . Nc        - The number of function components
18544bee2e38SMatthew G. Knepley - vals      - The function gradient values
18554bee2e38SMatthew G. Knepley 
18564bee2e38SMatthew G. Knepley   Output Parameter:
1857f9244615SMatthew G. Knepley . vals      - The transformed function gradient values
18584bee2e38SMatthew G. Knepley 
1859a4ce7ad1SMatthew G. Knepley   Level: intermediate
18604bee2e38SMatthew G. Knepley 
1861f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18622edcad52SToby Isaac 
1863db781477SPatrick Sanan .seealso: `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18644bee2e38SMatthew G. Knepley @*/
1865*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
1866*d71ae5a4SJacob Faibussowitsch {
186727f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
186827f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
18694bee2e38SMatthew G. Knepley 
18704bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18714bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18724bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1873dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
187427f02ce8SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
187563a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
187627f02ce8SMatthew G. Knepley #endif
18774bee2e38SMatthew G. Knepley   /* Transform gradient */
187827f02ce8SMatthew G. Knepley   if (dim == dE) {
18794bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
18804bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
18819371c9d4SSatish Balay         switch (dim) {
1882*d71ae5a4SJacob Faibussowitsch         case 1:
1883*d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim] *= fegeom->invJ[0];
1884*d71ae5a4SJacob Faibussowitsch           break;
1885*d71ae5a4SJacob Faibussowitsch         case 2:
1886*d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1887*d71ae5a4SJacob Faibussowitsch           break;
1888*d71ae5a4SJacob Faibussowitsch         case 3:
1889*d71ae5a4SJacob Faibussowitsch           DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]);
1890*d71ae5a4SJacob Faibussowitsch           break;
1891*d71ae5a4SJacob Faibussowitsch         default:
1892*d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18934bee2e38SMatthew G. Knepley         }
18944bee2e38SMatthew G. Knepley       }
18954bee2e38SMatthew G. Knepley     }
189627f02ce8SMatthew G. Knepley   } else {
189727f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1898ad540459SPierre 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]);
189927f02ce8SMatthew G. Knepley     }
190027f02ce8SMatthew G. Knepley   }
19014bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
19024bee2e38SMatthew G. Knepley   if (Nc == 1 || Nc != dim) PetscFunctionReturn(0);
19034bee2e38SMatthew G. Knepley   switch (trans) {
1904*d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
1905*d71ae5a4SJacob Faibussowitsch     break;
19064bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
19074bee2e38SMatthew G. Knepley     if (isInverse) {
19084bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19094bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19109371c9d4SSatish Balay           switch (dim) {
1911*d71ae5a4SJacob Faibussowitsch           case 2:
1912*d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1913*d71ae5a4SJacob Faibussowitsch             break;
1914*d71ae5a4SJacob Faibussowitsch           case 3:
1915*d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1916*d71ae5a4SJacob Faibussowitsch             break;
1917*d71ae5a4SJacob Faibussowitsch           default:
1918*d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19194bee2e38SMatthew G. Knepley           }
19204bee2e38SMatthew G. Knepley         }
19214bee2e38SMatthew G. Knepley       }
19224bee2e38SMatthew G. Knepley     } else {
19234bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19244bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19259371c9d4SSatish Balay           switch (dim) {
1926*d71ae5a4SJacob Faibussowitsch           case 2:
1927*d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1928*d71ae5a4SJacob Faibussowitsch             break;
1929*d71ae5a4SJacob Faibussowitsch           case 3:
1930*d71ae5a4SJacob Faibussowitsch             DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1931*d71ae5a4SJacob Faibussowitsch             break;
1932*d71ae5a4SJacob Faibussowitsch           default:
1933*d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19344bee2e38SMatthew G. Knepley           }
19354bee2e38SMatthew G. Knepley         }
19364bee2e38SMatthew G. Knepley       }
19374bee2e38SMatthew G. Knepley     }
19384bee2e38SMatthew G. Knepley     break;
19394bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
19404bee2e38SMatthew G. Knepley     if (isInverse) {
19414bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19424bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19439371c9d4SSatish Balay           switch (dim) {
1944*d71ae5a4SJacob Faibussowitsch           case 2:
1945*d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1946*d71ae5a4SJacob Faibussowitsch             break;
1947*d71ae5a4SJacob Faibussowitsch           case 3:
1948*d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1949*d71ae5a4SJacob Faibussowitsch             break;
1950*d71ae5a4SJacob Faibussowitsch           default:
1951*d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19524bee2e38SMatthew G. Knepley           }
19534bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
19544bee2e38SMatthew G. Knepley         }
19554bee2e38SMatthew G. Knepley       }
19564bee2e38SMatthew G. Knepley     } else {
19574bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
19584bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
19599371c9d4SSatish Balay           switch (dim) {
1960*d71ae5a4SJacob Faibussowitsch           case 2:
1961*d71ae5a4SJacob Faibussowitsch             DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1962*d71ae5a4SJacob Faibussowitsch             break;
1963*d71ae5a4SJacob Faibussowitsch           case 3:
1964*d71ae5a4SJacob Faibussowitsch             DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]);
1965*d71ae5a4SJacob Faibussowitsch             break;
1966*d71ae5a4SJacob Faibussowitsch           default:
1967*d71ae5a4SJacob Faibussowitsch             SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
19684bee2e38SMatthew G. Knepley           }
19694bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
19704bee2e38SMatthew G. Knepley         }
19714bee2e38SMatthew G. Knepley       }
19724bee2e38SMatthew G. Knepley     }
19734bee2e38SMatthew G. Knepley     break;
19744bee2e38SMatthew G. Knepley   }
19754bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
19764bee2e38SMatthew G. Knepley }
19774bee2e38SMatthew G. Knepley 
19784bee2e38SMatthew G. Knepley /*@C
1979f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
1980f9244615SMatthew G. Knepley 
1981f9244615SMatthew G. Knepley   Input Parameters:
1982f9244615SMatthew G. Knepley + dsp       - The PetscDualSpace
1983f9244615SMatthew G. Knepley . trans     - The type of transform
1984f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
1985f9244615SMatthew G. Knepley . fegeom    - The cell geometry
1986f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
1987f9244615SMatthew G. Knepley . Nc        - The number of function components
1988f9244615SMatthew G. Knepley - vals      - The function gradient values
1989f9244615SMatthew G. Knepley 
1990f9244615SMatthew G. Knepley   Output Parameter:
1991f9244615SMatthew G. Knepley . vals      - The transformed function Hessian values
1992f9244615SMatthew G. Knepley 
1993f9244615SMatthew G. Knepley   Level: intermediate
1994f9244615SMatthew G. Knepley 
1995f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
1996f9244615SMatthew G. Knepley 
1997db781477SPatrick Sanan .seealso: `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
1998f9244615SMatthew G. Knepley @*/
1999*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[])
2000*d71ae5a4SJacob Faibussowitsch {
2001f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
2002f9244615SMatthew G. Knepley   PetscInt       v, c;
2003f9244615SMatthew G. Knepley 
2004f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2005f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2006f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
2007dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
2008f9244615SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
200963a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
2010f9244615SMatthew G. Knepley #endif
2011f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
2012f9244615SMatthew G. Knepley   if (dim == dE) {
2013f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2014f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
20159371c9d4SSatish Balay         switch (dim) {
2016*d71ae5a4SJacob Faibussowitsch         case 1:
2017*d71ae5a4SJacob Faibussowitsch           vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]);
2018*d71ae5a4SJacob Faibussowitsch           break;
2019*d71ae5a4SJacob Faibussowitsch         case 2:
2020*d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2021*d71ae5a4SJacob Faibussowitsch           break;
2022*d71ae5a4SJacob Faibussowitsch         case 3:
2023*d71ae5a4SJacob Faibussowitsch           DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]);
2024*d71ae5a4SJacob Faibussowitsch           break;
2025*d71ae5a4SJacob Faibussowitsch         default:
2026*d71ae5a4SJacob Faibussowitsch           SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
2027f9244615SMatthew G. Knepley         }
2028f9244615SMatthew G. Knepley       }
2029f9244615SMatthew G. Knepley     }
2030f9244615SMatthew G. Knepley   } else {
2031f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
2032ad540459SPierre 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]);
2033f9244615SMatthew G. Knepley     }
2034f9244615SMatthew G. Knepley   }
2035f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
2036f9244615SMatthew G. Knepley   if (Nc == 1 || Nc != dim) PetscFunctionReturn(0);
2037f9244615SMatthew G. Knepley   switch (trans) {
2038*d71ae5a4SJacob Faibussowitsch   case IDENTITY_TRANSFORM:
2039*d71ae5a4SJacob Faibussowitsch     break;
2040*d71ae5a4SJacob Faibussowitsch   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
2041*d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2042*d71ae5a4SJacob Faibussowitsch   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
2043*d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
2044f9244615SMatthew G. Knepley   }
2045f9244615SMatthew G. Knepley   PetscFunctionReturn(0);
2046f9244615SMatthew G. Knepley }
2047f9244615SMatthew G. Knepley 
2048f9244615SMatthew G. Knepley /*@C
20494bee2e38SMatthew 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.
20504bee2e38SMatthew G. Knepley 
20514bee2e38SMatthew G. Knepley   Input Parameters:
20524bee2e38SMatthew G. Knepley + dsp        - The PetscDualSpace
20534bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
20544bee2e38SMatthew G. Knepley . Nq         - The number of function samples
20554bee2e38SMatthew G. Knepley . Nc         - The number of function components
20564bee2e38SMatthew G. Knepley - pointEval  - The function values
20574bee2e38SMatthew G. Knepley 
20584bee2e38SMatthew G. Knepley   Output Parameter:
20594bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
20604bee2e38SMatthew G. Knepley 
20614bee2e38SMatthew G. Knepley   Level: advanced
20624bee2e38SMatthew G. Knepley 
20634bee2e38SMatthew G. Knepley   Note: 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.
20644bee2e38SMatthew G. Knepley 
20652edcad52SToby Isaac   Note: This only handles tranformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
20662edcad52SToby Isaac 
2067db781477SPatrick Sanan .seealso: `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
20684bee2e38SMatthew G. Knepley @*/
2069*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2070*d71ae5a4SJacob Faibussowitsch {
20714bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2072b4457527SToby Isaac   PetscInt                    k;
20734bee2e38SMatthew G. Knepley 
20744bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
20754bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20764bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2077dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
20784bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
20794bee2e38SMatthew G. Knepley      This determines their transformation properties. */
20809566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
20819371c9d4SSatish Balay   switch (k) {
2082*d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2083*d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2084*d71ae5a4SJacob Faibussowitsch     break;
2085*d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2086*d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2087*d71ae5a4SJacob Faibussowitsch     break;
2088b4457527SToby Isaac   case 2:
2089*d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2090*d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2091*d71ae5a4SJacob Faibussowitsch     break;
2092*d71ae5a4SJacob Faibussowitsch   default:
2093*d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
20944bee2e38SMatthew G. Knepley   }
20959566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
20964bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
20974bee2e38SMatthew G. Knepley }
20984bee2e38SMatthew G. Knepley 
20994bee2e38SMatthew G. Knepley /*@C
21004bee2e38SMatthew 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.
21014bee2e38SMatthew G. Knepley 
21024bee2e38SMatthew G. Knepley   Input Parameters:
21034bee2e38SMatthew G. Knepley + dsp        - The PetscDualSpace
21044bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
21054bee2e38SMatthew G. Knepley . Nq         - The number of function samples
21064bee2e38SMatthew G. Knepley . Nc         - The number of function components
21074bee2e38SMatthew G. Knepley - pointEval  - The function values
21084bee2e38SMatthew G. Knepley 
21094bee2e38SMatthew G. Knepley   Output Parameter:
21104bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
21114bee2e38SMatthew G. Knepley 
21124bee2e38SMatthew G. Knepley   Level: advanced
21134bee2e38SMatthew G. Knepley 
21144bee2e38SMatthew G. Knepley   Note: 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.
21154bee2e38SMatthew G. Knepley 
2116f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21172edcad52SToby Isaac 
2118db781477SPatrick Sanan .seealso: `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
21194bee2e38SMatthew G. Knepley @*/
2120*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2121*d71ae5a4SJacob Faibussowitsch {
21224bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2123b4457527SToby Isaac   PetscInt                    k;
21244bee2e38SMatthew G. Knepley 
21254bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21264bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21274bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2128dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21294bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21304bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21319566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21329371c9d4SSatish Balay   switch (k) {
2133*d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2134*d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2135*d71ae5a4SJacob Faibussowitsch     break;
2136*d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2137*d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2138*d71ae5a4SJacob Faibussowitsch     break;
2139b4457527SToby Isaac   case 2:
2140*d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2141*d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2142*d71ae5a4SJacob Faibussowitsch     break;
2143*d71ae5a4SJacob Faibussowitsch   default:
2144*d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21454bee2e38SMatthew G. Knepley   }
21469566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
21474bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
21484bee2e38SMatthew G. Knepley }
21494bee2e38SMatthew G. Knepley 
21504bee2e38SMatthew G. Knepley /*@C
21514bee2e38SMatthew 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.
21524bee2e38SMatthew G. Knepley 
21534bee2e38SMatthew G. Knepley   Input Parameters:
21544bee2e38SMatthew G. Knepley + dsp        - The PetscDualSpace
21554bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
21564bee2e38SMatthew G. Knepley . Nq         - The number of function gradient samples
21574bee2e38SMatthew G. Knepley . Nc         - The number of function components
21584bee2e38SMatthew G. Knepley - pointEval  - The function gradient values
21594bee2e38SMatthew G. Knepley 
21604bee2e38SMatthew G. Knepley   Output Parameter:
21614bee2e38SMatthew G. Knepley . pointEval  - The transformed function gradient values
21624bee2e38SMatthew G. Knepley 
21634bee2e38SMatthew G. Knepley   Level: advanced
21644bee2e38SMatthew G. Knepley 
21654bee2e38SMatthew G. Knepley   Note: 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.
21664bee2e38SMatthew G. Knepley 
2167f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
21682edcad52SToby Isaac 
2169db781477SPatrick Sanan .seealso: `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2170dc0529c6SBarry Smith @*/
2171*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2172*d71ae5a4SJacob Faibussowitsch {
21734bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2174b4457527SToby Isaac   PetscInt                    k;
21754bee2e38SMatthew G. Knepley 
21764bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
21774bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
21784bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2179dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
21804bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
21814bee2e38SMatthew G. Knepley      This determines their transformation properties. */
21829566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21839371c9d4SSatish Balay   switch (k) {
2184*d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2185*d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2186*d71ae5a4SJacob Faibussowitsch     break;
2187*d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2188*d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2189*d71ae5a4SJacob Faibussowitsch     break;
2190b4457527SToby Isaac   case 2:
2191*d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2192*d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2193*d71ae5a4SJacob Faibussowitsch     break;
2194*d71ae5a4SJacob Faibussowitsch   default:
2195*d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
21964bee2e38SMatthew G. Knepley   }
21979566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
21984bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
21994bee2e38SMatthew G. Knepley }
2200f9244615SMatthew G. Knepley 
2201f9244615SMatthew G. Knepley /*@C
2202f9244615SMatthew 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.
2203f9244615SMatthew G. Knepley 
2204f9244615SMatthew G. Knepley   Input Parameters:
2205f9244615SMatthew G. Knepley + dsp        - The PetscDualSpace
2206f9244615SMatthew G. Knepley . fegeom     - The geometry for this cell
2207f9244615SMatthew G. Knepley . Nq         - The number of function Hessian samples
2208f9244615SMatthew G. Knepley . Nc         - The number of function components
2209f9244615SMatthew G. Knepley - pointEval  - The function gradient values
2210f9244615SMatthew G. Knepley 
2211f9244615SMatthew G. Knepley   Output Parameter:
2212f9244615SMatthew G. Knepley . pointEval  - The transformed function Hessian values
2213f9244615SMatthew G. Knepley 
2214f9244615SMatthew G. Knepley   Level: advanced
2215f9244615SMatthew G. Knepley 
2216f9244615SMatthew G. Knepley   Note: 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.
2217f9244615SMatthew G. Knepley 
2218f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2219f9244615SMatthew G. Knepley 
2220db781477SPatrick Sanan .seealso: `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2221f9244615SMatthew G. Knepley @*/
2222*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[])
2223*d71ae5a4SJacob Faibussowitsch {
2224f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2225f9244615SMatthew G. Knepley   PetscInt                    k;
2226f9244615SMatthew G. Knepley 
2227f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2228f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2229f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2230dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
2231f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2232f9244615SMatthew G. Knepley      This determines their transformation properties. */
22339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
22349371c9d4SSatish Balay   switch (k) {
2235*d71ae5a4SJacob Faibussowitsch   case 0: /* H^1 point evaluations */
2236*d71ae5a4SJacob Faibussowitsch     trans = IDENTITY_TRANSFORM;
2237*d71ae5a4SJacob Faibussowitsch     break;
2238*d71ae5a4SJacob Faibussowitsch   case 1: /* Hcurl preserves tangential edge traces  */
2239*d71ae5a4SJacob Faibussowitsch     trans = COVARIANT_PIOLA_TRANSFORM;
2240*d71ae5a4SJacob Faibussowitsch     break;
2241f9244615SMatthew G. Knepley   case 2:
2242*d71ae5a4SJacob Faibussowitsch   case 3: /* Hdiv preserve normal traces */
2243*d71ae5a4SJacob Faibussowitsch     trans = CONTRAVARIANT_PIOLA_TRANSFORM;
2244*d71ae5a4SJacob Faibussowitsch     break;
2245*d71ae5a4SJacob Faibussowitsch   default:
2246*d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2247f9244615SMatthew G. Knepley   }
22489566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
2249f9244615SMatthew G. Knepley   PetscFunctionReturn(0);
2250f9244615SMatthew G. Knepley }
2251