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