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