1 /* Basis Jet Tabulation
2
3 We would like to tabulate the nodal basis functions and derivatives at a set of points, usually quadrature points. We
4 follow here the derviation in http://www.math.ttu.edu/~kirby/papers/fiat-toms-2004.pdf. The nodal basis $\psi_i$ can
5 be expressed in terms of a prime basis $\phi_i$ which can be stably evaluated. In PETSc, we will use the Legendre basis
6 as a prime basis.
7
8 \psi_i = \sum_k \alpha_{ki} \phi_k
9
10 Our nodal basis is defined in terms of the dual basis $n_j$
11
12 n_j \cdot \psi_i = \delta_{ji}
13
14 and we may act on the first equation to obtain
15
16 n_j \cdot \psi_i = \sum_k \alpha_{ki} n_j \cdot \phi_k
17 \delta_{ji} = \sum_k \alpha_{ki} V_{jk}
18 I = V \alpha
19
20 so the coefficients of the nodal basis in the prime basis are
21
22 \alpha = V^{-1}
23
24 We will define the dual basis vectors $n_j$ using a quadrature rule.
25
26 Right now, we will just use the polynomial spaces P^k. I know some elements use the space of symmetric polynomials
27 (I think Nedelec), but we will neglect this for now. Constraints in the space, e.g. Arnold-Winther elements, can
28 be implemented exactly as in FIAT using functionals $L_j$.
29
30 I will have to count the degrees correctly for the Legendre product when we are on simplices.
31
32 We will have three objects:
33 - Space, P: this just need point evaluation I think
34 - Dual Space, P'+K: This looks like a set of functionals that can act on members of P, each n is defined by a Q
35 - FEM: This keeps {P, P', Q}
36 */
37 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
38 #include <petscdmplex.h>
39
40 PetscBool FEcite = PETSC_FALSE;
41 const char FECitation[] = "@article{kirby2004,\n"
42 " title = {Algorithm 839: FIAT, a New Paradigm for Computing Finite Element Basis Functions},\n"
43 " journal = {ACM Transactions on Mathematical Software},\n"
44 " author = {Robert C. Kirby},\n"
45 " volume = {30},\n"
46 " number = {4},\n"
47 " pages = {502--516},\n"
48 " doi = {10.1145/1039813.1039820},\n"
49 " year = {2004}\n}\n";
50
51 PetscClassId PETSCFE_CLASSID = 0;
52
53 PetscLogEvent PETSCFE_SetUp;
54
55 PetscFunctionList PetscFEList = NULL;
56 PetscBool PetscFERegisterAllCalled = PETSC_FALSE;
57
58 /*@C
59 PetscFERegister - Adds a new `PetscFEType`
60
61 Not Collective, No Fortran Support
62
63 Input Parameters:
64 + sname - The name of a new user-defined creation routine
65 - function - The creation routine
66
67 Example Usage:
68 .vb
69 PetscFERegister("my_fe", MyPetscFECreate);
70 .ve
71
72 Then, your PetscFE type can be chosen with the procedural interface via
73 .vb
74 PetscFECreate(MPI_Comm, PetscFE *);
75 PetscFESetType(PetscFE, "my_fe");
76 .ve
77 or at runtime via the option
78 .vb
79 -petscfe_type my_fe
80 .ve
81
82 Level: advanced
83
84 Note:
85 `PetscFERegister()` may be called multiple times to add several user-defined `PetscFE`s
86
87 .seealso: `PetscFE`, `PetscFEType`, `PetscFERegisterAll()`, `PetscFERegisterDestroy()`
88 @*/
PetscFERegister(const char sname[],PetscErrorCode (* function)(PetscFE))89 PetscErrorCode PetscFERegister(const char sname[], PetscErrorCode (*function)(PetscFE))
90 {
91 PetscFunctionBegin;
92 PetscCall(PetscFunctionListAdd(&PetscFEList, sname, function));
93 PetscFunctionReturn(PETSC_SUCCESS);
94 }
95
96 /*@
97 PetscFESetType - Builds a particular `PetscFE`
98
99 Collective
100
101 Input Parameters:
102 + fem - The `PetscFE` object
103 - name - The kind of FEM space
104
105 Options Database Key:
106 . -petscfe_type <type> - Sets the `PetscFE` type; use -help for a list of available types
107
108 Level: intermediate
109
110 .seealso: `PetscFEType`, `PetscFE`, `PetscFEGetType()`, `PetscFECreate()`
111 @*/
PetscFESetType(PetscFE fem,PetscFEType name)112 PetscErrorCode PetscFESetType(PetscFE fem, PetscFEType name)
113 {
114 PetscErrorCode (*r)(PetscFE);
115 PetscBool match;
116
117 PetscFunctionBegin;
118 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
119 PetscCall(PetscObjectTypeCompare((PetscObject)fem, name, &match));
120 if (match) PetscFunctionReturn(PETSC_SUCCESS);
121
122 if (!PetscFERegisterAllCalled) PetscCall(PetscFERegisterAll());
123 PetscCall(PetscFunctionListFind(PetscFEList, name, &r));
124 PetscCheck(r, PetscObjectComm((PetscObject)fem), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscFE type: %s", name);
125
126 PetscTryTypeMethod(fem, destroy);
127 fem->ops->destroy = NULL;
128
129 PetscCall((*r)(fem));
130 PetscCall(PetscObjectChangeTypeName((PetscObject)fem, name));
131 PetscFunctionReturn(PETSC_SUCCESS);
132 }
133
134 /*@
135 PetscFEGetType - Gets the `PetscFEType` (as a string) from the `PetscFE` object.
136
137 Not Collective
138
139 Input Parameter:
140 . fem - The `PetscFE`
141
142 Output Parameter:
143 . name - The `PetscFEType` name
144
145 Level: intermediate
146
147 .seealso: `PetscFEType`, `PetscFE`, `PetscFESetType()`, `PetscFECreate()`
148 @*/
PetscFEGetType(PetscFE fem,PetscFEType * name)149 PetscErrorCode PetscFEGetType(PetscFE fem, PetscFEType *name)
150 {
151 PetscFunctionBegin;
152 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
153 PetscAssertPointer(name, 2);
154 if (!PetscFERegisterAllCalled) PetscCall(PetscFERegisterAll());
155 *name = ((PetscObject)fem)->type_name;
156 PetscFunctionReturn(PETSC_SUCCESS);
157 }
158
159 /*@
160 PetscFEViewFromOptions - View from a `PetscFE` based on values in the options database
161
162 Collective
163
164 Input Parameters:
165 + A - the `PetscFE` object
166 . obj - Optional object that provides the options prefix, pass `NULL` to use the options prefix of `A`
167 - name - command line option name
168
169 Level: intermediate
170
171 .seealso: `PetscFE`, `PetscFEView()`, `PetscObjectViewFromOptions()`, `PetscFECreate()`
172 @*/
PetscFEViewFromOptions(PetscFE A,PeOp PetscObject obj,const char name[])173 PetscErrorCode PetscFEViewFromOptions(PetscFE A, PeOp PetscObject obj, const char name[])
174 {
175 PetscFunctionBegin;
176 PetscValidHeaderSpecific(A, PETSCFE_CLASSID, 1);
177 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
178 PetscFunctionReturn(PETSC_SUCCESS);
179 }
180
181 /*@
182 PetscFEView - Views a `PetscFE`
183
184 Collective
185
186 Input Parameters:
187 + fem - the `PetscFE` object to view
188 - viewer - the viewer
189
190 Level: beginner
191
192 .seealso: `PetscFE`, `PetscViewer`, `PetscFEDestroy()`, `PetscFEViewFromOptions()`
193 @*/
PetscFEView(PetscFE fem,PetscViewer viewer)194 PetscErrorCode PetscFEView(PetscFE fem, PetscViewer viewer)
195 {
196 PetscBool isascii;
197
198 PetscFunctionBegin;
199 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
200 if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
201 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)fem), &viewer));
202 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)fem, viewer));
203 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
204 PetscTryTypeMethod(fem, view, viewer);
205 PetscFunctionReturn(PETSC_SUCCESS);
206 }
207
208 /*@
209 PetscFESetFromOptions - sets parameters in a `PetscFE` from the options database
210
211 Collective
212
213 Input Parameter:
214 . fem - the `PetscFE` object to set options for
215
216 Options Database Keys:
217 + -petscfe_num_blocks - the number of cell blocks to integrate concurrently
218 - -petscfe_num_batches - the number of cell batches to integrate serially
219
220 Level: intermediate
221
222 .seealso: `PetscFE`, `PetscFEView()`
223 @*/
PetscFESetFromOptions(PetscFE fem)224 PetscErrorCode PetscFESetFromOptions(PetscFE fem)
225 {
226 const char *defaultType;
227 char name[256];
228 PetscBool flg;
229
230 PetscFunctionBegin;
231 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
232 if (!((PetscObject)fem)->type_name) {
233 defaultType = PETSCFEBASIC;
234 } else {
235 defaultType = ((PetscObject)fem)->type_name;
236 }
237 if (!PetscFERegisterAllCalled) PetscCall(PetscFERegisterAll());
238
239 PetscObjectOptionsBegin((PetscObject)fem);
240 PetscCall(PetscOptionsFList("-petscfe_type", "Finite element space", "PetscFESetType", PetscFEList, defaultType, name, 256, &flg));
241 if (flg) {
242 PetscCall(PetscFESetType(fem, name));
243 } else if (!((PetscObject)fem)->type_name) {
244 PetscCall(PetscFESetType(fem, defaultType));
245 }
246 PetscCall(PetscOptionsBoundedInt("-petscfe_num_blocks", "The number of cell blocks to integrate concurrently", "PetscSpaceSetTileSizes", fem->numBlocks, &fem->numBlocks, NULL, 1));
247 PetscCall(PetscOptionsBoundedInt("-petscfe_num_batches", "The number of cell batches to integrate serially", "PetscSpaceSetTileSizes", fem->numBatches, &fem->numBatches, NULL, 1));
248 PetscTryTypeMethod(fem, setfromoptions, PetscOptionsObject);
249 /* process any options handlers added with PetscObjectAddOptionsHandler() */
250 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)fem, PetscOptionsObject));
251 PetscOptionsEnd();
252 PetscCall(PetscFEViewFromOptions(fem, NULL, "-petscfe_view"));
253 PetscFunctionReturn(PETSC_SUCCESS);
254 }
255
256 /*@
257 PetscFESetUp - Construct data structures for the `PetscFE` after the `PetscFEType` has been set
258
259 Collective
260
261 Input Parameter:
262 . fem - the `PetscFE` object to setup
263
264 Level: intermediate
265
266 .seealso: `PetscFE`, `PetscFEView()`, `PetscFEDestroy()`
267 @*/
PetscFESetUp(PetscFE fem)268 PetscErrorCode PetscFESetUp(PetscFE fem)
269 {
270 PetscFunctionBegin;
271 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
272 if (fem->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
273 PetscCall(PetscLogEventBegin(PETSCFE_SetUp, fem, 0, 0, 0));
274 fem->setupcalled = PETSC_TRUE;
275 PetscTryTypeMethod(fem, setup);
276 PetscCall(PetscLogEventEnd(PETSCFE_SetUp, fem, 0, 0, 0));
277 PetscFunctionReturn(PETSC_SUCCESS);
278 }
279
280 /*@
281 PetscFEDestroy - Destroys a `PetscFE` object
282
283 Collective
284
285 Input Parameter:
286 . fem - the `PetscFE` object to destroy
287
288 Level: beginner
289
290 .seealso: `PetscFE`, `PetscFEView()`
291 @*/
PetscFEDestroy(PetscFE * fem)292 PetscErrorCode PetscFEDestroy(PetscFE *fem)
293 {
294 PetscFunctionBegin;
295 if (!*fem) PetscFunctionReturn(PETSC_SUCCESS);
296 PetscValidHeaderSpecific(*fem, PETSCFE_CLASSID, 1);
297
298 if (--((PetscObject)*fem)->refct > 0) {
299 *fem = NULL;
300 PetscFunctionReturn(PETSC_SUCCESS);
301 }
302 ((PetscObject)*fem)->refct = 0;
303
304 if ((*fem)->subspaces) {
305 PetscInt dim, d;
306
307 PetscCall(PetscDualSpaceGetDimension((*fem)->dualSpace, &dim));
308 for (d = 0; d < dim; ++d) PetscCall(PetscFEDestroy(&(*fem)->subspaces[d]));
309 }
310 PetscCall(PetscFree((*fem)->subspaces));
311 PetscCall(PetscFree((*fem)->invV));
312 PetscCall(PetscTabulationDestroy(&(*fem)->T));
313 PetscCall(PetscTabulationDestroy(&(*fem)->Tf));
314 PetscCall(PetscTabulationDestroy(&(*fem)->Tc));
315 PetscCall(PetscSpaceDestroy(&(*fem)->basisSpace));
316 PetscCall(PetscDualSpaceDestroy(&(*fem)->dualSpace));
317 PetscCall(PetscQuadratureDestroy(&(*fem)->quadrature));
318 PetscCall(PetscQuadratureDestroy(&(*fem)->faceQuadrature));
319 #ifdef PETSC_HAVE_LIBCEED
320 PetscCallCEED(CeedBasisDestroy(&(*fem)->ceedBasis));
321 PetscCallCEED(CeedDestroy(&(*fem)->ceed));
322 #endif
323
324 PetscTryTypeMethod(*fem, destroy);
325 PetscCall(PetscHeaderDestroy(fem));
326 PetscFunctionReturn(PETSC_SUCCESS);
327 }
328
329 /*@
330 PetscFECreate - Creates an empty `PetscFE` object. The type can then be set with `PetscFESetType()`.
331
332 Collective
333
334 Input Parameter:
335 . comm - The communicator for the `PetscFE` object
336
337 Output Parameter:
338 . fem - The `PetscFE` object
339
340 Level: beginner
341
342 .seealso: `PetscFE`, `PetscFEType`, `PetscFESetType()`, `PetscFECreateDefault()`, `PETSCFEGALERKIN`
343 @*/
PetscFECreate(MPI_Comm comm,PetscFE * fem)344 PetscErrorCode PetscFECreate(MPI_Comm comm, PetscFE *fem)
345 {
346 PetscFE f;
347
348 PetscFunctionBegin;
349 PetscAssertPointer(fem, 2);
350 PetscCall(PetscCitationsRegister(FECitation, &FEcite));
351 PetscCall(PetscFEInitializePackage());
352
353 PetscCall(PetscHeaderCreate(f, PETSCFE_CLASSID, "PetscFE", "Finite Element", "PetscFE", comm, PetscFEDestroy, PetscFEView));
354
355 f->basisSpace = NULL;
356 f->dualSpace = NULL;
357 f->numComponents = 1;
358 f->subspaces = NULL;
359 f->invV = NULL;
360 f->T = NULL;
361 f->Tf = NULL;
362 f->Tc = NULL;
363 PetscCall(PetscArrayzero(&f->quadrature, 1));
364 PetscCall(PetscArrayzero(&f->faceQuadrature, 1));
365 f->blockSize = 0;
366 f->numBlocks = 1;
367 f->batchSize = 0;
368 f->numBatches = 1;
369
370 *fem = f;
371 PetscFunctionReturn(PETSC_SUCCESS);
372 }
373
374 /*@
375 PetscFEGetSpatialDimension - Returns the spatial dimension of the element
376
377 Not Collective
378
379 Input Parameter:
380 . fem - The `PetscFE` object
381
382 Output Parameter:
383 . dim - The spatial dimension
384
385 Level: intermediate
386
387 .seealso: `PetscFE`, `PetscFECreate()`
388 @*/
PetscFEGetSpatialDimension(PetscFE fem,PetscInt * dim)389 PetscErrorCode PetscFEGetSpatialDimension(PetscFE fem, PetscInt *dim)
390 {
391 DM dm;
392
393 PetscFunctionBegin;
394 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
395 PetscAssertPointer(dim, 2);
396 PetscCall(PetscDualSpaceGetDM(fem->dualSpace, &dm));
397 PetscCall(DMGetDimension(dm, dim));
398 PetscFunctionReturn(PETSC_SUCCESS);
399 }
400
401 /*@
402 PetscFESetNumComponents - Sets the number of field components in the element
403
404 Not Collective
405
406 Input Parameters:
407 + fem - The `PetscFE` object
408 - comp - The number of field components
409
410 Level: intermediate
411
412 .seealso: `PetscFE`, `PetscFECreate()`, `PetscFEGetSpatialDimension()`, `PetscFEGetNumComponents()`
413 @*/
PetscFESetNumComponents(PetscFE fem,PetscInt comp)414 PetscErrorCode PetscFESetNumComponents(PetscFE fem, PetscInt comp)
415 {
416 PetscFunctionBegin;
417 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
418 fem->numComponents = comp;
419 PetscFunctionReturn(PETSC_SUCCESS);
420 }
421
422 /*@
423 PetscFEGetNumComponents - Returns the number of components in the element
424
425 Not Collective
426
427 Input Parameter:
428 . fem - The `PetscFE` object
429
430 Output Parameter:
431 . comp - The number of field components
432
433 Level: intermediate
434
435 .seealso: `PetscFE`, `PetscFECreate()`, `PetscFEGetSpatialDimension()`
436 @*/
PetscFEGetNumComponents(PetscFE fem,PetscInt * comp)437 PetscErrorCode PetscFEGetNumComponents(PetscFE fem, PetscInt *comp)
438 {
439 PetscFunctionBegin;
440 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
441 PetscAssertPointer(comp, 2);
442 *comp = fem->numComponents;
443 PetscFunctionReturn(PETSC_SUCCESS);
444 }
445
446 /*@
447 PetscFESetTileSizes - Sets the tile sizes for evaluation
448
449 Not Collective
450
451 Input Parameters:
452 + fem - The `PetscFE` object
453 . blockSize - The number of elements in a block
454 . numBlocks - The number of blocks in a batch
455 . batchSize - The number of elements in a batch
456 - numBatches - The number of batches in a chunk
457
458 Level: intermediate
459
460 .seealso: `PetscFE`, `PetscFECreate()`, `PetscFEGetTileSizes()`
461 @*/
PetscFESetTileSizes(PetscFE fem,PetscInt blockSize,PetscInt numBlocks,PetscInt batchSize,PetscInt numBatches)462 PetscErrorCode PetscFESetTileSizes(PetscFE fem, PetscInt blockSize, PetscInt numBlocks, PetscInt batchSize, PetscInt numBatches)
463 {
464 PetscFunctionBegin;
465 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
466 fem->blockSize = blockSize;
467 fem->numBlocks = numBlocks;
468 fem->batchSize = batchSize;
469 fem->numBatches = numBatches;
470 PetscFunctionReturn(PETSC_SUCCESS);
471 }
472
473 /*@
474 PetscFEGetTileSizes - Returns the tile sizes for evaluation
475
476 Not Collective
477
478 Input Parameter:
479 . fem - The `PetscFE` object
480
481 Output Parameters:
482 + blockSize - The number of elements in a block, pass `NULL` if not needed
483 . numBlocks - The number of blocks in a batch, pass `NULL` if not needed
484 . batchSize - The number of elements in a batch, pass `NULL` if not needed
485 - numBatches - The number of batches in a chunk, pass `NULL` if not needed
486
487 Level: intermediate
488
489 .seealso: `PetscFE`, `PetscFECreate()`, `PetscFESetTileSizes()`
490 @*/
PetscFEGetTileSizes(PetscFE fem,PeOp PetscInt * blockSize,PeOp PetscInt * numBlocks,PeOp PetscInt * batchSize,PeOp PetscInt * numBatches)491 PetscErrorCode PetscFEGetTileSizes(PetscFE fem, PeOp PetscInt *blockSize, PeOp PetscInt *numBlocks, PeOp PetscInt *batchSize, PeOp PetscInt *numBatches)
492 {
493 PetscFunctionBegin;
494 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
495 if (blockSize) PetscAssertPointer(blockSize, 2);
496 if (numBlocks) PetscAssertPointer(numBlocks, 3);
497 if (batchSize) PetscAssertPointer(batchSize, 4);
498 if (numBatches) PetscAssertPointer(numBatches, 5);
499 if (blockSize) *blockSize = fem->blockSize;
500 if (numBlocks) *numBlocks = fem->numBlocks;
501 if (batchSize) *batchSize = fem->batchSize;
502 if (numBatches) *numBatches = fem->numBatches;
503 PetscFunctionReturn(PETSC_SUCCESS);
504 }
505
506 /*@
507 PetscFEGetBasisSpace - Returns the `PetscSpace` used for the approximation of the solution for the `PetscFE`
508
509 Not Collective
510
511 Input Parameter:
512 . fem - The `PetscFE` object
513
514 Output Parameter:
515 . sp - The `PetscSpace` object
516
517 Level: intermediate
518
519 .seealso: `PetscFE`, `PetscSpace`, `PetscFECreate()`
520 @*/
PetscFEGetBasisSpace(PetscFE fem,PetscSpace * sp)521 PetscErrorCode PetscFEGetBasisSpace(PetscFE fem, PetscSpace *sp)
522 {
523 PetscFunctionBegin;
524 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
525 PetscAssertPointer(sp, 2);
526 *sp = fem->basisSpace;
527 PetscFunctionReturn(PETSC_SUCCESS);
528 }
529
530 /*@
531 PetscFESetBasisSpace - Sets the `PetscSpace` used for the approximation of the solution
532
533 Not Collective
534
535 Input Parameters:
536 + fem - The `PetscFE` object
537 - sp - The `PetscSpace` object
538
539 Level: intermediate
540
541 Developer Notes:
542 There is `PetscFESetBasisSpace()` but the `PetscFESetDualSpace()`, likely the Basis is unneeded in the function name
543
544 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscFECreate()`, `PetscFESetDualSpace()`
545 @*/
PetscFESetBasisSpace(PetscFE fem,PetscSpace sp)546 PetscErrorCode PetscFESetBasisSpace(PetscFE fem, PetscSpace sp)
547 {
548 PetscFunctionBegin;
549 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
550 PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 2);
551 PetscCall(PetscSpaceDestroy(&fem->basisSpace));
552 fem->basisSpace = sp;
553 PetscCall(PetscObjectReference((PetscObject)fem->basisSpace));
554 PetscFunctionReturn(PETSC_SUCCESS);
555 }
556
557 /*@
558 PetscFEGetDualSpace - Returns the `PetscDualSpace` used to define the inner product for a `PetscFE`
559
560 Not Collective
561
562 Input Parameter:
563 . fem - The `PetscFE` object
564
565 Output Parameter:
566 . sp - The `PetscDualSpace` object
567
568 Level: intermediate
569
570 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscFECreate()`
571 @*/
PetscFEGetDualSpace(PetscFE fem,PetscDualSpace * sp)572 PetscErrorCode PetscFEGetDualSpace(PetscFE fem, PetscDualSpace *sp)
573 {
574 PetscFunctionBegin;
575 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
576 PetscAssertPointer(sp, 2);
577 *sp = fem->dualSpace;
578 PetscFunctionReturn(PETSC_SUCCESS);
579 }
580
581 /*@
582 PetscFESetDualSpace - Sets the `PetscDualSpace` used to define the inner product
583
584 Not Collective
585
586 Input Parameters:
587 + fem - The `PetscFE` object
588 - sp - The `PetscDualSpace` object
589
590 Level: intermediate
591
592 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscFECreate()`, `PetscFESetBasisSpace()`
593 @*/
PetscFESetDualSpace(PetscFE fem,PetscDualSpace sp)594 PetscErrorCode PetscFESetDualSpace(PetscFE fem, PetscDualSpace sp)
595 {
596 PetscFunctionBegin;
597 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
598 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 2);
599 PetscCall(PetscDualSpaceDestroy(&fem->dualSpace));
600 fem->dualSpace = sp;
601 PetscCall(PetscObjectReference((PetscObject)fem->dualSpace));
602 PetscFunctionReturn(PETSC_SUCCESS);
603 }
604
605 /*@
606 PetscFEGetQuadrature - Returns the `PetscQuadrature` used to calculate inner products
607
608 Not Collective
609
610 Input Parameter:
611 . fem - The `PetscFE` object
612
613 Output Parameter:
614 . q - The `PetscQuadrature` object
615
616 Level: intermediate
617
618 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscQuadrature`, `PetscFECreate()`
619 @*/
PetscFEGetQuadrature(PetscFE fem,PetscQuadrature * q)620 PetscErrorCode PetscFEGetQuadrature(PetscFE fem, PetscQuadrature *q)
621 {
622 PetscFunctionBegin;
623 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
624 PetscAssertPointer(q, 2);
625 *q = fem->quadrature;
626 PetscFunctionReturn(PETSC_SUCCESS);
627 }
628
629 /*@
630 PetscFESetQuadrature - Sets the `PetscQuadrature` used to calculate inner products
631
632 Not Collective
633
634 Input Parameters:
635 + fem - The `PetscFE` object
636 - q - The `PetscQuadrature` object
637
638 Level: intermediate
639
640 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscQuadrature`, `PetscFECreate()`, `PetscFEGetFaceQuadrature()`
641 @*/
PetscFESetQuadrature(PetscFE fem,PetscQuadrature q)642 PetscErrorCode PetscFESetQuadrature(PetscFE fem, PetscQuadrature q)
643 {
644 PetscInt Nc, qNc;
645
646 PetscFunctionBegin;
647 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
648 if (q == fem->quadrature) PetscFunctionReturn(PETSC_SUCCESS);
649 PetscCall(PetscFEGetNumComponents(fem, &Nc));
650 PetscCall(PetscQuadratureGetNumComponents(q, &qNc));
651 PetscCheck(!(qNc != 1) || !(Nc != qNc), PetscObjectComm((PetscObject)fem), PETSC_ERR_ARG_SIZ, "FE components %" PetscInt_FMT " != Quadrature components %" PetscInt_FMT " and non-scalar quadrature", Nc, qNc);
652 PetscCall(PetscTabulationDestroy(&fem->T));
653 PetscCall(PetscTabulationDestroy(&fem->Tc));
654 PetscCall(PetscObjectReference((PetscObject)q));
655 PetscCall(PetscQuadratureDestroy(&fem->quadrature));
656 fem->quadrature = q;
657 PetscFunctionReturn(PETSC_SUCCESS);
658 }
659
660 /*@
661 PetscFEGetFaceQuadrature - Returns the `PetscQuadrature` used to calculate inner products on faces
662
663 Not Collective
664
665 Input Parameter:
666 . fem - The `PetscFE` object
667
668 Output Parameter:
669 . q - The `PetscQuadrature` object
670
671 Level: intermediate
672
673 Developer Notes:
674 There is a special face quadrature but not edge, likely this API would benefit from a refactorization
675
676 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscQuadrature`, `PetscFECreate()`, `PetscFESetQuadrature()`, `PetscFESetFaceQuadrature()`
677 @*/
PetscFEGetFaceQuadrature(PetscFE fem,PetscQuadrature * q)678 PetscErrorCode PetscFEGetFaceQuadrature(PetscFE fem, PetscQuadrature *q)
679 {
680 PetscFunctionBegin;
681 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
682 PetscAssertPointer(q, 2);
683 *q = fem->faceQuadrature;
684 PetscFunctionReturn(PETSC_SUCCESS);
685 }
686
687 /*@
688 PetscFESetFaceQuadrature - Sets the `PetscQuadrature` used to calculate inner products on faces
689
690 Not Collective
691
692 Input Parameters:
693 + fem - The `PetscFE` object
694 - q - The `PetscQuadrature` object
695
696 Level: intermediate
697
698 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscQuadrature`, `PetscFECreate()`, `PetscFESetQuadrature()`
699 @*/
PetscFESetFaceQuadrature(PetscFE fem,PetscQuadrature q)700 PetscErrorCode PetscFESetFaceQuadrature(PetscFE fem, PetscQuadrature q)
701 {
702 PetscInt Nc, qNc;
703
704 PetscFunctionBegin;
705 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
706 if (q == fem->faceQuadrature) PetscFunctionReturn(PETSC_SUCCESS);
707 PetscCall(PetscFEGetNumComponents(fem, &Nc));
708 PetscCall(PetscQuadratureGetNumComponents(q, &qNc));
709 PetscCheck(!(qNc != 1) || !(Nc != qNc), PetscObjectComm((PetscObject)fem), PETSC_ERR_ARG_SIZ, "FE components %" PetscInt_FMT " != Quadrature components %" PetscInt_FMT " and non-scalar quadrature", Nc, qNc);
710 PetscCall(PetscTabulationDestroy(&fem->Tf));
711 PetscCall(PetscObjectReference((PetscObject)q));
712 PetscCall(PetscQuadratureDestroy(&fem->faceQuadrature));
713 fem->faceQuadrature = q;
714 PetscFunctionReturn(PETSC_SUCCESS);
715 }
716
717 /*@
718 PetscFECopyQuadrature - Copy both volumetric and surface quadrature to a new `PetscFE`
719
720 Not Collective
721
722 Input Parameters:
723 + sfe - The `PetscFE` source for the quadratures
724 - tfe - The `PetscFE` target for the quadratures
725
726 Level: intermediate
727
728 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscQuadrature`, `PetscFECreate()`, `PetscFESetQuadrature()`, `PetscFESetFaceQuadrature()`
729 @*/
PetscFECopyQuadrature(PetscFE sfe,PetscFE tfe)730 PetscErrorCode PetscFECopyQuadrature(PetscFE sfe, PetscFE tfe)
731 {
732 PetscQuadrature q;
733
734 PetscFunctionBegin;
735 PetscValidHeaderSpecific(sfe, PETSCFE_CLASSID, 1);
736 PetscValidHeaderSpecific(tfe, PETSCFE_CLASSID, 2);
737 PetscCall(PetscFEGetQuadrature(sfe, &q));
738 PetscCall(PetscFESetQuadrature(tfe, q));
739 PetscCall(PetscFEGetFaceQuadrature(sfe, &q));
740 PetscCall(PetscFESetFaceQuadrature(tfe, q));
741 PetscFunctionReturn(PETSC_SUCCESS);
742 }
743
744 /*@C
745 PetscFEGetNumDof - Returns the number of dofs (dual basis vectors) associated to mesh points on the reference cell of a given dimension
746
747 Not Collective
748
749 Input Parameter:
750 . fem - The `PetscFE` object
751
752 Output Parameter:
753 . numDof - Array of length `dim` with the number of dofs in each dimension
754
755 Level: intermediate
756
757 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscFECreate()`
758 @*/
PetscFEGetNumDof(PetscFE fem,const PetscInt * numDof[])759 PetscErrorCode PetscFEGetNumDof(PetscFE fem, const PetscInt *numDof[])
760 {
761 PetscFunctionBegin;
762 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
763 PetscAssertPointer(numDof, 2);
764 PetscCall(PetscDualSpaceGetNumDof(fem->dualSpace, numDof));
765 PetscFunctionReturn(PETSC_SUCCESS);
766 }
767
768 /*@C
769 PetscFEGetCellTabulation - Returns the tabulation of the basis functions at the quadrature points on the reference cell
770
771 Not Collective
772
773 Input Parameters:
774 + fem - The `PetscFE` object
775 - k - The highest derivative we need to tabulate, very often 1
776
777 Output Parameter:
778 . T - The basis function values and derivatives at quadrature points
779
780 Level: intermediate
781
782 Note:
783 .vb
784 T->T[0] = B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
785 T->T[1] = D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
786 T->T[2] = H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e
787 .ve
788
789 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscTabulation`, `PetscFECreateTabulation()`, `PetscTabulationDestroy()`
790 @*/
PetscFEGetCellTabulation(PetscFE fem,PetscInt k,PetscTabulation * T)791 PetscErrorCode PetscFEGetCellTabulation(PetscFE fem, PetscInt k, PetscTabulation *T)
792 {
793 PetscInt npoints;
794 const PetscReal *points;
795
796 PetscFunctionBegin;
797 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
798 PetscAssertPointer(T, 3);
799 PetscCall(PetscQuadratureGetData(fem->quadrature, NULL, NULL, &npoints, &points, NULL));
800 if (!fem->T) PetscCall(PetscFECreateTabulation(fem, 1, npoints, points, k, &fem->T));
801 PetscCheck(!fem->T || k <= fem->T->K || (!fem->T->cdim && !fem->T->K), PetscObjectComm((PetscObject)fem), PETSC_ERR_ARG_OUTOFRANGE, "Requested %" PetscInt_FMT " derivatives, but only tabulated %" PetscInt_FMT, k, fem->T->K);
802 *T = fem->T;
803 PetscFunctionReturn(PETSC_SUCCESS);
804 }
805
PetscFEExpandFaceQuadrature(PetscFE fe,PetscQuadrature fq,PetscQuadrature * efq)806 PetscErrorCode PetscFEExpandFaceQuadrature(PetscFE fe, PetscQuadrature fq, PetscQuadrature *efq)
807 {
808 DM dm;
809 PetscDualSpace sp;
810 const PetscInt *faces;
811 const PetscReal *points, *weights;
812 DMPolytopeType ct;
813 PetscReal *facePoints, *faceWeights;
814 PetscInt dim, cStart, Nf, Nc, Np, order;
815
816 PetscFunctionBegin;
817 PetscCall(PetscFEGetDualSpace(fe, &sp));
818 PetscCall(PetscDualSpaceGetDM(sp, &dm));
819 PetscCall(DMGetDimension(dm, &dim));
820 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
821 PetscCall(DMPlexGetConeSize(dm, cStart, &Nf));
822 PetscCall(DMPlexGetCone(dm, cStart, &faces));
823 PetscCall(PetscQuadratureGetData(fq, NULL, &Nc, &Np, &points, &weights));
824 PetscCall(PetscMalloc1(Nf * Np * dim, &facePoints));
825 PetscCall(PetscMalloc1(Nf * Np * Nc, &faceWeights));
826 for (PetscInt f = 0; f < Nf; ++f) {
827 const PetscReal xi0[3] = {-1., -1., -1.};
828 PetscReal v0[3], J[9], detJ;
829
830 PetscCall(DMPlexComputeCellGeometryFEM(dm, faces[f], NULL, v0, J, NULL, &detJ));
831 for (PetscInt q = 0; q < Np; ++q) {
832 CoordinatesRefToReal(dim, dim - 1, xi0, v0, J, &points[q * (dim - 1)], &facePoints[(f * Np + q) * dim]);
833 for (PetscInt c = 0; c < Nc; ++c) faceWeights[(f * Np + q) * Nc + c] = weights[q * Nc + c];
834 }
835 }
836 PetscCall(PetscQuadratureCreate(PetscObjectComm((PetscObject)fq), efq));
837 PetscCall(PetscQuadratureGetCellType(fq, &ct));
838 PetscCall(PetscQuadratureSetCellType(*efq, ct));
839 PetscCall(PetscQuadratureGetOrder(fq, &order));
840 PetscCall(PetscQuadratureSetOrder(*efq, order));
841 PetscCall(PetscQuadratureSetData(*efq, dim, Nc, Nf * Np, facePoints, faceWeights));
842 PetscFunctionReturn(PETSC_SUCCESS);
843 }
844
845 /*@C
846 PetscFEGetFaceTabulation - Returns the tabulation of the basis functions at the face quadrature points for each face of the reference cell
847
848 Not Collective
849
850 Input Parameters:
851 + fem - The `PetscFE` object
852 - k - The highest derivative we need to tabulate, very often 1
853
854 Output Parameter:
855 . Tf - The basis function values and derivatives at face quadrature points
856
857 Level: intermediate
858
859 Note:
860 .vb
861 T->T[0] = Bf[((f*Nq + q)*pdim + i)*Nc + c] is the value at point f,q for basis function i and component c
862 T->T[1] = Df[(((f*Nq + q)*pdim + i)*Nc + c)*dim + d] is the derivative value at point f,q for basis function i, component c, in direction d
863 T->T[2] = Hf[((((f*Nq + q)*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point f,q for basis function i, component c, in directions d and e
864 .ve
865
866 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscTabulation`, `PetscFEGetCellTabulation()`, `PetscFECreateTabulation()`, `PetscTabulationDestroy()`
867 @*/
PetscFEGetFaceTabulation(PetscFE fem,PetscInt k,PetscTabulation * Tf)868 PetscErrorCode PetscFEGetFaceTabulation(PetscFE fem, PetscInt k, PetscTabulation *Tf)
869 {
870 PetscFunctionBegin;
871 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
872 PetscAssertPointer(Tf, 3);
873 if (!fem->Tf) {
874 PetscQuadrature fq;
875
876 PetscCall(PetscFEGetFaceQuadrature(fem, &fq));
877 if (fq) {
878 PetscQuadrature efq;
879 const PetscReal *facePoints;
880 PetscInt Np, eNp;
881
882 PetscCall(PetscFEExpandFaceQuadrature(fem, fq, &efq));
883 PetscCall(PetscQuadratureGetData(fq, NULL, NULL, &Np, NULL, NULL));
884 PetscCall(PetscQuadratureGetData(efq, NULL, NULL, &eNp, &facePoints, NULL));
885 if (PetscDefined(USE_DEBUG)) {
886 PetscDualSpace sp;
887 DM dm;
888 PetscInt cStart, Nf;
889
890 PetscCall(PetscFEGetDualSpace(fem, &sp));
891 PetscCall(PetscDualSpaceGetDM(sp, &dm));
892 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
893 PetscCall(DMPlexGetConeSize(dm, cStart, &Nf));
894 PetscCheck(Nf == eNp / Np, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of faces %" PetscInt_FMT " != %" PetscInt_FMT " number of quadrature replicas", Nf, eNp / Np);
895 }
896 PetscCall(PetscFECreateTabulation(fem, eNp / Np, Np, facePoints, k, &fem->Tf));
897 PetscCall(PetscQuadratureDestroy(&efq));
898 }
899 }
900 PetscCheck(!fem->Tf || k <= fem->Tf->K, PetscObjectComm((PetscObject)fem), PETSC_ERR_ARG_OUTOFRANGE, "Requested %" PetscInt_FMT " derivatives, but only tabulated %" PetscInt_FMT, k, fem->Tf->K);
901 *Tf = fem->Tf;
902 PetscFunctionReturn(PETSC_SUCCESS);
903 }
904
905 /*@C
906 PetscFEGetFaceCentroidTabulation - Returns the tabulation of the basis functions at the face centroid points
907
908 Not Collective
909
910 Input Parameter:
911 . fem - The `PetscFE` object
912
913 Output Parameter:
914 . Tc - The basis function values at face centroid points
915
916 Level: intermediate
917
918 Note:
919 .vb
920 T->T[0] = Bf[(f*pdim + i)*Nc + c] is the value at point f for basis function i and component c
921 .ve
922
923 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscTabulation`, `PetscFEGetFaceTabulation()`, `PetscFEGetCellTabulation()`, `PetscFECreateTabulation()`, `PetscTabulationDestroy()`
924 @*/
PetscFEGetFaceCentroidTabulation(PetscFE fem,PetscTabulation * Tc)925 PetscErrorCode PetscFEGetFaceCentroidTabulation(PetscFE fem, PetscTabulation *Tc)
926 {
927 PetscFunctionBegin;
928 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
929 PetscAssertPointer(Tc, 2);
930 if (!fem->Tc) {
931 PetscDualSpace sp;
932 DM dm;
933 const PetscInt *cone;
934 PetscReal *centroids;
935 PetscInt dim, numFaces, f;
936
937 PetscCall(PetscFEGetDualSpace(fem, &sp));
938 PetscCall(PetscDualSpaceGetDM(sp, &dm));
939 PetscCall(DMGetDimension(dm, &dim));
940 PetscCall(DMPlexGetConeSize(dm, 0, &numFaces));
941 PetscCall(DMPlexGetCone(dm, 0, &cone));
942 PetscCall(PetscMalloc1(numFaces * dim, ¢roids));
943 for (f = 0; f < numFaces; ++f) PetscCall(DMPlexComputeCellGeometryFVM(dm, cone[f], NULL, ¢roids[f * dim], NULL));
944 PetscCall(PetscFECreateTabulation(fem, 1, numFaces, centroids, 0, &fem->Tc));
945 PetscCall(PetscFree(centroids));
946 }
947 *Tc = fem->Tc;
948 PetscFunctionReturn(PETSC_SUCCESS);
949 }
950
951 /*@C
952 PetscFECreateTabulation - Tabulates the basis functions, and perhaps derivatives, at the points provided.
953
954 Not Collective
955
956 Input Parameters:
957 + fem - The `PetscFE` object
958 . nrepl - The number of replicas
959 . npoints - The number of tabulation points in a replica
960 . points - The tabulation point coordinates
961 - K - The number of derivatives calculated
962
963 Output Parameter:
964 . T - The basis function values and derivatives at tabulation points
965
966 Level: intermediate
967
968 Note:
969 .vb
970 T->T[0] = B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
971 T->T[1] = D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
972 T->T[2] = H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis
973 T->function i, component c, in directions d and e
974 .ve
975
976 .seealso: `PetscTabulation`, `PetscFEGetCellTabulation()`, `PetscTabulationDestroy()`
977 @*/
PetscFECreateTabulation(PetscFE fem,PetscInt nrepl,PetscInt npoints,const PetscReal points[],PetscInt K,PetscTabulation * T)978 PetscErrorCode PetscFECreateTabulation(PetscFE fem, PetscInt nrepl, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation *T)
979 {
980 DM dm;
981 PetscDualSpace Q;
982 PetscInt Nb; /* Dimension of FE space P */
983 PetscInt Nc; /* Field components */
984 PetscInt cdim; /* Reference coordinate dimension */
985 PetscInt k;
986
987 PetscFunctionBegin;
988 if (!npoints || !fem->dualSpace || K < 0) {
989 *T = NULL;
990 PetscFunctionReturn(PETSC_SUCCESS);
991 }
992 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
993 PetscAssertPointer(points, 4);
994 PetscAssertPointer(T, 6);
995 PetscCall(PetscFEGetDualSpace(fem, &Q));
996 PetscCall(PetscDualSpaceGetDM(Q, &dm));
997 PetscCall(DMGetDimension(dm, &cdim));
998 PetscCall(PetscDualSpaceGetDimension(Q, &Nb));
999 PetscCall(PetscFEGetNumComponents(fem, &Nc));
1000 PetscCall(PetscMalloc1(1, T));
1001 (*T)->K = !cdim ? 0 : K;
1002 (*T)->Nr = nrepl;
1003 (*T)->Np = npoints;
1004 (*T)->Nb = Nb;
1005 (*T)->Nc = Nc;
1006 (*T)->cdim = cdim;
1007 PetscCall(PetscMalloc1((*T)->K + 1, &(*T)->T));
1008 for (k = 0; k <= (*T)->K; ++k) PetscCall(PetscCalloc1(nrepl * npoints * Nb * Nc * PetscPowInt(cdim, k), &(*T)->T[k]));
1009 PetscUseTypeMethod(fem, computetabulation, nrepl * npoints, points, K, *T);
1010 PetscFunctionReturn(PETSC_SUCCESS);
1011 }
1012
1013 /*@C
1014 PetscFEComputeTabulation - Tabulates the basis functions, and perhaps derivatives, at the points provided.
1015
1016 Not Collective
1017
1018 Input Parameters:
1019 + fem - The `PetscFE` object
1020 . npoints - The number of tabulation points
1021 . points - The tabulation point coordinates
1022 . K - The number of derivatives calculated
1023 - T - An existing tabulation object with enough allocated space
1024
1025 Output Parameter:
1026 . T - The basis function values and derivatives at tabulation points
1027
1028 Level: intermediate
1029
1030 Note:
1031 .vb
1032 T->T[0] = B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
1033 T->T[1] = D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
1034 T->T[2] = H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e
1035 .ve
1036
1037 .seealso: `PetscTabulation`, `PetscFEGetCellTabulation()`, `PetscTabulationDestroy()`
1038 @*/
PetscFEComputeTabulation(PetscFE fem,PetscInt npoints,const PetscReal points[],PetscInt K,PetscTabulation T)1039 PetscErrorCode PetscFEComputeTabulation(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation T)
1040 {
1041 PetscFunctionBeginHot;
1042 if (!npoints || !fem->dualSpace || K < 0) PetscFunctionReturn(PETSC_SUCCESS);
1043 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1044 PetscAssertPointer(points, 3);
1045 PetscAssertPointer(T, 5);
1046 if (PetscDefined(USE_DEBUG)) {
1047 DM dm;
1048 PetscDualSpace Q;
1049 PetscInt Nb; /* Dimension of FE space P */
1050 PetscInt Nc; /* Field components */
1051 PetscInt cdim; /* Reference coordinate dimension */
1052
1053 PetscCall(PetscFEGetDualSpace(fem, &Q));
1054 PetscCall(PetscDualSpaceGetDM(Q, &dm));
1055 PetscCall(DMGetDimension(dm, &cdim));
1056 PetscCall(PetscDualSpaceGetDimension(Q, &Nb));
1057 PetscCall(PetscFEGetNumComponents(fem, &Nc));
1058 PetscCheck(T->K == (!cdim ? 0 : K), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Tabulation K %" PetscInt_FMT " must match requested K %" PetscInt_FMT, T->K, !cdim ? 0 : K);
1059 PetscCheck(T->Nb == Nb, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Tabulation Nb %" PetscInt_FMT " must match requested Nb %" PetscInt_FMT, T->Nb, Nb);
1060 PetscCheck(T->Nc == Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Tabulation Nc %" PetscInt_FMT " must match requested Nc %" PetscInt_FMT, T->Nc, Nc);
1061 PetscCheck(T->cdim == cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Tabulation cdim %" PetscInt_FMT " must match requested cdim %" PetscInt_FMT, T->cdim, cdim);
1062 }
1063 T->Nr = 1;
1064 T->Np = npoints;
1065 PetscUseTypeMethod(fem, computetabulation, npoints, points, K, T);
1066 PetscFunctionReturn(PETSC_SUCCESS);
1067 }
1068
1069 /*@
1070 PetscTabulationDestroy - Frees memory from the associated tabulation.
1071
1072 Not Collective
1073
1074 Input Parameter:
1075 . T - The tabulation
1076
1077 Level: intermediate
1078
1079 .seealso: `PetscTabulation`, `PetscFECreateTabulation()`, `PetscFEGetCellTabulation()`
1080 @*/
PetscTabulationDestroy(PetscTabulation * T)1081 PetscErrorCode PetscTabulationDestroy(PetscTabulation *T)
1082 {
1083 PetscInt k;
1084
1085 PetscFunctionBegin;
1086 PetscAssertPointer(T, 1);
1087 if (!T || !*T) PetscFunctionReturn(PETSC_SUCCESS);
1088 for (k = 0; k <= (*T)->K; ++k) PetscCall(PetscFree((*T)->T[k]));
1089 PetscCall(PetscFree((*T)->T));
1090 PetscCall(PetscFree(*T));
1091 *T = NULL;
1092 PetscFunctionReturn(PETSC_SUCCESS);
1093 }
1094
PetscFECreatePointTraceDefault_Internal(PetscFE fe,PetscInt refPoint,PetscFE * trFE)1095 static PetscErrorCode PetscFECreatePointTraceDefault_Internal(PetscFE fe, PetscInt refPoint, PetscFE *trFE)
1096 {
1097 PetscSpace bsp, bsubsp;
1098 PetscDualSpace dsp, dsubsp;
1099 PetscInt dim, depth, numComp, i, j, coneSize, order;
1100 DM dm;
1101 DMLabel label;
1102 PetscReal *xi, *v, *J, detJ;
1103 const char *name;
1104 PetscQuadrature origin, fullQuad, subQuad;
1105
1106 PetscFunctionBegin;
1107 PetscCall(PetscFEGetBasisSpace(fe, &bsp));
1108 PetscCall(PetscFEGetDualSpace(fe, &dsp));
1109 PetscCall(PetscDualSpaceGetDM(dsp, &dm));
1110 PetscCall(DMGetDimension(dm, &dim));
1111 PetscCall(DMPlexGetDepthLabel(dm, &label));
1112 PetscCall(DMLabelGetValue(label, refPoint, &depth));
1113 PetscCall(PetscCalloc1(depth, &xi));
1114 PetscCall(PetscMalloc1(dim, &v));
1115 PetscCall(PetscMalloc1(dim * dim, &J));
1116 for (i = 0; i < depth; i++) xi[i] = 0.;
1117 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &origin));
1118 PetscCall(PetscQuadratureSetData(origin, depth, 0, 1, xi, NULL));
1119 PetscCall(DMPlexComputeCellGeometryFEM(dm, refPoint, origin, v, J, NULL, &detJ));
1120 /* CellGeometryFEM computes the expanded Jacobian, we want the true jacobian */
1121 for (i = 1; i < dim; i++) {
1122 for (j = 0; j < depth; j++) J[i * depth + j] = J[i * dim + j];
1123 }
1124 PetscCall(PetscQuadratureDestroy(&origin));
1125 PetscCall(PetscDualSpaceGetPointSubspace(dsp, refPoint, &dsubsp));
1126 PetscCall(PetscSpaceCreateSubspace(bsp, dsubsp, v, J, NULL, NULL, PETSC_OWN_POINTER, &bsubsp));
1127 PetscCall(PetscSpaceSetUp(bsubsp));
1128 PetscCall(PetscFECreate(PetscObjectComm((PetscObject)fe), trFE));
1129 PetscCall(PetscFESetType(*trFE, PETSCFEBASIC));
1130 PetscCall(PetscFEGetNumComponents(fe, &numComp));
1131 PetscCall(PetscFESetNumComponents(*trFE, numComp));
1132 PetscCall(PetscFESetBasisSpace(*trFE, bsubsp));
1133 PetscCall(PetscFESetDualSpace(*trFE, dsubsp));
1134 PetscCall(PetscObjectGetName((PetscObject)fe, &name));
1135 if (name) PetscCall(PetscFESetName(*trFE, name));
1136 PetscCall(PetscFEGetQuadrature(fe, &fullQuad));
1137 PetscCall(PetscQuadratureGetOrder(fullQuad, &order));
1138 PetscCall(DMPlexGetConeSize(dm, refPoint, &coneSize));
1139 if (coneSize == 2 * depth) PetscCall(PetscDTGaussTensorQuadrature(depth, 1, (order + 2) / 2, -1., 1., &subQuad));
1140 else PetscCall(PetscDTSimplexQuadrature(depth, order, PETSCDTSIMPLEXQUAD_DEFAULT, &subQuad));
1141 PetscCall(PetscFESetQuadrature(*trFE, subQuad));
1142 PetscCall(PetscFESetUp(*trFE));
1143 PetscCall(PetscQuadratureDestroy(&subQuad));
1144 PetscCall(PetscSpaceDestroy(&bsubsp));
1145 PetscFunctionReturn(PETSC_SUCCESS);
1146 }
1147
PetscFECreatePointTrace(PetscFE fe,PetscInt refPoint,PetscFE * trFE)1148 PETSC_EXTERN PetscErrorCode PetscFECreatePointTrace(PetscFE fe, PetscInt refPoint, PetscFE *trFE)
1149 {
1150 PetscFunctionBegin;
1151 PetscValidHeaderSpecific(fe, PETSCFE_CLASSID, 1);
1152 PetscAssertPointer(trFE, 3);
1153 if (fe->ops->createpointtrace) PetscUseTypeMethod(fe, createpointtrace, refPoint, trFE);
1154 else PetscCall(PetscFECreatePointTraceDefault_Internal(fe, refPoint, trFE));
1155 PetscFunctionReturn(PETSC_SUCCESS);
1156 }
1157
PetscFECreateHeightTrace(PetscFE fe,PetscInt height,PetscFE * trFE)1158 PetscErrorCode PetscFECreateHeightTrace(PetscFE fe, PetscInt height, PetscFE *trFE)
1159 {
1160 PetscInt hStart, hEnd;
1161 PetscDualSpace dsp;
1162 DM dm;
1163
1164 PetscFunctionBegin;
1165 PetscValidHeaderSpecific(fe, PETSCFE_CLASSID, 1);
1166 PetscAssertPointer(trFE, 3);
1167 *trFE = NULL;
1168 PetscCall(PetscFEGetDualSpace(fe, &dsp));
1169 PetscCall(PetscDualSpaceGetDM(dsp, &dm));
1170 PetscCall(DMPlexGetHeightStratum(dm, height, &hStart, &hEnd));
1171 if (hEnd <= hStart) PetscFunctionReturn(PETSC_SUCCESS);
1172 PetscCall(PetscFECreatePointTrace(fe, hStart, trFE));
1173 PetscFunctionReturn(PETSC_SUCCESS);
1174 }
1175
1176 /*@
1177 PetscFEGetDimension - Get the dimension of the finite element space on a cell
1178
1179 Not Collective
1180
1181 Input Parameter:
1182 . fem - The `PetscFE`
1183
1184 Output Parameter:
1185 . dim - The dimension
1186
1187 Level: intermediate
1188
1189 .seealso: `PetscFE`, `PetscFECreate()`, `PetscSpaceGetDimension()`, `PetscDualSpaceGetDimension()`
1190 @*/
PetscFEGetDimension(PetscFE fem,PetscInt * dim)1191 PetscErrorCode PetscFEGetDimension(PetscFE fem, PetscInt *dim)
1192 {
1193 PetscFunctionBegin;
1194 PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1195 PetscAssertPointer(dim, 2);
1196 PetscTryTypeMethod(fem, getdimension, dim);
1197 PetscFunctionReturn(PETSC_SUCCESS);
1198 }
1199
1200 /*@
1201 PetscFEPushforward - Map the reference element function to real space
1202
1203 Input Parameters:
1204 + fe - The `PetscFE`
1205 . fegeom - The cell geometry
1206 . Nv - The number of function values
1207 - vals - The function values
1208
1209 Output Parameter:
1210 . vals - The transformed function values
1211
1212 Level: advanced
1213
1214 Notes:
1215 This just forwards the call onto `PetscDualSpacePushforward()`.
1216
1217 It only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
1218
1219 .seealso: `PetscFE`, `PetscFEGeom`, `PetscDualSpace`, `PetscDualSpacePushforward()`
1220 @*/
PetscFEPushforward(PetscFE fe,PetscFEGeom * fegeom,PetscInt Nv,PetscScalar vals[])1221 PetscErrorCode PetscFEPushforward(PetscFE fe, PetscFEGeom *fegeom, PetscInt Nv, PetscScalar vals[])
1222 {
1223 PetscFunctionBeginHot;
1224 PetscCall(PetscDualSpacePushforward(fe->dualSpace, fegeom, Nv, fe->numComponents, vals));
1225 PetscFunctionReturn(PETSC_SUCCESS);
1226 }
1227
1228 /*@
1229 PetscFEPushforwardGradient - Map the reference element function gradient to real space
1230
1231 Input Parameters:
1232 + fe - The `PetscFE`
1233 . fegeom - The cell geometry
1234 . Nv - The number of function gradient values
1235 - vals - The function gradient values
1236
1237 Output Parameter:
1238 . vals - The transformed function gradient values
1239
1240 Level: advanced
1241
1242 Notes:
1243 This just forwards the call onto `PetscDualSpacePushforwardGradient()`.
1244
1245 It only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
1246
1247 .seealso: `PetscFE`, `PetscFEGeom`, `PetscDualSpace`, `PetscFEPushforward()`, `PetscDualSpacePushforwardGradient()`, `PetscDualSpacePushforward()`
1248 @*/
PetscFEPushforwardGradient(PetscFE fe,PetscFEGeom * fegeom,PetscInt Nv,PetscScalar vals[])1249 PetscErrorCode PetscFEPushforwardGradient(PetscFE fe, PetscFEGeom *fegeom, PetscInt Nv, PetscScalar vals[])
1250 {
1251 PetscFunctionBeginHot;
1252 PetscCall(PetscDualSpacePushforwardGradient(fe->dualSpace, fegeom, Nv, fe->numComponents, vals));
1253 PetscFunctionReturn(PETSC_SUCCESS);
1254 }
1255
1256 /*@
1257 PetscFEPushforwardHessian - Map the reference element function Hessian to real space
1258
1259 Input Parameters:
1260 + fe - The `PetscFE`
1261 . fegeom - The cell geometry
1262 . Nv - The number of function Hessian values
1263 - vals - The function Hessian values
1264
1265 Output Parameter:
1266 . vals - The transformed function Hessian values
1267
1268 Level: advanced
1269
1270 Notes:
1271 This just forwards the call onto `PetscDualSpacePushforwardHessian()`.
1272
1273 It only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension.
1274
1275 Developer Notes:
1276 It is unclear why all these one line convenience routines are desirable
1277
1278 .seealso: `PetscFE`, `PetscFEGeom`, `PetscDualSpace`, `PetscFEPushforward()`, `PetscDualSpacePushforwardHessian()`, `PetscDualSpacePushforward()`
1279 @*/
PetscFEPushforwardHessian(PetscFE fe,PetscFEGeom * fegeom,PetscInt Nv,PetscScalar vals[])1280 PetscErrorCode PetscFEPushforwardHessian(PetscFE fe, PetscFEGeom *fegeom, PetscInt Nv, PetscScalar vals[])
1281 {
1282 PetscFunctionBeginHot;
1283 PetscCall(PetscDualSpacePushforwardHessian(fe->dualSpace, fegeom, Nv, fe->numComponents, vals));
1284 PetscFunctionReturn(PETSC_SUCCESS);
1285 }
1286
1287 /*
1288 Purpose: Compute element vector for chunk of elements
1289
1290 Input:
1291 Sizes:
1292 Ne: number of elements
1293 Nf: number of fields
1294 PetscFE
1295 dim: spatial dimension
1296 Nb: number of basis functions
1297 Nc: number of field components
1298 PetscQuadrature
1299 Nq: number of quadrature points
1300
1301 Geometry:
1302 PetscFEGeom[Ne] possibly *Nq
1303 PetscReal v0s[dim]
1304 PetscReal n[dim]
1305 PetscReal jacobians[dim*dim]
1306 PetscReal jacobianInverses[dim*dim]
1307 PetscReal jacobianDeterminants
1308 FEM:
1309 PetscFE
1310 PetscQuadrature
1311 PetscReal quadPoints[Nq*dim]
1312 PetscReal quadWeights[Nq]
1313 PetscReal basis[Nq*Nb*Nc]
1314 PetscReal basisDer[Nq*Nb*Nc*dim]
1315 PetscScalar coefficients[Ne*Nb*Nc]
1316 PetscScalar elemVec[Ne*Nb*Nc]
1317
1318 Problem:
1319 PetscInt f: the active field
1320 f0, f1
1321
1322 Work Space:
1323 PetscFE
1324 PetscScalar f0[Nq*dim];
1325 PetscScalar f1[Nq*dim*dim];
1326 PetscScalar u[Nc];
1327 PetscScalar gradU[Nc*dim];
1328 PetscReal x[dim];
1329 PetscScalar realSpaceDer[dim];
1330
1331 Purpose: Compute element vector for N_cb batches of elements
1332
1333 Input:
1334 Sizes:
1335 N_cb: Number of serial cell batches
1336
1337 Geometry:
1338 PetscReal v0s[Ne*dim]
1339 PetscReal jacobians[Ne*dim*dim] possibly *Nq
1340 PetscReal jacobianInverses[Ne*dim*dim] possibly *Nq
1341 PetscReal jacobianDeterminants[Ne] possibly *Nq
1342 FEM:
1343 static PetscReal quadPoints[Nq*dim]
1344 static PetscReal quadWeights[Nq]
1345 static PetscReal basis[Nq*Nb*Nc]
1346 static PetscReal basisDer[Nq*Nb*Nc*dim]
1347 PetscScalar coefficients[Ne*Nb*Nc]
1348 PetscScalar elemVec[Ne*Nb*Nc]
1349
1350 ex62.c:
1351 PetscErrorCode PetscFEIntegrateResidualBatch(PetscInt Ne, PetscInt numFields, PetscInt field, PetscQuadrature quad[], const PetscScalar coefficients[],
1352 const PetscReal v0s[], const PetscReal jacobians[], const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[],
1353 void (*f0_func)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]),
1354 void (*f1_func)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]), PetscScalar elemVec[])
1355
1356 ex52.c:
1357 PetscErrorCode IntegrateLaplacianBatchCPU(PetscInt Ne, PetscInt Nb, const PetscScalar coefficients[], const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscInt Nq, const PetscReal quadPoints[], const PetscReal quadWeights[], const PetscReal basisTabulation[], const PetscReal basisDerTabulation[], PetscScalar elemVec[], AppCtx *user)
1358 PetscErrorCode IntegrateElasticityBatchCPU(PetscInt Ne, PetscInt Nb, PetscInt Ncomp, const PetscScalar coefficients[], const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscInt Nq, const PetscReal quadPoints[], const PetscReal quadWeights[], const PetscReal basisTabulation[], const PetscReal basisDerTabulation[], PetscScalar elemVec[], AppCtx *user)
1359
1360 ex52_integrateElement.cu
1361 __global__ void integrateElementQuadrature(int N_cb, realType *coefficients, realType *jacobianInverses, realType *jacobianDeterminants, realType *elemVec)
1362
1363 PETSC_EXTERN PetscErrorCode IntegrateElementBatchGPU(PetscInt spatial_dim, PetscInt Ne, PetscInt Ncb, PetscInt Nbc, PetscInt Nbl, const PetscScalar coefficients[],
1364 const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscScalar elemVec[],
1365 PetscLogEvent event, PetscInt debug, PetscInt pde_op)
1366
1367 ex52_integrateElementOpenCL.c:
1368 PETSC_EXTERN PetscErrorCode IntegrateElementBatchGPU(PetscInt spatial_dim, PetscInt Ne, PetscInt Ncb, PetscInt Nbc, PetscInt N_bl, const PetscScalar coefficients[],
1369 const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscScalar elemVec[],
1370 PetscLogEvent event, PetscInt debug, PetscInt pde_op)
1371
1372 __kernel void integrateElementQuadrature(int N_cb, __global float *coefficients, __global float *jacobianInverses, __global float *jacobianDeterminants, __global float *elemVec)
1373 */
1374
1375 /*@
1376 PetscFEIntegrate - Produce the integral for the given field for a chunk of elements by quadrature integration
1377
1378 Not Collective
1379
1380 Input Parameters:
1381 + prob - The `PetscDS` specifying the discretizations and continuum functions
1382 . field - The field being integrated
1383 . Ne - The number of elements in the chunk
1384 . cgeom - The cell geometry for each cell in the chunk
1385 . coefficients - The array of FEM basis coefficients for the elements
1386 . probAux - The `PetscDS` specifying the auxiliary discretizations
1387 - coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1388
1389 Output Parameter:
1390 . integral - the integral for this field
1391
1392 Level: intermediate
1393
1394 Developer Notes:
1395 The function name begins with `PetscFE` and yet the first argument is `PetscDS` and it has no `PetscFE` arguments.
1396
1397 .seealso: `PetscFE`, `PetscDS`, `PetscFEIntegrateResidual()`, `PetscFEIntegrateBd()`
1398 @*/
PetscFEIntegrate(PetscDS prob,PetscInt field,PetscInt Ne,PetscFEGeom * cgeom,const PetscScalar coefficients[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscScalar integral[])1399 PetscErrorCode PetscFEIntegrate(PetscDS prob, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
1400 {
1401 PetscFE fe;
1402
1403 PetscFunctionBegin;
1404 PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1405 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe));
1406 if (fe->ops->integrate) PetscCall((*fe->ops->integrate)(prob, field, Ne, cgeom, coefficients, probAux, coefficientsAux, integral));
1407 PetscFunctionReturn(PETSC_SUCCESS);
1408 }
1409
1410 /*@C
1411 PetscFEIntegrateBd - Produce the integral for the given field for a chunk of elements by quadrature integration
1412
1413 Not Collective
1414
1415 Input Parameters:
1416 + prob - The `PetscDS` specifying the discretizations and continuum functions
1417 . field - The field being integrated
1418 . obj_func - The function to be integrated
1419 . Ne - The number of elements in the chunk
1420 . geom - The face geometry for each face in the chunk
1421 . coefficients - The array of FEM basis coefficients for the elements
1422 . probAux - The `PetscDS` specifying the auxiliary discretizations
1423 - coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1424
1425 Output Parameter:
1426 . integral - the integral for this field
1427
1428 Level: intermediate
1429
1430 Developer Notes:
1431 The function name begins with `PetscFE` and yet the first argument is `PetscDS` and it has no `PetscFE` arguments.
1432
1433 .seealso: `PetscFE`, `PetscDS`, `PetscFEIntegrateResidual()`, `PetscFEIntegrate()`
1434 @*/
PetscFEIntegrateBd(PetscDS prob,PetscInt field,void (* obj_func)(PetscInt,PetscInt,PetscInt,const PetscInt[],const PetscInt[],const PetscScalar[],const PetscScalar[],const PetscScalar[],const PetscInt[],const PetscInt[],const PetscScalar[],const PetscScalar[],const PetscScalar[],PetscReal,const PetscReal[],const PetscReal[],PetscInt,const PetscScalar[],PetscScalar[]),PetscInt Ne,PetscFEGeom * geom,const PetscScalar coefficients[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscScalar integral[])1435 PetscErrorCode PetscFEIntegrateBd(PetscDS prob, PetscInt field, void (*obj_func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscInt Ne, PetscFEGeom *geom, const PetscScalar coefficients[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
1436 {
1437 PetscFE fe;
1438
1439 PetscFunctionBegin;
1440 PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1441 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe));
1442 if (fe->ops->integratebd) PetscCall((*fe->ops->integratebd)(prob, field, obj_func, Ne, geom, coefficients, probAux, coefficientsAux, integral));
1443 PetscFunctionReturn(PETSC_SUCCESS);
1444 }
1445
1446 /*@
1447 PetscFEIntegrateResidual - Produce the element residual vector for a chunk of elements by quadrature integration
1448
1449 Not Collective
1450
1451 Input Parameters:
1452 + ds - The `PetscDS` specifying the discretizations and continuum functions
1453 . key - The (label+value, field) being integrated
1454 . Ne - The number of elements in the chunk
1455 . cgeom - The cell geometry for each cell in the chunk
1456 . coefficients - The array of FEM basis coefficients for the elements
1457 . coefficients_t - The array of FEM basis time derivative coefficients for the elements
1458 . probAux - The `PetscDS` specifying the auxiliary discretizations
1459 . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1460 - t - The time
1461
1462 Output Parameter:
1463 . elemVec - the element residual vectors from each element
1464
1465 Level: intermediate
1466
1467 Note:
1468 .vb
1469 Loop over batch of elements (e):
1470 Loop over quadrature points (q):
1471 Make u_q and gradU_q (loops over fields,Nb,Ncomp) and x_q
1472 Call f_0 and f_1
1473 Loop over element vector entries (f,fc --> i):
1474 elemVec[i] += \psi^{fc}_f(q) f0_{fc}(u, \nabla u) + \nabla\psi^{fc}_f(q) \cdot f1_{fc,df}(u, \nabla u)
1475 .ve
1476
1477 .seealso: `PetscFEIntegrateBdResidual()`
1478 @*/
PetscFEIntegrateResidual(PetscDS ds,PetscFormKey key,PetscInt Ne,PetscFEGeom * cgeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscReal t,PetscScalar elemVec[])1479 PetscErrorCode PetscFEIntegrateResidual(PetscDS ds, PetscFormKey key, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
1480 {
1481 PetscFE fe;
1482
1483 PetscFunctionBeginHot;
1484 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1485 PetscCall(PetscDSGetDiscretization(ds, key.field, (PetscObject *)&fe));
1486 if (fe->ops->integrateresidual) PetscCall((*fe->ops->integrateresidual)(ds, key, Ne, cgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, elemVec));
1487 PetscFunctionReturn(PETSC_SUCCESS);
1488 }
1489
1490 /*@
1491 PetscFEIntegrateBdResidual - Produce the element residual vector for a chunk of elements by quadrature integration over a boundary
1492
1493 Not Collective
1494
1495 Input Parameters:
1496 + ds - The `PetscDS` specifying the discretizations and continuum functions
1497 . wf - The PetscWeakForm object holding the pointwise functions
1498 . key - The (label+value, field) being integrated
1499 . Ne - The number of elements in the chunk
1500 . fgeom - The face geometry for each cell in the chunk
1501 . coefficients - The array of FEM basis coefficients for the elements
1502 . coefficients_t - The array of FEM basis time derivative coefficients for the elements
1503 . probAux - The `PetscDS` specifying the auxiliary discretizations
1504 . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1505 - t - The time
1506
1507 Output Parameter:
1508 . elemVec - the element residual vectors from each element
1509
1510 Level: intermediate
1511
1512 .seealso: `PetscFEIntegrateResidual()`
1513 @*/
PetscFEIntegrateBdResidual(PetscDS ds,PetscWeakForm wf,PetscFormKey key,PetscInt Ne,PetscFEGeom * fgeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscReal t,PetscScalar elemVec[])1514 PetscErrorCode PetscFEIntegrateBdResidual(PetscDS ds, PetscWeakForm wf, PetscFormKey key, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
1515 {
1516 PetscFE fe;
1517
1518 PetscFunctionBegin;
1519 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1520 PetscCall(PetscDSGetDiscretization(ds, key.field, (PetscObject *)&fe));
1521 if (fe->ops->integratebdresidual) PetscCall((*fe->ops->integratebdresidual)(ds, wf, key, Ne, fgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, elemVec));
1522 PetscFunctionReturn(PETSC_SUCCESS);
1523 }
1524
1525 /*@
1526 PetscFEIntegrateHybridResidual - Produce the element residual vector for a chunk of hybrid element faces by quadrature integration
1527
1528 Not Collective
1529
1530 Input Parameters:
1531 + ds - The `PetscDS` specifying the discretizations and continuum functions
1532 . dsIn - The `PetscDS` specifying the discretizations and continuum functions for input
1533 . key - The (label+value, field) being integrated
1534 . s - The side of the cell being integrated, 0 for negative and 1 for positive
1535 . Ne - The number of elements in the chunk
1536 . fgeom - The face geometry for each cell in the chunk
1537 . cgeom - The cell geometry for each neighbor cell in the chunk
1538 . coefficients - The array of FEM basis coefficients for the elements
1539 . coefficients_t - The array of FEM basis time derivative coefficients for the elements
1540 . probAux - The `PetscDS` specifying the auxiliary discretizations
1541 . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1542 - t - The time
1543
1544 Output Parameter:
1545 . elemVec - the element residual vectors from each element
1546
1547 Level: developer
1548
1549 .seealso: `PetscFEIntegrateResidual()`
1550 @*/
PetscFEIntegrateHybridResidual(PetscDS ds,PetscDS dsIn,PetscFormKey key,PetscInt s,PetscInt Ne,PetscFEGeom * fgeom,PetscFEGeom * cgeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscReal t,PetscScalar elemVec[])1551 PetscErrorCode PetscFEIntegrateHybridResidual(PetscDS ds, PetscDS dsIn, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom, PetscFEGeom *cgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
1552 {
1553 PetscFE fe;
1554
1555 PetscFunctionBegin;
1556 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1557 PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 2);
1558 PetscCall(PetscDSGetDiscretization(ds, key.field, (PetscObject *)&fe));
1559 if (fe->ops->integratehybridresidual) PetscCall((*fe->ops->integratehybridresidual)(ds, dsIn, key, s, Ne, fgeom, cgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, elemVec));
1560 PetscFunctionReturn(PETSC_SUCCESS);
1561 }
1562
1563 /*@
1564 PetscFEIntegrateJacobian - Produce the element Jacobian for a chunk of elements by quadrature integration
1565
1566 Not Collective
1567
1568 Input Parameters:
1569 + rds - The `PetscDS` specifying the row discretizations and continuum functions
1570 . cds - The `PetscDS` specifying the column discretizations
1571 . jtype - The type of matrix pointwise functions that should be used
1572 . key - The (label+value, fieldI*Nf + fieldJ) being integrated
1573 . Ne - The number of elements in the chunk
1574 . cgeom - The cell geometry for each cell in the chunk
1575 . coefficients - The array of FEM basis coefficients for the elements for the Jacobian evaluation point
1576 . coefficients_t - The array of FEM basis time derivative coefficients for the elements
1577 . dsAux - The `PetscDS` specifying the auxiliary discretizations
1578 . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1579 . t - The time
1580 - u_tshift - A multiplier for the dF/du_t term (as opposed to the dF/du term)
1581
1582 Output Parameter:
1583 . elemMat - the element matrices for the Jacobian from each element
1584
1585 Level: intermediate
1586
1587 Note:
1588 .vb
1589 Loop over batch of elements (e):
1590 Loop over element matrix entries (f,fc,g,gc --> i,j):
1591 Loop over quadrature points (q):
1592 Make u_q and gradU_q (loops over fields,Nb,Ncomp)
1593 elemMat[i,j] += \psi^{fc}_f(q) g0_{fc,gc}(u, \nabla u) \phi^{gc}_g(q)
1594 + \psi^{fc}_f(q) \cdot g1_{fc,gc,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
1595 + \nabla\psi^{fc}_f(q) \cdot g2_{fc,gc,df}(u, \nabla u) \phi^{gc}_g(q)
1596 + \nabla\psi^{fc}_f(q) \cdot g3_{fc,gc,df,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
1597 .ve
1598
1599 .seealso: `PetscFEIntegrateResidual()`
1600 @*/
PetscFEIntegrateJacobian(PetscDS rds,PetscDS cds,PetscFEJacobianType jtype,PetscFormKey key,PetscInt Ne,PetscFEGeom * cgeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscDS dsAux,const PetscScalar coefficientsAux[],PetscReal t,PetscReal u_tshift,PetscScalar elemMat[])1601 PetscErrorCode PetscFEIntegrateJacobian(PetscDS rds, PetscDS cds, PetscFEJacobianType jtype, PetscFormKey key, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
1602 {
1603 PetscFE fe;
1604 PetscInt Nf;
1605
1606 PetscFunctionBegin;
1607 PetscValidHeaderSpecific(rds, PETSCDS_CLASSID, 1);
1608 PetscValidHeaderSpecific(cds, PETSCDS_CLASSID, 2);
1609 PetscCall(PetscDSGetNumFields(rds, &Nf));
1610 PetscCall(PetscDSGetDiscretization(rds, key.field / Nf, (PetscObject *)&fe));
1611 if (fe->ops->integratejacobian) PetscCall((*fe->ops->integratejacobian)(rds, cds, jtype, key, Ne, cgeom, coefficients, coefficients_t, dsAux, coefficientsAux, t, u_tshift, elemMat));
1612 PetscFunctionReturn(PETSC_SUCCESS);
1613 }
1614
1615 /*@
1616 PetscFEIntegrateBdJacobian - Produce the boundary element Jacobian for a chunk of elements by quadrature integration
1617
1618 Not Collective
1619
1620 Input Parameters:
1621 + ds - The `PetscDS` specifying the discretizations and continuum functions
1622 . wf - The PetscWeakForm holding the pointwise functions
1623 . jtype - The type of matrix pointwise functions that should be used
1624 . key - The (label+value, fieldI*Nf + fieldJ) being integrated
1625 . Ne - The number of elements in the chunk
1626 . fgeom - The face geometry for each cell in the chunk
1627 . coefficients - The array of FEM basis coefficients for the elements for the Jacobian evaluation point
1628 . coefficients_t - The array of FEM basis time derivative coefficients for the elements
1629 . probAux - The `PetscDS` specifying the auxiliary discretizations
1630 . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1631 . t - The time
1632 - u_tshift - A multiplier for the dF/du_t term (as opposed to the dF/du term)
1633
1634 Output Parameter:
1635 . elemMat - the element matrices for the Jacobian from each element
1636
1637 Level: intermediate
1638
1639 Note:
1640 .vb
1641 Loop over batch of elements (e):
1642 Loop over element matrix entries (f,fc,g,gc --> i,j):
1643 Loop over quadrature points (q):
1644 Make u_q and gradU_q (loops over fields,Nb,Ncomp)
1645 elemMat[i,j] += \psi^{fc}_f(q) g0_{fc,gc}(u, \nabla u) \phi^{gc}_g(q)
1646 + \psi^{fc}_f(q) \cdot g1_{fc,gc,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
1647 + \nabla\psi^{fc}_f(q) \cdot g2_{fc,gc,df}(u, \nabla u) \phi^{gc}_g(q)
1648 + \nabla\psi^{fc}_f(q) \cdot g3_{fc,gc,df,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
1649 .ve
1650
1651 .seealso: `PetscFEIntegrateJacobian()`, `PetscFEIntegrateResidual()`
1652 @*/
PetscFEIntegrateBdJacobian(PetscDS ds,PetscWeakForm wf,PetscFEJacobianType jtype,PetscFormKey key,PetscInt Ne,PetscFEGeom * fgeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscReal t,PetscReal u_tshift,PetscScalar elemMat[])1653 PetscErrorCode PetscFEIntegrateBdJacobian(PetscDS ds, PetscWeakForm wf, PetscFEJacobianType jtype, PetscFormKey key, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
1654 {
1655 PetscFE fe;
1656 PetscInt Nf;
1657
1658 PetscFunctionBegin;
1659 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1660 PetscCall(PetscDSGetNumFields(ds, &Nf));
1661 PetscCall(PetscDSGetDiscretization(ds, key.field / Nf, (PetscObject *)&fe));
1662 if (fe->ops->integratebdjacobian) PetscCall((*fe->ops->integratebdjacobian)(ds, wf, jtype, key, Ne, fgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, u_tshift, elemMat));
1663 PetscFunctionReturn(PETSC_SUCCESS);
1664 }
1665
1666 /*@
1667 PetscFEIntegrateHybridJacobian - Produce the boundary element Jacobian for a chunk of hybrid elements by quadrature integration
1668
1669 Not Collective
1670
1671 Input Parameters:
1672 + ds - The `PetscDS` specifying the discretizations and continuum functions for the output
1673 . dsIn - The `PetscDS` specifying the discretizations and continuum functions for the input
1674 . jtype - The type of matrix pointwise functions that should be used
1675 . key - The (label+value, fieldI*Nf + fieldJ) being integrated
1676 . s - The side of the cell being integrated, 0 for negative and 1 for positive
1677 . Ne - The number of elements in the chunk
1678 . fgeom - The face geometry for each cell in the chunk
1679 . cgeom - The cell geometry for each neighbor cell in the chunk
1680 . coefficients - The array of FEM basis coefficients for the elements for the Jacobian evaluation point
1681 . coefficients_t - The array of FEM basis time derivative coefficients for the elements
1682 . probAux - The `PetscDS` specifying the auxiliary discretizations
1683 . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
1684 . t - The time
1685 - u_tshift - A multiplier for the dF/du_t term (as opposed to the dF/du term)
1686
1687 Output Parameter:
1688 . elemMat - the element matrices for the Jacobian from each element
1689
1690 Level: developer
1691
1692 Note:
1693 .vb
1694 Loop over batch of elements (e):
1695 Loop over element matrix entries (f,fc,g,gc --> i,j):
1696 Loop over quadrature points (q):
1697 Make u_q and gradU_q (loops over fields,Nb,Ncomp)
1698 elemMat[i,j] += \psi^{fc}_f(q) g0_{fc,gc}(u, \nabla u) \phi^{gc}_g(q)
1699 + \psi^{fc}_f(q) \cdot g1_{fc,gc,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
1700 + \nabla\psi^{fc}_f(q) \cdot g2_{fc,gc,df}(u, \nabla u) \phi^{gc}_g(q)
1701 + \nabla\psi^{fc}_f(q) \cdot g3_{fc,gc,df,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
1702 .ve
1703
1704 .seealso: `PetscFEIntegrateJacobian()`, `PetscFEIntegrateResidual()`
1705 @*/
PetscFEIntegrateHybridJacobian(PetscDS ds,PetscDS dsIn,PetscFEJacobianType jtype,PetscFormKey key,PetscInt s,PetscInt Ne,PetscFEGeom * fgeom,PetscFEGeom * cgeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscDS probAux,const PetscScalar coefficientsAux[],PetscReal t,PetscReal u_tshift,PetscScalar elemMat[])1706 PetscErrorCode PetscFEIntegrateHybridJacobian(PetscDS ds, PetscDS dsIn, PetscFEJacobianType jtype, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom, PetscFEGeom *cgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
1707 {
1708 PetscFE fe;
1709 PetscInt Nf;
1710
1711 PetscFunctionBegin;
1712 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1713 PetscCall(PetscDSGetNumFields(ds, &Nf));
1714 PetscCall(PetscDSGetDiscretization(ds, key.field / Nf, (PetscObject *)&fe));
1715 if (fe->ops->integratehybridjacobian) PetscCall((*fe->ops->integratehybridjacobian)(ds, dsIn, jtype, key, s, Ne, fgeom, cgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, u_tshift, elemMat));
1716 PetscFunctionReturn(PETSC_SUCCESS);
1717 }
1718
1719 /*@
1720 PetscFEGetHeightSubspace - Get the subspace of this space for a mesh point of a given height
1721
1722 Input Parameters:
1723 + fe - The finite element space
1724 - height - The height of the `DMPLEX` point
1725
1726 Output Parameter:
1727 . subfe - The subspace of this `PetscFE` space
1728
1729 Level: advanced
1730
1731 Note:
1732 For example, if we want the subspace of this space for a face, we would choose height = 1.
1733
1734 .seealso: `PetscFECreateDefault()`
1735 @*/
PetscFEGetHeightSubspace(PetscFE fe,PetscInt height,PetscFE * subfe)1736 PetscErrorCode PetscFEGetHeightSubspace(PetscFE fe, PetscInt height, PetscFE *subfe)
1737 {
1738 PetscSpace P, subP;
1739 PetscDualSpace Q, subQ;
1740 PetscQuadrature subq;
1741 PetscInt dim, Nc;
1742
1743 PetscFunctionBegin;
1744 PetscValidHeaderSpecific(fe, PETSCFE_CLASSID, 1);
1745 PetscAssertPointer(subfe, 3);
1746 if (height == 0) {
1747 *subfe = fe;
1748 PetscFunctionReturn(PETSC_SUCCESS);
1749 }
1750 PetscCall(PetscFEGetBasisSpace(fe, &P));
1751 PetscCall(PetscFEGetDualSpace(fe, &Q));
1752 PetscCall(PetscFEGetNumComponents(fe, &Nc));
1753 PetscCall(PetscFEGetFaceQuadrature(fe, &subq));
1754 PetscCall(PetscDualSpaceGetDimension(Q, &dim));
1755 PetscCheck(height <= dim && height >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Asked for space at height %" PetscInt_FMT " for dimension %" PetscInt_FMT " space", height, dim);
1756 if (!fe->subspaces) PetscCall(PetscCalloc1(dim, &fe->subspaces));
1757 if (height <= dim) {
1758 if (!fe->subspaces[height - 1]) {
1759 PetscFE sub = NULL;
1760 const char *name;
1761
1762 PetscCall(PetscSpaceGetHeightSubspace(P, height, &subP));
1763 PetscCall(PetscDualSpaceGetHeightSubspace(Q, height, &subQ));
1764 if (subQ) {
1765 PetscCall(PetscObjectReference((PetscObject)subP));
1766 PetscCall(PetscObjectReference((PetscObject)subQ));
1767 PetscCall(PetscObjectReference((PetscObject)subq));
1768 PetscCall(PetscFECreateFromSpaces(subP, subQ, subq, NULL, &sub));
1769 }
1770 if (sub) {
1771 PetscCall(PetscObjectGetName((PetscObject)fe, &name));
1772 if (name) PetscCall(PetscFESetName(sub, name));
1773 }
1774 fe->subspaces[height - 1] = sub;
1775 }
1776 *subfe = fe->subspaces[height - 1];
1777 } else {
1778 *subfe = NULL;
1779 }
1780 PetscFunctionReturn(PETSC_SUCCESS);
1781 }
1782
1783 /*@
1784 PetscFERefine - Create a "refined" `PetscFE` object that refines the reference cell into
1785 smaller copies.
1786
1787 Collective
1788
1789 Input Parameter:
1790 . fe - The initial `PetscFE`
1791
1792 Output Parameter:
1793 . feRef - The refined `PetscFE`
1794
1795 Level: advanced
1796
1797 Notes:
1798 This is typically used to generate a preconditioner for a higher order method from a lower order method on a
1799 refined mesh having the same number of dofs (but more sparsity). It is also used to create an
1800 interpolation between regularly refined meshes.
1801
1802 .seealso: `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`
1803 @*/
PetscFERefine(PetscFE fe,PetscFE * feRef)1804 PetscErrorCode PetscFERefine(PetscFE fe, PetscFE *feRef)
1805 {
1806 PetscSpace P, Pref;
1807 PetscDualSpace Q, Qref;
1808 DM K, Kref;
1809 PetscQuadrature q, qref;
1810 const PetscReal *v0, *jac;
1811 PetscInt numComp, numSubelements;
1812 PetscInt cStart, cEnd, c;
1813 PetscDualSpace *cellSpaces;
1814
1815 PetscFunctionBegin;
1816 PetscCall(PetscFEGetBasisSpace(fe, &P));
1817 PetscCall(PetscFEGetDualSpace(fe, &Q));
1818 PetscCall(PetscFEGetQuadrature(fe, &q));
1819 PetscCall(PetscDualSpaceGetDM(Q, &K));
1820 /* Create space */
1821 PetscCall(PetscObjectReference((PetscObject)P));
1822 Pref = P;
1823 /* Create dual space */
1824 PetscCall(PetscDualSpaceDuplicate(Q, &Qref));
1825 PetscCall(PetscDualSpaceSetType(Qref, PETSCDUALSPACEREFINED));
1826 PetscCall(DMRefine(K, PetscObjectComm((PetscObject)fe), &Kref));
1827 PetscCall(DMGetCoordinatesLocalSetUp(Kref));
1828 PetscCall(PetscDualSpaceSetDM(Qref, Kref));
1829 PetscCall(DMPlexGetHeightStratum(Kref, 0, &cStart, &cEnd));
1830 PetscCall(PetscMalloc1(cEnd - cStart, &cellSpaces));
1831 /* TODO: fix for non-uniform refinement */
1832 for (c = 0; c < cEnd - cStart; c++) cellSpaces[c] = Q;
1833 PetscCall(PetscDualSpaceRefinedSetCellSpaces(Qref, cellSpaces));
1834 PetscCall(PetscFree(cellSpaces));
1835 PetscCall(DMDestroy(&Kref));
1836 PetscCall(PetscDualSpaceSetUp(Qref));
1837 /* Create element */
1838 PetscCall(PetscFECreate(PetscObjectComm((PetscObject)fe), feRef));
1839 PetscCall(PetscFESetType(*feRef, PETSCFECOMPOSITE));
1840 PetscCall(PetscFESetBasisSpace(*feRef, Pref));
1841 PetscCall(PetscFESetDualSpace(*feRef, Qref));
1842 PetscCall(PetscFEGetNumComponents(fe, &numComp));
1843 PetscCall(PetscFESetNumComponents(*feRef, numComp));
1844 PetscCall(PetscFESetUp(*feRef));
1845 PetscCall(PetscSpaceDestroy(&Pref));
1846 PetscCall(PetscDualSpaceDestroy(&Qref));
1847 /* Create quadrature */
1848 PetscCall(PetscFECompositeGetMapping(*feRef, &numSubelements, &v0, &jac, NULL));
1849 PetscCall(PetscQuadratureExpandComposite(q, numSubelements, v0, jac, &qref));
1850 PetscCall(PetscFESetQuadrature(*feRef, qref));
1851 PetscCall(PetscQuadratureDestroy(&qref));
1852 PetscFunctionReturn(PETSC_SUCCESS);
1853 }
1854
PetscFESetDefaultName_Private(PetscFE fe)1855 static PetscErrorCode PetscFESetDefaultName_Private(PetscFE fe)
1856 {
1857 PetscSpace P;
1858 PetscDualSpace Q;
1859 DM K;
1860 DMPolytopeType ct;
1861 PetscInt degree;
1862 char name[64];
1863
1864 PetscFunctionBegin;
1865 PetscCall(PetscFEGetBasisSpace(fe, &P));
1866 PetscCall(PetscSpaceGetDegree(P, °ree, NULL));
1867 PetscCall(PetscFEGetDualSpace(fe, &Q));
1868 PetscCall(PetscDualSpaceGetDM(Q, &K));
1869 PetscCall(DMPlexGetCellType(K, 0, &ct));
1870 switch (ct) {
1871 case DM_POLYTOPE_SEGMENT:
1872 case DM_POLYTOPE_POINT_PRISM_TENSOR:
1873 case DM_POLYTOPE_QUADRILATERAL:
1874 case DM_POLYTOPE_SEG_PRISM_TENSOR:
1875 case DM_POLYTOPE_HEXAHEDRON:
1876 case DM_POLYTOPE_QUAD_PRISM_TENSOR:
1877 PetscCall(PetscSNPrintf(name, sizeof(name), "Q%" PetscInt_FMT, degree));
1878 break;
1879 case DM_POLYTOPE_TRIANGLE:
1880 case DM_POLYTOPE_TETRAHEDRON:
1881 PetscCall(PetscSNPrintf(name, sizeof(name), "P%" PetscInt_FMT, degree));
1882 break;
1883 case DM_POLYTOPE_TRI_PRISM:
1884 case DM_POLYTOPE_TRI_PRISM_TENSOR:
1885 PetscCall(PetscSNPrintf(name, sizeof(name), "P%" PetscInt_FMT "xQ%" PetscInt_FMT, degree, degree));
1886 break;
1887 default:
1888 PetscCall(PetscSNPrintf(name, sizeof(name), "FE"));
1889 }
1890 PetscCall(PetscFESetName(fe, name));
1891 PetscFunctionReturn(PETSC_SUCCESS);
1892 }
1893
1894 /*@
1895 PetscFECreateFromSpaces - Create a `PetscFE` from the basis and dual spaces
1896
1897 Collective
1898
1899 Input Parameters:
1900 + P - The basis space
1901 . Q - The dual space
1902 . q - The cell quadrature
1903 - fq - The face quadrature
1904
1905 Output Parameter:
1906 . fem - The `PetscFE` object
1907
1908 Level: beginner
1909
1910 Note:
1911 The `PetscFE` takes ownership of these spaces by calling destroy on each. They should not be used after this call, and for borrowed references from `PetscFEGetSpace()` and the like, the caller must use `PetscObjectReference` before this call.
1912
1913 .seealso: `PetscFE`, `PetscSpace`, `PetscDualSpace`, `PetscQuadrature`,
1914 `PetscFECreateLagrangeByCell()`, `PetscFECreateDefault()`, `PetscFECreateByCell()`, `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
1915 @*/
PetscFECreateFromSpaces(PetscSpace P,PetscDualSpace Q,PetscQuadrature q,PetscQuadrature fq,PetscFE * fem)1916 PetscErrorCode PetscFECreateFromSpaces(PetscSpace P, PetscDualSpace Q, PetscQuadrature q, PetscQuadrature fq, PetscFE *fem)
1917 {
1918 PetscInt Nc;
1919 PetscInt p_Ns = -1, p_Nc = -1, q_Ns = -1, q_Nc = -1;
1920 PetscBool p_is_uniform_sum = PETSC_FALSE, p_interleave_basis = PETSC_FALSE, p_interleave_components = PETSC_FALSE;
1921 PetscBool q_is_uniform_sum = PETSC_FALSE, q_interleave_basis = PETSC_FALSE, q_interleave_components = PETSC_FALSE;
1922 const char *prefix;
1923
1924 PetscFunctionBegin;
1925 PetscCall(PetscObjectTypeCompare((PetscObject)P, PETSCSPACESUM, &p_is_uniform_sum));
1926 if (p_is_uniform_sum) {
1927 PetscSpace subsp_0 = NULL;
1928 PetscCall(PetscSpaceSumGetNumSubspaces(P, &p_Ns));
1929 PetscCall(PetscSpaceGetNumComponents(P, &p_Nc));
1930 PetscCall(PetscSpaceSumGetConcatenate(P, &p_is_uniform_sum));
1931 PetscCall(PetscSpaceSumGetInterleave(P, &p_interleave_basis, &p_interleave_components));
1932 for (PetscInt s = 0; s < p_Ns; s++) {
1933 PetscSpace subsp;
1934
1935 PetscCall(PetscSpaceSumGetSubspace(P, s, &subsp));
1936 if (!s) {
1937 subsp_0 = subsp;
1938 } else if (subsp != subsp_0) {
1939 p_is_uniform_sum = PETSC_FALSE;
1940 }
1941 }
1942 }
1943 PetscCall(PetscObjectTypeCompare((PetscObject)Q, PETSCDUALSPACESUM, &q_is_uniform_sum));
1944 if (q_is_uniform_sum) {
1945 PetscDualSpace subsp_0 = NULL;
1946 PetscCall(PetscDualSpaceSumGetNumSubspaces(Q, &q_Ns));
1947 PetscCall(PetscDualSpaceGetNumComponents(Q, &q_Nc));
1948 PetscCall(PetscDualSpaceSumGetConcatenate(Q, &q_is_uniform_sum));
1949 PetscCall(PetscDualSpaceSumGetInterleave(Q, &q_interleave_basis, &q_interleave_components));
1950 for (PetscInt s = 0; s < q_Ns; s++) {
1951 PetscDualSpace subsp;
1952
1953 PetscCall(PetscDualSpaceSumGetSubspace(Q, s, &subsp));
1954 if (!s) {
1955 subsp_0 = subsp;
1956 } else if (subsp != subsp_0) {
1957 q_is_uniform_sum = PETSC_FALSE;
1958 }
1959 }
1960 }
1961 if (p_is_uniform_sum && q_is_uniform_sum && (p_interleave_basis == q_interleave_basis) && (p_interleave_components == q_interleave_components) && (p_Ns == q_Ns) && (p_Nc == q_Nc)) {
1962 PetscSpace scalar_space;
1963 PetscDualSpace scalar_dspace;
1964 PetscFE scalar_fe;
1965
1966 PetscCall(PetscSpaceSumGetSubspace(P, 0, &scalar_space));
1967 PetscCall(PetscDualSpaceSumGetSubspace(Q, 0, &scalar_dspace));
1968 PetscCall(PetscObjectReference((PetscObject)scalar_space));
1969 PetscCall(PetscObjectReference((PetscObject)scalar_dspace));
1970 PetscCall(PetscObjectReference((PetscObject)q));
1971 PetscCall(PetscObjectReference((PetscObject)fq));
1972 PetscCall(PetscFECreateFromSpaces(scalar_space, scalar_dspace, q, fq, &scalar_fe));
1973 PetscCall(PetscFECreateVector(scalar_fe, p_Ns, p_interleave_basis, p_interleave_components, fem));
1974 PetscCall(PetscFEDestroy(&scalar_fe));
1975 } else {
1976 PetscCall(PetscFECreate(PetscObjectComm((PetscObject)P), fem));
1977 PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
1978 }
1979 PetscCall(PetscSpaceGetNumComponents(P, &Nc));
1980 PetscCall(PetscFESetNumComponents(*fem, Nc));
1981 PetscCall(PetscFESetBasisSpace(*fem, P));
1982 PetscCall(PetscFESetDualSpace(*fem, Q));
1983 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)P, &prefix));
1984 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
1985 PetscCall(PetscFESetUp(*fem));
1986 PetscCall(PetscSpaceDestroy(&P));
1987 PetscCall(PetscDualSpaceDestroy(&Q));
1988 PetscCall(PetscFESetQuadrature(*fem, q));
1989 PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1990 PetscCall(PetscQuadratureDestroy(&q));
1991 PetscCall(PetscQuadratureDestroy(&fq));
1992 PetscCall(PetscFESetDefaultName_Private(*fem));
1993 PetscFunctionReturn(PETSC_SUCCESS);
1994 }
1995
PetscFECreate_Internal(MPI_Comm comm,PetscInt dim,PetscInt Nc,DMPolytopeType ct,const char prefix[],PetscInt degree,PetscInt qorder,PetscBool setFromOptions,PetscFE * fem)1996 static PetscErrorCode PetscFECreate_Internal(MPI_Comm comm, PetscInt dim, PetscInt Nc, DMPolytopeType ct, const char prefix[], PetscInt degree, PetscInt qorder, PetscBool setFromOptions, PetscFE *fem)
1997 {
1998 DM K;
1999 PetscSpace P;
2000 PetscDualSpace Q;
2001 PetscQuadrature q, fq;
2002 PetscBool tensor;
2003
2004 PetscFunctionBegin;
2005 if (prefix) PetscAssertPointer(prefix, 5);
2006 PetscAssertPointer(fem, 9);
2007 switch (ct) {
2008 case DM_POLYTOPE_SEGMENT:
2009 case DM_POLYTOPE_POINT_PRISM_TENSOR:
2010 case DM_POLYTOPE_QUADRILATERAL:
2011 case DM_POLYTOPE_SEG_PRISM_TENSOR:
2012 case DM_POLYTOPE_HEXAHEDRON:
2013 case DM_POLYTOPE_QUAD_PRISM_TENSOR:
2014 tensor = PETSC_TRUE;
2015 break;
2016 default:
2017 tensor = PETSC_FALSE;
2018 }
2019 /* Create space */
2020 PetscCall(PetscSpaceCreate(comm, &P));
2021 PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
2022 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
2023 PetscCall(PetscSpacePolynomialSetTensor(P, tensor));
2024 PetscCall(PetscSpaceSetNumComponents(P, Nc));
2025 PetscCall(PetscSpaceSetNumVariables(P, dim));
2026 if (degree >= 0) {
2027 PetscCall(PetscSpaceSetDegree(P, degree, PETSC_DETERMINE));
2028 if (ct == DM_POLYTOPE_TRI_PRISM || ct == DM_POLYTOPE_TRI_PRISM_TENSOR) {
2029 PetscSpace Pend, Pside;
2030
2031 PetscCall(PetscSpaceSetNumComponents(P, 1));
2032 PetscCall(PetscSpaceCreate(comm, &Pend));
2033 PetscCall(PetscSpaceSetType(Pend, PETSCSPACEPOLYNOMIAL));
2034 PetscCall(PetscSpacePolynomialSetTensor(Pend, PETSC_FALSE));
2035 PetscCall(PetscSpaceSetNumComponents(Pend, 1));
2036 PetscCall(PetscSpaceSetNumVariables(Pend, dim - 1));
2037 PetscCall(PetscSpaceSetDegree(Pend, degree, PETSC_DETERMINE));
2038 PetscCall(PetscSpaceCreate(comm, &Pside));
2039 PetscCall(PetscSpaceSetType(Pside, PETSCSPACEPOLYNOMIAL));
2040 PetscCall(PetscSpacePolynomialSetTensor(Pside, PETSC_FALSE));
2041 PetscCall(PetscSpaceSetNumComponents(Pside, 1));
2042 PetscCall(PetscSpaceSetNumVariables(Pside, 1));
2043 PetscCall(PetscSpaceSetDegree(Pside, degree, PETSC_DETERMINE));
2044 PetscCall(PetscSpaceSetType(P, PETSCSPACETENSOR));
2045 PetscCall(PetscSpaceTensorSetNumSubspaces(P, 2));
2046 PetscCall(PetscSpaceTensorSetSubspace(P, 0, Pend));
2047 PetscCall(PetscSpaceTensorSetSubspace(P, 1, Pside));
2048 PetscCall(PetscSpaceDestroy(&Pend));
2049 PetscCall(PetscSpaceDestroy(&Pside));
2050
2051 if (Nc > 1) {
2052 PetscSpace scalar_P = P;
2053
2054 PetscCall(PetscSpaceCreate(comm, &P));
2055 PetscCall(PetscSpaceSetNumVariables(P, dim));
2056 PetscCall(PetscSpaceSetNumComponents(P, Nc));
2057 PetscCall(PetscSpaceSetType(P, PETSCSPACESUM));
2058 PetscCall(PetscSpaceSumSetNumSubspaces(P, Nc));
2059 PetscCall(PetscSpaceSumSetConcatenate(P, PETSC_TRUE));
2060 PetscCall(PetscSpaceSumSetInterleave(P, PETSC_TRUE, PETSC_FALSE));
2061 for (PetscInt i = 0; i < Nc; i++) PetscCall(PetscSpaceSumSetSubspace(P, i, scalar_P));
2062 PetscCall(PetscSpaceDestroy(&scalar_P));
2063 }
2064 }
2065 }
2066 if (setFromOptions) PetscCall(PetscSpaceSetFromOptions(P));
2067 PetscCall(PetscSpaceSetUp(P));
2068 PetscCall(PetscSpaceGetDegree(P, °ree, NULL));
2069 PetscCall(PetscSpacePolynomialGetTensor(P, &tensor));
2070 PetscCall(PetscSpaceGetNumComponents(P, &Nc));
2071 /* Create dual space */
2072 PetscCall(PetscDualSpaceCreate(comm, &Q));
2073 PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
2074 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
2075 PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &K));
2076 PetscCall(PetscDualSpaceSetDM(Q, K));
2077 PetscCall(DMDestroy(&K));
2078 PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
2079 PetscCall(PetscDualSpaceSetOrder(Q, degree));
2080 PetscCall(PetscDualSpaceLagrangeSetTensor(Q, (tensor || (ct == DM_POLYTOPE_TRI_PRISM)) ? PETSC_TRUE : PETSC_FALSE));
2081 if (setFromOptions) PetscCall(PetscDualSpaceSetFromOptions(Q));
2082 PetscCall(PetscDualSpaceSetUp(Q));
2083 /* Create quadrature */
2084 PetscDTSimplexQuadratureType qtype = PETSCDTSIMPLEXQUAD_DEFAULT;
2085
2086 qorder = qorder >= 0 ? qorder : degree;
2087 if (setFromOptions) {
2088 PetscObjectOptionsBegin((PetscObject)P);
2089 PetscCall(PetscOptionsBoundedInt("-petscfe_default_quadrature_order", "Quadrature order is one less than quadrature points per edge", "PetscFECreateDefault", qorder, &qorder, NULL, 0));
2090 PetscCall(PetscOptionsEnum("-petscfe_default_quadrature_type", "Simplex quadrature type", "PetscDTSimplexQuadratureType", PetscDTSimplexQuadratureTypes, (PetscEnum)qtype, (PetscEnum *)&qtype, NULL));
2091 PetscOptionsEnd();
2092 }
2093 PetscCall(PetscDTCreateQuadratureByCell(ct, qorder, qtype, &q, &fq));
2094 /* Create finite element */
2095 PetscCall(PetscFECreateFromSpaces(P, Q, q, fq, fem));
2096 if (setFromOptions) PetscCall(PetscFESetFromOptions(*fem));
2097 PetscFunctionReturn(PETSC_SUCCESS);
2098 }
2099
2100 /*@
2101 PetscFECreateDefault - Create a `PetscFE` for basic FEM computation
2102
2103 Collective
2104
2105 Input Parameters:
2106 + comm - The MPI comm
2107 . dim - The spatial dimension
2108 . Nc - The number of components
2109 . isSimplex - Flag for simplex reference cell, otherwise its a tensor product
2110 . prefix - The options prefix, or `NULL`
2111 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
2112
2113 Output Parameter:
2114 . fem - The `PetscFE` object
2115
2116 Level: beginner
2117
2118 Note:
2119 Each subobject is SetFromOption() during creation, so that the object may be customized from the command line, using the prefix specified above. See the links below for the particular options available.
2120
2121 .seealso: `PetscFECreateLagrange()`, `PetscFECreateByCell()`, `PetscSpaceSetFromOptions()`, `PetscDualSpaceSetFromOptions()`, `PetscFESetFromOptions()`, `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
2122 @*/
PetscFECreateDefault(MPI_Comm comm,PetscInt dim,PetscInt Nc,PetscBool isSimplex,const char prefix[],PetscInt qorder,PetscFE * fem)2123 PetscErrorCode PetscFECreateDefault(MPI_Comm comm, PetscInt dim, PetscInt Nc, PetscBool isSimplex, const char prefix[], PetscInt qorder, PetscFE *fem)
2124 {
2125 PetscFunctionBegin;
2126 PetscCall(PetscFECreate_Internal(comm, dim, Nc, DMPolytopeTypeSimpleShape(dim, isSimplex), prefix, PETSC_DECIDE, qorder, PETSC_TRUE, fem));
2127 PetscFunctionReturn(PETSC_SUCCESS);
2128 }
2129
2130 /*@
2131 PetscFECreateByCell - Create a `PetscFE` for basic FEM computation
2132
2133 Collective
2134
2135 Input Parameters:
2136 + comm - The MPI comm
2137 . dim - The spatial dimension
2138 . Nc - The number of components
2139 . ct - The celltype of the reference cell
2140 . prefix - The options prefix, or `NULL`
2141 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
2142
2143 Output Parameter:
2144 . fem - The `PetscFE` object
2145
2146 Level: beginner
2147
2148 Note:
2149 Each subobject is SetFromOption() during creation, so that the object may be customized from the command line, using the prefix specified above. See the links below for the particular options available.
2150
2151 .seealso: `PetscFECreateDefault()`, `PetscFECreateLagrange()`, `PetscSpaceSetFromOptions()`, `PetscDualSpaceSetFromOptions()`, `PetscFESetFromOptions()`, `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
2152 @*/
PetscFECreateByCell(MPI_Comm comm,PetscInt dim,PetscInt Nc,DMPolytopeType ct,const char prefix[],PetscInt qorder,PetscFE * fem)2153 PetscErrorCode PetscFECreateByCell(MPI_Comm comm, PetscInt dim, PetscInt Nc, DMPolytopeType ct, const char prefix[], PetscInt qorder, PetscFE *fem)
2154 {
2155 PetscFunctionBegin;
2156 PetscCall(PetscFECreate_Internal(comm, dim, Nc, ct, prefix, PETSC_DECIDE, qorder, PETSC_TRUE, fem));
2157 PetscFunctionReturn(PETSC_SUCCESS);
2158 }
2159
2160 /*@
2161 PetscFECreateLagrange - Create a `PetscFE` for the basic Lagrange space of degree k
2162
2163 Collective
2164
2165 Input Parameters:
2166 + comm - The MPI comm
2167 . dim - The spatial dimension
2168 . Nc - The number of components
2169 . isSimplex - Flag for simplex reference cell, otherwise its a tensor product
2170 . k - The degree k of the space
2171 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
2172
2173 Output Parameter:
2174 . fem - The `PetscFE` object
2175
2176 Level: beginner
2177
2178 Note:
2179 For simplices, this element is the space of maximum polynomial degree k, otherwise it is a tensor product of 1D polynomials, each with maximal degree k.
2180
2181 .seealso: `PetscFECreateLagrangeByCell()`, `PetscFECreateDefault()`, `PetscFECreateByCell()`, `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
2182 @*/
PetscFECreateLagrange(MPI_Comm comm,PetscInt dim,PetscInt Nc,PetscBool isSimplex,PetscInt k,PetscInt qorder,PetscFE * fem)2183 PetscErrorCode PetscFECreateLagrange(MPI_Comm comm, PetscInt dim, PetscInt Nc, PetscBool isSimplex, PetscInt k, PetscInt qorder, PetscFE *fem)
2184 {
2185 PetscFunctionBegin;
2186 PetscCall(PetscFECreate_Internal(comm, dim, Nc, DMPolytopeTypeSimpleShape(dim, isSimplex), NULL, k, qorder, PETSC_FALSE, fem));
2187 PetscFunctionReturn(PETSC_SUCCESS);
2188 }
2189
2190 /*@
2191 PetscFECreateLagrangeByCell - Create a `PetscFE` for the basic Lagrange space of degree k
2192
2193 Collective
2194
2195 Input Parameters:
2196 + comm - The MPI comm
2197 . dim - The spatial dimension
2198 . Nc - The number of components
2199 . ct - The celltype of the reference cell
2200 . k - The degree k of the space
2201 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
2202
2203 Output Parameter:
2204 . fem - The `PetscFE` object
2205
2206 Level: beginner
2207
2208 Note:
2209 For simplices, this element is the space of maximum polynomial degree k, otherwise it is a tensor product of 1D polynomials, each with maximal degree k.
2210
2211 .seealso: `PetscFECreateLagrange()`, `PetscFECreateDefault()`, `PetscFECreateByCell()`, `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
2212 @*/
PetscFECreateLagrangeByCell(MPI_Comm comm,PetscInt dim,PetscInt Nc,DMPolytopeType ct,PetscInt k,PetscInt qorder,PetscFE * fem)2213 PetscErrorCode PetscFECreateLagrangeByCell(MPI_Comm comm, PetscInt dim, PetscInt Nc, DMPolytopeType ct, PetscInt k, PetscInt qorder, PetscFE *fem)
2214 {
2215 PetscFunctionBegin;
2216 PetscCall(PetscFECreate_Internal(comm, dim, Nc, ct, NULL, k, qorder, PETSC_FALSE, fem));
2217 PetscFunctionReturn(PETSC_SUCCESS);
2218 }
2219
2220 /*@
2221 PetscFELimitDegree - Copy a `PetscFE` but limit the degree to be in the given range
2222
2223 Collective
2224
2225 Input Parameters:
2226 + fe - The `PetscFE`
2227 . minDegree - The minimum degree, or `PETSC_DETERMINE` for no limit
2228 - maxDegree - The maximum degree, or `PETSC_DETERMINE` for no limit
2229
2230 Output Parameter:
2231 . newfe - The `PetscFE` object
2232
2233 Level: advanced
2234
2235 Note:
2236 This currently only works for Lagrange elements.
2237
2238 .seealso: `PetscFECreateLagrange()`, `PetscFECreateDefault()`, `PetscFECreateByCell()`, `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
2239 @*/
PetscFELimitDegree(PetscFE fe,PetscInt minDegree,PetscInt maxDegree,PetscFE * newfe)2240 PetscErrorCode PetscFELimitDegree(PetscFE fe, PetscInt minDegree, PetscInt maxDegree, PetscFE *newfe)
2241 {
2242 PetscDualSpace Q;
2243 PetscBool islag, issum;
2244 PetscInt oldk = 0, k;
2245
2246 PetscFunctionBegin;
2247 PetscCall(PetscFEGetDualSpace(fe, &Q));
2248 PetscCall(PetscObjectTypeCompare((PetscObject)Q, PETSCDUALSPACELAGRANGE, &islag));
2249 PetscCall(PetscObjectTypeCompare((PetscObject)Q, PETSCDUALSPACESUM, &issum));
2250 if (islag) {
2251 PetscCall(PetscDualSpaceGetOrder(Q, &oldk));
2252 } else if (issum) {
2253 PetscDualSpace subQ;
2254
2255 PetscCall(PetscDualSpaceSumGetSubspace(Q, 0, &subQ));
2256 PetscCall(PetscDualSpaceGetOrder(subQ, &oldk));
2257 } else {
2258 PetscCall(PetscObjectReference((PetscObject)fe));
2259 *newfe = fe;
2260 PetscFunctionReturn(PETSC_SUCCESS);
2261 }
2262 k = oldk;
2263 if (minDegree >= 0) k = PetscMax(k, minDegree);
2264 if (maxDegree >= 0) k = PetscMin(k, maxDegree);
2265 if (k != oldk) {
2266 DM K;
2267 PetscSpace P;
2268 PetscQuadrature q;
2269 DMPolytopeType ct;
2270 PetscInt dim, Nc;
2271
2272 PetscCall(PetscFEGetBasisSpace(fe, &P));
2273 PetscCall(PetscSpaceGetNumVariables(P, &dim));
2274 PetscCall(PetscSpaceGetNumComponents(P, &Nc));
2275 PetscCall(PetscDualSpaceGetDM(Q, &K));
2276 PetscCall(DMPlexGetCellType(K, 0, &ct));
2277 PetscCall(PetscFECreateLagrangeByCell(PetscObjectComm((PetscObject)fe), dim, Nc, ct, k, PETSC_DETERMINE, newfe));
2278 PetscCall(PetscFEGetQuadrature(fe, &q));
2279 PetscCall(PetscFESetQuadrature(*newfe, q));
2280 } else {
2281 PetscCall(PetscObjectReference((PetscObject)fe));
2282 *newfe = fe;
2283 }
2284 PetscFunctionReturn(PETSC_SUCCESS);
2285 }
2286
2287 /*@
2288 PetscFECreateBrokenElement - Create a discontinuous version of the input `PetscFE`
2289
2290 Collective
2291
2292 Input Parameters:
2293 . cgfe - The continuous `PetscFE` object
2294
2295 Output Parameter:
2296 . dgfe - The discontinuous `PetscFE` object
2297
2298 Level: advanced
2299
2300 Note:
2301 This only works for Lagrange elements.
2302
2303 .seealso: `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`, `PetscFECreateLagrange()`, `PetscFECreateLagrangeByCell()`, `PetscDualSpaceLagrangeSetContinuity()`
2304 @*/
PetscFECreateBrokenElement(PetscFE cgfe,PetscFE * dgfe)2305 PetscErrorCode PetscFECreateBrokenElement(PetscFE cgfe, PetscFE *dgfe)
2306 {
2307 PetscSpace P;
2308 PetscDualSpace Q, dgQ;
2309 PetscQuadrature q, fq;
2310 PetscBool is_lagrange, is_sum;
2311
2312 PetscFunctionBegin;
2313 PetscCall(PetscFEGetBasisSpace(cgfe, &P));
2314 PetscCall(PetscObjectReference((PetscObject)P));
2315 PetscCall(PetscFEGetDualSpace(cgfe, &Q));
2316 PetscCall(PetscObjectTypeCompare((PetscObject)Q, PETSCDUALSPACELAGRANGE, &is_lagrange));
2317 PetscCall(PetscObjectTypeCompare((PetscObject)Q, PETSCDUALSPACESUM, &is_sum));
2318 PetscCheck(is_lagrange || is_sum, PETSC_COMM_SELF, PETSC_ERR_SUP, "Can only create broken elements of Lagrange elements");
2319 PetscCall(PetscDualSpaceDuplicate(Q, &dgQ));
2320 PetscCall(PetscDualSpaceLagrangeSetContinuity(dgQ, PETSC_FALSE));
2321 PetscCall(PetscDualSpaceSetUp(dgQ));
2322 PetscCall(PetscFEGetQuadrature(cgfe, &q));
2323 PetscCall(PetscObjectReference((PetscObject)q));
2324 PetscCall(PetscFEGetFaceQuadrature(cgfe, &fq));
2325 PetscCall(PetscObjectReference((PetscObject)fq));
2326 PetscCall(PetscFECreateFromSpaces(P, dgQ, q, fq, dgfe));
2327 PetscFunctionReturn(PETSC_SUCCESS);
2328 }
2329
2330 /*@
2331 PetscFESetName - Names the `PetscFE` and its subobjects
2332
2333 Not Collective
2334
2335 Input Parameters:
2336 + fe - The `PetscFE`
2337 - name - The name
2338
2339 Level: intermediate
2340
2341 .seealso: `PetscFECreate()`, `PetscSpaceCreate()`, `PetscDualSpaceCreate()`
2342 @*/
PetscFESetName(PetscFE fe,const char name[])2343 PetscErrorCode PetscFESetName(PetscFE fe, const char name[])
2344 {
2345 PetscSpace P;
2346 PetscDualSpace Q;
2347
2348 PetscFunctionBegin;
2349 PetscCall(PetscFEGetBasisSpace(fe, &P));
2350 PetscCall(PetscFEGetDualSpace(fe, &Q));
2351 PetscCall(PetscObjectSetName((PetscObject)fe, name));
2352 PetscCall(PetscObjectSetName((PetscObject)P, name));
2353 PetscCall(PetscObjectSetName((PetscObject)Q, name));
2354 PetscFunctionReturn(PETSC_SUCCESS);
2355 }
2356
PetscFEEvaluateFieldJets_Internal(PetscDS ds,PetscInt Nf,PetscInt r,PetscInt q,PetscTabulation T[],PetscFEGeom * fegeom,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscScalar u[],PetscScalar u_x[],PetscScalar u_t[])2357 PetscErrorCode PetscFEEvaluateFieldJets_Internal(PetscDS ds, PetscInt Nf, PetscInt r, PetscInt q, PetscTabulation T[], PetscFEGeom *fegeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscScalar u[], PetscScalar u_x[], PetscScalar u_t[])
2358 {
2359 PetscInt dOffset = 0, fOffset = 0, f, g;
2360
2361 for (f = 0; f < Nf; ++f) {
2362 PetscCheck(r < T[f]->Nr, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ")", r, T[f]->Nr);
2363 PetscCheck(q < T[f]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ")", q, T[f]->Np);
2364 PetscFE fe;
2365 const PetscInt k = ds->jetDegree[f];
2366 const PetscInt cdim = T[f]->cdim;
2367 const PetscInt dE = fegeom->dimEmbed;
2368 const PetscInt Nq = T[f]->Np;
2369 const PetscInt Nbf = T[f]->Nb;
2370 const PetscInt Ncf = T[f]->Nc;
2371 const PetscReal *Bq = &T[f]->T[0][(r * Nq + q) * Nbf * Ncf];
2372 const PetscReal *Dq = &T[f]->T[1][(r * Nq + q) * Nbf * Ncf * cdim];
2373 const PetscReal *Hq = k > 1 ? &T[f]->T[2][(r * Nq + q) * Nbf * Ncf * cdim * cdim] : NULL;
2374 PetscInt hOffset = 0, b, c, d;
2375
2376 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe));
2377 for (c = 0; c < Ncf; ++c) u[fOffset + c] = 0.0;
2378 for (d = 0; d < dE * Ncf; ++d) u_x[fOffset * dE + d] = 0.0;
2379 for (b = 0; b < Nbf; ++b) {
2380 for (c = 0; c < Ncf; ++c) {
2381 const PetscInt cidx = b * Ncf + c;
2382
2383 u[fOffset + c] += Bq[cidx] * coefficients[dOffset + b];
2384 for (d = 0; d < cdim; ++d) u_x[(fOffset + c) * dE + d] += Dq[cidx * cdim + d] * coefficients[dOffset + b];
2385 }
2386 }
2387 if (k > 1) {
2388 for (g = 0; g < Nf; ++g) hOffset += T[g]->Nc * dE;
2389 for (d = 0; d < dE * dE * Ncf; ++d) u_x[hOffset + fOffset * dE * dE + d] = 0.0;
2390 for (b = 0; b < Nbf; ++b) {
2391 for (c = 0; c < Ncf; ++c) {
2392 const PetscInt cidx = b * Ncf + c;
2393
2394 for (d = 0; d < cdim * cdim; ++d) u_x[hOffset + (fOffset + c) * dE * dE + d] += Hq[cidx * cdim * cdim + d] * coefficients[dOffset + b];
2395 }
2396 }
2397 PetscCall(PetscFEPushforwardHessian(fe, fegeom, 1, &u_x[hOffset + fOffset * dE * dE]));
2398 }
2399 PetscCall(PetscFEPushforward(fe, fegeom, 1, &u[fOffset]));
2400 PetscCall(PetscFEPushforwardGradient(fe, fegeom, 1, &u_x[fOffset * dE]));
2401 if (u_t) {
2402 for (c = 0; c < Ncf; ++c) u_t[fOffset + c] = 0.0;
2403 for (b = 0; b < Nbf; ++b) {
2404 for (c = 0; c < Ncf; ++c) {
2405 const PetscInt cidx = b * Ncf + c;
2406
2407 u_t[fOffset + c] += Bq[cidx] * coefficients_t[dOffset + b];
2408 }
2409 }
2410 PetscCall(PetscFEPushforward(fe, fegeom, 1, &u_t[fOffset]));
2411 }
2412 fOffset += Ncf;
2413 dOffset += Nbf;
2414 }
2415 return PETSC_SUCCESS;
2416 }
2417
PetscFEEvaluateFieldJets_Hybrid_Internal(PetscDS ds,PetscInt Nf,PetscInt rc,PetscInt qc,PetscTabulation Tab[],const PetscInt rf[],const PetscInt qf[],PetscTabulation Tabf[],PetscFEGeom * fegeom,PetscFEGeom * fegeomNbr,const PetscScalar coefficients[],const PetscScalar coefficients_t[],PetscScalar u[],PetscScalar u_x[],PetscScalar u_t[])2418 PetscErrorCode PetscFEEvaluateFieldJets_Hybrid_Internal(PetscDS ds, PetscInt Nf, PetscInt rc, PetscInt qc, PetscTabulation Tab[], const PetscInt rf[], const PetscInt qf[], PetscTabulation Tabf[], PetscFEGeom *fegeom, PetscFEGeom *fegeomNbr, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscScalar u[], PetscScalar u_x[], PetscScalar u_t[])
2419 {
2420 PetscInt dOffset = 0, fOffset = 0, f;
2421
2422 /* f is the field number in the DS */
2423 for (f = 0; f < Nf; ++f) {
2424 PetscBool isCohesive;
2425 PetscInt Ns, s;
2426
2427 if (!Tab[f]) continue;
2428 PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
2429 Ns = isCohesive ? 1 : 2;
2430 {
2431 PetscTabulation T = isCohesive ? Tab[f] : Tabf[f];
2432 PetscFE fe = (PetscFE)ds->disc[f];
2433 const PetscInt dEt = T->cdim;
2434 const PetscInt dE = fegeom->dimEmbed;
2435 const PetscInt Nq = T->Np;
2436 const PetscInt Nbf = T->Nb;
2437 const PetscInt Ncf = T->Nc;
2438
2439 for (s = 0; s < Ns; ++s) {
2440 const PetscInt r = isCohesive ? rc : rf[s];
2441 const PetscInt q = isCohesive ? qc : qf[s];
2442 const PetscReal *Bq = &T->T[0][(r * Nq + q) * Nbf * Ncf];
2443 const PetscReal *Dq = &T->T[1][(r * Nq + q) * Nbf * Ncf * dEt];
2444 PetscInt b, c, d;
2445
2446 PetscCheck(r < T->Nr, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " Side %" PetscInt_FMT " Replica number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ")", f, s, r, T->Nr);
2447 PetscCheck(q < T->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " Side %" PetscInt_FMT " Point number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ")", f, s, q, T->Np);
2448 for (c = 0; c < Ncf; ++c) u[fOffset + c] = 0.0;
2449 for (d = 0; d < dE * Ncf; ++d) u_x[fOffset * dE + d] = 0.0;
2450 for (b = 0; b < Nbf; ++b) {
2451 for (c = 0; c < Ncf; ++c) {
2452 const PetscInt cidx = b * Ncf + c;
2453
2454 u[fOffset + c] += Bq[cidx] * coefficients[dOffset + b];
2455 for (d = 0; d < dEt; ++d) u_x[(fOffset + c) * dE + d] += Dq[cidx * dEt + d] * coefficients[dOffset + b];
2456 }
2457 }
2458 PetscCall(PetscFEPushforward(fe, isCohesive ? fegeom : &fegeomNbr[s], 1, &u[fOffset]));
2459 PetscCall(PetscFEPushforwardGradient(fe, isCohesive ? fegeom : &fegeomNbr[s], 1, &u_x[fOffset * dE]));
2460 if (u_t) {
2461 for (c = 0; c < Ncf; ++c) u_t[fOffset + c] = 0.0;
2462 for (b = 0; b < Nbf; ++b) {
2463 for (c = 0; c < Ncf; ++c) {
2464 const PetscInt cidx = b * Ncf + c;
2465
2466 u_t[fOffset + c] += Bq[cidx] * coefficients_t[dOffset + b];
2467 }
2468 }
2469 PetscCall(PetscFEPushforward(fe, fegeom, 1, &u_t[fOffset]));
2470 }
2471 fOffset += Ncf;
2472 dOffset += Nbf;
2473 }
2474 }
2475 }
2476 return PETSC_SUCCESS;
2477 }
2478
PetscFEEvaluateFaceFields_Internal(PetscDS prob,PetscInt field,PetscInt faceLoc,const PetscScalar coefficients[],PetscScalar u[])2479 PetscErrorCode PetscFEEvaluateFaceFields_Internal(PetscDS prob, PetscInt field, PetscInt faceLoc, const PetscScalar coefficients[], PetscScalar u[])
2480 {
2481 PetscFE fe;
2482 PetscTabulation Tc;
2483 PetscInt b, c;
2484
2485 if (!prob) return PETSC_SUCCESS;
2486 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe));
2487 PetscCall(PetscFEGetFaceCentroidTabulation(fe, &Tc));
2488 {
2489 const PetscReal *faceBasis = Tc->T[0];
2490 const PetscInt Nb = Tc->Nb;
2491 const PetscInt Nc = Tc->Nc;
2492
2493 for (c = 0; c < Nc; ++c) u[c] = 0.0;
2494 for (b = 0; b < Nb; ++b) {
2495 for (c = 0; c < Nc; ++c) u[c] += coefficients[b] * faceBasis[(faceLoc * Nb + b) * Nc + c];
2496 }
2497 }
2498 return PETSC_SUCCESS;
2499 }
2500
PetscFEUpdateElementVec_Internal(PetscFE fe,PetscTabulation T,PetscInt r,PetscScalar tmpBasis[],PetscScalar tmpBasisDer[],PetscInt e,PetscFEGeom * fegeom,PetscScalar f0[],PetscScalar f1[],PetscScalar elemVec[])2501 PetscErrorCode PetscFEUpdateElementVec_Internal(PetscFE fe, PetscTabulation T, PetscInt r, PetscScalar tmpBasis[], PetscScalar tmpBasisDer[], PetscInt e, PetscFEGeom *fegeom, PetscScalar f0[], PetscScalar f1[], PetscScalar elemVec[])
2502 {
2503 PetscFEGeom pgeom;
2504 const PetscInt dEt = T->cdim;
2505 const PetscInt dE = fegeom->dimEmbed;
2506 const PetscInt Nq = T->Np;
2507 const PetscInt Nb = T->Nb;
2508 const PetscInt Nc = T->Nc;
2509 const PetscReal *basis = &T->T[0][r * Nq * Nb * Nc];
2510 const PetscReal *basisDer = &T->T[1][r * Nq * Nb * Nc * dEt];
2511 PetscInt q, b, c, d;
2512
2513 for (q = 0; q < Nq; ++q) {
2514 for (b = 0; b < Nb; ++b) {
2515 for (c = 0; c < Nc; ++c) {
2516 const PetscInt bcidx = b * Nc + c;
2517
2518 tmpBasis[bcidx] = basis[q * Nb * Nc + bcidx];
2519 for (d = 0; d < dEt; ++d) tmpBasisDer[bcidx * dE + d] = basisDer[q * Nb * Nc * dEt + bcidx * dEt + d];
2520 for (d = dEt; d < dE; ++d) tmpBasisDer[bcidx * dE + d] = 0.0;
2521 }
2522 }
2523 PetscCall(PetscFEGeomGetCellPoint(fegeom, e, q, &pgeom));
2524 PetscCall(PetscFEPushforward(fe, &pgeom, Nb, tmpBasis));
2525 PetscCall(PetscFEPushforwardGradient(fe, &pgeom, Nb, tmpBasisDer));
2526 for (b = 0; b < Nb; ++b) {
2527 for (c = 0; c < Nc; ++c) {
2528 const PetscInt bcidx = b * Nc + c;
2529 const PetscInt qcidx = q * Nc + c;
2530
2531 elemVec[b] += tmpBasis[bcidx] * f0[qcidx];
2532 for (d = 0; d < dE; ++d) elemVec[b] += tmpBasisDer[bcidx * dE + d] * f1[qcidx * dE + d];
2533 }
2534 }
2535 }
2536 return PETSC_SUCCESS;
2537 }
2538
PetscFEUpdateElementVec_Hybrid_Internal(PetscFE fe,PetscTabulation T,PetscInt r,PetscInt side,PetscScalar tmpBasis[],PetscScalar tmpBasisDer[],PetscFEGeom * fegeom,PetscScalar f0[],PetscScalar f1[],PetscScalar elemVec[])2539 PetscErrorCode PetscFEUpdateElementVec_Hybrid_Internal(PetscFE fe, PetscTabulation T, PetscInt r, PetscInt side, PetscScalar tmpBasis[], PetscScalar tmpBasisDer[], PetscFEGeom *fegeom, PetscScalar f0[], PetscScalar f1[], PetscScalar elemVec[])
2540 {
2541 const PetscInt dE = T->cdim;
2542 const PetscInt Nq = T->Np;
2543 const PetscInt Nb = T->Nb;
2544 const PetscInt Nc = T->Nc;
2545 const PetscReal *basis = &T->T[0][r * Nq * Nb * Nc];
2546 const PetscReal *basisDer = &T->T[1][r * Nq * Nb * Nc * dE];
2547
2548 for (PetscInt q = 0; q < Nq; ++q) {
2549 for (PetscInt b = 0; b < Nb; ++b) {
2550 for (PetscInt c = 0; c < Nc; ++c) {
2551 const PetscInt bcidx = b * Nc + c;
2552
2553 tmpBasis[bcidx] = basis[q * Nb * Nc + bcidx];
2554 for (PetscInt d = 0; d < dE; ++d) tmpBasisDer[bcidx * dE + d] = basisDer[q * Nb * Nc * dE + bcidx * dE + d];
2555 }
2556 }
2557 PetscCall(PetscFEPushforward(fe, fegeom, Nb, tmpBasis));
2558 // TODO This is currently broken since we do not pull the geometry down to the lower dimension
2559 // PetscCall(PetscFEPushforwardGradient(fe, fegeom, Nb, tmpBasisDer));
2560 if (side == 2) {
2561 // Integrating over whole cohesive cell, so insert for both sides
2562 for (PetscInt s = 0; s < 2; ++s) {
2563 for (PetscInt b = 0; b < Nb; ++b) {
2564 for (PetscInt c = 0; c < Nc; ++c) {
2565 const PetscInt bcidx = b * Nc + c;
2566 const PetscInt qcidx = (q * 2 + s) * Nc + c;
2567
2568 elemVec[Nb * s + b] += tmpBasis[bcidx] * f0[qcidx];
2569 for (PetscInt d = 0; d < dE; ++d) elemVec[Nb * s + b] += tmpBasisDer[bcidx * dE + d] * f1[qcidx * dE + d];
2570 }
2571 }
2572 }
2573 } else {
2574 // Integrating over endcaps of cohesive cell, so insert for correct side
2575 for (PetscInt b = 0; b < Nb; ++b) {
2576 for (PetscInt c = 0; c < Nc; ++c) {
2577 const PetscInt bcidx = b * Nc + c;
2578 const PetscInt qcidx = q * Nc + c;
2579
2580 elemVec[Nb * side + b] += tmpBasis[bcidx] * f0[qcidx];
2581 for (PetscInt d = 0; d < dE; ++d) elemVec[Nb * side + b] += tmpBasisDer[bcidx * dE + d] * f1[qcidx * dE + d];
2582 }
2583 }
2584 }
2585 }
2586 return PETSC_SUCCESS;
2587 }
2588
2589 #define petsc_elemmat_kernel_g1(_NbI, _NcI, _NbJ, _NcJ, _dE) \
2590 do { \
2591 for (PetscInt fc = 0; fc < (_NcI); ++fc) { \
2592 for (PetscInt gc = 0; gc < (_NcJ); ++gc) { \
2593 const PetscScalar *G = g1 + (fc * (_NcJ) + gc) * _dE; \
2594 for (PetscInt f = 0; f < (_NbI); ++f) { \
2595 const PetscScalar tBIv = tmpBasisI[f * (_NcI) + fc]; \
2596 for (PetscInt g = 0; g < (_NbJ); ++g) { \
2597 const PetscScalar *tBDJ = tmpBasisDerJ + (g * (_NcJ) + gc) * (_dE); \
2598 PetscScalar s = 0.0; \
2599 for (PetscInt df = 0; df < _dE; ++df) s += G[df] * tBDJ[df]; \
2600 elemMat[(offsetI + f) * totDim + (offsetJ + g)] += s * tBIv; \
2601 } \
2602 } \
2603 } \
2604 } \
2605 } while (0)
2606
2607 #define petsc_elemmat_kernel_g2(_NbI, _NcI, _NbJ, _NcJ, _dE) \
2608 do { \
2609 for (PetscInt gc = 0; gc < (_NcJ); ++gc) { \
2610 for (PetscInt fc = 0; fc < (_NcI); ++fc) { \
2611 const PetscScalar *G = g2 + (fc * (_NcJ) + gc) * _dE; \
2612 for (PetscInt g = 0; g < (_NbJ); ++g) { \
2613 const PetscScalar tBJv = tmpBasisJ[g * (_NcJ) + gc]; \
2614 for (PetscInt f = 0; f < (_NbI); ++f) { \
2615 const PetscScalar *tBDI = tmpBasisDerI + (f * (_NcI) + fc) * (_dE); \
2616 PetscScalar s = 0.0; \
2617 for (PetscInt df = 0; df < _dE; ++df) s += tBDI[df] * G[df]; \
2618 elemMat[(offsetI + f) * totDim + (offsetJ + g)] += s * tBJv; \
2619 } \
2620 } \
2621 } \
2622 } \
2623 } while (0)
2624
2625 #define petsc_elemmat_kernel_g3(_NbI, _NcI, _NbJ, _NcJ, _dE) \
2626 do { \
2627 for (PetscInt fc = 0; fc < (_NcI); ++fc) { \
2628 for (PetscInt gc = 0; gc < (_NcJ); ++gc) { \
2629 const PetscScalar *G = g3 + (fc * (_NcJ) + gc) * (_dE) * (_dE); \
2630 for (PetscInt f = 0; f < (_NbI); ++f) { \
2631 const PetscScalar *tBDI = tmpBasisDerI + (f * (_NcI) + fc) * (_dE); \
2632 for (PetscInt g = 0; g < (_NbJ); ++g) { \
2633 PetscScalar s = 0.0; \
2634 const PetscScalar *tBDJ = tmpBasisDerJ + (g * (_NcJ) + gc) * (_dE); \
2635 for (PetscInt df = 0; df < (_dE); ++df) { \
2636 for (PetscInt dg = 0; dg < (_dE); ++dg) s += tBDI[df] * G[df * (_dE) + dg] * tBDJ[dg]; \
2637 } \
2638 elemMat[(offsetI + f) * totDim + (offsetJ + g)] += s; \
2639 } \
2640 } \
2641 } \
2642 } \
2643 } while (0)
2644
PetscFEUpdateElementMat_Internal(PetscFE feI,PetscFE feJ,PetscInt r,PetscInt q,PetscTabulation TI,PetscScalar tmpBasisI[],PetscScalar tmpBasisDerI[],PetscTabulation TJ,PetscScalar tmpBasisJ[],PetscScalar tmpBasisDerJ[],PetscFEGeom * fegeom,const PetscScalar g0[],const PetscScalar g1[],const PetscScalar g2[],const PetscScalar g3[],PetscInt totDim,PetscInt offsetI,PetscInt offsetJ,PetscScalar elemMat[])2645 PetscErrorCode PetscFEUpdateElementMat_Internal(PetscFE feI, PetscFE feJ, PetscInt r, PetscInt q, PetscTabulation TI, PetscScalar tmpBasisI[], PetscScalar tmpBasisDerI[], PetscTabulation TJ, PetscScalar tmpBasisJ[], PetscScalar tmpBasisDerJ[], PetscFEGeom *fegeom, const PetscScalar g0[], const PetscScalar g1[], const PetscScalar g2[], const PetscScalar g3[], PetscInt totDim, PetscInt offsetI, PetscInt offsetJ, PetscScalar elemMat[])
2646 {
2647 const PetscInt cdim = TI->cdim;
2648 const PetscInt dE = fegeom->dimEmbed;
2649 const PetscInt NqI = TI->Np;
2650 const PetscInt NbI = TI->Nb;
2651 const PetscInt NcI = TI->Nc;
2652 const PetscReal *basisI = &TI->T[0][(r * NqI + q) * NbI * NcI];
2653 const PetscReal *basisDerI = &TI->T[1][(r * NqI + q) * NbI * NcI * cdim];
2654 const PetscInt NqJ = TJ->Np;
2655 const PetscInt NbJ = TJ->Nb;
2656 const PetscInt NcJ = TJ->Nc;
2657 const PetscReal *basisJ = &TJ->T[0][(r * NqJ + q) * NbJ * NcJ];
2658 const PetscReal *basisDerJ = &TJ->T[1][(r * NqJ + q) * NbJ * NcJ * cdim];
2659
2660 for (PetscInt f = 0; f < NbI; ++f) {
2661 for (PetscInt fc = 0; fc < NcI; ++fc) {
2662 const PetscInt fidx = f * NcI + fc; /* Test function basis index */
2663
2664 tmpBasisI[fidx] = basisI[fidx];
2665 for (PetscInt df = 0; df < cdim; ++df) tmpBasisDerI[fidx * dE + df] = basisDerI[fidx * cdim + df];
2666 }
2667 }
2668 PetscCall(PetscFEPushforward(feI, fegeom, NbI, tmpBasisI));
2669 PetscCall(PetscFEPushforwardGradient(feI, fegeom, NbI, tmpBasisDerI));
2670 if (feI != feJ) {
2671 for (PetscInt g = 0; g < NbJ; ++g) {
2672 for (PetscInt gc = 0; gc < NcJ; ++gc) {
2673 const PetscInt gidx = g * NcJ + gc; /* Trial function basis index */
2674
2675 tmpBasisJ[gidx] = basisJ[gidx];
2676 for (PetscInt dg = 0; dg < cdim; ++dg) tmpBasisDerJ[gidx * dE + dg] = basisDerJ[gidx * cdim + dg];
2677 }
2678 }
2679 PetscCall(PetscFEPushforward(feJ, fegeom, NbJ, tmpBasisJ));
2680 PetscCall(PetscFEPushforwardGradient(feJ, fegeom, NbJ, tmpBasisDerJ));
2681 } else {
2682 tmpBasisJ = tmpBasisI;
2683 tmpBasisDerJ = tmpBasisDerI;
2684 }
2685 if (PetscUnlikely(g0)) {
2686 for (PetscInt f = 0; f < NbI; ++f) {
2687 const PetscInt i = offsetI + f; /* Element matrix row */
2688
2689 for (PetscInt fc = 0; fc < NcI; ++fc) {
2690 const PetscScalar bI = tmpBasisI[f * NcI + fc]; /* Test function basis value */
2691
2692 for (PetscInt g = 0; g < NbJ; ++g) {
2693 const PetscInt j = offsetJ + g; /* Element matrix column */
2694 const PetscInt fOff = i * totDim + j;
2695
2696 for (PetscInt gc = 0; gc < NcJ; ++gc) elemMat[fOff] += bI * g0[fc * NcJ + gc] * tmpBasisJ[g * NcJ + gc];
2697 }
2698 }
2699 }
2700 }
2701 if (PetscUnlikely(g1)) {
2702 #if 1
2703 if (dE == 2) {
2704 petsc_elemmat_kernel_g1(NbI, NcI, NbJ, NcJ, 2);
2705 } else if (dE == 3) {
2706 petsc_elemmat_kernel_g1(NbI, NcI, NbJ, NcJ, 3);
2707 } else {
2708 petsc_elemmat_kernel_g1(NbI, NcI, NbJ, NcJ, dE);
2709 }
2710 #else
2711 for (PetscInt f = 0; f < NbI; ++f) {
2712 const PetscInt i = offsetI + f; /* Element matrix row */
2713
2714 for (PetscInt fc = 0; fc < NcI; ++fc) {
2715 const PetscScalar bI = tmpBasisI[f * NcI + fc]; /* Test function basis value */
2716
2717 for (PetscInt g = 0; g < NbJ; ++g) {
2718 const PetscInt j = offsetJ + g; /* Element matrix column */
2719 const PetscInt fOff = i * totDim + j;
2720
2721 for (PetscInt gc = 0; gc < NcJ; ++gc) {
2722 const PetscInt gidx = g * NcJ + gc; /* Trial function basis index */
2723
2724 for (PetscInt df = 0; df < dE; ++df) elemMat[fOff] += bI * g1[(fc * NcJ + gc) * dE + df] * tmpBasisDerJ[gidx * dE + df];
2725 }
2726 }
2727 }
2728 }
2729 #endif
2730 }
2731 if (PetscUnlikely(g2)) {
2732 #if 1
2733 if (dE == 2) {
2734 petsc_elemmat_kernel_g2(NbI, NcI, NbJ, NcJ, 2);
2735 } else if (dE == 3) {
2736 petsc_elemmat_kernel_g2(NbI, NcI, NbJ, NcJ, 3);
2737 } else {
2738 petsc_elemmat_kernel_g2(NbI, NcI, NbJ, NcJ, dE);
2739 }
2740 #else
2741 for (PetscInt g = 0; g < NbJ; ++g) {
2742 const PetscInt j = offsetJ + g; /* Element matrix column */
2743
2744 for (PetscInt gc = 0; gc < NcJ; ++gc) {
2745 const PetscScalar bJ = tmpBasisJ[g * NcJ + gc]; /* Trial function basis value */
2746
2747 for (PetscInt f = 0; f < NbI; ++f) {
2748 const PetscInt i = offsetI + f; /* Element matrix row */
2749 const PetscInt fOff = i * totDim + j;
2750
2751 for (PetscInt fc = 0; fc < NcI; ++fc) {
2752 const PetscInt fidx = f * NcI + fc; /* Test function basis index */
2753
2754 for (PetscInt df = 0; df < dE; ++df) elemMat[fOff] += tmpBasisDerI[fidx * dE + df] * g2[(fc * NcJ + gc) * dE + df] * bJ;
2755 }
2756 }
2757 }
2758 }
2759 #endif
2760 }
2761 if (PetscUnlikely(g3)) {
2762 #if 1
2763 if (dE == 2) {
2764 petsc_elemmat_kernel_g3(NbI, NcI, NbJ, NcJ, 2);
2765 } else if (dE == 3) {
2766 petsc_elemmat_kernel_g3(NbI, NcI, NbJ, NcJ, 3);
2767 } else {
2768 petsc_elemmat_kernel_g3(NbI, NcI, NbJ, NcJ, dE);
2769 }
2770 #else
2771 for (PetscInt f = 0; f < NbI; ++f) {
2772 const PetscInt i = offsetI + f; /* Element matrix row */
2773
2774 for (PetscInt fc = 0; fc < NcI; ++fc) {
2775 const PetscInt fidx = f * NcI + fc; /* Test function basis index */
2776
2777 for (PetscInt g = 0; g < NbJ; ++g) {
2778 const PetscInt j = offsetJ + g; /* Element matrix column */
2779 const PetscInt fOff = i * totDim + j;
2780
2781 for (PetscInt gc = 0; gc < NcJ; ++gc) {
2782 const PetscInt gidx = g * NcJ + gc; /* Trial function basis index */
2783
2784 for (PetscInt df = 0; df < dE; ++df) {
2785 for (PetscInt dg = 0; dg < dE; ++dg) elemMat[fOff] += tmpBasisDerI[fidx * dE + df] * g3[((fc * NcJ + gc) * dE + df) * dE + dg] * tmpBasisDerJ[gidx * dE + dg];
2786 }
2787 }
2788 }
2789 }
2790 }
2791 #endif
2792 }
2793 return PETSC_SUCCESS;
2794 }
2795
2796 #undef petsc_elemmat_kernel_g1
2797 #undef petsc_elemmat_kernel_g2
2798 #undef petsc_elemmat_kernel_g3
2799
PetscFEUpdateElementMat_Hybrid_Internal(PetscFE feI,PetscBool isHybridI,PetscFE feJ,PetscBool isHybridJ,PetscInt r,PetscInt s,PetscInt t,PetscInt q,PetscTabulation TI,PetscScalar tmpBasisI[],PetscScalar tmpBasisDerI[],PetscTabulation TJ,PetscScalar tmpBasisJ[],PetscScalar tmpBasisDerJ[],PetscFEGeom * fegeom,const PetscScalar g0[],const PetscScalar g1[],const PetscScalar g2[],const PetscScalar g3[],PetscInt eOffset,PetscInt totDim,PetscInt offsetI,PetscInt offsetJ,PetscScalar elemMat[])2800 PetscErrorCode PetscFEUpdateElementMat_Hybrid_Internal(PetscFE feI, PetscBool isHybridI, PetscFE feJ, PetscBool isHybridJ, PetscInt r, PetscInt s, PetscInt t, PetscInt q, PetscTabulation TI, PetscScalar tmpBasisI[], PetscScalar tmpBasisDerI[], PetscTabulation TJ, PetscScalar tmpBasisJ[], PetscScalar tmpBasisDerJ[], PetscFEGeom *fegeom, const PetscScalar g0[], const PetscScalar g1[], const PetscScalar g2[], const PetscScalar g3[], PetscInt eOffset, PetscInt totDim, PetscInt offsetI, PetscInt offsetJ, PetscScalar elemMat[])
2801 {
2802 const PetscInt dE = TI->cdim;
2803 const PetscInt NqI = TI->Np;
2804 const PetscInt NbI = TI->Nb;
2805 const PetscInt NcI = TI->Nc;
2806 const PetscReal *basisI = &TI->T[0][(r * NqI + q) * NbI * NcI];
2807 const PetscReal *basisDerI = &TI->T[1][(r * NqI + q) * NbI * NcI * dE];
2808 const PetscInt NqJ = TJ->Np;
2809 const PetscInt NbJ = TJ->Nb;
2810 const PetscInt NcJ = TJ->Nc;
2811 const PetscReal *basisJ = &TJ->T[0][(r * NqJ + q) * NbJ * NcJ];
2812 const PetscReal *basisDerJ = &TJ->T[1][(r * NqJ + q) * NbJ * NcJ * dE];
2813 const PetscInt so = isHybridI ? 0 : s;
2814 const PetscInt to = isHybridJ ? 0 : t;
2815 PetscInt f, fc, g, gc, df, dg;
2816
2817 for (f = 0; f < NbI; ++f) {
2818 for (fc = 0; fc < NcI; ++fc) {
2819 const PetscInt fidx = f * NcI + fc; /* Test function basis index */
2820
2821 tmpBasisI[fidx] = basisI[fidx];
2822 for (df = 0; df < dE; ++df) tmpBasisDerI[fidx * dE + df] = basisDerI[fidx * dE + df];
2823 }
2824 }
2825 PetscCall(PetscFEPushforward(feI, fegeom, NbI, tmpBasisI));
2826 PetscCall(PetscFEPushforwardGradient(feI, fegeom, NbI, tmpBasisDerI));
2827 for (g = 0; g < NbJ; ++g) {
2828 for (gc = 0; gc < NcJ; ++gc) {
2829 const PetscInt gidx = g * NcJ + gc; /* Trial function basis index */
2830
2831 tmpBasisJ[gidx] = basisJ[gidx];
2832 for (dg = 0; dg < dE; ++dg) tmpBasisDerJ[gidx * dE + dg] = basisDerJ[gidx * dE + dg];
2833 }
2834 }
2835 PetscCall(PetscFEPushforward(feJ, fegeom, NbJ, tmpBasisJ));
2836 // TODO This is currently broken since we do not pull the geometry down to the lower dimension
2837 // PetscCall(PetscFEPushforwardGradient(feJ, fegeom, NbJ, tmpBasisDerJ));
2838 for (f = 0; f < NbI; ++f) {
2839 for (fc = 0; fc < NcI; ++fc) {
2840 const PetscInt fidx = f * NcI + fc; /* Test function basis index */
2841 const PetscInt i = offsetI + NbI * so + f; /* Element matrix row */
2842 for (g = 0; g < NbJ; ++g) {
2843 for (gc = 0; gc < NcJ; ++gc) {
2844 const PetscInt gidx = g * NcJ + gc; /* Trial function basis index */
2845 const PetscInt j = offsetJ + NbJ * to + g; /* Element matrix column */
2846 const PetscInt fOff = eOffset + i * totDim + j;
2847
2848 elemMat[fOff] += tmpBasisI[fidx] * g0[fc * NcJ + gc] * tmpBasisJ[gidx];
2849 for (df = 0; df < dE; ++df) {
2850 elemMat[fOff] += tmpBasisI[fidx] * g1[(fc * NcJ + gc) * dE + df] * tmpBasisDerJ[gidx * dE + df];
2851 elemMat[fOff] += tmpBasisDerI[fidx * dE + df] * g2[(fc * NcJ + gc) * dE + df] * tmpBasisJ[gidx];
2852 for (dg = 0; dg < dE; ++dg) elemMat[fOff] += tmpBasisDerI[fidx * dE + df] * g3[((fc * NcJ + gc) * dE + df) * dE + dg] * tmpBasisDerJ[gidx * dE + dg];
2853 }
2854 }
2855 }
2856 }
2857 }
2858 return PETSC_SUCCESS;
2859 }
2860
PetscFECreateCellGeometry(PetscFE fe,PetscQuadrature quad,PetscFEGeom * cgeom)2861 PetscErrorCode PetscFECreateCellGeometry(PetscFE fe, PetscQuadrature quad, PetscFEGeom *cgeom)
2862 {
2863 PetscDualSpace dsp;
2864 DM dm;
2865 PetscQuadrature quadDef;
2866 PetscInt dim, cdim, Nq;
2867
2868 PetscFunctionBegin;
2869 PetscCall(PetscFEGetDualSpace(fe, &dsp));
2870 PetscCall(PetscDualSpaceGetDM(dsp, &dm));
2871 PetscCall(DMGetDimension(dm, &dim));
2872 PetscCall(DMGetCoordinateDim(dm, &cdim));
2873 PetscCall(PetscFEGetQuadrature(fe, &quadDef));
2874 quad = quad ? quad : quadDef;
2875 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
2876 PetscCall(PetscMalloc1(Nq * cdim, &cgeom->v));
2877 PetscCall(PetscMalloc1(Nq * cdim * cdim, &cgeom->J));
2878 PetscCall(PetscMalloc1(Nq * cdim * cdim, &cgeom->invJ));
2879 PetscCall(PetscMalloc1(Nq, &cgeom->detJ));
2880 cgeom->dim = dim;
2881 cgeom->dimEmbed = cdim;
2882 cgeom->numCells = 1;
2883 cgeom->numPoints = Nq;
2884 PetscCall(DMPlexComputeCellGeometryFEM(dm, 0, quad, cgeom->v, cgeom->J, cgeom->invJ, cgeom->detJ));
2885 PetscFunctionReturn(PETSC_SUCCESS);
2886 }
2887
PetscFEDestroyCellGeometry(PetscFE fe,PetscFEGeom * cgeom)2888 PetscErrorCode PetscFEDestroyCellGeometry(PetscFE fe, PetscFEGeom *cgeom)
2889 {
2890 PetscFunctionBegin;
2891 PetscCall(PetscFree(cgeom->v));
2892 PetscCall(PetscFree(cgeom->J));
2893 PetscCall(PetscFree(cgeom->invJ));
2894 PetscCall(PetscFree(cgeom->detJ));
2895 PetscFunctionReturn(PETSC_SUCCESS);
2896 }
2897
2898 #if 0
2899 PetscErrorCode PetscFEUpdateElementMat_Internal_SparseIndices(PetscTabulation TI, PetscTabulation TJ, PetscInt dimEmbed, const PetscInt g0[], const PetscInt g1[], const PetscInt g2[], const PetscInt g3[], PetscInt totDim, PetscInt offsetI, PetscInt offsetJ, PetscInt *n_g0, PetscInt **g0_idxs_out, PetscInt *n_g1, PetscInt **g1_idxs_out, PetscInt *n_g2, PetscInt **g2_idxs_out, PetscInt *n_g3, PetscInt **g3_idxs_out)
2900 {
2901 const PetscInt dE = dimEmbed;
2902 const PetscInt NbI = TI->Nb;
2903 const PetscInt NcI = TI->Nc;
2904 const PetscInt NbJ = TJ->Nb;
2905 const PetscInt NcJ = TJ->Nc;
2906 PetscBool has_g0 = g0 ? PETSC_TRUE : PETSC_FALSE;
2907 PetscBool has_g1 = g1 ? PETSC_TRUE : PETSC_FALSE;
2908 PetscBool has_g2 = g2 ? PETSC_TRUE : PETSC_FALSE;
2909 PetscBool has_g3 = g3 ? PETSC_TRUE : PETSC_FALSE;
2910 PetscInt *g0_idxs = NULL, *g1_idxs = NULL, *g2_idxs = NULL, *g3_idxs = NULL;
2911 PetscInt g0_i, g1_i, g2_i, g3_i;
2912
2913 PetscFunctionBegin;
2914 g0_i = g1_i = g2_i = g3_i = 0;
2915 if (has_g0)
2916 for (PetscInt i = 0; i < NcI * NcJ; i++)
2917 if (g0[i]) g0_i += NbI * NbJ;
2918 if (has_g1)
2919 for (PetscInt i = 0; i < NcI * NcJ * dE; i++)
2920 if (g1[i]) g1_i += NbI * NbJ;
2921 if (has_g2)
2922 for (PetscInt i = 0; i < NcI * NcJ * dE; i++)
2923 if (g2[i]) g2_i += NbI * NbJ;
2924 if (has_g3)
2925 for (PetscInt i = 0; i < NcI * NcJ * dE * dE; i++)
2926 if (g3[i]) g3_i += NbI * NbJ;
2927 if (g0_i == NbI * NbJ * NcI * NcJ) g0_i = 0;
2928 if (g1_i == NbI * NbJ * NcI * NcJ * dE) g1_i = 0;
2929 if (g2_i == NbI * NbJ * NcI * NcJ * dE) g2_i = 0;
2930 if (g3_i == NbI * NbJ * NcI * NcJ * dE * dE) g3_i = 0;
2931 has_g0 = g0_i ? PETSC_TRUE : PETSC_FALSE;
2932 has_g1 = g1_i ? PETSC_TRUE : PETSC_FALSE;
2933 has_g2 = g2_i ? PETSC_TRUE : PETSC_FALSE;
2934 has_g3 = g3_i ? PETSC_TRUE : PETSC_FALSE;
2935 if (has_g0) PetscCall(PetscMalloc1(4 * g0_i, &g0_idxs));
2936 if (has_g1) PetscCall(PetscMalloc1(4 * g1_i, &g1_idxs));
2937 if (has_g2) PetscCall(PetscMalloc1(4 * g2_i, &g2_idxs));
2938 if (has_g3) PetscCall(PetscMalloc1(4 * g3_i, &g3_idxs));
2939 g0_i = g1_i = g2_i = g3_i = 0;
2940
2941 for (PetscInt f = 0; f < NbI; ++f) {
2942 const PetscInt i = offsetI + f; /* Element matrix row */
2943 for (PetscInt fc = 0; fc < NcI; ++fc) {
2944 const PetscInt fidx = f * NcI + fc; /* Test function basis index */
2945
2946 for (PetscInt g = 0; g < NbJ; ++g) {
2947 const PetscInt j = offsetJ + g; /* Element matrix column */
2948 const PetscInt fOff = i * totDim + j;
2949 for (PetscInt gc = 0; gc < NcJ; ++gc) {
2950 const PetscInt gidx = g * NcJ + gc; /* Trial function basis index */
2951
2952 if (has_g0) {
2953 if (g0[fc * NcJ + gc]) {
2954 g0_idxs[4 * g0_i + 0] = fidx;
2955 g0_idxs[4 * g0_i + 1] = fc * NcJ + gc;
2956 g0_idxs[4 * g0_i + 2] = gidx;
2957 g0_idxs[4 * g0_i + 3] = fOff;
2958 g0_i++;
2959 }
2960 }
2961
2962 for (PetscInt df = 0; df < dE; ++df) {
2963 if (has_g1) {
2964 if (g1[(fc * NcJ + gc) * dE + df]) {
2965 g1_idxs[4 * g1_i + 0] = fidx;
2966 g1_idxs[4 * g1_i + 1] = (fc * NcJ + gc) * dE + df;
2967 g1_idxs[4 * g1_i + 2] = gidx * dE + df;
2968 g1_idxs[4 * g1_i + 3] = fOff;
2969 g1_i++;
2970 }
2971 }
2972 if (has_g2) {
2973 if (g2[(fc * NcJ + gc) * dE + df]) {
2974 g2_idxs[4 * g2_i + 0] = fidx * dE + df;
2975 g2_idxs[4 * g2_i + 1] = (fc * NcJ + gc) * dE + df;
2976 g2_idxs[4 * g2_i + 2] = gidx;
2977 g2_idxs[4 * g2_i + 3] = fOff;
2978 g2_i++;
2979 }
2980 }
2981 if (has_g3) {
2982 for (PetscInt dg = 0; dg < dE; ++dg) {
2983 if (g3[((fc * NcJ + gc) * dE + df) * dE + dg]) {
2984 g3_idxs[4 * g3_i + 0] = fidx * dE + df;
2985 g3_idxs[4 * g3_i + 1] = ((fc * NcJ + gc) * dE + df) * dE + dg;
2986 g3_idxs[4 * g3_i + 2] = gidx * dE + dg;
2987 g3_idxs[4 * g3_i + 3] = fOff;
2988 g3_i++;
2989 }
2990 }
2991 }
2992 }
2993 }
2994 }
2995 }
2996 }
2997 *n_g0 = g0_i;
2998 *n_g1 = g1_i;
2999 *n_g2 = g2_i;
3000 *n_g3 = g3_i;
3001
3002 *g0_idxs_out = g0_idxs;
3003 *g1_idxs_out = g1_idxs;
3004 *g2_idxs_out = g2_idxs;
3005 *g3_idxs_out = g3_idxs;
3006 PetscFunctionReturn(PETSC_SUCCESS);
3007 }
3008
3009 //example HOW TO USE
3010 for (PetscInt i = 0; i < g0_sparse_n; i++) {
3011 PetscInt bM = g0_sparse_idxs[4 * i + 0];
3012 PetscInt bN = g0_sparse_idxs[4 * i + 1];
3013 PetscInt bK = g0_sparse_idxs[4 * i + 2];
3014 PetscInt bO = g0_sparse_idxs[4 * i + 3];
3015 elemMat[bO] += tmpBasisI[bM] * g0[bN] * tmpBasisJ[bK];
3016 }
3017 #endif
3018