xref: /petsc/src/dm/dt/dualspace/interface/dualspace.c (revision 063ee4adbc11f743c8903782eb67073d0c6dd346)
1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
2 #include <petscdmplex.h>
3 
4 PetscClassId PETSCDUALSPACE_CLASSID = 0;
5 
6 PetscFunctionList PetscDualSpaceList              = NULL;
7 PetscBool         PetscDualSpaceRegisterAllCalled = PETSC_FALSE;
8 
9 const char *const PetscDualSpaceReferenceCells[] = {"SIMPLEX", "TENSOR", "PetscDualSpaceReferenceCell", "PETSCDUALSPACE_REFCELL_",0};
10 
11 /*@C
12   PetscDualSpaceRegister - Adds a new PetscDualSpace implementation
13 
14   Not Collective
15 
16   Input Parameters:
17 + name        - The name of a new user-defined creation routine
18 - create_func - The creation routine itself
19 
20   Notes:
21   PetscDualSpaceRegister() may be called multiple times to add several user-defined PetscDualSpaces
22 
23   Sample usage:
24 .vb
25     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
26 .ve
27 
28   Then, your PetscDualSpace type can be chosen with the procedural interface via
29 .vb
30     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
31     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
32 .ve
33    or at runtime via the option
34 .vb
35     -petscdualspace_type my_dual_space
36 .ve
37 
38   Level: advanced
39 
40 .keywords: PetscDualSpace, register
41 .seealso: PetscDualSpaceRegisterAll(), PetscDualSpaceRegisterDestroy()
42 
43 @*/
44 PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace))
45 {
46   PetscErrorCode ierr;
47 
48   PetscFunctionBegin;
49   ierr = PetscFunctionListAdd(&PetscDualSpaceList, sname, function);CHKERRQ(ierr);
50   PetscFunctionReturn(0);
51 }
52 
53 /*@C
54   PetscDualSpaceSetType - Builds a particular PetscDualSpace
55 
56   Collective on PetscDualSpace
57 
58   Input Parameters:
59 + sp   - The PetscDualSpace object
60 - name - The kind of space
61 
62   Options Database Key:
63 . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types
64 
65   Level: intermediate
66 
67 .keywords: PetscDualSpace, set, type
68 .seealso: PetscDualSpaceGetType(), PetscDualSpaceCreate()
69 @*/
70 PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name)
71 {
72   PetscErrorCode (*r)(PetscDualSpace);
73   PetscBool      match;
74   PetscErrorCode ierr;
75 
76   PetscFunctionBegin;
77   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
78   ierr = PetscObjectTypeCompare((PetscObject) sp, name, &match);CHKERRQ(ierr);
79   if (match) PetscFunctionReturn(0);
80 
81   if (!PetscDualSpaceRegisterAllCalled) {ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr);}
82   ierr = PetscFunctionListFind(PetscDualSpaceList, name, &r);CHKERRQ(ierr);
83   if (!r) SETERRQ1(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name);
84 
85   if (sp->ops->destroy) {
86     ierr             = (*sp->ops->destroy)(sp);CHKERRQ(ierr);
87     sp->ops->destroy = NULL;
88   }
89   ierr = (*r)(sp);CHKERRQ(ierr);
90   ierr = PetscObjectChangeTypeName((PetscObject) sp, name);CHKERRQ(ierr);
91   PetscFunctionReturn(0);
92 }
93 
94 /*@C
95   PetscDualSpaceGetType - Gets the PetscDualSpace type name (as a string) from the object.
96 
97   Not Collective
98 
99   Input Parameter:
100 . sp  - The PetscDualSpace
101 
102   Output Parameter:
103 . name - The PetscDualSpace type name
104 
105   Level: intermediate
106 
107 .keywords: PetscDualSpace, get, type, name
108 .seealso: PetscDualSpaceSetType(), PetscDualSpaceCreate()
109 @*/
110 PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name)
111 {
112   PetscErrorCode ierr;
113 
114   PetscFunctionBegin;
115   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
116   PetscValidPointer(name, 2);
117   if (!PetscDualSpaceRegisterAllCalled) {
118     ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr);
119   }
120   *name = ((PetscObject) sp)->type_name;
121   PetscFunctionReturn(0);
122 }
123 
124 /*@
125   PetscDualSpaceView - Views a PetscDualSpace
126 
127   Collective on PetscDualSpace
128 
129   Input Parameter:
130 + sp - the PetscDualSpace object to view
131 - v  - the viewer
132 
133   Level: developer
134 
135 .seealso PetscDualSpaceDestroy()
136 @*/
137 PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
138 {
139   PetscBool      iascii;
140   PetscErrorCode ierr;
141 
142   PetscFunctionBegin;
143   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
144   if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
145   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) sp), &v);CHKERRQ(ierr);}
146   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)sp, v);CHKERRQ(ierr);
147   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
148   ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
149   if (iascii) {ierr = PetscViewerASCIIPrintf(v, "Dual space of order %D with %D components\n", sp->order, sp->Nc);CHKERRQ(ierr);}
150   if (sp->ops->view) {ierr = (*sp->ops->view)(sp, v);CHKERRQ(ierr);}
151   ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
152   PetscFunctionReturn(0);
153 }
154 
155 /*@
156   PetscDualSpaceSetFromOptions - sets parameters in a PetscDualSpace from the options database
157 
158   Collective on PetscDualSpace
159 
160   Input Parameter:
161 . sp - the PetscDualSpace object to set options for
162 
163   Options Database:
164 . -petscspace_degree the approximation order of the space
165 
166   Level: developer
167 
168 .seealso PetscDualSpaceView()
169 @*/
170 PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
171 {
172   PetscDualSpaceReferenceCell refCell = PETSCDUALSPACE_REFCELL_SIMPLEX;
173   PetscInt                    refDim  = 0;
174   PetscBool                   flg;
175   const char                 *defaultType;
176   char                        name[256];
177   PetscErrorCode              ierr;
178 
179   PetscFunctionBegin;
180   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
181   if (!((PetscObject) sp)->type_name) {
182     defaultType = PETSCDUALSPACELAGRANGE;
183   } else {
184     defaultType = ((PetscObject) sp)->type_name;
185   }
186   if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);}
187 
188   ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr);
189   ierr = PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg);CHKERRQ(ierr);
190   if (flg) {
191     ierr = PetscDualSpaceSetType(sp, name);CHKERRQ(ierr);
192   } else if (!((PetscObject) sp)->type_name) {
193     ierr = PetscDualSpaceSetType(sp, defaultType);CHKERRQ(ierr);
194   }
195   ierr = PetscOptionsInt("-petscdualspace_degree", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL);CHKERRQ(ierr);
196   ierr = PetscOptionsInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL);CHKERRQ(ierr);
197   if (sp->ops->setfromoptions) {
198     ierr = (*sp->ops->setfromoptions)(PetscOptionsObject,sp);CHKERRQ(ierr);
199   }
200   ierr = PetscOptionsInt("-petscdualspace_refdim", "The spatial dimension of the reference cell", "PetscDualSpaceSetReferenceCell", refDim, &refDim, NULL);CHKERRQ(ierr);
201   ierr = PetscOptionsEnum("-petscdualspace_refcell", "Reference cell", "PetscDualSpaceSetReferenceCell", PetscDualSpaceReferenceCells, (PetscEnum) refCell, (PetscEnum *) &refCell, &flg);CHKERRQ(ierr);
202   if (flg) {
203     DM K;
204 
205     if (!refDim) SETERRQ(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_INCOMP, "Reference cell specified without a dimension. Use -petscdualspace_refdim.");
206     ierr = PetscDualSpaceCreateReferenceCell(sp, refDim, refCell == PETSCDUALSPACE_REFCELL_SIMPLEX ? PETSC_TRUE : PETSC_FALSE, &K);CHKERRQ(ierr);
207     ierr = PetscDualSpaceSetDM(sp, K);CHKERRQ(ierr);
208     ierr = DMDestroy(&K);CHKERRQ(ierr);
209   }
210 
211   /* process any options handlers added with PetscObjectAddOptionsHandler() */
212   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) sp);CHKERRQ(ierr);
213   ierr = PetscOptionsEnd();CHKERRQ(ierr);
214   sp->setfromoptionscalled = PETSC_TRUE;
215   PetscFunctionReturn(0);
216 }
217 
218 /*@
219   PetscDualSpaceSetUp - Construct a basis for the PetscDualSpace
220 
221   Collective on PetscDualSpace
222 
223   Input Parameter:
224 . sp - the PetscDualSpace object to setup
225 
226   Level: developer
227 
228 .seealso PetscDualSpaceView(), PetscDualSpaceDestroy()
229 @*/
230 PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
231 {
232   PetscErrorCode ierr;
233 
234   PetscFunctionBegin;
235   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
236   if (sp->setupcalled) PetscFunctionReturn(0);
237   sp->setupcalled = PETSC_TRUE;
238   if (sp->ops->setup) {ierr = (*sp->ops->setup)(sp);CHKERRQ(ierr);}
239   if (sp->setfromoptionscalled) {ierr = PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view");CHKERRQ(ierr);}
240   PetscFunctionReturn(0);
241 }
242 
243 /*@
244   PetscDualSpaceDestroy - Destroys a PetscDualSpace object
245 
246   Collective on PetscDualSpace
247 
248   Input Parameter:
249 . sp - the PetscDualSpace object to destroy
250 
251   Level: developer
252 
253 .seealso PetscDualSpaceView()
254 @*/
255 PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
256 {
257   PetscInt       dim, f;
258   PetscErrorCode ierr;
259 
260   PetscFunctionBegin;
261   if (!*sp) PetscFunctionReturn(0);
262   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
263 
264   if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);}
265   ((PetscObject) (*sp))->refct = 0;
266 
267   ierr = PetscDualSpaceGetDimension(*sp, &dim);CHKERRQ(ierr);
268   for (f = 0; f < dim; ++f) {
269     ierr = PetscQuadratureDestroy(&(*sp)->functional[f]);CHKERRQ(ierr);
270   }
271   ierr = PetscFree((*sp)->functional);CHKERRQ(ierr);
272   ierr = PetscQuadratureDestroy(&(*sp)->allPoints);CHKERRQ(ierr);
273   ierr = DMDestroy(&(*sp)->dm);CHKERRQ(ierr);
274 
275   if ((*sp)->ops->destroy) {ierr = (*(*sp)->ops->destroy)(*sp);CHKERRQ(ierr);}
276   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
277   PetscFunctionReturn(0);
278 }
279 
280 /*@
281   PetscDualSpaceCreate - Creates an empty PetscDualSpace object. The type can then be set with PetscDualSpaceSetType().
282 
283   Collective on MPI_Comm
284 
285   Input Parameter:
286 . comm - The communicator for the PetscDualSpace object
287 
288   Output Parameter:
289 . sp - The PetscDualSpace object
290 
291   Level: beginner
292 
293 .seealso: PetscDualSpaceSetType(), PETSCDUALSPACELAGRANGE
294 @*/
295 PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
296 {
297   PetscDualSpace s;
298   PetscErrorCode ierr;
299 
300   PetscFunctionBegin;
301   PetscValidPointer(sp, 2);
302   ierr = PetscCitationsRegister(FECitation,&FEcite);CHKERRQ(ierr);
303   *sp  = NULL;
304   ierr = PetscFEInitializePackage();CHKERRQ(ierr);
305 
306   ierr = PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView);CHKERRQ(ierr);
307 
308   s->order = 0;
309   s->Nc    = 1;
310   s->setupcalled = PETSC_FALSE;
311 
312   *sp = s;
313   PetscFunctionReturn(0);
314 }
315 
316 /*@
317   PetscDualSpaceDuplicate - Creates a duplicate PetscDualSpace object, however it is not setup.
318 
319   Collective on PetscDualSpace
320 
321   Input Parameter:
322 . sp - The original PetscDualSpace
323 
324   Output Parameter:
325 . spNew - The duplicate PetscDualSpace
326 
327   Level: beginner
328 
329 .seealso: PetscDualSpaceCreate(), PetscDualSpaceSetType()
330 @*/
331 PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew)
332 {
333   PetscErrorCode ierr;
334 
335   PetscFunctionBegin;
336   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
337   PetscValidPointer(spNew, 2);
338   ierr = (*sp->ops->duplicate)(sp, spNew);CHKERRQ(ierr);
339   PetscFunctionReturn(0);
340 }
341 
342 /*@
343   PetscDualSpaceGetDM - Get the DM representing the reference cell
344 
345   Not collective
346 
347   Input Parameter:
348 . sp - The PetscDualSpace
349 
350   Output Parameter:
351 . dm - The reference cell
352 
353   Level: intermediate
354 
355 .seealso: PetscDualSpaceSetDM(), PetscDualSpaceCreate()
356 @*/
357 PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
358 {
359   PetscFunctionBegin;
360   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
361   PetscValidPointer(dm, 2);
362   *dm = sp->dm;
363   PetscFunctionReturn(0);
364 }
365 
366 /*@
367   PetscDualSpaceSetDM - Get the DM representing the reference cell
368 
369   Not collective
370 
371   Input Parameters:
372 + sp - The PetscDualSpace
373 - dm - The reference cell
374 
375   Level: intermediate
376 
377 .seealso: PetscDualSpaceGetDM(), PetscDualSpaceCreate()
378 @*/
379 PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
380 {
381   PetscErrorCode ierr;
382 
383   PetscFunctionBegin;
384   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
385   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
386   ierr = DMDestroy(&sp->dm);CHKERRQ(ierr);
387   ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
388   sp->dm = dm;
389   PetscFunctionReturn(0);
390 }
391 
392 /*@
393   PetscDualSpaceGetOrder - Get the order of the dual space
394 
395   Not collective
396 
397   Input Parameter:
398 . sp - The PetscDualSpace
399 
400   Output Parameter:
401 . order - The order
402 
403   Level: intermediate
404 
405 .seealso: PetscDualSpaceSetOrder(), PetscDualSpaceCreate()
406 @*/
407 PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
408 {
409   PetscFunctionBegin;
410   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
411   PetscValidPointer(order, 2);
412   *order = sp->order;
413   PetscFunctionReturn(0);
414 }
415 
416 /*@
417   PetscDualSpaceSetOrder - Set the order of the dual space
418 
419   Not collective
420 
421   Input Parameters:
422 + sp - The PetscDualSpace
423 - order - The order
424 
425   Level: intermediate
426 
427 .seealso: PetscDualSpaceGetOrder(), PetscDualSpaceCreate()
428 @*/
429 PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
430 {
431   PetscFunctionBegin;
432   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
433   sp->order = order;
434   PetscFunctionReturn(0);
435 }
436 
437 /*@
438   PetscDualSpaceGetNumComponents - Return the number of components for this space
439 
440   Input Parameter:
441 . sp - The PetscDualSpace
442 
443   Output Parameter:
444 . Nc - The number of components
445 
446   Note: A vector space, for example, will have d components, where d is the spatial dimension
447 
448   Level: intermediate
449 
450 .seealso: PetscDualSpaceSetNumComponents(), PetscDualSpaceGetDimension(), PetscDualSpaceCreate(), PetscDualSpace
451 @*/
452 PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc)
453 {
454   PetscFunctionBegin;
455   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
456   PetscValidPointer(Nc, 2);
457   *Nc = sp->Nc;
458   PetscFunctionReturn(0);
459 }
460 
461 /*@
462   PetscDualSpaceSetNumComponents - Set the number of components for this space
463 
464   Input Parameters:
465 + sp - The PetscDualSpace
466 - order - The number of components
467 
468   Level: intermediate
469 
470 .seealso: PetscDualSpaceGetNumComponents(), PetscDualSpaceCreate(), PetscDualSpace
471 @*/
472 PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc)
473 {
474   PetscFunctionBegin;
475   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
476   sp->Nc = Nc;
477   PetscFunctionReturn(0);
478 }
479 
480 /*@
481   PetscDualSpaceLagrangeGetTensor - Get the tensor nature of the dual space
482 
483   Not collective
484 
485   Input Parameter:
486 . sp - The PetscDualSpace
487 
488   Output Parameter:
489 . tensor - Whether the dual space has tensor layout (vs. simplicial)
490 
491   Level: intermediate
492 
493 .seealso: PetscDualSpaceLagrangeSetTensor(), PetscDualSpaceCreate()
494 @*/
495 PetscErrorCode PetscDualSpaceLagrangeGetTensor(PetscDualSpace sp, PetscBool *tensor)
496 {
497   PetscErrorCode ierr;
498 
499   PetscFunctionBegin;
500   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
501   PetscValidPointer(tensor, 2);
502   ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeGetTensor_C",(PetscDualSpace,PetscBool *),(sp,tensor));CHKERRQ(ierr);
503   PetscFunctionReturn(0);
504 }
505 
506 /*@
507   PetscDualSpaceLagrangeSetTensor - Set the tensor nature of the dual space
508 
509   Not collective
510 
511   Input Parameters:
512 + sp - The PetscDualSpace
513 - tensor - Whether the dual space has tensor layout (vs. simplicial)
514 
515   Level: intermediate
516 
517 .seealso: PetscDualSpaceLagrangeGetTensor(), PetscDualSpaceCreate()
518 @*/
519 PetscErrorCode PetscDualSpaceLagrangeSetTensor(PetscDualSpace sp, PetscBool tensor)
520 {
521   PetscErrorCode ierr;
522 
523   PetscFunctionBegin;
524   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
525   ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetTensor_C",(PetscDualSpace,PetscBool),(sp,tensor));CHKERRQ(ierr);
526   PetscFunctionReturn(0);
527 }
528 
529 /*@
530   PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space
531 
532   Not collective
533 
534   Input Parameters:
535 + sp - The PetscDualSpace
536 - i  - The basis number
537 
538   Output Parameter:
539 . functional - The basis functional
540 
541   Level: intermediate
542 
543 .seealso: PetscDualSpaceGetDimension(), PetscDualSpaceCreate()
544 @*/
545 PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
546 {
547   PetscInt       dim;
548   PetscErrorCode ierr;
549 
550   PetscFunctionBegin;
551   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
552   PetscValidPointer(functional, 3);
553   ierr = PetscDualSpaceGetDimension(sp, &dim);CHKERRQ(ierr);
554   if ((i < 0) || (i >= dim)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Functional index %d must be in [0, %d)", i, dim);
555   *functional = sp->functional[i];
556   PetscFunctionReturn(0);
557 }
558 
559 /*@
560   PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals
561 
562   Not collective
563 
564   Input Parameter:
565 . sp - The PetscDualSpace
566 
567   Output Parameter:
568 . dim - The dimension
569 
570   Level: intermediate
571 
572 .seealso: PetscDualSpaceGetFunctional(), PetscDualSpaceCreate()
573 @*/
574 PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
575 {
576   PetscErrorCode ierr;
577 
578   PetscFunctionBegin;
579   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
580   PetscValidPointer(dim, 2);
581   *dim = 0;
582   if (sp->ops->getdimension) {ierr = (*sp->ops->getdimension)(sp, dim);CHKERRQ(ierr);}
583   PetscFunctionReturn(0);
584 }
585 
586 /*@C
587   PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension
588 
589   Not collective
590 
591   Input Parameter:
592 . sp - The PetscDualSpace
593 
594   Output Parameter:
595 . numDof - An array of length dim+1 which holds the number of dofs for each dimension
596 
597   Level: intermediate
598 
599 .seealso: PetscDualSpaceGetFunctional(), PetscDualSpaceCreate()
600 @*/
601 PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof)
602 {
603   PetscErrorCode ierr;
604 
605   PetscFunctionBegin;
606   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
607   PetscValidPointer(numDof, 2);
608   ierr = (*sp->ops->getnumdof)(sp, numDof);CHKERRQ(ierr);
609   if (!*numDof) SETERRQ(PetscObjectComm((PetscObject) sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation");
610   PetscFunctionReturn(0);
611 }
612 
613 PetscErrorCode PetscDualSpaceCreateSection(PetscDualSpace sp, PetscSection *section)
614 {
615   DM             dm;
616   PetscInt       pStart, pEnd, depth, h, offset;
617   const PetscInt *numDof;
618   PetscErrorCode ierr;
619 
620   PetscFunctionBegin;
621   ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr);
622   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
623   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)sp),section);CHKERRQ(ierr);
624   ierr = PetscSectionSetChart(*section,pStart,pEnd);CHKERRQ(ierr);
625   ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr);
626   ierr = PetscDualSpaceGetNumDof(sp,&numDof);CHKERRQ(ierr);
627   for (h = 0; h <= depth; h++) {
628     PetscInt hStart, hEnd, p, dof;
629 
630     ierr = DMPlexGetHeightStratum(dm,h,&hStart,&hEnd);CHKERRQ(ierr);
631     dof = numDof[depth - h];
632     for (p = hStart; p < hEnd; p++) {
633       ierr = PetscSectionSetDof(*section,p,dof);CHKERRQ(ierr);
634     }
635   }
636   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
637   for (h = 0, offset = 0; h <= depth; h++) {
638     PetscInt hStart, hEnd, p, dof;
639 
640     ierr = DMPlexGetHeightStratum(dm,h,&hStart,&hEnd);CHKERRQ(ierr);
641     dof = numDof[depth - h];
642     for (p = hStart; p < hEnd; p++) {
643       ierr = PetscSectionGetDof(*section,p,&dof);CHKERRQ(ierr);
644       ierr = PetscSectionSetOffset(*section,p,offset);CHKERRQ(ierr);
645       offset += dof;
646     }
647   }
648   PetscFunctionReturn(0);
649 }
650 
651 /*@
652   PetscDualSpaceCreateReferenceCell - Create a DMPLEX with the appropriate FEM reference cell
653 
654   Collective on PetscDualSpace
655 
656   Input Parameters:
657 + sp      - The PetscDualSpace
658 . dim     - The spatial dimension
659 - simplex - Flag for simplex, otherwise use a tensor-product cell
660 
661   Output Parameter:
662 . refdm - The reference cell
663 
664   Level: advanced
665 
666 .keywords: PetscDualSpace, reference cell
667 .seealso: PetscDualSpaceCreate(), DMPLEX
668 @*/
669 PetscErrorCode PetscDualSpaceCreateReferenceCell(PetscDualSpace sp, PetscInt dim, PetscBool simplex, DM *refdm)
670 {
671   PetscErrorCode ierr;
672 
673   PetscFunctionBeginUser;
674   ierr = DMPlexCreateReferenceCell(PetscObjectComm((PetscObject) sp), dim, simplex, refdm);CHKERRQ(ierr);
675   PetscFunctionReturn(0);
676 }
677 
678 /*@C
679   PetscDualSpaceApply - Apply a functional from the dual space basis to an input function
680 
681   Input Parameters:
682 + sp      - The PetscDualSpace object
683 . f       - The basis functional index
684 . time    - The time
685 . 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)
686 . numComp - The number of components for the function
687 . func    - The input function
688 - ctx     - A context for the function
689 
690   Output Parameter:
691 . value   - numComp output values
692 
693   Note: The calling sequence for the callback func is given by:
694 
695 $ func(PetscInt dim, PetscReal time, const PetscReal x[],
696 $      PetscInt numComponents, PetscScalar values[], void *ctx)
697 
698   Level: developer
699 
700 .seealso: PetscDualSpaceCreate()
701 @*/
702 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)
703 {
704   PetscErrorCode ierr;
705 
706   PetscFunctionBegin;
707   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
708   PetscValidPointer(cgeom, 4);
709   PetscValidPointer(value, 8);
710   ierr = (*sp->ops->apply)(sp, f, time, cgeom, numComp, func, ctx, value);CHKERRQ(ierr);
711   PetscFunctionReturn(0);
712 }
713 
714 /*@C
715   PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllPoints()
716 
717   Input Parameters:
718 + sp        - The PetscDualSpace object
719 - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllPoints()
720 
721   Output Parameter:
722 . spValue   - The values of all dual space functionals
723 
724   Level: developer
725 
726 .seealso: PetscDualSpaceCreate()
727 @*/
728 PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
729 {
730   PetscErrorCode ierr;
731 
732   PetscFunctionBegin;
733   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
734   ierr = (*sp->ops->applyall)(sp, pointEval, spValue);CHKERRQ(ierr);
735   PetscFunctionReturn(0);
736 }
737 
738 /*@C
739   PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional.
740 
741   Input Parameters:
742 + sp    - The PetscDualSpace object
743 . f     - The basis functional index
744 . time  - The time
745 . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian)
746 . Nc    - The number of components for the function
747 . func  - The input function
748 - ctx   - A context for the function
749 
750   Output Parameter:
751 . value   - The output value
752 
753   Note: The calling sequence for the callback func is given by:
754 
755 $ func(PetscInt dim, PetscReal time, const PetscReal x[],
756 $      PetscInt numComponents, PetscScalar values[], void *ctx)
757 
758 and the idea is to evaluate the functional as an integral
759 
760 $ n(f) = int dx n(x) . f(x)
761 
762 where both n and f have Nc components.
763 
764   Level: developer
765 
766 .seealso: PetscDualSpaceCreate()
767 @*/
768 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)
769 {
770   DM               dm;
771   PetscQuadrature  n;
772   const PetscReal *points, *weights;
773   PetscReal        x[3];
774   PetscScalar     *val;
775   PetscInt         dim, dE, qNc, c, Nq, q;
776   PetscBool        isAffine;
777   PetscErrorCode   ierr;
778 
779   PetscFunctionBegin;
780   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
781   PetscValidPointer(value, 5);
782   ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr);
783   ierr = PetscDualSpaceGetFunctional(sp, f, &n);CHKERRQ(ierr);
784   ierr = PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights);CHKERRQ(ierr);
785   if (dim != cgeom->dim) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature spatial dimension %D != cell geometry dimension %D", dim, cgeom->dim);
786   if (qNc != Nc) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature components %D != function components %D", qNc, Nc);
787   ierr = DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr);
788   *value = 0.0;
789   isAffine = cgeom->isAffine;
790   dE = cgeom->dimEmbed;
791   for (q = 0; q < Nq; ++q) {
792     if (isAffine) {
793       CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q*dim], x);
794       ierr = (*func)(dE, time, x, Nc, val, ctx);CHKERRQ(ierr);
795     } else {
796       ierr = (*func)(dE, time, &cgeom->v[dE*q], Nc, val, ctx);CHKERRQ(ierr);
797     }
798     for (c = 0; c < Nc; ++c) {
799       *value += val[c]*weights[q*Nc+c];
800     }
801   }
802   ierr = DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr);
803   PetscFunctionReturn(0);
804 }
805 
806 /*@C
807   PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllPoints()
808 
809   Input Parameters:
810 + sp        - The PetscDualSpace object
811 - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllPoints()
812 
813   Output Parameter:
814 . spValue   - The values of all dual space functionals
815 
816   Level: developer
817 
818 .seealso: PetscDualSpaceCreate()
819 @*/
820 PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue)
821 {
822   PetscQuadrature  n;
823   const PetscReal *points, *weights;
824   PetscInt         qNc, c, Nq, q, f, spdim, Nc;
825   PetscInt         offset;
826   PetscErrorCode   ierr;
827 
828   PetscFunctionBegin;
829   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
830   PetscValidScalarPointer(pointEval, 2);
831   PetscValidScalarPointer(spValue, 5);
832   ierr = PetscDualSpaceGetDimension(sp, &spdim);CHKERRQ(ierr);
833   ierr = PetscDualSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr);
834   for (f = 0, offset = 0; f < spdim; f++) {
835     ierr = PetscDualSpaceGetFunctional(sp, f, &n);CHKERRQ(ierr);
836     ierr = PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights);CHKERRQ(ierr);
837     if (qNc != Nc) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature components %D != function components %D", qNc, Nc);
838     spValue[f] = 0.0;
839     for (q = 0; q < Nq; ++q) {
840       for (c = 0; c < Nc; ++c) {
841         spValue[f] += pointEval[offset++]*weights[q*Nc+c];
842       }
843     }
844   }
845   PetscFunctionReturn(0);
846 }
847 
848 PetscErrorCode PetscDualSpaceGetAllPoints(PetscDualSpace sp, PetscQuadrature *allPoints)
849 {
850   PetscErrorCode ierr;
851 
852   PetscFunctionBegin;
853   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
854   PetscValidPointer(allPoints,2);
855   if (!sp->allPoints && sp->ops->createallpoints) {
856     ierr = (*sp->ops->createallpoints)(sp,&sp->allPoints);CHKERRQ(ierr);
857   }
858   *allPoints = sp->allPoints;
859   PetscFunctionReturn(0);
860 }
861 
862 PetscErrorCode PetscDualSpaceCreateAllPointsDefault(PetscDualSpace sp, PetscQuadrature *allPoints)
863 {
864   PetscInt        spdim;
865   PetscInt        numPoints, offset;
866   PetscReal       *points;
867   PetscInt        f, dim;
868   PetscQuadrature q;
869   PetscErrorCode  ierr;
870 
871   PetscFunctionBegin;
872   ierr = PetscDualSpaceGetDimension(sp,&spdim);CHKERRQ(ierr);
873   if (!spdim) {
874     ierr = PetscQuadratureCreate(PETSC_COMM_SELF,allPoints);CHKERRQ(ierr);
875     ierr = PetscQuadratureSetData(*allPoints,0,0,0,NULL,NULL);CHKERRQ(ierr);
876   }
877   ierr = PetscDualSpaceGetFunctional(sp,0,&q);CHKERRQ(ierr);
878   ierr = PetscQuadratureGetData(q,&dim,NULL,&numPoints,NULL,NULL);CHKERRQ(ierr);
879   for (f = 1; f < spdim; f++) {
880     PetscInt Np;
881 
882     ierr = PetscDualSpaceGetFunctional(sp,f,&q);CHKERRQ(ierr);
883     ierr = PetscQuadratureGetData(q,NULL,NULL,&Np,NULL,NULL);CHKERRQ(ierr);
884     numPoints += Np;
885   }
886   ierr = PetscMalloc1(dim*numPoints,&points);CHKERRQ(ierr);
887   for (f = 0, offset = 0; f < spdim; f++) {
888     const PetscReal *p;
889     PetscInt        Np, i;
890 
891     ierr = PetscDualSpaceGetFunctional(sp,f,&q);CHKERRQ(ierr);
892     ierr = PetscQuadratureGetData(q,NULL,NULL,&Np,&p,NULL);CHKERRQ(ierr);
893     for (i = 0; i < Np * dim; i++) {
894       points[offset + i] = p[i];
895     }
896     offset += Np * dim;
897   }
898   ierr = PetscQuadratureCreate(PETSC_COMM_SELF,allPoints);CHKERRQ(ierr);
899   ierr = PetscQuadratureSetData(*allPoints,dim,0,numPoints,points,NULL);CHKERRQ(ierr);
900   PetscFunctionReturn(0);
901 }
902 
903 /*@C
904   PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid.
905 
906   Input Parameters:
907 + sp    - The PetscDualSpace object
908 . f     - The basis functional index
909 . time  - The time
910 . cgeom - A context with geometric information for this cell, we currently just use the centroid
911 . Nc    - The number of components for the function
912 . func  - The input function
913 - ctx   - A context for the function
914 
915   Output Parameter:
916 . value - The output value (scalar)
917 
918   Note: The calling sequence for the callback func is given by:
919 
920 $ func(PetscInt dim, PetscReal time, const PetscReal x[],
921 $      PetscInt numComponents, PetscScalar values[], void *ctx)
922 
923 and the idea is to evaluate the functional as an integral
924 
925 $ n(f) = int dx n(x) . f(x)
926 
927 where both n and f have Nc components.
928 
929   Level: developer
930 
931 .seealso: PetscDualSpaceCreate()
932 @*/
933 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)
934 {
935   DM               dm;
936   PetscQuadrature  n;
937   const PetscReal *points, *weights;
938   PetscScalar     *val;
939   PetscInt         dimEmbed, qNc, c, Nq, q;
940   PetscErrorCode   ierr;
941 
942   PetscFunctionBegin;
943   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
944   PetscValidPointer(value, 5);
945   ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr);
946   ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr);
947   ierr = PetscDualSpaceGetFunctional(sp, f, &n);CHKERRQ(ierr);
948   ierr = PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights);CHKERRQ(ierr);
949   if (qNc != Nc) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature components %D != function components %D", qNc, Nc);
950   ierr = DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr);
951   *value = 0.;
952   for (q = 0; q < Nq; ++q) {
953     ierr = (*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx);CHKERRQ(ierr);
954     for (c = 0; c < Nc; ++c) {
955       *value += val[c]*weights[q*Nc+c];
956     }
957   }
958   ierr = DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr);
959   PetscFunctionReturn(0);
960 }
961 
962 /*@
963   PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a
964   given height.  This assumes that the reference cell is symmetric over points of this height.
965 
966   If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and
967   pointwise values are not defined on the element boundaries), or if the implementation of PetscDualSpace does not
968   support extracting subspaces, then NULL is returned.
969 
970   This does not increment the reference count on the returned dual space, and the user should not destroy it.
971 
972   Not collective
973 
974   Input Parameters:
975 + sp - the PetscDualSpace object
976 - height - the height of the mesh point for which the subspace is desired
977 
978   Output Parameter:
979 . subsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
980   point, which will be of lesser dimension if height > 0.
981 
982   Level: advanced
983 
984 .seealso: PetscSpaceGetHeightSubspace(), PetscDualSpace
985 @*/
986 PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp)
987 {
988   PetscErrorCode ierr;
989 
990   PetscFunctionBegin;
991   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
992   PetscValidPointer(subsp, 3);
993   *subsp = NULL;
994   if (sp->ops->getheightsubspace) {
995     ierr = (*sp->ops->getheightsubspace)(sp, height, subsp);CHKERRQ(ierr);
996   }
997   PetscFunctionReturn(0);
998 }
999 
1000 /*@
1001   PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point.
1002 
1003   If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not
1004   defined on the element boundaries), or if the implementation of PetscDualSpace does not support extracting
1005   subspaces, then NULL is returned.
1006 
1007   This does not increment the reference count on the returned dual space, and the user should not destroy it.
1008 
1009   Not collective
1010 
1011   Input Parameters:
1012 + sp - the PetscDualSpace object
1013 - point - the point (in the dual space's DM) for which the subspace is desired
1014 
1015   Output Parameters:
1016   bdsp - the subspace.  Note that the functionals in the subspace are with respect to the intrinsic geometry of the
1017   point, which will be of lesser dimension if height > 0.
1018 
1019   Level: advanced
1020 
1021 .seealso: PetscDualSpace
1022 @*/
1023 PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp)
1024 {
1025   PetscErrorCode ierr;
1026 
1027   PetscFunctionBegin;
1028   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1029   PetscValidPointer(bdsp,2);
1030   *bdsp = NULL;
1031   if (sp->ops->getpointsubspace) {
1032     ierr = (*sp->ops->getpointsubspace)(sp,point,bdsp);CHKERRQ(ierr);
1033   } else if (sp->ops->getheightsubspace) {
1034     DM       dm;
1035     DMLabel  label;
1036     PetscInt dim, depth, height;
1037 
1038     ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr);
1039     ierr = DMPlexGetDepth(dm,&dim);CHKERRQ(ierr);
1040     ierr = DMPlexGetDepthLabel(dm,&label);CHKERRQ(ierr);
1041     ierr = DMLabelGetValue(label,point,&depth);CHKERRQ(ierr);
1042     height = dim - depth;
1043     ierr = (*sp->ops->getheightsubspace)(sp,height,bdsp);CHKERRQ(ierr);
1044   }
1045   PetscFunctionReturn(0);
1046 }
1047 
1048