xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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 */
289371c9d4SSatish Balay PetscErrorCode PetscDualSpaceLatticePointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[]) {
296f905325SMatthew G. Knepley   PetscFunctionBegin;
306f905325SMatthew G. Knepley   while (len--) {
316f905325SMatthew G. Knepley     max -= tup[len];
326f905325SMatthew G. Knepley     if (!max) {
336f905325SMatthew G. Knepley       tup[len] = 0;
346f905325SMatthew G. Knepley       break;
356f905325SMatthew G. Knepley     }
366f905325SMatthew G. Knepley   }
376f905325SMatthew G. Knepley   tup[++len]++;
386f905325SMatthew G. Knepley   PetscFunctionReturn(0);
396f905325SMatthew G. Knepley }
406f905325SMatthew G. Knepley 
416f905325SMatthew G. Knepley /*
426f905325SMatthew G. Knepley   PetscDualSpaceTensorPointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max'.
436f905325SMatthew G. Knepley                                                     Ordering is lexicographic with lowest index as least significant in ordering.
446f905325SMatthew 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}.
456f905325SMatthew G. Knepley 
466f905325SMatthew G. Knepley   Input Parameters:
476f905325SMatthew G. Knepley + len - The length of the tuple
486f905325SMatthew G. Knepley . max - The maximum value
496f905325SMatthew G. Knepley - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition
506f905325SMatthew G. Knepley 
516f905325SMatthew G. Knepley   Output Parameter:
526f905325SMatthew G. Knepley . tup - A tuple of len integers whos sum is at most 'max'
536f905325SMatthew G. Knepley 
546f905325SMatthew G. Knepley   Level: developer
556f905325SMatthew G. Knepley 
56db781477SPatrick Sanan .seealso: `PetscDualSpaceLatticePointLexicographic_Internal()`
576f905325SMatthew G. Knepley */
589371c9d4SSatish Balay PetscErrorCode PetscDualSpaceTensorPointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[]) {
596f905325SMatthew G. Knepley   PetscInt i;
606f905325SMatthew G. Knepley 
616f905325SMatthew G. Knepley   PetscFunctionBegin;
626f905325SMatthew G. Knepley   for (i = 0; i < len; i++) {
636f905325SMatthew G. Knepley     if (tup[i] < max) {
646f905325SMatthew G. Knepley       break;
656f905325SMatthew G. Knepley     } else {
666f905325SMatthew G. Knepley       tup[i] = 0;
676f905325SMatthew G. Knepley     }
686f905325SMatthew G. Knepley   }
696f905325SMatthew G. Knepley   tup[i]++;
706f905325SMatthew G. Knepley   PetscFunctionReturn(0);
716f905325SMatthew G. Knepley }
726f905325SMatthew G. Knepley 
7320cf1dd8SToby Isaac /*@C
7420cf1dd8SToby Isaac   PetscDualSpaceRegister - Adds a new PetscDualSpace implementation
7520cf1dd8SToby Isaac 
7620cf1dd8SToby Isaac   Not Collective
7720cf1dd8SToby Isaac 
7820cf1dd8SToby Isaac   Input Parameters:
7920cf1dd8SToby Isaac + name        - The name of a new user-defined creation routine
8020cf1dd8SToby Isaac - create_func - The creation routine itself
8120cf1dd8SToby Isaac 
8220cf1dd8SToby Isaac   Notes:
8320cf1dd8SToby Isaac   PetscDualSpaceRegister() may be called multiple times to add several user-defined PetscDualSpaces
8420cf1dd8SToby Isaac 
8520cf1dd8SToby Isaac   Sample usage:
8620cf1dd8SToby Isaac .vb
8720cf1dd8SToby Isaac     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
8820cf1dd8SToby Isaac .ve
8920cf1dd8SToby Isaac 
9020cf1dd8SToby Isaac   Then, your PetscDualSpace type can be chosen with the procedural interface via
9120cf1dd8SToby Isaac .vb
9220cf1dd8SToby Isaac     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
9320cf1dd8SToby Isaac     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
9420cf1dd8SToby Isaac .ve
9520cf1dd8SToby Isaac    or at runtime via the option
9620cf1dd8SToby Isaac .vb
9720cf1dd8SToby Isaac     -petscdualspace_type my_dual_space
9820cf1dd8SToby Isaac .ve
9920cf1dd8SToby Isaac 
10020cf1dd8SToby Isaac   Level: advanced
10120cf1dd8SToby Isaac 
102db781477SPatrick Sanan .seealso: `PetscDualSpaceRegisterAll()`, `PetscDualSpaceRegisterDestroy()`
10320cf1dd8SToby Isaac 
10420cf1dd8SToby Isaac @*/
1059371c9d4SSatish Balay PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace)) {
10620cf1dd8SToby Isaac   PetscFunctionBegin;
1079566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&PetscDualSpaceList, sname, function));
10820cf1dd8SToby Isaac   PetscFunctionReturn(0);
10920cf1dd8SToby Isaac }
11020cf1dd8SToby Isaac 
11120cf1dd8SToby Isaac /*@C
11220cf1dd8SToby Isaac   PetscDualSpaceSetType - Builds a particular PetscDualSpace
11320cf1dd8SToby Isaac 
114d083f849SBarry Smith   Collective on sp
11520cf1dd8SToby Isaac 
11620cf1dd8SToby Isaac   Input Parameters:
11720cf1dd8SToby Isaac + sp   - The PetscDualSpace object
11820cf1dd8SToby Isaac - name - The kind of space
11920cf1dd8SToby Isaac 
12020cf1dd8SToby Isaac   Options Database Key:
12120cf1dd8SToby Isaac . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types
12220cf1dd8SToby Isaac 
12320cf1dd8SToby Isaac   Level: intermediate
12420cf1dd8SToby Isaac 
125db781477SPatrick Sanan .seealso: `PetscDualSpaceGetType()`, `PetscDualSpaceCreate()`
12620cf1dd8SToby Isaac @*/
1279371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name) {
12820cf1dd8SToby Isaac   PetscErrorCode (*r)(PetscDualSpace);
12920cf1dd8SToby Isaac   PetscBool match;
13020cf1dd8SToby Isaac 
13120cf1dd8SToby Isaac   PetscFunctionBegin;
13220cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)sp, name, &match));
13420cf1dd8SToby Isaac   if (match) PetscFunctionReturn(0);
13520cf1dd8SToby Isaac 
1369566063dSJacob Faibussowitsch   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
1379566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(PetscDualSpaceList, name, &r));
13828b400f6SJacob Faibussowitsch   PetscCheck(r, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name);
13920cf1dd8SToby Isaac 
140dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, destroy);
14120cf1dd8SToby Isaac   sp->ops->destroy = NULL;
142dbbe0bcdSBarry Smith 
1439566063dSJacob Faibussowitsch   PetscCall((*r)(sp));
1449566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)sp, name));
14520cf1dd8SToby Isaac   PetscFunctionReturn(0);
14620cf1dd8SToby Isaac }
14720cf1dd8SToby Isaac 
14820cf1dd8SToby Isaac /*@C
14920cf1dd8SToby Isaac   PetscDualSpaceGetType - Gets the PetscDualSpace type name (as a string) from the object.
15020cf1dd8SToby Isaac 
15120cf1dd8SToby Isaac   Not Collective
15220cf1dd8SToby Isaac 
15320cf1dd8SToby Isaac   Input Parameter:
15420cf1dd8SToby Isaac . sp  - The PetscDualSpace
15520cf1dd8SToby Isaac 
15620cf1dd8SToby Isaac   Output Parameter:
15720cf1dd8SToby Isaac . name - The PetscDualSpace type name
15820cf1dd8SToby Isaac 
15920cf1dd8SToby Isaac   Level: intermediate
16020cf1dd8SToby Isaac 
161db781477SPatrick Sanan .seealso: `PetscDualSpaceSetType()`, `PetscDualSpaceCreate()`
16220cf1dd8SToby Isaac @*/
1639371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name) {
16420cf1dd8SToby Isaac   PetscFunctionBegin;
16520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16620cf1dd8SToby Isaac   PetscValidPointer(name, 2);
167*48a46eb9SPierre Jolivet   if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll());
16820cf1dd8SToby Isaac   *name = ((PetscObject)sp)->type_name;
16920cf1dd8SToby Isaac   PetscFunctionReturn(0);
17020cf1dd8SToby Isaac }
17120cf1dd8SToby Isaac 
1729371c9d4SSatish Balay static PetscErrorCode PetscDualSpaceView_ASCII(PetscDualSpace sp, PetscViewer v) {
173221d6281SMatthew G. Knepley   PetscViewerFormat format;
174221d6281SMatthew G. Knepley   PetscInt          pdim, f;
175221d6281SMatthew G. Knepley 
176221d6281SMatthew G. Knepley   PetscFunctionBegin;
1779566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &pdim));
1789566063dSJacob Faibussowitsch   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sp, v));
1799566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(v));
180b4457527SToby Isaac   if (sp->k) {
18163a3b9bcSJacob 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));
182b4457527SToby Isaac   } else {
18363a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(v, "Dual space with %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", sp->Nc, pdim));
184b4457527SToby Isaac   }
185dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, view, v);
1869566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(v, &format));
187221d6281SMatthew G. Knepley   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1889566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(v));
189221d6281SMatthew G. Knepley     for (f = 0; f < pdim; ++f) {
19063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(v, "Dual basis vector %" PetscInt_FMT "\n", f));
1919566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(v));
1929566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureView(sp->functional[f], v));
1939566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(v));
194221d6281SMatthew G. Knepley     }
1959566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(v));
196221d6281SMatthew G. Knepley   }
1979566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
198221d6281SMatthew G. Knepley   PetscFunctionReturn(0);
199221d6281SMatthew G. Knepley }
200221d6281SMatthew G. Knepley 
201fe2efc57SMark /*@C
202fe2efc57SMark    PetscDualSpaceViewFromOptions - View from Options
203fe2efc57SMark 
204fe2efc57SMark    Collective on PetscDualSpace
205fe2efc57SMark 
206fe2efc57SMark    Input Parameters:
207fe2efc57SMark +  A - the PetscDualSpace object
208736c3998SJose E. Roman .  obj - Optional object, proivides prefix
209736c3998SJose E. Roman -  name - command line option
210fe2efc57SMark 
211fe2efc57SMark    Level: intermediate
212db781477SPatrick Sanan .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()`
213fe2efc57SMark @*/
2149371c9d4SSatish Balay PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PetscObject obj, const char name[]) {
215fe2efc57SMark   PetscFunctionBegin;
216fe2efc57SMark   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
2179566063dSJacob Faibussowitsch   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
218fe2efc57SMark   PetscFunctionReturn(0);
219fe2efc57SMark }
220fe2efc57SMark 
22120cf1dd8SToby Isaac /*@
22220cf1dd8SToby Isaac   PetscDualSpaceView - Views a PetscDualSpace
22320cf1dd8SToby Isaac 
224d083f849SBarry Smith   Collective on sp
22520cf1dd8SToby Isaac 
226d8d19677SJose E. Roman   Input Parameters:
22720cf1dd8SToby Isaac + sp - the PetscDualSpace object to view
22820cf1dd8SToby Isaac - v  - the viewer
22920cf1dd8SToby Isaac 
230a4ce7ad1SMatthew G. Knepley   Level: beginner
23120cf1dd8SToby Isaac 
232db781477SPatrick Sanan .seealso `PetscDualSpaceDestroy()`, `PetscDualSpace`
23320cf1dd8SToby Isaac @*/
2349371c9d4SSatish Balay PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v) {
235d9bac1caSLisandro Dalcin   PetscBool iascii;
23620cf1dd8SToby Isaac 
23720cf1dd8SToby Isaac   PetscFunctionBegin;
23820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
239d9bac1caSLisandro Dalcin   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
2409566063dSJacob Faibussowitsch   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v));
2419566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
2429566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v));
24320cf1dd8SToby Isaac   PetscFunctionReturn(0);
24420cf1dd8SToby Isaac }
24520cf1dd8SToby Isaac 
24620cf1dd8SToby Isaac /*@
24720cf1dd8SToby Isaac   PetscDualSpaceSetFromOptions - sets parameters in a PetscDualSpace from the options database
24820cf1dd8SToby Isaac 
249d083f849SBarry Smith   Collective on sp
25020cf1dd8SToby Isaac 
25120cf1dd8SToby Isaac   Input Parameter:
25220cf1dd8SToby Isaac . sp - the PetscDualSpace object to set options for
25320cf1dd8SToby Isaac 
25420cf1dd8SToby Isaac   Options Database:
2558f2aacc6SMatthew G. Knepley + -petscdualspace_order <order>      - the approximation order of the space
256fe36a153SMatthew G. Knepley . -petscdualspace_form_degree <deg>  - the form degree, say 0 for point evaluations, or 2 for area integrals
2578f2aacc6SMatthew G. Knepley . -petscdualspace_components <c>     - the number of components, say d for a vector field
2588f2aacc6SMatthew G. Knepley - -petscdualspace_refcell <celltype> - Reference cell type name
25920cf1dd8SToby Isaac 
260a4ce7ad1SMatthew G. Knepley   Level: intermediate
26120cf1dd8SToby Isaac 
262db781477SPatrick Sanan .seealso `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()`
26320cf1dd8SToby Isaac @*/
2649371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp) {
2652df84da0SMatthew G. Knepley   DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE;
26620cf1dd8SToby Isaac   const char    *defaultType;
26720cf1dd8SToby Isaac   char           name[256];
268f783ec47SMatthew G. Knepley   PetscBool      flg;
26920cf1dd8SToby Isaac 
27020cf1dd8SToby Isaac   PetscFunctionBegin;
27120cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
27220cf1dd8SToby Isaac   if (!((PetscObject)sp)->type_name) {
27320cf1dd8SToby Isaac     defaultType = PETSCDUALSPACELAGRANGE;
27420cf1dd8SToby Isaac   } else {
27520cf1dd8SToby Isaac     defaultType = ((PetscObject)sp)->type_name;
27620cf1dd8SToby Isaac   }
2779566063dSJacob Faibussowitsch   if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll());
27820cf1dd8SToby Isaac 
279d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)sp);
2809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg));
28120cf1dd8SToby Isaac   if (flg) {
2829566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, name));
28320cf1dd8SToby Isaac   } else if (!((PetscObject)sp)->type_name) {
2849566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetType(sp, defaultType));
28520cf1dd8SToby Isaac   }
2869566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0));
2879566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL));
2889566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1));
289dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject);
2909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg));
291063ee4adSMatthew G. Knepley   if (flg) {
292063ee4adSMatthew G. Knepley     DM K;
293063ee4adSMatthew G. Knepley 
2949566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K));
2959566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetDM(sp, K));
2969566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&K));
297063ee4adSMatthew G. Knepley   }
298063ee4adSMatthew G. Knepley 
29920cf1dd8SToby Isaac   /* process any options handlers added with PetscObjectAddOptionsHandler() */
300dbbe0bcdSBarry Smith   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject));
301d0609cedSBarry Smith   PetscOptionsEnd();
302063ee4adSMatthew G. Knepley   sp->setfromoptionscalled = PETSC_TRUE;
30320cf1dd8SToby Isaac   PetscFunctionReturn(0);
30420cf1dd8SToby Isaac }
30520cf1dd8SToby Isaac 
30620cf1dd8SToby Isaac /*@
30720cf1dd8SToby Isaac   PetscDualSpaceSetUp - Construct a basis for the PetscDualSpace
30820cf1dd8SToby Isaac 
309d083f849SBarry Smith   Collective on sp
31020cf1dd8SToby Isaac 
31120cf1dd8SToby Isaac   Input Parameter:
31220cf1dd8SToby Isaac . sp - the PetscDualSpace object to setup
31320cf1dd8SToby Isaac 
314a4ce7ad1SMatthew G. Knepley   Level: intermediate
31520cf1dd8SToby Isaac 
316db781477SPatrick Sanan .seealso `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace`
31720cf1dd8SToby Isaac @*/
3189371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp) {
31920cf1dd8SToby Isaac   PetscFunctionBegin;
32020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
32120cf1dd8SToby Isaac   if (sp->setupcalled) PetscFunctionReturn(0);
3229566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
32320cf1dd8SToby Isaac   sp->setupcalled = PETSC_TRUE;
324dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, setup);
3259566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0));
3269566063dSJacob Faibussowitsch   if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view"));
32720cf1dd8SToby Isaac   PetscFunctionReturn(0);
32820cf1dd8SToby Isaac }
32920cf1dd8SToby Isaac 
3309371c9d4SSatish Balay static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm) {
331b4457527SToby Isaac   PetscInt pStart = -1, pEnd = -1, depth = -1;
332b4457527SToby Isaac 
333b4457527SToby Isaac   PetscFunctionBegin;
334b4457527SToby Isaac   if (!dm) PetscFunctionReturn(0);
3359566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
337b4457527SToby Isaac 
338b4457527SToby Isaac   if (sp->pointSpaces) {
339b4457527SToby Isaac     PetscInt i;
340b4457527SToby Isaac 
341*48a46eb9SPierre Jolivet     for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&(sp->pointSpaces[i])));
342b4457527SToby Isaac   }
3439566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->pointSpaces));
344b4457527SToby Isaac 
345b4457527SToby Isaac   if (sp->heightSpaces) {
346b4457527SToby Isaac     PetscInt i;
347b4457527SToby Isaac 
348*48a46eb9SPierre Jolivet     for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&(sp->heightSpaces[i])));
349b4457527SToby Isaac   }
3509566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->heightSpaces));
351b4457527SToby Isaac 
3529566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&(sp->pointSection)));
3539566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
3549566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intDofValues)));
3559566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->intNodeValues)));
3569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->intMat)));
3579566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
3589566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allDofValues)));
3599566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&(sp->allNodeValues)));
3609566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&(sp->allMat)));
3619566063dSJacob Faibussowitsch   PetscCall(PetscFree(sp->numDof));
362b4457527SToby Isaac   PetscFunctionReturn(0);
363b4457527SToby Isaac }
364b4457527SToby Isaac 
36520cf1dd8SToby Isaac /*@
36620cf1dd8SToby Isaac   PetscDualSpaceDestroy - Destroys a PetscDualSpace object
36720cf1dd8SToby Isaac 
368d083f849SBarry Smith   Collective on sp
36920cf1dd8SToby Isaac 
37020cf1dd8SToby Isaac   Input Parameter:
37120cf1dd8SToby Isaac . sp - the PetscDualSpace object to destroy
37220cf1dd8SToby Isaac 
373a4ce7ad1SMatthew G. Knepley   Level: beginner
37420cf1dd8SToby Isaac 
375db781477SPatrick Sanan .seealso `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()`
37620cf1dd8SToby Isaac @*/
3779371c9d4SSatish Balay PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp) {
37820cf1dd8SToby Isaac   PetscInt dim, f;
379b4457527SToby Isaac   DM       dm;
38020cf1dd8SToby Isaac 
38120cf1dd8SToby Isaac   PetscFunctionBegin;
38220cf1dd8SToby Isaac   if (!*sp) PetscFunctionReturn(0);
38320cf1dd8SToby Isaac   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
38420cf1dd8SToby Isaac 
3859371c9d4SSatish Balay   if (--((PetscObject)(*sp))->refct > 0) {
3869371c9d4SSatish Balay     *sp = NULL;
3879371c9d4SSatish Balay     PetscFunctionReturn(0);
3889371c9d4SSatish Balay   }
38920cf1dd8SToby Isaac   ((PetscObject)(*sp))->refct = 0;
39020cf1dd8SToby Isaac 
3919566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(*sp, &dim));
392b4457527SToby Isaac   dm = (*sp)->dm;
393b4457527SToby Isaac 
394dbbe0bcdSBarry Smith   PetscTryTypeMethod((*sp), destroy);
3959566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm));
396b4457527SToby Isaac 
397*48a46eb9SPierre Jolivet   for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f]));
3989566063dSJacob Faibussowitsch   PetscCall(PetscFree((*sp)->functional));
3999566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&(*sp)->dm));
4009566063dSJacob Faibussowitsch   PetscCall(PetscHeaderDestroy(sp));
40120cf1dd8SToby Isaac   PetscFunctionReturn(0);
40220cf1dd8SToby Isaac }
40320cf1dd8SToby Isaac 
40420cf1dd8SToby Isaac /*@
40520cf1dd8SToby Isaac   PetscDualSpaceCreate - Creates an empty PetscDualSpace object. The type can then be set with PetscDualSpaceSetType().
40620cf1dd8SToby Isaac 
407d083f849SBarry Smith   Collective
40820cf1dd8SToby Isaac 
40920cf1dd8SToby Isaac   Input Parameter:
41020cf1dd8SToby Isaac . comm - The communicator for the PetscDualSpace object
41120cf1dd8SToby Isaac 
41220cf1dd8SToby Isaac   Output Parameter:
41320cf1dd8SToby Isaac . sp - The PetscDualSpace object
41420cf1dd8SToby Isaac 
41520cf1dd8SToby Isaac   Level: beginner
41620cf1dd8SToby Isaac 
417db781477SPatrick Sanan .seealso: `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE`
41820cf1dd8SToby Isaac @*/
4199371c9d4SSatish Balay PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp) {
42020cf1dd8SToby Isaac   PetscDualSpace s;
42120cf1dd8SToby Isaac 
42220cf1dd8SToby Isaac   PetscFunctionBegin;
42320cf1dd8SToby Isaac   PetscValidPointer(sp, 2);
4249566063dSJacob Faibussowitsch   PetscCall(PetscCitationsRegister(FECitation, &FEcite));
42520cf1dd8SToby Isaac   *sp = NULL;
4269566063dSJacob Faibussowitsch   PetscCall(PetscFEInitializePackage());
42720cf1dd8SToby Isaac 
4289566063dSJacob Faibussowitsch   PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView));
42920cf1dd8SToby Isaac 
43020cf1dd8SToby Isaac   s->order       = 0;
43120cf1dd8SToby Isaac   s->Nc          = 1;
4324bee2e38SMatthew G. Knepley   s->k           = 0;
433b4457527SToby Isaac   s->spdim       = -1;
434b4457527SToby Isaac   s->spintdim    = -1;
435b4457527SToby Isaac   s->uniform     = PETSC_TRUE;
43620cf1dd8SToby Isaac   s->setupcalled = PETSC_FALSE;
43720cf1dd8SToby Isaac 
43820cf1dd8SToby Isaac   *sp = s;
43920cf1dd8SToby Isaac   PetscFunctionReturn(0);
44020cf1dd8SToby Isaac }
44120cf1dd8SToby Isaac 
44220cf1dd8SToby Isaac /*@
44320cf1dd8SToby Isaac   PetscDualSpaceDuplicate - Creates a duplicate PetscDualSpace object, however it is not setup.
44420cf1dd8SToby Isaac 
445d083f849SBarry Smith   Collective on sp
44620cf1dd8SToby Isaac 
44720cf1dd8SToby Isaac   Input Parameter:
44820cf1dd8SToby Isaac . sp - The original PetscDualSpace
44920cf1dd8SToby Isaac 
45020cf1dd8SToby Isaac   Output Parameter:
45120cf1dd8SToby Isaac . spNew - The duplicate PetscDualSpace
45220cf1dd8SToby Isaac 
45320cf1dd8SToby Isaac   Level: beginner
45420cf1dd8SToby Isaac 
455db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()`
45620cf1dd8SToby Isaac @*/
4579371c9d4SSatish Balay PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew) {
458b4457527SToby Isaac   DM                 dm;
459b4457527SToby Isaac   PetscDualSpaceType type;
460b4457527SToby Isaac   const char        *name;
46120cf1dd8SToby Isaac 
46220cf1dd8SToby Isaac   PetscFunctionBegin;
46320cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
46420cf1dd8SToby Isaac   PetscValidPointer(spNew, 2);
4659566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew));
4669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetName((PetscObject)sp, &name));
4679566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)*spNew, name));
4689566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetType(sp, &type));
4699566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(*spNew, type));
4709566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
4719566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(*spNew, dm));
472b4457527SToby Isaac 
473b4457527SToby Isaac   (*spNew)->order   = sp->order;
474b4457527SToby Isaac   (*spNew)->k       = sp->k;
475b4457527SToby Isaac   (*spNew)->Nc      = sp->Nc;
476b4457527SToby Isaac   (*spNew)->uniform = sp->uniform;
477dbbe0bcdSBarry Smith   PetscTryTypeMethod(sp, duplicate, *spNew);
47820cf1dd8SToby Isaac   PetscFunctionReturn(0);
47920cf1dd8SToby Isaac }
48020cf1dd8SToby Isaac 
48120cf1dd8SToby Isaac /*@
48220cf1dd8SToby Isaac   PetscDualSpaceGetDM - Get the DM representing the reference cell
48320cf1dd8SToby Isaac 
48420cf1dd8SToby Isaac   Not collective
48520cf1dd8SToby Isaac 
48620cf1dd8SToby Isaac   Input Parameter:
48720cf1dd8SToby Isaac . sp - The PetscDualSpace
48820cf1dd8SToby Isaac 
48920cf1dd8SToby Isaac   Output Parameter:
49020cf1dd8SToby Isaac . dm - The reference cell
49120cf1dd8SToby Isaac 
49220cf1dd8SToby Isaac   Level: intermediate
49320cf1dd8SToby Isaac 
494db781477SPatrick Sanan .seealso: `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()`
49520cf1dd8SToby Isaac @*/
4969371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm) {
49720cf1dd8SToby Isaac   PetscFunctionBegin;
49820cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
49920cf1dd8SToby Isaac   PetscValidPointer(dm, 2);
50020cf1dd8SToby Isaac   *dm = sp->dm;
50120cf1dd8SToby Isaac   PetscFunctionReturn(0);
50220cf1dd8SToby Isaac }
50320cf1dd8SToby Isaac 
50420cf1dd8SToby Isaac /*@
50520cf1dd8SToby Isaac   PetscDualSpaceSetDM - Get the DM representing the reference cell
50620cf1dd8SToby Isaac 
50720cf1dd8SToby Isaac   Not collective
50820cf1dd8SToby Isaac 
50920cf1dd8SToby Isaac   Input Parameters:
51020cf1dd8SToby Isaac + sp - The PetscDualSpace
51120cf1dd8SToby Isaac - dm - The reference cell
51220cf1dd8SToby Isaac 
51320cf1dd8SToby Isaac   Level: intermediate
51420cf1dd8SToby Isaac 
515db781477SPatrick Sanan .seealso: `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()`
51620cf1dd8SToby Isaac @*/
5179371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm) {
51820cf1dd8SToby Isaac   PetscFunctionBegin;
51920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
52020cf1dd8SToby Isaac   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
52128b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up");
5229566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)dm));
523*48a46eb9SPierre Jolivet   if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm));
5249566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&sp->dm));
52520cf1dd8SToby Isaac   sp->dm = dm;
52620cf1dd8SToby Isaac   PetscFunctionReturn(0);
52720cf1dd8SToby Isaac }
52820cf1dd8SToby Isaac 
52920cf1dd8SToby Isaac /*@
53020cf1dd8SToby Isaac   PetscDualSpaceGetOrder - Get the order of the dual space
53120cf1dd8SToby Isaac 
53220cf1dd8SToby Isaac   Not collective
53320cf1dd8SToby Isaac 
53420cf1dd8SToby Isaac   Input Parameter:
53520cf1dd8SToby Isaac . sp - The PetscDualSpace
53620cf1dd8SToby Isaac 
53720cf1dd8SToby Isaac   Output Parameter:
53820cf1dd8SToby Isaac . order - The order
53920cf1dd8SToby Isaac 
54020cf1dd8SToby Isaac   Level: intermediate
54120cf1dd8SToby Isaac 
542db781477SPatrick Sanan .seealso: `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()`
54320cf1dd8SToby Isaac @*/
5449371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order) {
54520cf1dd8SToby Isaac   PetscFunctionBegin;
54620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
547dadcf809SJacob Faibussowitsch   PetscValidIntPointer(order, 2);
54820cf1dd8SToby Isaac   *order = sp->order;
54920cf1dd8SToby Isaac   PetscFunctionReturn(0);
55020cf1dd8SToby Isaac }
55120cf1dd8SToby Isaac 
55220cf1dd8SToby Isaac /*@
55320cf1dd8SToby Isaac   PetscDualSpaceSetOrder - Set the order of the dual space
55420cf1dd8SToby Isaac 
55520cf1dd8SToby Isaac   Not collective
55620cf1dd8SToby Isaac 
55720cf1dd8SToby Isaac   Input Parameters:
55820cf1dd8SToby Isaac + sp - The PetscDualSpace
55920cf1dd8SToby Isaac - order - The order
56020cf1dd8SToby Isaac 
56120cf1dd8SToby Isaac   Level: intermediate
56220cf1dd8SToby Isaac 
563db781477SPatrick Sanan .seealso: `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()`
56420cf1dd8SToby Isaac @*/
5659371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order) {
56620cf1dd8SToby Isaac   PetscFunctionBegin;
56720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
56828b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up");
56920cf1dd8SToby Isaac   sp->order = order;
57020cf1dd8SToby Isaac   PetscFunctionReturn(0);
57120cf1dd8SToby Isaac }
57220cf1dd8SToby Isaac 
57320cf1dd8SToby Isaac /*@
57420cf1dd8SToby Isaac   PetscDualSpaceGetNumComponents - Return the number of components for this space
57520cf1dd8SToby Isaac 
57620cf1dd8SToby Isaac   Input Parameter:
57720cf1dd8SToby Isaac . sp - The PetscDualSpace
57820cf1dd8SToby Isaac 
57920cf1dd8SToby Isaac   Output Parameter:
58020cf1dd8SToby Isaac . Nc - The number of components
58120cf1dd8SToby Isaac 
58220cf1dd8SToby Isaac   Note: A vector space, for example, will have d components, where d is the spatial dimension
58320cf1dd8SToby Isaac 
58420cf1dd8SToby Isaac   Level: intermediate
58520cf1dd8SToby Isaac 
586db781477SPatrick Sanan .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
58720cf1dd8SToby Isaac @*/
5889371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc) {
58920cf1dd8SToby Isaac   PetscFunctionBegin;
59020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
591dadcf809SJacob Faibussowitsch   PetscValidIntPointer(Nc, 2);
59220cf1dd8SToby Isaac   *Nc = sp->Nc;
59320cf1dd8SToby Isaac   PetscFunctionReturn(0);
59420cf1dd8SToby Isaac }
59520cf1dd8SToby Isaac 
59620cf1dd8SToby Isaac /*@
59720cf1dd8SToby Isaac   PetscDualSpaceSetNumComponents - Set the number of components for this space
59820cf1dd8SToby Isaac 
59920cf1dd8SToby Isaac   Input Parameters:
60020cf1dd8SToby Isaac + sp - The PetscDualSpace
60120cf1dd8SToby Isaac - order - The number of components
60220cf1dd8SToby Isaac 
60320cf1dd8SToby Isaac   Level: intermediate
60420cf1dd8SToby Isaac 
605db781477SPatrick Sanan .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace`
60620cf1dd8SToby Isaac @*/
6079371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc) {
60820cf1dd8SToby Isaac   PetscFunctionBegin;
60920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
61028b400f6SJacob Faibussowitsch   PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
61120cf1dd8SToby Isaac   sp->Nc = Nc;
61220cf1dd8SToby Isaac   PetscFunctionReturn(0);
61320cf1dd8SToby Isaac }
61420cf1dd8SToby Isaac 
61520cf1dd8SToby Isaac /*@
61620cf1dd8SToby Isaac   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
61720cf1dd8SToby Isaac 
61820cf1dd8SToby Isaac   Not collective
61920cf1dd8SToby Isaac 
62020cf1dd8SToby Isaac   Input Parameters:
62120cf1dd8SToby Isaac + sp - The PetscDualSpace
62220cf1dd8SToby Isaac - i  - The basis number
62320cf1dd8SToby Isaac 
62420cf1dd8SToby Isaac   Output Parameter:
62520cf1dd8SToby Isaac . functional - The basis functional
62620cf1dd8SToby Isaac 
62720cf1dd8SToby Isaac   Level: intermediate
62820cf1dd8SToby Isaac 
629db781477SPatrick Sanan .seealso: `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`
63020cf1dd8SToby Isaac @*/
6319371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional) {
63220cf1dd8SToby Isaac   PetscInt dim;
63320cf1dd8SToby Isaac 
63420cf1dd8SToby Isaac   PetscFunctionBegin;
63520cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
63620cf1dd8SToby Isaac   PetscValidPointer(functional, 3);
6379566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &dim));
63863a3b9bcSJacob 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);
63920cf1dd8SToby Isaac   *functional = sp->functional[i];
64020cf1dd8SToby Isaac   PetscFunctionReturn(0);
64120cf1dd8SToby Isaac }
64220cf1dd8SToby Isaac 
64320cf1dd8SToby Isaac /*@
64420cf1dd8SToby Isaac   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
64520cf1dd8SToby Isaac 
64620cf1dd8SToby Isaac   Not collective
64720cf1dd8SToby Isaac 
64820cf1dd8SToby Isaac   Input Parameter:
64920cf1dd8SToby Isaac . sp - The PetscDualSpace
65020cf1dd8SToby Isaac 
65120cf1dd8SToby Isaac   Output Parameter:
65220cf1dd8SToby Isaac . dim - The dimension
65320cf1dd8SToby Isaac 
65420cf1dd8SToby Isaac   Level: intermediate
65520cf1dd8SToby Isaac 
656db781477SPatrick Sanan .seealso: `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
65720cf1dd8SToby Isaac @*/
6589371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim) {
65920cf1dd8SToby Isaac   PetscFunctionBegin;
66020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
661dadcf809SJacob Faibussowitsch   PetscValidIntPointer(dim, 2);
662b4457527SToby Isaac   if (sp->spdim < 0) {
663b4457527SToby Isaac     PetscSection section;
664b4457527SToby Isaac 
6659566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
666b4457527SToby Isaac     if (section) {
6679566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(section, &(sp->spdim)));
668b4457527SToby Isaac     } else sp->spdim = 0;
669b4457527SToby Isaac   }
670b4457527SToby Isaac   *dim = sp->spdim;
67120cf1dd8SToby Isaac   PetscFunctionReturn(0);
67220cf1dd8SToby Isaac }
67320cf1dd8SToby Isaac 
674b4457527SToby Isaac /*@
675b4457527SToby 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
676b4457527SToby Isaac 
677b4457527SToby Isaac   Not collective
678b4457527SToby Isaac 
679b4457527SToby Isaac   Input Parameter:
680b4457527SToby Isaac . sp - The PetscDualSpace
681b4457527SToby Isaac 
682b4457527SToby Isaac   Output Parameter:
683b4457527SToby Isaac . dim - The dimension
684b4457527SToby Isaac 
685b4457527SToby Isaac   Level: intermediate
686b4457527SToby Isaac 
687db781477SPatrick Sanan .seealso: `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
688b4457527SToby Isaac @*/
6899371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim) {
690b4457527SToby Isaac   PetscFunctionBegin;
691b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
692dadcf809SJacob Faibussowitsch   PetscValidIntPointer(intdim, 2);
693b4457527SToby Isaac   if (sp->spintdim < 0) {
694b4457527SToby Isaac     PetscSection section;
695b4457527SToby Isaac 
6969566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
697b4457527SToby Isaac     if (section) {
6989566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetConstrainedStorageSize(section, &(sp->spintdim)));
699b4457527SToby Isaac     } else sp->spintdim = 0;
700b4457527SToby Isaac   }
701b4457527SToby Isaac   *intdim = sp->spintdim;
702b4457527SToby Isaac   PetscFunctionReturn(0);
703b4457527SToby Isaac }
704b4457527SToby Isaac 
705b4457527SToby Isaac /*@
706b4457527SToby Isaac    PetscDualSpaceGetUniform - Whether this dual space is uniform
707b4457527SToby Isaac 
708b4457527SToby Isaac    Not collective
709b4457527SToby Isaac 
710b4457527SToby Isaac    Input Parameters:
711b4457527SToby Isaac .  sp - A dual space
712b4457527SToby Isaac 
713b4457527SToby Isaac    Output Parameters:
714b4457527SToby Isaac .  uniform - PETSC_TRUE if (a) the dual space is the same for each point in a stratum of the reference DMPlex, and
715b4457527SToby Isaac              (b) every symmetry of each point in the reference DMPlex is also a symmetry of the point's dual space.
716b4457527SToby Isaac 
717b4457527SToby Isaac    Level: advanced
718b4457527SToby Isaac 
719b4457527SToby Isaac    Note: all of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells
720b4457527SToby Isaac    with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform.
721b4457527SToby Isaac 
722db781477SPatrick Sanan .seealso: `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()`
723b4457527SToby Isaac @*/
7249371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform) {
725b4457527SToby Isaac   PetscFunctionBegin;
726b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
727dadcf809SJacob Faibussowitsch   PetscValidBoolPointer(uniform, 2);
728b4457527SToby Isaac   *uniform = sp->uniform;
729b4457527SToby Isaac   PetscFunctionReturn(0);
730b4457527SToby Isaac }
731b4457527SToby Isaac 
73220cf1dd8SToby Isaac /*@C
73320cf1dd8SToby Isaac   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
73420cf1dd8SToby Isaac 
73520cf1dd8SToby Isaac   Not collective
73620cf1dd8SToby Isaac 
73720cf1dd8SToby Isaac   Input Parameter:
73820cf1dd8SToby Isaac . sp - The PetscDualSpace
73920cf1dd8SToby Isaac 
74020cf1dd8SToby Isaac   Output Parameter:
74120cf1dd8SToby Isaac . numDof - An array of length dim+1 which holds the number of dofs for each dimension
74220cf1dd8SToby Isaac 
74320cf1dd8SToby Isaac   Level: intermediate
74420cf1dd8SToby Isaac 
745db781477SPatrick Sanan .seealso: `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()`
74620cf1dd8SToby Isaac @*/
7479371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof) {
74820cf1dd8SToby Isaac   PetscFunctionBegin;
74920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
75020cf1dd8SToby Isaac   PetscValidPointer(numDof, 2);
75128b400f6SJacob 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");
752b4457527SToby Isaac   if (!sp->numDof) {
753b4457527SToby Isaac     DM           dm;
754b4457527SToby Isaac     PetscInt     depth, d;
755b4457527SToby Isaac     PetscSection section;
756b4457527SToby Isaac 
7579566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(sp, &dm));
7589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepth(dm, &depth));
7599566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->numDof)));
7609566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetSection(sp, &section));
761b4457527SToby Isaac     for (d = 0; d <= depth; d++) {
762b4457527SToby Isaac       PetscInt dStart, dEnd;
763b4457527SToby Isaac 
7649566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd));
765b4457527SToby Isaac       if (dEnd <= dStart) continue;
7669566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, dStart, &(sp->numDof[d])));
767b4457527SToby Isaac     }
768b4457527SToby Isaac   }
769b4457527SToby Isaac   *numDof = sp->numDof;
77008401ef6SPierre Jolivet   PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
77120cf1dd8SToby Isaac   PetscFunctionReturn(0);
77220cf1dd8SToby Isaac }
77320cf1dd8SToby Isaac 
774b4457527SToby Isaac /* create the section of the right size and set a permutation for topological ordering */
7759371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection) {
776b4457527SToby Isaac   DM           dm;
777b4457527SToby Isaac   PetscInt     pStart, pEnd, cStart, cEnd, c, depth, count, i;
778b4457527SToby Isaac   PetscInt    *seen, *perm;
779b4457527SToby Isaac   PetscSection section;
780b4457527SToby Isaac 
781b4457527SToby Isaac   PetscFunctionBegin;
782b4457527SToby Isaac   dm = sp->dm;
7839566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
7849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7859566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, pStart, pEnd));
7869566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(pEnd - pStart, &seen));
7879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pEnd - pStart, &perm));
7889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
7899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
790b4457527SToby Isaac   for (c = cStart, count = 0; c < cEnd; c++) {
791b4457527SToby Isaac     PetscInt  closureSize = -1, e;
792b4457527SToby Isaac     PetscInt *closure     = NULL;
793b4457527SToby Isaac 
794b4457527SToby Isaac     perm[count++]    = c;
795b4457527SToby Isaac     seen[c - pStart] = 1;
7969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
797b4457527SToby Isaac     for (e = 0; e < closureSize; e++) {
798b4457527SToby Isaac       PetscInt point = closure[2 * e];
799b4457527SToby Isaac 
800b4457527SToby Isaac       if (seen[point - pStart]) continue;
801b4457527SToby Isaac       perm[count++]        = point;
802b4457527SToby Isaac       seen[point - pStart] = 1;
803b4457527SToby Isaac     }
8049566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure));
805b4457527SToby Isaac   }
8061dca8a05SBarry Smith   PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering");
8079371c9d4SSatish Balay   for (i = 0; i < pEnd - pStart; i++)
8089371c9d4SSatish Balay     if (perm[i] != i) break;
809b4457527SToby Isaac   if (i < pEnd - pStart) {
810b4457527SToby Isaac     IS permIS;
811b4457527SToby Isaac 
8129566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS));
8139566063dSJacob Faibussowitsch     PetscCall(ISSetPermutation(permIS));
8149566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetPermutation(section, permIS));
8159566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
816b4457527SToby Isaac   } else {
8179566063dSJacob Faibussowitsch     PetscCall(PetscFree(perm));
818b4457527SToby Isaac   }
8199566063dSJacob Faibussowitsch   PetscCall(PetscFree(seen));
820b4457527SToby Isaac   *topSection = section;
821b4457527SToby Isaac   PetscFunctionReturn(0);
822b4457527SToby Isaac }
823b4457527SToby Isaac 
824b4457527SToby Isaac /* mark boundary points and set up */
8259371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section) {
826b4457527SToby Isaac   DM       dm;
827b4457527SToby Isaac   DMLabel  boundary;
828b4457527SToby Isaac   PetscInt pStart, pEnd, p;
829b4457527SToby Isaac 
830b4457527SToby Isaac   PetscFunctionBegin;
831b4457527SToby Isaac   dm = sp->dm;
8329566063dSJacob Faibussowitsch   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary));
8339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
8349566063dSJacob Faibussowitsch   PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary));
8359566063dSJacob Faibussowitsch   PetscCall(DMPlexLabelComplete(dm, boundary));
8369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
837b4457527SToby Isaac   for (p = pStart; p < pEnd; p++) {
838b4457527SToby Isaac     PetscInt bval;
839b4457527SToby Isaac 
8409566063dSJacob Faibussowitsch     PetscCall(DMLabelGetValue(boundary, p, &bval));
841b4457527SToby Isaac     if (bval == 1) {
842b4457527SToby Isaac       PetscInt dof;
843b4457527SToby Isaac 
8449566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(section, p, &dof));
8459566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetConstraintDof(section, p, dof));
846b4457527SToby Isaac     }
847b4457527SToby Isaac   }
8489566063dSJacob Faibussowitsch   PetscCall(DMLabelDestroy(&boundary));
8499566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
850b4457527SToby Isaac   PetscFunctionReturn(0);
851b4457527SToby Isaac }
852b4457527SToby Isaac 
853a4ce7ad1SMatthew G. Knepley /*@
854b4457527SToby Isaac   PetscDualSpaceGetSection - Create a PetscSection over the reference cell with the layout from this space
855a4ce7ad1SMatthew G. Knepley 
856a4ce7ad1SMatthew G. Knepley   Collective on sp
857a4ce7ad1SMatthew G. Knepley 
858a4ce7ad1SMatthew G. Knepley   Input Parameters:
859f0fc11ceSJed Brown . sp      - The PetscDualSpace
860a4ce7ad1SMatthew G. Knepley 
861a4ce7ad1SMatthew G. Knepley   Output Parameter:
862a4ce7ad1SMatthew G. Knepley . section - The section
863a4ce7ad1SMatthew G. Knepley 
864a4ce7ad1SMatthew G. Knepley   Level: advanced
865a4ce7ad1SMatthew G. Knepley 
866db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `DMPLEX`
867a4ce7ad1SMatthew G. Knepley @*/
8689371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section) {
869b4457527SToby Isaac   PetscInt pStart, pEnd, p;
870b4457527SToby Isaac 
871b4457527SToby Isaac   PetscFunctionBegin;
87278f1d139SRomain Beucher   if (!sp->dm) {
87378f1d139SRomain Beucher     *section = NULL;
87478f1d139SRomain Beucher     PetscFunctionReturn(0);
87578f1d139SRomain Beucher   }
876b4457527SToby Isaac   if (!sp->pointSection) {
877b4457527SToby Isaac     /* mark the boundary */
8789566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &(sp->pointSection)));
8799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd));
880b4457527SToby Isaac     for (p = pStart; p < pEnd; p++) {
881b4457527SToby Isaac       PetscDualSpace psp;
882b4457527SToby Isaac 
8839566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp));
884b4457527SToby Isaac       if (psp) {
885b4457527SToby Isaac         PetscInt dof;
886b4457527SToby Isaac 
8879566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof));
8889566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(sp->pointSection, p, dof));
889b4457527SToby Isaac       }
890b4457527SToby Isaac     }
8919566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection));
892b4457527SToby Isaac   }
893b4457527SToby Isaac   *section = sp->pointSection;
894b4457527SToby Isaac   PetscFunctionReturn(0);
895b4457527SToby Isaac }
896b4457527SToby Isaac 
897b4457527SToby Isaac /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs
898b4457527SToby Isaac  * have one cell */
8999371c9d4SSatish Balay PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd) {
900b4457527SToby Isaac   PetscReal   *sv0, *v0, *J;
901b4457527SToby Isaac   PetscSection section;
902b4457527SToby Isaac   PetscInt     dim, s, k;
90320cf1dd8SToby Isaac   DM           dm;
90420cf1dd8SToby Isaac 
90520cf1dd8SToby Isaac   PetscFunctionBegin;
9069566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
9079566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
9089566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
9099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J));
9109566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFormDegree(sp, &k));
911b4457527SToby Isaac   for (s = sStart; s < sEnd; s++) {
912b4457527SToby Isaac     PetscReal      detJ, hdetJ;
913b4457527SToby Isaac     PetscDualSpace ssp;
914b4457527SToby Isaac     PetscInt       dof, off, f, sdim;
915b4457527SToby Isaac     PetscInt       i, j;
916b4457527SToby Isaac     DM             sdm;
91720cf1dd8SToby Isaac 
9189566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp));
919b4457527SToby Isaac     if (!ssp) continue;
9209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, s, &dof));
9219566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, s, &off));
922b4457527SToby Isaac     /* get the first vertex of the reference cell */
9239566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetDM(ssp, &sdm));
9249566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(sdm, &sdim));
9259566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ));
9269566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ));
927b4457527SToby Isaac     /* compactify Jacobian */
9289371c9d4SSatish Balay     for (i = 0; i < dim; i++)
9299371c9d4SSatish Balay       for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j];
930b4457527SToby Isaac     for (f = 0; f < dof; f++) {
931b4457527SToby Isaac       PetscQuadrature fn;
93220cf1dd8SToby Isaac 
9339566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn));
9349566063dSJacob Faibussowitsch       PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &(sp->functional[off + f])));
93520cf1dd8SToby Isaac     }
93620cf1dd8SToby Isaac   }
9379566063dSJacob Faibussowitsch   PetscCall(PetscFree3(v0, sv0, J));
93820cf1dd8SToby Isaac   PetscFunctionReturn(0);
93920cf1dd8SToby Isaac }
94020cf1dd8SToby Isaac 
94120cf1dd8SToby Isaac /*@C
94220cf1dd8SToby Isaac   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
94320cf1dd8SToby Isaac 
94420cf1dd8SToby Isaac   Input Parameters:
94520cf1dd8SToby Isaac + sp      - The PetscDualSpace object
94620cf1dd8SToby Isaac . f       - The basis functional index
94720cf1dd8SToby Isaac . time    - The time
94820cf1dd8SToby 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)
94920cf1dd8SToby Isaac . numComp - The number of components for the function
95020cf1dd8SToby Isaac . func    - The input function
95120cf1dd8SToby Isaac - ctx     - A context for the function
95220cf1dd8SToby Isaac 
95320cf1dd8SToby Isaac   Output Parameter:
95420cf1dd8SToby Isaac . value   - numComp output values
95520cf1dd8SToby Isaac 
95620cf1dd8SToby Isaac   Note: The calling sequence for the callback func is given by:
95720cf1dd8SToby Isaac 
95820cf1dd8SToby Isaac $ func(PetscInt dim, PetscReal time, const PetscReal x[],
95920cf1dd8SToby Isaac $      PetscInt numComponents, PetscScalar values[], void *ctx)
96020cf1dd8SToby Isaac 
961a4ce7ad1SMatthew G. Knepley   Level: beginner
96220cf1dd8SToby Isaac 
963db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
96420cf1dd8SToby Isaac @*/
9659371c9d4SSatish Balay 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) {
96620cf1dd8SToby Isaac   PetscFunctionBegin;
96720cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
96820cf1dd8SToby Isaac   PetscValidPointer(cgeom, 4);
969dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
970dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value);
97120cf1dd8SToby Isaac   PetscFunctionReturn(0);
97220cf1dd8SToby Isaac }
97320cf1dd8SToby Isaac 
97420cf1dd8SToby Isaac /*@C
975b4457527SToby Isaac   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllData()
97620cf1dd8SToby Isaac 
97720cf1dd8SToby Isaac   Input Parameters:
97820cf1dd8SToby Isaac + sp        - The PetscDualSpace object
979b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllData()
98020cf1dd8SToby Isaac 
98120cf1dd8SToby Isaac   Output Parameter:
98220cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
98320cf1dd8SToby Isaac 
984a4ce7ad1SMatthew G. Knepley   Level: beginner
98520cf1dd8SToby Isaac 
986db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
98720cf1dd8SToby Isaac @*/
9889371c9d4SSatish Balay PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) {
98920cf1dd8SToby Isaac   PetscFunctionBegin;
99020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
991dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyall, pointEval, spValue);
99220cf1dd8SToby Isaac   PetscFunctionReturn(0);
99320cf1dd8SToby Isaac }
99420cf1dd8SToby Isaac 
99520cf1dd8SToby Isaac /*@C
996b4457527SToby Isaac   PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetInteriorData()
997b4457527SToby Isaac 
998b4457527SToby Isaac   Input Parameters:
999b4457527SToby Isaac + sp        - The PetscDualSpace object
1000b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetInteriorData()
1001b4457527SToby Isaac 
1002b4457527SToby Isaac   Output Parameter:
1003b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1004b4457527SToby Isaac 
1005b4457527SToby Isaac   Level: beginner
1006b4457527SToby Isaac 
1007db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1008b4457527SToby Isaac @*/
10099371c9d4SSatish Balay PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) {
1010b4457527SToby Isaac   PetscFunctionBegin;
1011b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1012dbbe0bcdSBarry Smith   PetscUseTypeMethod(sp, applyint, pointEval, spValue);
1013b4457527SToby Isaac   PetscFunctionReturn(0);
1014b4457527SToby Isaac }
1015b4457527SToby Isaac 
1016b4457527SToby Isaac /*@C
101720cf1dd8SToby Isaac   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
101820cf1dd8SToby Isaac 
101920cf1dd8SToby Isaac   Input Parameters:
102020cf1dd8SToby Isaac + sp    - The PetscDualSpace object
102120cf1dd8SToby Isaac . f     - The basis functional index
102220cf1dd8SToby Isaac . time  - The time
102320cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
102420cf1dd8SToby Isaac . Nc    - The number of components for the function
102520cf1dd8SToby Isaac . func  - The input function
102620cf1dd8SToby Isaac - ctx   - A context for the function
102720cf1dd8SToby Isaac 
102820cf1dd8SToby Isaac   Output Parameter:
102920cf1dd8SToby Isaac . value   - The output value
103020cf1dd8SToby Isaac 
103120cf1dd8SToby Isaac   Note: The calling sequence for the callback func is given by:
103220cf1dd8SToby Isaac 
103320cf1dd8SToby Isaac $ func(PetscInt dim, PetscReal time, const PetscReal x[],
103420cf1dd8SToby Isaac $      PetscInt numComponents, PetscScalar values[], void *ctx)
103520cf1dd8SToby Isaac 
103620cf1dd8SToby Isaac and the idea is to evaluate the functional as an integral
103720cf1dd8SToby Isaac 
103820cf1dd8SToby Isaac $ n(f) = int dx n(x) . f(x)
103920cf1dd8SToby Isaac 
104020cf1dd8SToby Isaac where both n and f have Nc components.
104120cf1dd8SToby Isaac 
1042a4ce7ad1SMatthew G. Knepley   Level: beginner
104320cf1dd8SToby Isaac 
1044db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
104520cf1dd8SToby Isaac @*/
10469371c9d4SSatish Balay 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) {
104720cf1dd8SToby Isaac   DM               dm;
104820cf1dd8SToby Isaac   PetscQuadrature  n;
104920cf1dd8SToby Isaac   const PetscReal *points, *weights;
105020cf1dd8SToby Isaac   PetscReal        x[3];
105120cf1dd8SToby Isaac   PetscScalar     *val;
105220cf1dd8SToby Isaac   PetscInt         dim, dE, qNc, c, Nq, q;
105320cf1dd8SToby Isaac   PetscBool        isAffine;
105420cf1dd8SToby Isaac 
105520cf1dd8SToby Isaac   PetscFunctionBegin;
105620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1057dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
10589566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
10599566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
10609566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights));
106163a3b9bcSJacob 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);
106263a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
10639566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
106420cf1dd8SToby Isaac   *value   = 0.0;
106520cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
106620cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
106720cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
106820cf1dd8SToby Isaac     if (isAffine) {
106920cf1dd8SToby Isaac       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x);
10709566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, x, Nc, val, ctx));
107120cf1dd8SToby Isaac     } else {
10729566063dSJacob Faibussowitsch       PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx));
107320cf1dd8SToby Isaac     }
10749371c9d4SSatish Balay     for (c = 0; c < Nc; ++c) { *value += val[c] * weights[q * Nc + c]; }
107520cf1dd8SToby Isaac   }
10769566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
107720cf1dd8SToby Isaac   PetscFunctionReturn(0);
107820cf1dd8SToby Isaac }
107920cf1dd8SToby Isaac 
108020cf1dd8SToby Isaac /*@C
1081b4457527SToby Isaac   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllData()
108220cf1dd8SToby Isaac 
108320cf1dd8SToby Isaac   Input Parameters:
108420cf1dd8SToby Isaac + sp        - The PetscDualSpace object
1085b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllData()
108620cf1dd8SToby Isaac 
108720cf1dd8SToby Isaac   Output Parameter:
108820cf1dd8SToby Isaac . spValue   - The values of all dual space functionals
108920cf1dd8SToby Isaac 
1090a4ce7ad1SMatthew G. Knepley   Level: beginner
109120cf1dd8SToby Isaac 
1092db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
109320cf1dd8SToby Isaac @*/
10949371c9d4SSatish Balay PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) {
1095b4457527SToby Isaac   Vec pointValues, dofValues;
1096b4457527SToby Isaac   Mat allMat;
109720cf1dd8SToby Isaac 
109820cf1dd8SToby Isaac   PetscFunctionBegin;
109920cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
110020cf1dd8SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1101064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11029566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat));
1103*48a46eb9SPierre Jolivet   if (!(sp->allNodeValues)) PetscCall(MatCreateVecs(allMat, &(sp->allNodeValues), NULL));
1104b4457527SToby Isaac   pointValues = sp->allNodeValues;
1105*48a46eb9SPierre Jolivet   if (!(sp->allDofValues)) PetscCall(MatCreateVecs(allMat, NULL, &(sp->allDofValues)));
1106b4457527SToby Isaac   dofValues = sp->allDofValues;
11079566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11089566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11099566063dSJacob Faibussowitsch   PetscCall(MatMult(allMat, pointValues, dofValues));
11109566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11119566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
1112b4457527SToby Isaac   PetscFunctionReturn(0);
111320cf1dd8SToby Isaac }
1114b4457527SToby Isaac 
1115b4457527SToby Isaac /*@C
1116b4457527SToby Isaac   PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetInteriorData()
1117b4457527SToby Isaac 
1118b4457527SToby Isaac   Input Parameters:
1119b4457527SToby Isaac + sp        - The PetscDualSpace object
1120b4457527SToby Isaac - pointEval - Evaluation at the points returned by PetscDualSpaceGetInteriorData()
1121b4457527SToby Isaac 
1122b4457527SToby Isaac   Output Parameter:
1123b4457527SToby Isaac . spValue   - The values of interior dual space functionals
1124b4457527SToby Isaac 
1125b4457527SToby Isaac   Level: beginner
1126b4457527SToby Isaac 
1127db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1128b4457527SToby Isaac @*/
11299371c9d4SSatish Balay PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) {
1130b4457527SToby Isaac   Vec pointValues, dofValues;
1131b4457527SToby Isaac   Mat intMat;
1132b4457527SToby Isaac 
1133b4457527SToby Isaac   PetscFunctionBegin;
1134b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1135b4457527SToby Isaac   PetscValidScalarPointer(pointEval, 2);
1136064a246eSJacob Faibussowitsch   PetscValidScalarPointer(spValue, 3);
11379566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat));
1138*48a46eb9SPierre Jolivet   if (!(sp->intNodeValues)) PetscCall(MatCreateVecs(intMat, &(sp->intNodeValues), NULL));
1139b4457527SToby Isaac   pointValues = sp->intNodeValues;
1140*48a46eb9SPierre Jolivet   if (!(sp->intDofValues)) PetscCall(MatCreateVecs(intMat, NULL, &(sp->intDofValues)));
1141b4457527SToby Isaac   dofValues = sp->intDofValues;
11429566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(pointValues, pointEval));
11439566063dSJacob Faibussowitsch   PetscCall(VecPlaceArray(dofValues, spValue));
11449566063dSJacob Faibussowitsch   PetscCall(MatMult(intMat, pointValues, dofValues));
11459566063dSJacob Faibussowitsch   PetscCall(VecResetArray(dofValues));
11469566063dSJacob Faibussowitsch   PetscCall(VecResetArray(pointValues));
114720cf1dd8SToby Isaac   PetscFunctionReturn(0);
114820cf1dd8SToby Isaac }
114920cf1dd8SToby Isaac 
1150a4ce7ad1SMatthew G. Knepley /*@
1151b4457527SToby Isaac   PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values
1152a4ce7ad1SMatthew G. Knepley 
1153a4ce7ad1SMatthew G. Knepley   Input Parameter:
1154a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1155a4ce7ad1SMatthew G. Knepley 
1156d8d19677SJose E. Roman   Output Parameters:
1157b4457527SToby Isaac + allNodes - A PetscQuadrature object containing all evaluation nodes
1158b4457527SToby Isaac - allMat - A Mat for the node-to-dof transformation
1159a4ce7ad1SMatthew G. Knepley 
1160a4ce7ad1SMatthew G. Knepley   Level: advanced
1161a4ce7ad1SMatthew G. Knepley 
1162db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1163a4ce7ad1SMatthew G. Knepley @*/
11649371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat) {
116520cf1dd8SToby Isaac   PetscFunctionBegin;
116620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1167b4457527SToby Isaac   if (allNodes) PetscValidPointer(allNodes, 2);
1168b4457527SToby Isaac   if (allMat) PetscValidPointer(allMat, 3);
1169b4457527SToby Isaac   if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) {
1170b4457527SToby Isaac     PetscQuadrature qpoints;
1171b4457527SToby Isaac     Mat             amat;
1172b4457527SToby Isaac 
1173dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createalldata, &qpoints, &amat);
11749566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->allNodes)));
11759566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->allMat)));
1176b4457527SToby Isaac     sp->allNodes = qpoints;
1177b4457527SToby Isaac     sp->allMat   = amat;
117820cf1dd8SToby Isaac   }
1179b4457527SToby Isaac   if (allNodes) *allNodes = sp->allNodes;
1180b4457527SToby Isaac   if (allMat) *allMat = sp->allMat;
118120cf1dd8SToby Isaac   PetscFunctionReturn(0);
118220cf1dd8SToby Isaac }
118320cf1dd8SToby Isaac 
1184a4ce7ad1SMatthew G. Knepley /*@
1185b4457527SToby Isaac   PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals
1186a4ce7ad1SMatthew G. Knepley 
1187a4ce7ad1SMatthew G. Knepley   Input Parameter:
1188a4ce7ad1SMatthew G. Knepley . sp - The dualspace
1189a4ce7ad1SMatthew G. Knepley 
1190d8d19677SJose E. Roman   Output Parameters:
1191b4457527SToby Isaac + allNodes - A PetscQuadrature object containing all evaluation nodes
1192b4457527SToby Isaac - allMat - A Mat for the node-to-dof transformation
1193a4ce7ad1SMatthew G. Knepley 
1194a4ce7ad1SMatthew G. Knepley   Level: advanced
1195a4ce7ad1SMatthew G. Knepley 
1196db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
1197a4ce7ad1SMatthew G. Knepley @*/
11989371c9d4SSatish Balay PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat) {
119920cf1dd8SToby Isaac   PetscInt        spdim;
120020cf1dd8SToby Isaac   PetscInt        numPoints, offset;
120120cf1dd8SToby Isaac   PetscReal      *points;
120220cf1dd8SToby Isaac   PetscInt        f, dim;
1203b4457527SToby Isaac   PetscInt        Nc, nrows, ncols;
1204b4457527SToby Isaac   PetscInt        maxNumPoints;
120520cf1dd8SToby Isaac   PetscQuadrature q;
1206b4457527SToby Isaac   Mat             A;
120720cf1dd8SToby Isaac 
120820cf1dd8SToby Isaac   PetscFunctionBegin;
12099566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
12109566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(sp, &spdim));
121120cf1dd8SToby Isaac   if (!spdim) {
12129566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12139566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL));
121420cf1dd8SToby Isaac   }
1215b4457527SToby Isaac   nrows = spdim;
12169566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q));
12179566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL));
1218b4457527SToby Isaac   maxNumPoints = numPoints;
121920cf1dd8SToby Isaac   for (f = 1; f < spdim; f++) {
122020cf1dd8SToby Isaac     PetscInt Np;
122120cf1dd8SToby Isaac 
12229566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12239566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
122420cf1dd8SToby Isaac     numPoints += Np;
1225b4457527SToby Isaac     maxNumPoints = PetscMax(maxNumPoints, Np);
122620cf1dd8SToby Isaac   }
1227b4457527SToby Isaac   ncols = numPoints * Nc;
12289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
12299566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A));
123020cf1dd8SToby Isaac   for (f = 0, offset = 0; f < spdim; f++) {
1231b4457527SToby Isaac     const PetscReal *p, *w;
123220cf1dd8SToby Isaac     PetscInt         Np, i;
1233b4457527SToby Isaac     PetscInt         fnc;
123420cf1dd8SToby Isaac 
12359566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(sp, f, &q));
12369566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w));
123708401ef6SPierre Jolivet     PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch");
12389371c9d4SSatish Balay     for (i = 0; i < Np * dim; i++) { points[offset * dim + i] = p[i]; }
1239*48a46eb9SPierre Jolivet     for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES));
1240b4457527SToby Isaac     offset += Np;
1241b4457527SToby Isaac   }
12429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
12439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
12449566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes));
12459566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL));
1246b4457527SToby Isaac   *allMat = A;
1247b4457527SToby Isaac   PetscFunctionReturn(0);
1248b4457527SToby Isaac }
1249b4457527SToby Isaac 
1250b4457527SToby Isaac /*@
1251b4457527SToby Isaac   PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from
1252b4457527SToby Isaac   this space, as well as the matrix that computes the degrees of freedom from the quadrature values.  Degrees of
1253b4457527SToby Isaac   freedom are interior degrees of freedom if they belong (by PetscDualSpaceGetSection()) to interior points in the
1254b4457527SToby Isaac   reference DMPlex: complementary boundary degrees of freedom are marked as constrained in the section returned by
1255b4457527SToby Isaac   PetscDualSpaceGetSection()).
1256b4457527SToby Isaac 
1257b4457527SToby Isaac   Input Parameter:
1258b4457527SToby Isaac . sp - The dualspace
1259b4457527SToby Isaac 
1260d8d19677SJose E. Roman   Output Parameters:
1261b4457527SToby Isaac + intNodes - A PetscQuadrature object containing all evaluation points needed to evaluate interior degrees of freedom
1262b4457527SToby Isaac - intMat   - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1263b4457527SToby Isaac              the size of the constrained layout (PetscSectionGetConstrainStorageSize()) of the dual space section,
1264b4457527SToby Isaac              npoints is the number of points in intNodes and nc is PetscDualSpaceGetNumComponents().
1265b4457527SToby Isaac 
1266b4457527SToby Isaac   Level: advanced
1267b4457527SToby Isaac 
1268db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()`
1269b4457527SToby Isaac @*/
12709371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat) {
1271b4457527SToby Isaac   PetscFunctionBegin;
1272b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1273b4457527SToby Isaac   if (intNodes) PetscValidPointer(intNodes, 2);
1274b4457527SToby Isaac   if (intMat) PetscValidPointer(intMat, 3);
1275b4457527SToby Isaac   if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) {
1276b4457527SToby Isaac     PetscQuadrature qpoints;
1277b4457527SToby Isaac     Mat             imat;
1278b4457527SToby Isaac 
1279dbbe0bcdSBarry Smith     PetscUseTypeMethod(sp, createintdata, &qpoints, &imat);
12809566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureDestroy(&(sp->intNodes)));
12819566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(sp->intMat)));
1282b4457527SToby Isaac     sp->intNodes = qpoints;
1283b4457527SToby Isaac     sp->intMat   = imat;
1284b4457527SToby Isaac   }
1285b4457527SToby Isaac   if (intNodes) *intNodes = sp->intNodes;
1286b4457527SToby Isaac   if (intMat) *intMat = sp->intMat;
1287b4457527SToby Isaac   PetscFunctionReturn(0);
1288b4457527SToby Isaac }
1289b4457527SToby Isaac 
1290b4457527SToby Isaac /*@
1291b4457527SToby Isaac   PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values
1292b4457527SToby Isaac 
1293b4457527SToby Isaac   Input Parameter:
1294b4457527SToby Isaac . sp - The dualspace
1295b4457527SToby Isaac 
1296d8d19677SJose E. Roman   Output Parameters:
1297b4457527SToby Isaac + intNodes - A PetscQuadrature object containing all evaluation points needed to evaluate interior degrees of freedom
1298b4457527SToby Isaac - intMat    - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is
1299b4457527SToby Isaac               the size of the constrained layout (PetscSectionGetConstrainStorageSize()) of the dual space section,
1300b4457527SToby Isaac               npoints is the number of points in allNodes and nc is PetscDualSpaceGetNumComponents().
1301b4457527SToby Isaac 
1302b4457527SToby Isaac   Level: advanced
1303b4457527SToby Isaac 
1304db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()`
1305b4457527SToby Isaac @*/
13069371c9d4SSatish Balay PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat) {
1307b4457527SToby Isaac   DM              dm;
1308b4457527SToby Isaac   PetscInt        spdim0;
1309b4457527SToby Isaac   PetscInt        Nc;
1310b4457527SToby Isaac   PetscInt        pStart, pEnd, p, f;
1311b4457527SToby Isaac   PetscSection    section;
1312b4457527SToby Isaac   PetscInt        numPoints, offset, matoffset;
1313b4457527SToby Isaac   PetscReal      *points;
1314b4457527SToby Isaac   PetscInt        dim;
1315b4457527SToby Isaac   PetscInt       *nnz;
1316b4457527SToby Isaac   PetscQuadrature q;
1317b4457527SToby Isaac   Mat             imat;
1318b4457527SToby Isaac 
1319b4457527SToby Isaac   PetscFunctionBegin;
1320b4457527SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
13219566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetSection(sp, &section));
13229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0));
1323b4457527SToby Isaac   if (!spdim0) {
1324b4457527SToby Isaac     *intNodes = NULL;
1325b4457527SToby Isaac     *intMat   = NULL;
1326b4457527SToby Isaac     PetscFunctionReturn(0);
1327b4457527SToby Isaac   }
13289566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc));
13299566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
13309566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
13319566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
13329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(spdim0, &nnz));
1333b4457527SToby Isaac   for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) {
1334b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1335b4457527SToby Isaac 
13369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13379566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1338b4457527SToby Isaac     if (!(dof - cdof)) continue;
13399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1340b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1341b4457527SToby Isaac       PetscInt Np;
1342b4457527SToby Isaac 
13439566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
13449566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL));
1345b4457527SToby Isaac       nnz[f] = Np * Nc;
1346b4457527SToby Isaac       numPoints += Np;
1347b4457527SToby Isaac     }
1348b4457527SToby Isaac   }
13499566063dSJacob Faibussowitsch   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat));
13509566063dSJacob Faibussowitsch   PetscCall(PetscFree(nnz));
13519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(dim * numPoints, &points));
1352b4457527SToby Isaac   for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) {
1353b4457527SToby Isaac     PetscInt dof, cdof, off, d;
1354b4457527SToby Isaac 
13559566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(section, p, &dof));
13569566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1357b4457527SToby Isaac     if (!(dof - cdof)) continue;
13589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
1359b4457527SToby Isaac     for (d = 0; d < dof; d++, off++, f++) {
1360b4457527SToby Isaac       const PetscReal *p;
1361b4457527SToby Isaac       const PetscReal *w;
1362b4457527SToby Isaac       PetscInt         Np, i;
1363b4457527SToby Isaac 
13649566063dSJacob Faibussowitsch       PetscCall(PetscDualSpaceGetFunctional(sp, off, &q));
13659566063dSJacob Faibussowitsch       PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w));
13669371c9d4SSatish Balay       for (i = 0; i < Np * dim; i++) { points[offset + i] = p[i]; }
1367*48a46eb9SPierre Jolivet       for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES));
1368b4457527SToby Isaac       offset += Np * dim;
1369b4457527SToby Isaac       matoffset += Np * Nc;
1370b4457527SToby Isaac     }
1371b4457527SToby Isaac   }
13729566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes));
13739566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL));
13749566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY));
13759566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY));
1376b4457527SToby Isaac   *intMat = imat;
137720cf1dd8SToby Isaac   PetscFunctionReturn(0);
137820cf1dd8SToby Isaac }
137920cf1dd8SToby Isaac 
13804f9ab2b4SJed Brown /*@
13814f9ab2b4SJed Brown   PetscDualSpaceEqual - Determine if a dual space is equivalent
13824f9ab2b4SJed Brown 
13834f9ab2b4SJed Brown   Input Parameters:
13844f9ab2b4SJed Brown + A    - A PetscDualSpace object
13854f9ab2b4SJed Brown - B    - Another PetscDualSpace object
13864f9ab2b4SJed Brown 
13874f9ab2b4SJed Brown   Output Parameter:
13884f9ab2b4SJed Brown . equal - PETSC_TRUE if the dual spaces are equivalent
13894f9ab2b4SJed Brown 
13904f9ab2b4SJed Brown   Level: advanced
13914f9ab2b4SJed Brown 
1392db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
13934f9ab2b4SJed Brown @*/
13949371c9d4SSatish Balay PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal) {
13954f9ab2b4SJed Brown   PetscInt        sizeA, sizeB, dimA, dimB;
13964f9ab2b4SJed Brown   const PetscInt *dofA, *dofB;
13974f9ab2b4SJed Brown   PetscQuadrature quadA, quadB;
13984f9ab2b4SJed Brown   Mat             matA, matB;
13994f9ab2b4SJed Brown 
14004f9ab2b4SJed Brown   PetscFunctionBegin;
14014f9ab2b4SJed Brown   PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1);
14024f9ab2b4SJed Brown   PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2);
14034f9ab2b4SJed Brown   PetscValidBoolPointer(equal, 3);
14044f9ab2b4SJed Brown   *equal = PETSC_FALSE;
14059566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(A, &sizeA));
14069566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(B, &sizeB));
14079371c9d4SSatish Balay   if (sizeB != sizeA) { PetscFunctionReturn(0); }
14089566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(A->dm, &dimA));
14099566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(B->dm, &dimB));
14109371c9d4SSatish Balay   if (dimA != dimB) { PetscFunctionReturn(0); }
14114f9ab2b4SJed Brown 
14129566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(A, &dofA));
14139566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetNumDof(B, &dofB));
14144f9ab2b4SJed Brown   for (PetscInt d = 0; d < dimA; d++) {
14159371c9d4SSatish Balay     if (dofA[d] != dofB[d]) { PetscFunctionReturn(0); }
14164f9ab2b4SJed Brown   }
14174f9ab2b4SJed Brown 
14189566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA));
14199566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB));
14204f9ab2b4SJed Brown   if (!quadA && !quadB) {
14214f9ab2b4SJed Brown     *equal = PETSC_TRUE;
14224f9ab2b4SJed Brown   } else if (quadA && quadB) {
14239566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureEqual(quadA, quadB, equal));
14244f9ab2b4SJed Brown     if (*equal == PETSC_FALSE) PetscFunctionReturn(0);
14254f9ab2b4SJed Brown     if (!matA && !matB) PetscFunctionReturn(0);
14269566063dSJacob Faibussowitsch     if (matA && matB) PetscCall(MatEqual(matA, matB, equal));
14274f9ab2b4SJed Brown     else *equal = PETSC_FALSE;
14284f9ab2b4SJed Brown   }
14294f9ab2b4SJed Brown   PetscFunctionReturn(0);
14304f9ab2b4SJed Brown }
14314f9ab2b4SJed Brown 
143220cf1dd8SToby Isaac /*@C
143320cf1dd8SToby Isaac   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
143420cf1dd8SToby Isaac 
143520cf1dd8SToby Isaac   Input Parameters:
143620cf1dd8SToby Isaac + sp    - The PetscDualSpace object
143720cf1dd8SToby Isaac . f     - The basis functional index
143820cf1dd8SToby Isaac . time  - The time
143920cf1dd8SToby Isaac . cgeom - A context with geometric information for this cell, we currently just use the centroid
144020cf1dd8SToby Isaac . Nc    - The number of components for the function
144120cf1dd8SToby Isaac . func  - The input function
144220cf1dd8SToby Isaac - ctx   - A context for the function
144320cf1dd8SToby Isaac 
144420cf1dd8SToby Isaac   Output Parameter:
144520cf1dd8SToby Isaac . value - The output value (scalar)
144620cf1dd8SToby Isaac 
144720cf1dd8SToby Isaac   Note: The calling sequence for the callback func is given by:
144820cf1dd8SToby Isaac 
144920cf1dd8SToby Isaac $ func(PetscInt dim, PetscReal time, const PetscReal x[],
145020cf1dd8SToby Isaac $      PetscInt numComponents, PetscScalar values[], void *ctx)
145120cf1dd8SToby Isaac 
145220cf1dd8SToby Isaac and the idea is to evaluate the functional as an integral
145320cf1dd8SToby Isaac 
145420cf1dd8SToby Isaac $ n(f) = int dx n(x) . f(x)
145520cf1dd8SToby Isaac 
145620cf1dd8SToby Isaac where both n and f have Nc components.
145720cf1dd8SToby Isaac 
1458a4ce7ad1SMatthew G. Knepley   Level: beginner
145920cf1dd8SToby Isaac 
1460db781477SPatrick Sanan .seealso: `PetscDualSpaceCreate()`
146120cf1dd8SToby Isaac @*/
14629371c9d4SSatish Balay 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) {
146320cf1dd8SToby Isaac   DM               dm;
146420cf1dd8SToby Isaac   PetscQuadrature  n;
146520cf1dd8SToby Isaac   const PetscReal *points, *weights;
146620cf1dd8SToby Isaac   PetscScalar     *val;
146720cf1dd8SToby Isaac   PetscInt         dimEmbed, qNc, c, Nq, q;
146820cf1dd8SToby Isaac 
146920cf1dd8SToby Isaac   PetscFunctionBegin;
147020cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1471dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(value, 8);
14729566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(sp, &dm));
14739566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &dimEmbed));
14749566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetFunctional(sp, f, &n));
14759566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights));
147663a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc);
14779566063dSJacob Faibussowitsch   PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val));
147820cf1dd8SToby Isaac   *value = 0.;
147920cf1dd8SToby Isaac   for (q = 0; q < Nq; ++q) {
14809566063dSJacob Faibussowitsch     PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx));
14819371c9d4SSatish Balay     for (c = 0; c < Nc; ++c) { *value += val[c] * weights[q * Nc + c]; }
148220cf1dd8SToby Isaac   }
14839566063dSJacob Faibussowitsch   PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val));
148420cf1dd8SToby Isaac   PetscFunctionReturn(0);
148520cf1dd8SToby Isaac }
148620cf1dd8SToby Isaac 
148720cf1dd8SToby Isaac /*@
148820cf1dd8SToby Isaac   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
148920cf1dd8SToby Isaac   given height.  This assumes that the reference cell is symmetric over points of this height.
149020cf1dd8SToby Isaac 
149120cf1dd8SToby Isaac   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
149220cf1dd8SToby Isaac   pointwise values are not defined on the element boundaries), or if the implementation of PetscDualSpace does not
149320cf1dd8SToby Isaac   support extracting subspaces, then NULL is returned.
149420cf1dd8SToby Isaac 
149520cf1dd8SToby Isaac   This does not increment the reference count on the returned dual space, and the user should not destroy it.
149620cf1dd8SToby Isaac 
149720cf1dd8SToby Isaac   Not collective
149820cf1dd8SToby Isaac 
149920cf1dd8SToby Isaac   Input Parameters:
150020cf1dd8SToby Isaac + sp - the PetscDualSpace object
150120cf1dd8SToby Isaac - height - the height of the mesh point for which the subspace is desired
150220cf1dd8SToby Isaac 
150320cf1dd8SToby Isaac   Output Parameter:
150420cf1dd8SToby Isaac . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
150520cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
150620cf1dd8SToby Isaac 
150720cf1dd8SToby Isaac   Level: advanced
150820cf1dd8SToby Isaac 
1509db781477SPatrick Sanan .seealso: `PetscSpaceGetHeightSubspace()`, `PetscDualSpace`
151020cf1dd8SToby Isaac @*/
15119371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp) {
1512b4457527SToby Isaac   PetscInt depth = -1, cStart, cEnd;
1513b4457527SToby Isaac   DM       dm;
151420cf1dd8SToby Isaac 
151520cf1dd8SToby Isaac   PetscFunctionBegin;
151620cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1517064a246eSJacob Faibussowitsch   PetscValidPointer(subsp, 3);
151808401ef6SPierre 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");
151920cf1dd8SToby Isaac   *subsp = NULL;
1520b4457527SToby Isaac   dm     = sp->dm;
15219566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepth(dm, &depth));
15221dca8a05SBarry Smith   PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height");
15239566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1524b4457527SToby Isaac   if (height == 0 && cEnd == cStart + 1) {
1525b4457527SToby Isaac     *subsp = sp;
1526b4457527SToby Isaac     PetscFunctionReturn(0);
1527b4457527SToby Isaac   }
1528b4457527SToby Isaac   if (!sp->heightSpaces) {
1529b4457527SToby Isaac     PetscInt h;
15309566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(depth + 1, &(sp->heightSpaces)));
1531b4457527SToby Isaac 
1532b4457527SToby Isaac     for (h = 0; h <= depth; h++) {
1533b4457527SToby Isaac       if (h == 0 && cEnd == cStart + 1) continue;
15349566063dSJacob Faibussowitsch       if (sp->ops->createheightsubspace) PetscCall((*sp->ops->createheightsubspace)(sp, height, &(sp->heightSpaces[h])));
1535b4457527SToby Isaac       else if (sp->pointSpaces) {
1536b4457527SToby Isaac         PetscInt hStart, hEnd;
1537b4457527SToby Isaac 
15389566063dSJacob Faibussowitsch         PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd));
1539b4457527SToby Isaac         if (hEnd > hStart) {
1540665f567fSMatthew G. Knepley           const char *name;
1541665f567fSMatthew G. Knepley 
15429566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)(sp->pointSpaces[hStart])));
1543665f567fSMatthew G. Knepley           if (sp->pointSpaces[hStart]) {
15449566063dSJacob Faibussowitsch             PetscCall(PetscObjectGetName((PetscObject)sp, &name));
15459566063dSJacob Faibussowitsch             PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name));
1546665f567fSMatthew G. Knepley           }
1547b4457527SToby Isaac           sp->heightSpaces[h] = sp->pointSpaces[hStart];
1548b4457527SToby Isaac         }
1549b4457527SToby Isaac       }
1550b4457527SToby Isaac     }
1551b4457527SToby Isaac   }
1552b4457527SToby Isaac   *subsp = sp->heightSpaces[height];
155320cf1dd8SToby Isaac   PetscFunctionReturn(0);
155420cf1dd8SToby Isaac }
155520cf1dd8SToby Isaac 
155620cf1dd8SToby Isaac /*@
155720cf1dd8SToby Isaac   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
155820cf1dd8SToby Isaac 
155920cf1dd8SToby Isaac   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
156020cf1dd8SToby Isaac   defined on the element boundaries), or if the implementation of PetscDualSpace does not support extracting
156120cf1dd8SToby Isaac   subspaces, then NULL is returned.
156220cf1dd8SToby Isaac 
156320cf1dd8SToby Isaac   This does not increment the reference count on the returned dual space, and the user should not destroy it.
156420cf1dd8SToby Isaac 
156520cf1dd8SToby Isaac   Not collective
156620cf1dd8SToby Isaac 
156720cf1dd8SToby Isaac   Input Parameters:
156820cf1dd8SToby Isaac + sp - the PetscDualSpace object
156920cf1dd8SToby Isaac - point - the point (in the dual space's DM) for which the subspace is desired
157020cf1dd8SToby Isaac 
157120cf1dd8SToby Isaac   Output Parameters:
157220cf1dd8SToby Isaac   bdsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
157320cf1dd8SToby Isaac   point, which will be of lesser dimension if height > 0.
157420cf1dd8SToby Isaac 
157520cf1dd8SToby Isaac   Level: advanced
157620cf1dd8SToby Isaac 
1577db781477SPatrick Sanan .seealso: `PetscDualSpace`
157820cf1dd8SToby Isaac @*/
15799371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp) {
1580b4457527SToby Isaac   PetscInt pStart = 0, pEnd = 0, cStart, cEnd;
1581b4457527SToby Isaac   DM       dm;
158220cf1dd8SToby Isaac 
158320cf1dd8SToby Isaac   PetscFunctionBegin;
158420cf1dd8SToby Isaac   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1585064a246eSJacob Faibussowitsch   PetscValidPointer(bdsp, 3);
158620cf1dd8SToby Isaac   *bdsp = NULL;
1587b4457527SToby Isaac   dm    = sp->dm;
15889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
15891dca8a05SBarry Smith   PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point");
15909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
1591b4457527SToby 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 */
1592b4457527SToby Isaac     *bdsp = sp;
1593b4457527SToby Isaac     PetscFunctionReturn(0);
1594b4457527SToby Isaac   }
1595b4457527SToby Isaac   if (!sp->pointSpaces) {
1596b4457527SToby Isaac     PetscInt p;
15979566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(pEnd - pStart, &(sp->pointSpaces)));
159820cf1dd8SToby Isaac 
1599b4457527SToby Isaac     for (p = 0; p < pEnd - pStart; p++) {
1600b4457527SToby Isaac       if (p + pStart == cStart && cEnd == cStart + 1) continue;
16019566063dSJacob Faibussowitsch       if (sp->ops->createpointsubspace) PetscCall((*sp->ops->createpointsubspace)(sp, p + pStart, &(sp->pointSpaces[p])));
1602b4457527SToby Isaac       else if (sp->heightSpaces || sp->ops->createheightsubspace) {
1603b4457527SToby Isaac         PetscInt dim, depth, height;
1604b4457527SToby Isaac         DMLabel  label;
1605b4457527SToby Isaac 
16069566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepth(dm, &dim));
16079566063dSJacob Faibussowitsch         PetscCall(DMPlexGetDepthLabel(dm, &label));
16089566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(label, p + pStart, &depth));
160920cf1dd8SToby Isaac         height = dim - depth;
16109566063dSJacob Faibussowitsch         PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &(sp->pointSpaces[p])));
16119566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p]));
161220cf1dd8SToby Isaac       }
1613b4457527SToby Isaac     }
1614b4457527SToby Isaac   }
1615b4457527SToby Isaac   *bdsp = sp->pointSpaces[point - pStart];
161620cf1dd8SToby Isaac   PetscFunctionReturn(0);
161720cf1dd8SToby Isaac }
161820cf1dd8SToby Isaac 
16196f905325SMatthew G. Knepley /*@C
16206f905325SMatthew G. Knepley   PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis
16216f905325SMatthew G. Knepley 
16226f905325SMatthew G. Knepley   Not collective
16236f905325SMatthew G. Knepley 
16246f905325SMatthew G. Knepley   Input Parameter:
16256f905325SMatthew G. Knepley . sp - the PetscDualSpace object
16266f905325SMatthew G. Knepley 
16276f905325SMatthew G. Knepley   Output Parameters:
1628b4457527SToby Isaac + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation
1629b4457527SToby Isaac - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation
16306f905325SMatthew G. Knepley 
16316f905325SMatthew G. Knepley   Note: The permutation and flip arrays are organized in the following way
16326f905325SMatthew G. Knepley $ perms[p][ornt][dof # on point] = new local dof #
16336f905325SMatthew G. Knepley $ flips[p][ornt][dof # on point] = reversal or not
16346f905325SMatthew G. Knepley 
16356f905325SMatthew G. Knepley   Level: developer
16366f905325SMatthew G. Knepley 
16376f905325SMatthew G. Knepley @*/
16389371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips) {
16396f905325SMatthew G. Knepley   PetscFunctionBegin;
16406f905325SMatthew G. Knepley   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
16419371c9d4SSatish Balay   if (perms) {
16429371c9d4SSatish Balay     PetscValidPointer(perms, 2);
16439371c9d4SSatish Balay     *perms = NULL;
16449371c9d4SSatish Balay   }
16459371c9d4SSatish Balay   if (flips) {
16469371c9d4SSatish Balay     PetscValidPointer(flips, 3);
16479371c9d4SSatish Balay     *flips = NULL;
16489371c9d4SSatish Balay   }
16499566063dSJacob Faibussowitsch   if (sp->ops->getsymmetries) PetscCall((sp->ops->getsymmetries)(sp, perms, flips));
16506f905325SMatthew G. Knepley   PetscFunctionReturn(0);
16516f905325SMatthew G. Knepley }
16524bee2e38SMatthew G. Knepley 
16534bee2e38SMatthew G. Knepley /*@
1654b4457527SToby Isaac   PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this
1655b4457527SToby Isaac   dual space's functionals.
1656b4457527SToby Isaac 
1657b4457527SToby Isaac   Input Parameter:
1658b4457527SToby Isaac . dsp - The PetscDualSpace
1659b4457527SToby Isaac 
1660b4457527SToby Isaac   Output Parameter:
1661b4457527SToby 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
1662b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1663b4457527SToby 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).
1664b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1665b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1666b4457527SToby Isaac         but are stored as 1-forms.
1667b4457527SToby Isaac 
1668b4457527SToby Isaac   Level: developer
1669b4457527SToby Isaac 
1670db781477SPatrick Sanan .seealso: `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1671b4457527SToby Isaac @*/
16729371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k) {
1673b4457527SToby Isaac   PetscFunctionBeginHot;
1674b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1675dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1676b4457527SToby Isaac   *k = dsp->k;
1677b4457527SToby Isaac   PetscFunctionReturn(0);
1678b4457527SToby Isaac }
1679b4457527SToby Isaac 
1680b4457527SToby Isaac /*@
1681b4457527SToby Isaac   PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this
1682b4457527SToby Isaac   dual space's functionals.
1683b4457527SToby Isaac 
1684d8d19677SJose E. Roman   Input Parameters:
1685b4457527SToby Isaac + dsp - The PetscDualSpace
1686b4457527SToby 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
1687b4457527SToby Isaac         in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms.  So for example,
1688b4457527SToby 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).
1689b4457527SToby Isaac         If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the
1690b4457527SToby Isaac         Hodge star map.  So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms
1691b4457527SToby Isaac         but are stored as 1-forms.
1692b4457527SToby Isaac 
1693b4457527SToby Isaac   Level: developer
1694b4457527SToby Isaac 
1695db781477SPatrick Sanan .seealso: `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
1696b4457527SToby Isaac @*/
16979371c9d4SSatish Balay PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k) {
1698b4457527SToby Isaac   PetscInt dim;
1699b4457527SToby Isaac 
1700b4457527SToby Isaac   PetscFunctionBeginHot;
1701b4457527SToby Isaac   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
170228b400f6SJacob Faibussowitsch   PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up");
1703b4457527SToby Isaac   dim = dsp->dm->dim;
17041dca8a05SBarry 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);
1705b4457527SToby Isaac   dsp->k = k;
1706b4457527SToby Isaac   PetscFunctionReturn(0);
1707b4457527SToby Isaac }
1708b4457527SToby Isaac 
1709b4457527SToby Isaac /*@
17104bee2e38SMatthew G. Knepley   PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space
17114bee2e38SMatthew G. Knepley 
17124bee2e38SMatthew G. Knepley   Input Parameter:
17134bee2e38SMatthew G. Knepley . dsp - The PetscDualSpace
17144bee2e38SMatthew G. Knepley 
17154bee2e38SMatthew G. Knepley   Output Parameter:
17164bee2e38SMatthew G. Knepley . k   - The simplex dimension
17174bee2e38SMatthew G. Knepley 
1718a4ce7ad1SMatthew G. Knepley   Level: developer
17194bee2e38SMatthew G. Knepley 
17204bee2e38SMatthew G. Knepley   Note: Currently supported values are
17214bee2e38SMatthew G. Knepley $ 0: These are H_1 methods that only transform coordinates
17224bee2e38SMatthew G. Knepley $ 1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM)
17234bee2e38SMatthew G. Knepley $ 2: These are the same as 1
17244bee2e38SMatthew G. Knepley $ 3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM)
17254bee2e38SMatthew G. Knepley 
1726db781477SPatrick Sanan .seealso: `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType`
17274bee2e38SMatthew G. Knepley @*/
17289371c9d4SSatish Balay PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k) {
1729b4457527SToby Isaac   PetscInt dim;
1730b4457527SToby Isaac 
17314bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
17324bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1733dadcf809SJacob Faibussowitsch   PetscValidIntPointer(k, 2);
1734b4457527SToby Isaac   dim = dsp->dm->dim;
1735b4457527SToby Isaac   if (!dsp->k) *k = IDENTITY_TRANSFORM;
1736b4457527SToby Isaac   else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM;
1737b4457527SToby Isaac   else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM;
1738b4457527SToby Isaac   else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation");
17394bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
17404bee2e38SMatthew G. Knepley }
17414bee2e38SMatthew G. Knepley 
17424bee2e38SMatthew G. Knepley /*@C
17434bee2e38SMatthew G. Knepley   PetscDualSpaceTransform - Transform the function values
17444bee2e38SMatthew G. Knepley 
17454bee2e38SMatthew G. Knepley   Input Parameters:
17464bee2e38SMatthew G. Knepley + dsp       - The PetscDualSpace
17474bee2e38SMatthew G. Knepley . trans     - The type of transform
17484bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
17494bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
17504bee2e38SMatthew G. Knepley . Nv        - The number of function samples
17514bee2e38SMatthew G. Knepley . Nc        - The number of function components
17524bee2e38SMatthew G. Knepley - vals      - The function values
17534bee2e38SMatthew G. Knepley 
17544bee2e38SMatthew G. Knepley   Output Parameter:
17554bee2e38SMatthew G. Knepley . vals      - The transformed function values
17564bee2e38SMatthew G. Knepley 
1757a4ce7ad1SMatthew G. Knepley   Level: intermediate
17584bee2e38SMatthew G. Knepley 
1759f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
17602edcad52SToby Isaac 
1761db781477SPatrick Sanan .seealso: `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
17624bee2e38SMatthew G. Knepley @*/
17639371c9d4SSatish Balay PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) {
1764b4457527SToby Isaac   PetscReal Jstar[9] = {0};
1765b4457527SToby Isaac   PetscInt  dim, v, c, Nk;
17664bee2e38SMatthew G. Knepley 
17674bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
17684bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
17694bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1770dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
1771b4457527SToby Isaac   /* TODO: not handling dimEmbed != dim right now */
17722ae266adSMatthew G. Knepley   dim = dsp->dm->dim;
1773b4457527SToby Isaac   /* No change needed for 0-forms */
1774b4457527SToby Isaac   if (!dsp->k) PetscFunctionReturn(0);
17759566063dSJacob Faibussowitsch   PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk));
1776b4457527SToby Isaac   /* TODO: use fegeom->isAffine */
17779566063dSJacob Faibussowitsch   PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar));
17784bee2e38SMatthew G. Knepley   for (v = 0; v < Nv; ++v) {
1779b4457527SToby Isaac     switch (Nk) {
1780b4457527SToby Isaac     case 1:
1781b4457527SToby Isaac       for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0];
17824bee2e38SMatthew G. Knepley       break;
1783b4457527SToby Isaac     case 2:
1784b4457527SToby Isaac       for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
17854bee2e38SMatthew G. Knepley       break;
1786b4457527SToby Isaac     case 3:
1787b4457527SToby Isaac       for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]);
1788b4457527SToby Isaac       break;
178963a3b9bcSJacob Faibussowitsch     default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk);
1790b4457527SToby Isaac     }
17914bee2e38SMatthew G. Knepley   }
17924bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
17934bee2e38SMatthew G. Knepley }
1794b4457527SToby Isaac 
17954bee2e38SMatthew G. Knepley /*@C
17964bee2e38SMatthew G. Knepley   PetscDualSpaceTransformGradient - Transform the function gradient values
17974bee2e38SMatthew G. Knepley 
17984bee2e38SMatthew G. Knepley   Input Parameters:
17994bee2e38SMatthew G. Knepley + dsp       - The PetscDualSpace
18004bee2e38SMatthew G. Knepley . trans     - The type of transform
18014bee2e38SMatthew G. Knepley . isInverse - Flag to invert the transform
18024bee2e38SMatthew G. Knepley . fegeom    - The cell geometry
18034bee2e38SMatthew G. Knepley . Nv        - The number of function gradient samples
18044bee2e38SMatthew G. Knepley . Nc        - The number of function components
18054bee2e38SMatthew G. Knepley - vals      - The function gradient values
18064bee2e38SMatthew G. Knepley 
18074bee2e38SMatthew G. Knepley   Output Parameter:
1808f9244615SMatthew G. Knepley . vals      - The transformed function gradient values
18094bee2e38SMatthew G. Knepley 
1810a4ce7ad1SMatthew G. Knepley   Level: intermediate
18114bee2e38SMatthew G. Knepley 
1812f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
18132edcad52SToby Isaac 
1814db781477SPatrick Sanan .seealso: `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
18154bee2e38SMatthew G. Knepley @*/
18169371c9d4SSatish Balay PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) {
181727f02ce8SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
181827f02ce8SMatthew G. Knepley   PetscInt       v, c, d;
18194bee2e38SMatthew G. Knepley 
18204bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
18214bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
18224bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1823dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
182427f02ce8SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
182563a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
182627f02ce8SMatthew G. Knepley #endif
18274bee2e38SMatthew G. Knepley   /* Transform gradient */
182827f02ce8SMatthew G. Knepley   if (dim == dE) {
18294bee2e38SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
18304bee2e38SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
18319371c9d4SSatish Balay         switch (dim) {
1832100a78e1SStefano Zampini         case 1: vals[(v * Nc + c) * dim] *= fegeom->invJ[0]; break;
18336142fa51SMatthew G. Knepley         case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]); break;
18346142fa51SMatthew G. Knepley         case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]); break;
183563a3b9bcSJacob Faibussowitsch         default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18364bee2e38SMatthew G. Knepley         }
18374bee2e38SMatthew G. Knepley       }
18384bee2e38SMatthew G. Knepley     }
183927f02ce8SMatthew G. Knepley   } else {
184027f02ce8SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
18419371c9d4SSatish Balay       for (c = 0; c < Nc; ++c) { DMPlex_MultTransposeReal_Internal(fegeom->invJ, dim, dE, 1, &vals[(v * Nc + c) * dE], &vals[(v * Nc + c) * dE]); }
184227f02ce8SMatthew G. Knepley     }
184327f02ce8SMatthew G. Knepley   }
18444bee2e38SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
18454bee2e38SMatthew G. Knepley   if (Nc == 1 || Nc != dim) PetscFunctionReturn(0);
18464bee2e38SMatthew G. Knepley   switch (trans) {
18474bee2e38SMatthew G. Knepley   case IDENTITY_TRANSFORM: break;
18484bee2e38SMatthew G. Knepley   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */
18494bee2e38SMatthew G. Knepley     if (isInverse) {
18504bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
18514bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
18529371c9d4SSatish Balay           switch (dim) {
18536142fa51SMatthew G. Knepley           case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
18546142fa51SMatthew G. Knepley           case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
185563a3b9bcSJacob Faibussowitsch           default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18564bee2e38SMatthew G. Knepley           }
18574bee2e38SMatthew G. Knepley         }
18584bee2e38SMatthew G. Knepley       }
18594bee2e38SMatthew G. Knepley     } else {
18604bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
18614bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
18629371c9d4SSatish Balay           switch (dim) {
18636142fa51SMatthew G. Knepley           case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
18646142fa51SMatthew G. Knepley           case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
186563a3b9bcSJacob Faibussowitsch           default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18664bee2e38SMatthew G. Knepley           }
18674bee2e38SMatthew G. Knepley         }
18684bee2e38SMatthew G. Knepley       }
18694bee2e38SMatthew G. Knepley     }
18704bee2e38SMatthew G. Knepley     break;
18714bee2e38SMatthew G. Knepley   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */
18724bee2e38SMatthew G. Knepley     if (isInverse) {
18734bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
18744bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
18759371c9d4SSatish Balay           switch (dim) {
18766142fa51SMatthew G. Knepley           case 2: DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
18776142fa51SMatthew G. Knepley           case 3: DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
187863a3b9bcSJacob Faibussowitsch           default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18794bee2e38SMatthew G. Knepley           }
18804bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0];
18814bee2e38SMatthew G. Knepley         }
18824bee2e38SMatthew G. Knepley       }
18834bee2e38SMatthew G. Knepley     } else {
18844bee2e38SMatthew G. Knepley       for (v = 0; v < Nv; ++v) {
18854bee2e38SMatthew G. Knepley         for (d = 0; d < dim; ++d) {
18869371c9d4SSatish Balay           switch (dim) {
18876142fa51SMatthew G. Knepley           case 2: DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
18886142fa51SMatthew G. Knepley           case 3: DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); break;
188963a3b9bcSJacob Faibussowitsch           default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
18904bee2e38SMatthew G. Knepley           }
18914bee2e38SMatthew G. Knepley           for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0];
18924bee2e38SMatthew G. Knepley         }
18934bee2e38SMatthew G. Knepley       }
18944bee2e38SMatthew G. Knepley     }
18954bee2e38SMatthew G. Knepley     break;
18964bee2e38SMatthew G. Knepley   }
18974bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
18984bee2e38SMatthew G. Knepley }
18994bee2e38SMatthew G. Knepley 
19004bee2e38SMatthew G. Knepley /*@C
1901f9244615SMatthew G. Knepley   PetscDualSpaceTransformHessian - Transform the function Hessian values
1902f9244615SMatthew G. Knepley 
1903f9244615SMatthew G. Knepley   Input Parameters:
1904f9244615SMatthew G. Knepley + dsp       - The PetscDualSpace
1905f9244615SMatthew G. Knepley . trans     - The type of transform
1906f9244615SMatthew G. Knepley . isInverse - Flag to invert the transform
1907f9244615SMatthew G. Knepley . fegeom    - The cell geometry
1908f9244615SMatthew G. Knepley . Nv        - The number of function Hessian samples
1909f9244615SMatthew G. Knepley . Nc        - The number of function components
1910f9244615SMatthew G. Knepley - vals      - The function gradient values
1911f9244615SMatthew G. Knepley 
1912f9244615SMatthew G. Knepley   Output Parameter:
1913f9244615SMatthew G. Knepley . vals      - The transformed function Hessian values
1914f9244615SMatthew G. Knepley 
1915f9244615SMatthew G. Knepley   Level: intermediate
1916f9244615SMatthew G. Knepley 
1917f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
1918f9244615SMatthew G. Knepley 
1919db781477SPatrick Sanan .seealso: `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType`
1920f9244615SMatthew G. Knepley @*/
19219371c9d4SSatish Balay PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) {
1922f9244615SMatthew G. Knepley   const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed;
1923f9244615SMatthew G. Knepley   PetscInt       v, c;
1924f9244615SMatthew G. Knepley 
1925f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
1926f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
1927f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 4);
1928dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(vals, 7);
1929f9244615SMatthew G. Knepley #ifdef PETSC_USE_DEBUG
193063a3b9bcSJacob Faibussowitsch   PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE);
1931f9244615SMatthew G. Knepley #endif
1932f9244615SMatthew G. Knepley   /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */
1933f9244615SMatthew G. Knepley   if (dim == dE) {
1934f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
1935f9244615SMatthew G. Knepley       for (c = 0; c < Nc; ++c) {
19369371c9d4SSatish Balay         switch (dim) {
1937f9244615SMatthew G. Knepley         case 1: vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]); break;
1938f9244615SMatthew G. Knepley         case 2: DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]); break;
1939f9244615SMatthew G. Knepley         case 3: DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]); break;
194063a3b9bcSJacob Faibussowitsch         default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim);
1941f9244615SMatthew G. Knepley         }
1942f9244615SMatthew G. Knepley       }
1943f9244615SMatthew G. Knepley     }
1944f9244615SMatthew G. Knepley   } else {
1945f9244615SMatthew G. Knepley     for (v = 0; v < Nv; ++v) {
19469371c9d4SSatish Balay       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]); }
1947f9244615SMatthew G. Knepley     }
1948f9244615SMatthew G. Knepley   }
1949f9244615SMatthew G. Knepley   /* Assume its a vector, otherwise assume its a bunch of scalars */
1950f9244615SMatthew G. Knepley   if (Nc == 1 || Nc != dim) PetscFunctionReturn(0);
1951f9244615SMatthew G. Knepley   switch (trans) {
1952f9244615SMatthew G. Knepley   case IDENTITY_TRANSFORM: break;
19539371c9d4SSatish Balay   case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */ SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
19549371c9d4SSatish Balay   case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */ SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported");
1955f9244615SMatthew G. Knepley   }
1956f9244615SMatthew G. Knepley   PetscFunctionReturn(0);
1957f9244615SMatthew G. Knepley }
1958f9244615SMatthew G. Knepley 
1959f9244615SMatthew G. Knepley /*@C
19604bee2e38SMatthew 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.
19614bee2e38SMatthew G. Knepley 
19624bee2e38SMatthew G. Knepley   Input Parameters:
19634bee2e38SMatthew G. Knepley + dsp        - The PetscDualSpace
19644bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
19654bee2e38SMatthew G. Knepley . Nq         - The number of function samples
19664bee2e38SMatthew G. Knepley . Nc         - The number of function components
19674bee2e38SMatthew G. Knepley - pointEval  - The function values
19684bee2e38SMatthew G. Knepley 
19694bee2e38SMatthew G. Knepley   Output Parameter:
19704bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
19714bee2e38SMatthew G. Knepley 
19724bee2e38SMatthew G. Knepley   Level: advanced
19734bee2e38SMatthew G. Knepley 
19744bee2e38SMatthew 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.
19754bee2e38SMatthew G. Knepley 
19762edcad52SToby Isaac   Note: This only handles tranformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
19772edcad52SToby Isaac 
1978db781477SPatrick Sanan .seealso: `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
19794bee2e38SMatthew G. Knepley @*/
19809371c9d4SSatish Balay PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) {
19814bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
1982b4457527SToby Isaac   PetscInt                    k;
19834bee2e38SMatthew G. Knepley 
19844bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
19854bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
19864bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
1987dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
19884bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
19894bee2e38SMatthew G. Knepley      This determines their transformation properties. */
19909566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
19919371c9d4SSatish Balay   switch (k) {
19929371c9d4SSatish Balay   case 0: /* H^1 point evaluations */ trans = IDENTITY_TRANSFORM; break;
19939371c9d4SSatish Balay   case 1: /* Hcurl preserves tangential edge traces  */ trans = COVARIANT_PIOLA_TRANSFORM; break;
1994b4457527SToby Isaac   case 2:
19959371c9d4SSatish Balay   case 3: /* Hdiv preserve normal traces */ trans = CONTRAVARIANT_PIOLA_TRANSFORM; break;
199663a3b9bcSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
19974bee2e38SMatthew G. Knepley   }
19989566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval));
19994bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
20004bee2e38SMatthew G. Knepley }
20014bee2e38SMatthew G. Knepley 
20024bee2e38SMatthew G. Knepley /*@C
20034bee2e38SMatthew 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.
20044bee2e38SMatthew G. Knepley 
20054bee2e38SMatthew G. Knepley   Input Parameters:
20064bee2e38SMatthew G. Knepley + dsp        - The PetscDualSpace
20074bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
20084bee2e38SMatthew G. Knepley . Nq         - The number of function samples
20094bee2e38SMatthew G. Knepley . Nc         - The number of function components
20104bee2e38SMatthew G. Knepley - pointEval  - The function values
20114bee2e38SMatthew G. Knepley 
20124bee2e38SMatthew G. Knepley   Output Parameter:
20134bee2e38SMatthew G. Knepley . pointEval  - The transformed function values
20144bee2e38SMatthew G. Knepley 
20154bee2e38SMatthew G. Knepley   Level: advanced
20164bee2e38SMatthew G. Knepley 
20174bee2e38SMatthew 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.
20184bee2e38SMatthew G. Knepley 
2019f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
20202edcad52SToby Isaac 
2021db781477SPatrick Sanan .seealso: `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
20224bee2e38SMatthew G. Knepley @*/
20239371c9d4SSatish Balay PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) {
20244bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2025b4457527SToby Isaac   PetscInt                    k;
20264bee2e38SMatthew G. Knepley 
20274bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
20284bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20294bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2030dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
20314bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
20324bee2e38SMatthew G. Knepley      This determines their transformation properties. */
20339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
20349371c9d4SSatish Balay   switch (k) {
20359371c9d4SSatish Balay   case 0: /* H^1 point evaluations */ trans = IDENTITY_TRANSFORM; break;
20369371c9d4SSatish Balay   case 1: /* Hcurl preserves tangential edge traces  */ trans = COVARIANT_PIOLA_TRANSFORM; break;
2037b4457527SToby Isaac   case 2:
20389371c9d4SSatish Balay   case 3: /* Hdiv preserve normal traces */ trans = CONTRAVARIANT_PIOLA_TRANSFORM; break;
203963a3b9bcSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
20404bee2e38SMatthew G. Knepley   }
20419566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
20424bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
20434bee2e38SMatthew G. Knepley }
20444bee2e38SMatthew G. Knepley 
20454bee2e38SMatthew G. Knepley /*@C
20464bee2e38SMatthew 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.
20474bee2e38SMatthew G. Knepley 
20484bee2e38SMatthew G. Knepley   Input Parameters:
20494bee2e38SMatthew G. Knepley + dsp        - The PetscDualSpace
20504bee2e38SMatthew G. Knepley . fegeom     - The geometry for this cell
20514bee2e38SMatthew G. Knepley . Nq         - The number of function gradient samples
20524bee2e38SMatthew G. Knepley . Nc         - The number of function components
20534bee2e38SMatthew G. Knepley - pointEval  - The function gradient values
20544bee2e38SMatthew G. Knepley 
20554bee2e38SMatthew G. Knepley   Output Parameter:
20564bee2e38SMatthew G. Knepley . pointEval  - The transformed function gradient values
20574bee2e38SMatthew G. Knepley 
20584bee2e38SMatthew G. Knepley   Level: advanced
20594bee2e38SMatthew G. Knepley 
20604bee2e38SMatthew 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.
20614bee2e38SMatthew G. Knepley 
2062f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
20632edcad52SToby Isaac 
2064db781477SPatrick Sanan .seealso: `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2065dc0529c6SBarry Smith @*/
20669371c9d4SSatish Balay PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) {
20674bee2e38SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2068b4457527SToby Isaac   PetscInt                    k;
20694bee2e38SMatthew G. Knepley 
20704bee2e38SMatthew G. Knepley   PetscFunctionBeginHot;
20714bee2e38SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
20724bee2e38SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2073dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
20744bee2e38SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
20754bee2e38SMatthew G. Knepley      This determines their transformation properties. */
20769566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
20779371c9d4SSatish Balay   switch (k) {
20789371c9d4SSatish Balay   case 0: /* H^1 point evaluations */ trans = IDENTITY_TRANSFORM; break;
20799371c9d4SSatish Balay   case 1: /* Hcurl preserves tangential edge traces  */ trans = COVARIANT_PIOLA_TRANSFORM; break;
2080b4457527SToby Isaac   case 2:
20819371c9d4SSatish Balay   case 3: /* Hdiv preserve normal traces */ trans = CONTRAVARIANT_PIOLA_TRANSFORM; break;
208263a3b9bcSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
20834bee2e38SMatthew G. Knepley   }
20849566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
20854bee2e38SMatthew G. Knepley   PetscFunctionReturn(0);
20864bee2e38SMatthew G. Knepley }
2087f9244615SMatthew G. Knepley 
2088f9244615SMatthew G. Knepley /*@C
2089f9244615SMatthew 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.
2090f9244615SMatthew G. Knepley 
2091f9244615SMatthew G. Knepley   Input Parameters:
2092f9244615SMatthew G. Knepley + dsp        - The PetscDualSpace
2093f9244615SMatthew G. Knepley . fegeom     - The geometry for this cell
2094f9244615SMatthew G. Knepley . Nq         - The number of function Hessian samples
2095f9244615SMatthew G. Knepley . Nc         - The number of function components
2096f9244615SMatthew G. Knepley - pointEval  - The function gradient values
2097f9244615SMatthew G. Knepley 
2098f9244615SMatthew G. Knepley   Output Parameter:
2099f9244615SMatthew G. Knepley . pointEval  - The transformed function Hessian values
2100f9244615SMatthew G. Knepley 
2101f9244615SMatthew G. Knepley   Level: advanced
2102f9244615SMatthew G. Knepley 
2103f9244615SMatthew 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.
2104f9244615SMatthew G. Knepley 
2105f9244615SMatthew G. Knepley   Note: This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
2106f9244615SMatthew G. Knepley 
2107db781477SPatrick Sanan .seealso: `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()`
2108f9244615SMatthew G. Knepley @*/
21099371c9d4SSatish Balay PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) {
2110f9244615SMatthew G. Knepley   PetscDualSpaceTransformType trans;
2111f9244615SMatthew G. Knepley   PetscInt                    k;
2112f9244615SMatthew G. Knepley 
2113f9244615SMatthew G. Knepley   PetscFunctionBeginHot;
2114f9244615SMatthew G. Knepley   PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1);
2115f9244615SMatthew G. Knepley   PetscValidPointer(fegeom, 2);
2116dadcf809SJacob Faibussowitsch   PetscValidScalarPointer(pointEval, 5);
2117f9244615SMatthew G. Knepley   /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k.
2118f9244615SMatthew G. Knepley      This determines their transformation properties. */
21199566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDeRahm(dsp, &k));
21209371c9d4SSatish Balay   switch (k) {
21219371c9d4SSatish Balay   case 0: /* H^1 point evaluations */ trans = IDENTITY_TRANSFORM; break;
21229371c9d4SSatish Balay   case 1: /* Hcurl preserves tangential edge traces  */ trans = COVARIANT_PIOLA_TRANSFORM; break;
2123f9244615SMatthew G. Knepley   case 2:
21249371c9d4SSatish Balay   case 3: /* Hdiv preserve normal traces */ trans = CONTRAVARIANT_PIOLA_TRANSFORM; break;
212563a3b9bcSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k);
2126f9244615SMatthew G. Knepley   }
21279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval));
2128f9244615SMatthew G. Knepley   PetscFunctionReturn(0);
2129f9244615SMatthew G. Knepley }
2130