1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/ 2 #include <petscdmplex.h> 3 4 PetscClassId PETSCDUALSPACE_CLASSID = 0; 5 6 PetscFunctionList PetscDualSpaceList = NULL; 7 PetscBool PetscDualSpaceRegisterAllCalled = PETSC_FALSE; 8 9 const char *const PetscDualSpaceReferenceCells[] = {"SIMPLEX", "TENSOR", "PetscDualSpaceReferenceCell", "PETSCDUALSPACE_REFCELL_",0}; 10 11 /* 12 PetscDualSpaceLatticePointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to at most 'max'. 13 Ordering is lexicographic with lowest index as least significant in ordering. 14 e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,0}. 15 16 Input Parameters: 17 + len - The length of the tuple 18 . max - The maximum sum 19 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition 20 21 Output Parameter: 22 . tup - A tuple of len integers whos sum is at most 'max' 23 24 Level: developer 25 26 .seealso: PetscDualSpaceTensorPointLexicographic_Internal() 27 */ 28 PetscErrorCode PetscDualSpaceLatticePointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[]) 29 { 30 PetscFunctionBegin; 31 while (len--) { 32 max -= tup[len]; 33 if (!max) { 34 tup[len] = 0; 35 break; 36 } 37 } 38 tup[++len]++; 39 PetscFunctionReturn(0); 40 } 41 42 /* 43 PetscDualSpaceTensorPointLexicographic_Internal - Returns all tuples of size 'len' with nonnegative integers that are all less than or equal to 'max'. 44 Ordering is lexicographic with lowest index as least significant in ordering. 45 e.g. for len == 2 and max == 2, this will return, in order, {0,0}, {1,0}, {2,0}, {0,1}, {1,1}, {2,1}, {0,2}, {1,2}, {2,2}. 46 47 Input Parameters: 48 + len - The length of the tuple 49 . max - The maximum value 50 - tup - A tuple of length len+1: tup[len] > 0 indicates a stopping condition 51 52 Output Parameter: 53 . tup - A tuple of len integers whos sum is at most 'max' 54 55 Level: developer 56 57 .seealso: PetscDualSpaceLatticePointLexicographic_Internal() 58 */ 59 PetscErrorCode PetscDualSpaceTensorPointLexicographic_Internal(PetscInt len, PetscInt max, PetscInt tup[]) 60 { 61 PetscInt i; 62 63 PetscFunctionBegin; 64 for (i = 0; i < len; i++) { 65 if (tup[i] < max) { 66 break; 67 } else { 68 tup[i] = 0; 69 } 70 } 71 tup[i]++; 72 PetscFunctionReturn(0); 73 } 74 75 /*@C 76 PetscDualSpaceRegister - Adds a new PetscDualSpace implementation 77 78 Not Collective 79 80 Input Parameters: 81 + name - The name of a new user-defined creation routine 82 - create_func - The creation routine itself 83 84 Notes: 85 PetscDualSpaceRegister() may be called multiple times to add several user-defined PetscDualSpaces 86 87 Sample usage: 88 .vb 89 PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate); 90 .ve 91 92 Then, your PetscDualSpace type can be chosen with the procedural interface via 93 .vb 94 PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *); 95 PetscDualSpaceSetType(PetscDualSpace, "my_dual_space"); 96 .ve 97 or at runtime via the option 98 .vb 99 -petscdualspace_type my_dual_space 100 .ve 101 102 Level: advanced 103 104 .keywords: PetscDualSpace, register 105 .seealso: PetscDualSpaceRegisterAll(), PetscDualSpaceRegisterDestroy() 106 107 @*/ 108 PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace)) 109 { 110 PetscErrorCode ierr; 111 112 PetscFunctionBegin; 113 ierr = PetscFunctionListAdd(&PetscDualSpaceList, sname, function);CHKERRQ(ierr); 114 PetscFunctionReturn(0); 115 } 116 117 /*@C 118 PetscDualSpaceSetType - Builds a particular PetscDualSpace 119 120 Collective on PetscDualSpace 121 122 Input Parameters: 123 + sp - The PetscDualSpace object 124 - name - The kind of space 125 126 Options Database Key: 127 . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types 128 129 Level: intermediate 130 131 .keywords: PetscDualSpace, set, type 132 .seealso: PetscDualSpaceGetType(), PetscDualSpaceCreate() 133 @*/ 134 PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name) 135 { 136 PetscErrorCode (*r)(PetscDualSpace); 137 PetscBool match; 138 PetscErrorCode ierr; 139 140 PetscFunctionBegin; 141 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 142 ierr = PetscObjectTypeCompare((PetscObject) sp, name, &match);CHKERRQ(ierr); 143 if (match) PetscFunctionReturn(0); 144 145 if (!PetscDualSpaceRegisterAllCalled) {ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr);} 146 ierr = PetscFunctionListFind(PetscDualSpaceList, name, &r);CHKERRQ(ierr); 147 if (!r) SETERRQ1(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name); 148 149 if (sp->ops->destroy) { 150 ierr = (*sp->ops->destroy)(sp);CHKERRQ(ierr); 151 sp->ops->destroy = NULL; 152 } 153 ierr = (*r)(sp);CHKERRQ(ierr); 154 ierr = PetscObjectChangeTypeName((PetscObject) sp, name);CHKERRQ(ierr); 155 PetscFunctionReturn(0); 156 } 157 158 /*@C 159 PetscDualSpaceGetType - Gets the PetscDualSpace type name (as a string) from the object. 160 161 Not Collective 162 163 Input Parameter: 164 . sp - The PetscDualSpace 165 166 Output Parameter: 167 . name - The PetscDualSpace type name 168 169 Level: intermediate 170 171 .keywords: PetscDualSpace, get, type, name 172 .seealso: PetscDualSpaceSetType(), PetscDualSpaceCreate() 173 @*/ 174 PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name) 175 { 176 PetscErrorCode ierr; 177 178 PetscFunctionBegin; 179 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 180 PetscValidPointer(name, 2); 181 if (!PetscDualSpaceRegisterAllCalled) { 182 ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr); 183 } 184 *name = ((PetscObject) sp)->type_name; 185 PetscFunctionReturn(0); 186 } 187 188 static PetscErrorCode PetscDualSpaceView_ASCII(PetscDualSpace sp, PetscViewer v) 189 { 190 PetscViewerFormat format; 191 PetscInt pdim, f; 192 PetscErrorCode ierr; 193 194 PetscFunctionBegin; 195 ierr = PetscDualSpaceGetDimension(sp, &pdim);CHKERRQ(ierr); 196 ierr = PetscObjectPrintClassNamePrefixType((PetscObject) sp, v);CHKERRQ(ierr); 197 ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr); 198 ierr = PetscViewerASCIIPrintf(v, "Dual space with %D components, size %D\n", sp->Nc, pdim);CHKERRQ(ierr); 199 if (sp->ops->view) {ierr = (*sp->ops->view)(sp, v);CHKERRQ(ierr);} 200 ierr = PetscViewerGetFormat(v, &format);CHKERRQ(ierr); 201 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 202 ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr); 203 for (f = 0; f < pdim; ++f) { 204 ierr = PetscViewerASCIIPrintf(v, "Dual basis vector %D\n", f);CHKERRQ(ierr); 205 ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr); 206 ierr = PetscQuadratureView(sp->functional[f], v);CHKERRQ(ierr); 207 ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr); 208 } 209 ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr); 210 } 211 ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr); 212 PetscFunctionReturn(0); 213 } 214 215 /*@ 216 PetscDualSpaceView - Views a PetscDualSpace 217 218 Collective on PetscDualSpace 219 220 Input Parameter: 221 + sp - the PetscDualSpace object to view 222 - v - the viewer 223 224 Level: developer 225 226 .seealso PetscDualSpaceDestroy() 227 @*/ 228 PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v) 229 { 230 PetscBool iascii; 231 PetscErrorCode ierr; 232 233 PetscFunctionBegin; 234 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 235 if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2); 236 if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) sp), &v);CHKERRQ(ierr);} 237 ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 238 if (iascii) {ierr = PetscDualSpaceView_ASCII(sp, v);CHKERRQ(ierr);} 239 PetscFunctionReturn(0); 240 } 241 242 /*@ 243 PetscDualSpaceSetFromOptions - sets parameters in a PetscDualSpace from the options database 244 245 Collective on PetscDualSpace 246 247 Input Parameter: 248 . sp - the PetscDualSpace object to set options for 249 250 Options Database: 251 . -petscspace_degree the approximation order of the space 252 253 Level: developer 254 255 .seealso PetscDualSpaceView() 256 @*/ 257 PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp) 258 { 259 PetscDualSpaceReferenceCell refCell = PETSCDUALSPACE_REFCELL_SIMPLEX; 260 PetscInt refDim = 0; 261 PetscBool flg; 262 const char *defaultType; 263 char name[256]; 264 PetscErrorCode ierr; 265 266 PetscFunctionBegin; 267 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 268 if (!((PetscObject) sp)->type_name) { 269 defaultType = PETSCDUALSPACELAGRANGE; 270 } else { 271 defaultType = ((PetscObject) sp)->type_name; 272 } 273 if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);} 274 275 ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr); 276 ierr = PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg);CHKERRQ(ierr); 277 if (flg) { 278 ierr = PetscDualSpaceSetType(sp, name);CHKERRQ(ierr); 279 } else if (!((PetscObject) sp)->type_name) { 280 ierr = PetscDualSpaceSetType(sp, defaultType);CHKERRQ(ierr); 281 } 282 ierr = PetscOptionsInt("-petscdualspace_degree", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL);CHKERRQ(ierr); 283 ierr = PetscOptionsInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL);CHKERRQ(ierr); 284 if (sp->ops->setfromoptions) { 285 ierr = (*sp->ops->setfromoptions)(PetscOptionsObject,sp);CHKERRQ(ierr); 286 } 287 ierr = PetscOptionsInt("-petscdualspace_refdim", "The spatial dimension of the reference cell", "PetscDualSpaceSetReferenceCell", refDim, &refDim, NULL);CHKERRQ(ierr); 288 ierr = PetscOptionsEnum("-petscdualspace_refcell", "Reference cell", "PetscDualSpaceSetReferenceCell", PetscDualSpaceReferenceCells, (PetscEnum) refCell, (PetscEnum *) &refCell, &flg);CHKERRQ(ierr); 289 if (flg) { 290 DM K; 291 292 if (!refDim) SETERRQ(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_INCOMP, "Reference cell specified without a dimension. Use -petscdualspace_refdim."); 293 ierr = PetscDualSpaceCreateReferenceCell(sp, refDim, refCell == PETSCDUALSPACE_REFCELL_SIMPLEX ? PETSC_TRUE : PETSC_FALSE, &K);CHKERRQ(ierr); 294 ierr = PetscDualSpaceSetDM(sp, K);CHKERRQ(ierr); 295 ierr = DMDestroy(&K);CHKERRQ(ierr); 296 } 297 298 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 299 ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) sp);CHKERRQ(ierr); 300 ierr = PetscOptionsEnd();CHKERRQ(ierr); 301 sp->setfromoptionscalled = PETSC_TRUE; 302 PetscFunctionReturn(0); 303 } 304 305 /*@ 306 PetscDualSpaceSetUp - Construct a basis for the PetscDualSpace 307 308 Collective on PetscDualSpace 309 310 Input Parameter: 311 . sp - the PetscDualSpace object to setup 312 313 Level: developer 314 315 .seealso PetscDualSpaceView(), PetscDualSpaceDestroy() 316 @*/ 317 PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp) 318 { 319 PetscErrorCode ierr; 320 321 PetscFunctionBegin; 322 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 323 if (sp->setupcalled) PetscFunctionReturn(0); 324 sp->setupcalled = PETSC_TRUE; 325 if (sp->ops->setup) {ierr = (*sp->ops->setup)(sp);CHKERRQ(ierr);} 326 if (sp->setfromoptionscalled) {ierr = PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view");CHKERRQ(ierr);} 327 PetscFunctionReturn(0); 328 } 329 330 /*@ 331 PetscDualSpaceDestroy - Destroys a PetscDualSpace object 332 333 Collective on PetscDualSpace 334 335 Input Parameter: 336 . sp - the PetscDualSpace object to destroy 337 338 Level: developer 339 340 .seealso PetscDualSpaceView() 341 @*/ 342 PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp) 343 { 344 PetscInt dim, f; 345 PetscErrorCode ierr; 346 347 PetscFunctionBegin; 348 if (!*sp) PetscFunctionReturn(0); 349 PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1); 350 351 if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} 352 ((PetscObject) (*sp))->refct = 0; 353 354 ierr = PetscDualSpaceGetDimension(*sp, &dim);CHKERRQ(ierr); 355 for (f = 0; f < dim; ++f) { 356 ierr = PetscQuadratureDestroy(&(*sp)->functional[f]);CHKERRQ(ierr); 357 } 358 ierr = PetscFree((*sp)->functional);CHKERRQ(ierr); 359 ierr = PetscQuadratureDestroy(&(*sp)->allPoints);CHKERRQ(ierr); 360 ierr = DMDestroy(&(*sp)->dm);CHKERRQ(ierr); 361 362 if ((*sp)->ops->destroy) {ierr = (*(*sp)->ops->destroy)(*sp);CHKERRQ(ierr);} 363 ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); 364 PetscFunctionReturn(0); 365 } 366 367 /*@ 368 PetscDualSpaceCreate - Creates an empty PetscDualSpace object. The type can then be set with PetscDualSpaceSetType(). 369 370 Collective on MPI_Comm 371 372 Input Parameter: 373 . comm - The communicator for the PetscDualSpace object 374 375 Output Parameter: 376 . sp - The PetscDualSpace object 377 378 Level: beginner 379 380 .seealso: PetscDualSpaceSetType(), PETSCDUALSPACELAGRANGE 381 @*/ 382 PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp) 383 { 384 PetscDualSpace s; 385 PetscErrorCode ierr; 386 387 PetscFunctionBegin; 388 PetscValidPointer(sp, 2); 389 ierr = PetscCitationsRegister(FECitation,&FEcite);CHKERRQ(ierr); 390 *sp = NULL; 391 ierr = PetscFEInitializePackage();CHKERRQ(ierr); 392 393 ierr = PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView);CHKERRQ(ierr); 394 395 s->order = 0; 396 s->Nc = 1; 397 s->k = 0; 398 s->setupcalled = PETSC_FALSE; 399 400 *sp = s; 401 PetscFunctionReturn(0); 402 } 403 404 /*@ 405 PetscDualSpaceDuplicate - Creates a duplicate PetscDualSpace object, however it is not setup. 406 407 Collective on PetscDualSpace 408 409 Input Parameter: 410 . sp - The original PetscDualSpace 411 412 Output Parameter: 413 . spNew - The duplicate PetscDualSpace 414 415 Level: beginner 416 417 .seealso: PetscDualSpaceCreate(), PetscDualSpaceSetType() 418 @*/ 419 PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew) 420 { 421 PetscErrorCode ierr; 422 423 PetscFunctionBegin; 424 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 425 PetscValidPointer(spNew, 2); 426 ierr = (*sp->ops->duplicate)(sp, spNew);CHKERRQ(ierr); 427 PetscFunctionReturn(0); 428 } 429 430 /*@ 431 PetscDualSpaceGetDM - Get the DM representing the reference cell 432 433 Not collective 434 435 Input Parameter: 436 . sp - The PetscDualSpace 437 438 Output Parameter: 439 . dm - The reference cell 440 441 Level: intermediate 442 443 .seealso: PetscDualSpaceSetDM(), PetscDualSpaceCreate() 444 @*/ 445 PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm) 446 { 447 PetscFunctionBegin; 448 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 449 PetscValidPointer(dm, 2); 450 *dm = sp->dm; 451 PetscFunctionReturn(0); 452 } 453 454 /*@ 455 PetscDualSpaceSetDM - Get the DM representing the reference cell 456 457 Not collective 458 459 Input Parameters: 460 + sp - The PetscDualSpace 461 - dm - The reference cell 462 463 Level: intermediate 464 465 .seealso: PetscDualSpaceGetDM(), PetscDualSpaceCreate() 466 @*/ 467 PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm) 468 { 469 PetscErrorCode ierr; 470 471 PetscFunctionBegin; 472 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 473 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 474 ierr = DMDestroy(&sp->dm);CHKERRQ(ierr); 475 ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); 476 sp->dm = dm; 477 PetscFunctionReturn(0); 478 } 479 480 /*@ 481 PetscDualSpaceGetOrder - Get the order of the dual space 482 483 Not collective 484 485 Input Parameter: 486 . sp - The PetscDualSpace 487 488 Output Parameter: 489 . order - The order 490 491 Level: intermediate 492 493 .seealso: PetscDualSpaceSetOrder(), PetscDualSpaceCreate() 494 @*/ 495 PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order) 496 { 497 PetscFunctionBegin; 498 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 499 PetscValidPointer(order, 2); 500 *order = sp->order; 501 PetscFunctionReturn(0); 502 } 503 504 /*@ 505 PetscDualSpaceSetOrder - Set the order of the dual space 506 507 Not collective 508 509 Input Parameters: 510 + sp - The PetscDualSpace 511 - order - The order 512 513 Level: intermediate 514 515 .seealso: PetscDualSpaceGetOrder(), PetscDualSpaceCreate() 516 @*/ 517 PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order) 518 { 519 PetscFunctionBegin; 520 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 521 sp->order = order; 522 PetscFunctionReturn(0); 523 } 524 525 /*@ 526 PetscDualSpaceGetNumComponents - Return the number of components for this space 527 528 Input Parameter: 529 . sp - The PetscDualSpace 530 531 Output Parameter: 532 . Nc - The number of components 533 534 Note: A vector space, for example, will have d components, where d is the spatial dimension 535 536 Level: intermediate 537 538 .seealso: PetscDualSpaceSetNumComponents(), PetscDualSpaceGetDimension(), PetscDualSpaceCreate(), PetscDualSpace 539 @*/ 540 PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc) 541 { 542 PetscFunctionBegin; 543 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 544 PetscValidPointer(Nc, 2); 545 *Nc = sp->Nc; 546 PetscFunctionReturn(0); 547 } 548 549 /*@ 550 PetscDualSpaceSetNumComponents - Set the number of components for this space 551 552 Input Parameters: 553 + sp - The PetscDualSpace 554 - order - The number of components 555 556 Level: intermediate 557 558 .seealso: PetscDualSpaceGetNumComponents(), PetscDualSpaceCreate(), PetscDualSpace 559 @*/ 560 PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc) 561 { 562 PetscFunctionBegin; 563 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 564 sp->Nc = Nc; 565 PetscFunctionReturn(0); 566 } 567 568 /*@ 569 PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space 570 571 Not collective 572 573 Input Parameters: 574 + sp - The PetscDualSpace 575 - i - The basis number 576 577 Output Parameter: 578 . functional - The basis functional 579 580 Level: intermediate 581 582 .seealso: PetscDualSpaceGetDimension(), PetscDualSpaceCreate() 583 @*/ 584 PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional) 585 { 586 PetscInt dim; 587 PetscErrorCode ierr; 588 589 PetscFunctionBegin; 590 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 591 PetscValidPointer(functional, 3); 592 ierr = PetscDualSpaceGetDimension(sp, &dim);CHKERRQ(ierr); 593 if ((i < 0) || (i >= dim)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Functional index %d must be in [0, %d)", i, dim); 594 *functional = sp->functional[i]; 595 PetscFunctionReturn(0); 596 } 597 598 /*@ 599 PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals 600 601 Not collective 602 603 Input Parameter: 604 . sp - The PetscDualSpace 605 606 Output Parameter: 607 . dim - The dimension 608 609 Level: intermediate 610 611 .seealso: PetscDualSpaceGetFunctional(), PetscDualSpaceCreate() 612 @*/ 613 PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim) 614 { 615 PetscErrorCode ierr; 616 617 PetscFunctionBegin; 618 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 619 PetscValidPointer(dim, 2); 620 *dim = 0; 621 if (sp->ops->getdimension) {ierr = (*sp->ops->getdimension)(sp, dim);CHKERRQ(ierr);} 622 PetscFunctionReturn(0); 623 } 624 625 /*@C 626 PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension 627 628 Not collective 629 630 Input Parameter: 631 . sp - The PetscDualSpace 632 633 Output Parameter: 634 . numDof - An array of length dim+1 which holds the number of dofs for each dimension 635 636 Level: intermediate 637 638 .seealso: PetscDualSpaceGetFunctional(), PetscDualSpaceCreate() 639 @*/ 640 PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof) 641 { 642 PetscErrorCode ierr; 643 644 PetscFunctionBegin; 645 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 646 PetscValidPointer(numDof, 2); 647 ierr = (*sp->ops->getnumdof)(sp, numDof);CHKERRQ(ierr); 648 if (!*numDof) SETERRQ(PetscObjectComm((PetscObject) sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation"); 649 PetscFunctionReturn(0); 650 } 651 652 PetscErrorCode PetscDualSpaceCreateSection(PetscDualSpace sp, PetscSection *section) 653 { 654 DM dm; 655 PetscInt pStart, pEnd, depth, h, offset; 656 const PetscInt *numDof; 657 PetscErrorCode ierr; 658 659 PetscFunctionBegin; 660 ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr); 661 ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); 662 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)sp),section);CHKERRQ(ierr); 663 ierr = PetscSectionSetChart(*section,pStart,pEnd);CHKERRQ(ierr); 664 ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 665 ierr = PetscDualSpaceGetNumDof(sp,&numDof);CHKERRQ(ierr); 666 for (h = 0; h <= depth; h++) { 667 PetscInt hStart, hEnd, p, dof; 668 669 ierr = DMPlexGetHeightStratum(dm,h,&hStart,&hEnd);CHKERRQ(ierr); 670 dof = numDof[depth - h]; 671 for (p = hStart; p < hEnd; p++) { 672 ierr = PetscSectionSetDof(*section,p,dof);CHKERRQ(ierr); 673 } 674 } 675 ierr = PetscSectionSetUp(*section);CHKERRQ(ierr); 676 for (h = 0, offset = 0; h <= depth; h++) { 677 PetscInt hStart, hEnd, p, dof; 678 679 ierr = DMPlexGetHeightStratum(dm,h,&hStart,&hEnd);CHKERRQ(ierr); 680 dof = numDof[depth - h]; 681 for (p = hStart; p < hEnd; p++) { 682 ierr = PetscSectionGetDof(*section,p,&dof);CHKERRQ(ierr); 683 ierr = PetscSectionSetOffset(*section,p,offset);CHKERRQ(ierr); 684 offset += dof; 685 } 686 } 687 PetscFunctionReturn(0); 688 } 689 690 /*@ 691 PetscDualSpaceCreateReferenceCell - Create a DMPLEX with the appropriate FEM reference cell 692 693 Collective on PetscDualSpace 694 695 Input Parameters: 696 + sp - The PetscDualSpace 697 . dim - The spatial dimension 698 - simplex - Flag for simplex, otherwise use a tensor-product cell 699 700 Output Parameter: 701 . refdm - The reference cell 702 703 Level: advanced 704 705 .keywords: PetscDualSpace, reference cell 706 .seealso: PetscDualSpaceCreate(), DMPLEX 707 @*/ 708 PetscErrorCode PetscDualSpaceCreateReferenceCell(PetscDualSpace sp, PetscInt dim, PetscBool simplex, DM *refdm) 709 { 710 PetscErrorCode ierr; 711 712 PetscFunctionBeginUser; 713 ierr = DMPlexCreateReferenceCell(PetscObjectComm((PetscObject) sp), dim, simplex, refdm);CHKERRQ(ierr); 714 PetscFunctionReturn(0); 715 } 716 717 /*@C 718 PetscDualSpaceApply - Apply a functional from the dual space basis to an input function 719 720 Input Parameters: 721 + sp - The PetscDualSpace object 722 . f - The basis functional index 723 . time - The time 724 . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian) (or evaluated at the coordinates of the functional) 725 . numComp - The number of components for the function 726 . func - The input function 727 - ctx - A context for the function 728 729 Output Parameter: 730 . value - numComp output values 731 732 Note: The calling sequence for the callback func is given by: 733 734 $ func(PetscInt dim, PetscReal time, const PetscReal x[], 735 $ PetscInt numComponents, PetscScalar values[], void *ctx) 736 737 Level: developer 738 739 .seealso: PetscDualSpaceCreate() 740 @*/ 741 PetscErrorCode PetscDualSpaceApply(PetscDualSpace sp, PetscInt f, PetscReal time, PetscFEGeom *cgeom, PetscInt numComp, PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void *ctx, PetscScalar *value) 742 { 743 PetscErrorCode ierr; 744 745 PetscFunctionBegin; 746 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 747 PetscValidPointer(cgeom, 4); 748 PetscValidPointer(value, 8); 749 ierr = (*sp->ops->apply)(sp, f, time, cgeom, numComp, func, ctx, value);CHKERRQ(ierr); 750 PetscFunctionReturn(0); 751 } 752 753 /*@C 754 PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllPoints() 755 756 Input Parameters: 757 + sp - The PetscDualSpace object 758 - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllPoints() 759 760 Output Parameter: 761 . spValue - The values of all dual space functionals 762 763 Level: developer 764 765 .seealso: PetscDualSpaceCreate() 766 @*/ 767 PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) 768 { 769 PetscErrorCode ierr; 770 771 PetscFunctionBegin; 772 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 773 ierr = (*sp->ops->applyall)(sp, pointEval, spValue);CHKERRQ(ierr); 774 PetscFunctionReturn(0); 775 } 776 777 /*@C 778 PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional. 779 780 Input Parameters: 781 + sp - The PetscDualSpace object 782 . f - The basis functional index 783 . time - The time 784 . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian) 785 . Nc - The number of components for the function 786 . func - The input function 787 - ctx - A context for the function 788 789 Output Parameter: 790 . value - The output value 791 792 Note: The calling sequence for the callback func is given by: 793 794 $ func(PetscInt dim, PetscReal time, const PetscReal x[], 795 $ PetscInt numComponents, PetscScalar values[], void *ctx) 796 797 and the idea is to evaluate the functional as an integral 798 799 $ n(f) = int dx n(x) . f(x) 800 801 where both n and f have Nc components. 802 803 Level: developer 804 805 .seealso: PetscDualSpaceCreate() 806 @*/ 807 PetscErrorCode PetscDualSpaceApplyDefault(PetscDualSpace sp, PetscInt f, PetscReal time, PetscFEGeom *cgeom, PetscInt Nc, PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void *ctx, PetscScalar *value) 808 { 809 DM dm; 810 PetscQuadrature n; 811 const PetscReal *points, *weights; 812 PetscReal x[3]; 813 PetscScalar *val; 814 PetscInt dim, dE, qNc, c, Nq, q; 815 PetscBool isAffine; 816 PetscErrorCode ierr; 817 818 PetscFunctionBegin; 819 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 820 PetscValidPointer(value, 5); 821 ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr); 822 ierr = PetscDualSpaceGetFunctional(sp, f, &n);CHKERRQ(ierr); 823 ierr = PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights);CHKERRQ(ierr); 824 if (dim != cgeom->dim) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature spatial dimension %D != cell geometry dimension %D", dim, cgeom->dim); 825 if (qNc != Nc) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature components %D != function components %D", qNc, Nc); 826 ierr = DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr); 827 *value = 0.0; 828 isAffine = cgeom->isAffine; 829 dE = cgeom->dimEmbed; 830 for (q = 0; q < Nq; ++q) { 831 if (isAffine) { 832 CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q*dim], x); 833 ierr = (*func)(dE, time, x, Nc, val, ctx);CHKERRQ(ierr); 834 } else { 835 ierr = (*func)(dE, time, &cgeom->v[dE*q], Nc, val, ctx);CHKERRQ(ierr); 836 } 837 for (c = 0; c < Nc; ++c) { 838 *value += val[c]*weights[q*Nc+c]; 839 } 840 } 841 ierr = DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr); 842 PetscFunctionReturn(0); 843 } 844 845 /*@C 846 PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by PetscDualSpaceGetAllPoints() 847 848 Input Parameters: 849 + sp - The PetscDualSpace object 850 - pointEval - Evaluation at the points returned by PetscDualSpaceGetAllPoints() 851 852 Output Parameter: 853 . spValue - The values of all dual space functionals 854 855 Level: developer 856 857 .seealso: PetscDualSpaceCreate() 858 @*/ 859 PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) 860 { 861 PetscQuadrature n; 862 const PetscReal *points, *weights; 863 PetscInt qNc, c, Nq, q, f, spdim, Nc; 864 PetscInt offset; 865 PetscErrorCode ierr; 866 867 PetscFunctionBegin; 868 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 869 PetscValidScalarPointer(pointEval, 2); 870 PetscValidScalarPointer(spValue, 5); 871 ierr = PetscDualSpaceGetDimension(sp, &spdim);CHKERRQ(ierr); 872 ierr = PetscDualSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr); 873 for (f = 0, offset = 0; f < spdim; f++) { 874 ierr = PetscDualSpaceGetFunctional(sp, f, &n);CHKERRQ(ierr); 875 ierr = PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights);CHKERRQ(ierr); 876 if (qNc != Nc) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature components %D != function components %D", qNc, Nc); 877 spValue[f] = 0.0; 878 for (q = 0; q < Nq; ++q) { 879 for (c = 0; c < Nc; ++c) { 880 spValue[f] += pointEval[offset++]*weights[q*Nc+c]; 881 } 882 } 883 } 884 PetscFunctionReturn(0); 885 } 886 887 PetscErrorCode PetscDualSpaceGetAllPoints(PetscDualSpace sp, PetscQuadrature *allPoints) 888 { 889 PetscErrorCode ierr; 890 891 PetscFunctionBegin; 892 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 893 PetscValidPointer(allPoints,2); 894 if (!sp->allPoints && sp->ops->createallpoints) { 895 ierr = (*sp->ops->createallpoints)(sp,&sp->allPoints);CHKERRQ(ierr); 896 } 897 *allPoints = sp->allPoints; 898 PetscFunctionReturn(0); 899 } 900 901 PetscErrorCode PetscDualSpaceCreateAllPointsDefault(PetscDualSpace sp, PetscQuadrature *allPoints) 902 { 903 PetscInt spdim; 904 PetscInt numPoints, offset; 905 PetscReal *points; 906 PetscInt f, dim; 907 PetscQuadrature q; 908 PetscErrorCode ierr; 909 910 PetscFunctionBegin; 911 ierr = PetscDualSpaceGetDimension(sp,&spdim);CHKERRQ(ierr); 912 if (!spdim) { 913 ierr = PetscQuadratureCreate(PETSC_COMM_SELF,allPoints);CHKERRQ(ierr); 914 ierr = PetscQuadratureSetData(*allPoints,0,0,0,NULL,NULL);CHKERRQ(ierr); 915 } 916 ierr = PetscDualSpaceGetFunctional(sp,0,&q);CHKERRQ(ierr); 917 ierr = PetscQuadratureGetData(q,&dim,NULL,&numPoints,NULL,NULL);CHKERRQ(ierr); 918 for (f = 1; f < spdim; f++) { 919 PetscInt Np; 920 921 ierr = PetscDualSpaceGetFunctional(sp,f,&q);CHKERRQ(ierr); 922 ierr = PetscQuadratureGetData(q,NULL,NULL,&Np,NULL,NULL);CHKERRQ(ierr); 923 numPoints += Np; 924 } 925 ierr = PetscMalloc1(dim*numPoints,&points);CHKERRQ(ierr); 926 for (f = 0, offset = 0; f < spdim; f++) { 927 const PetscReal *p; 928 PetscInt Np, i; 929 930 ierr = PetscDualSpaceGetFunctional(sp,f,&q);CHKERRQ(ierr); 931 ierr = PetscQuadratureGetData(q,NULL,NULL,&Np,&p,NULL);CHKERRQ(ierr); 932 for (i = 0; i < Np * dim; i++) { 933 points[offset + i] = p[i]; 934 } 935 offset += Np * dim; 936 } 937 ierr = PetscQuadratureCreate(PETSC_COMM_SELF,allPoints);CHKERRQ(ierr); 938 ierr = PetscQuadratureSetData(*allPoints,dim,0,numPoints,points,NULL);CHKERRQ(ierr); 939 PetscFunctionReturn(0); 940 } 941 942 /*@C 943 PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid. 944 945 Input Parameters: 946 + sp - The PetscDualSpace object 947 . f - The basis functional index 948 . time - The time 949 . cgeom - A context with geometric information for this cell, we currently just use the centroid 950 . Nc - The number of components for the function 951 . func - The input function 952 - ctx - A context for the function 953 954 Output Parameter: 955 . value - The output value (scalar) 956 957 Note: The calling sequence for the callback func is given by: 958 959 $ func(PetscInt dim, PetscReal time, const PetscReal x[], 960 $ PetscInt numComponents, PetscScalar values[], void *ctx) 961 962 and the idea is to evaluate the functional as an integral 963 964 $ n(f) = int dx n(x) . f(x) 965 966 where both n and f have Nc components. 967 968 Level: developer 969 970 .seealso: PetscDualSpaceCreate() 971 @*/ 972 PetscErrorCode PetscDualSpaceApplyFVM(PetscDualSpace sp, PetscInt f, PetscReal time, PetscFVCellGeom *cgeom, PetscInt Nc, PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void *ctx, PetscScalar *value) 973 { 974 DM dm; 975 PetscQuadrature n; 976 const PetscReal *points, *weights; 977 PetscScalar *val; 978 PetscInt dimEmbed, qNc, c, Nq, q; 979 PetscErrorCode ierr; 980 981 PetscFunctionBegin; 982 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 983 PetscValidPointer(value, 5); 984 ierr = PetscDualSpaceGetDM(sp, &dm);CHKERRQ(ierr); 985 ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr); 986 ierr = PetscDualSpaceGetFunctional(sp, f, &n);CHKERRQ(ierr); 987 ierr = PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights);CHKERRQ(ierr); 988 if (qNc != Nc) SETERRQ2(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_SIZ, "The quadrature components %D != function components %D", qNc, Nc); 989 ierr = DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr); 990 *value = 0.; 991 for (q = 0; q < Nq; ++q) { 992 ierr = (*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx);CHKERRQ(ierr); 993 for (c = 0; c < Nc; ++c) { 994 *value += val[c]*weights[q*Nc+c]; 995 } 996 } 997 ierr = DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val);CHKERRQ(ierr); 998 PetscFunctionReturn(0); 999 } 1000 1001 /*@ 1002 PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a 1003 given height. This assumes that the reference cell is symmetric over points of this height. 1004 1005 If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and 1006 pointwise values are not defined on the element boundaries), or if the implementation of PetscDualSpace does not 1007 support extracting subspaces, then NULL is returned. 1008 1009 This does not increment the reference count on the returned dual space, and the user should not destroy it. 1010 1011 Not collective 1012 1013 Input Parameters: 1014 + sp - the PetscDualSpace object 1015 - height - the height of the mesh point for which the subspace is desired 1016 1017 Output Parameter: 1018 . subsp - the subspace. Note that the functionals in the subspace are with respect to the intrinsic geometry of the 1019 point, which will be of lesser dimension if height > 0. 1020 1021 Level: advanced 1022 1023 .seealso: PetscSpaceGetHeightSubspace(), PetscDualSpace 1024 @*/ 1025 PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp) 1026 { 1027 PetscErrorCode ierr; 1028 1029 PetscFunctionBegin; 1030 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1031 PetscValidPointer(subsp, 3); 1032 *subsp = NULL; 1033 if (sp->ops->getheightsubspace) {ierr = (*sp->ops->getheightsubspace)(sp, height, subsp);CHKERRQ(ierr);} 1034 PetscFunctionReturn(0); 1035 } 1036 1037 /*@ 1038 PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point. 1039 1040 If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not 1041 defined on the element boundaries), or if the implementation of PetscDualSpace does not support extracting 1042 subspaces, then NULL is returned. 1043 1044 This does not increment the reference count on the returned dual space, and the user should not destroy it. 1045 1046 Not collective 1047 1048 Input Parameters: 1049 + sp - the PetscDualSpace object 1050 - point - the point (in the dual space's DM) for which the subspace is desired 1051 1052 Output Parameters: 1053 bdsp - the subspace. Note that the functionals in the subspace are with respect to the intrinsic geometry of the 1054 point, which will be of lesser dimension if height > 0. 1055 1056 Level: advanced 1057 1058 .seealso: PetscDualSpace 1059 @*/ 1060 PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp) 1061 { 1062 PetscErrorCode ierr; 1063 1064 PetscFunctionBegin; 1065 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1066 PetscValidPointer(bdsp,2); 1067 *bdsp = NULL; 1068 if (sp->ops->getpointsubspace) { 1069 ierr = (*sp->ops->getpointsubspace)(sp,point,bdsp);CHKERRQ(ierr); 1070 } else if (sp->ops->getheightsubspace) { 1071 DM dm; 1072 DMLabel label; 1073 PetscInt dim, depth, height; 1074 1075 ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr); 1076 ierr = DMPlexGetDepth(dm,&dim);CHKERRQ(ierr); 1077 ierr = DMPlexGetDepthLabel(dm,&label);CHKERRQ(ierr); 1078 ierr = DMLabelGetValue(label,point,&depth);CHKERRQ(ierr); 1079 height = dim - depth; 1080 ierr = (*sp->ops->getheightsubspace)(sp,height,bdsp);CHKERRQ(ierr); 1081 } 1082 PetscFunctionReturn(0); 1083 } 1084 1085 /*@C 1086 PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis 1087 1088 Not collective 1089 1090 Input Parameter: 1091 . sp - the PetscDualSpace object 1092 1093 Output Parameters: 1094 + perms - Permutations of the local degrees of freedom, parameterized by the point orientation 1095 - flips - Sign reversal of the local degrees of freedom, parameterized by the point orientation 1096 1097 Note: The permutation and flip arrays are organized in the following way 1098 $ perms[p][ornt][dof # on point] = new local dof # 1099 $ flips[p][ornt][dof # on point] = reversal or not 1100 1101 Level: developer 1102 1103 .seealso: PetscDualSpaceSetSymmetries() 1104 @*/ 1105 PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips) 1106 { 1107 PetscErrorCode ierr; 1108 1109 PetscFunctionBegin; 1110 PetscValidHeaderSpecific(sp,PETSCDUALSPACE_CLASSID,1); 1111 if (perms) {PetscValidPointer(perms,2); *perms = NULL;} 1112 if (flips) {PetscValidPointer(flips,3); *flips = NULL;} 1113 if (sp->ops->getsymmetries) {ierr = (sp->ops->getsymmetries)(sp,perms,flips);CHKERRQ(ierr);} 1114 PetscFunctionReturn(0); 1115 } 1116 1117 /*@ 1118 PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space 1119 1120 Input Parameter: 1121 . dsp - The PetscDualSpace 1122 1123 Output Parameter: 1124 . k - The simplex dimension 1125 1126 Level: advanced 1127 1128 Note: Currently supported values are 1129 $ 0: These are H_1 methods that only transform coordinates 1130 $ 1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM) 1131 $ 2: These are the same as 1 1132 $ 3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM) 1133 1134 .seealso: PetscDualSpacePullback(), PetscDualSpacePushforward(), PetscDualSpaceTransform(), PetscDualSpaceTransformType 1135 @*/ 1136 PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k) 1137 { 1138 PetscFunctionBeginHot; 1139 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1140 PetscValidPointer(k, 2); 1141 *k = dsp->k; 1142 PetscFunctionReturn(0); 1143 } 1144 1145 /*@C 1146 PetscDualSpaceTransform - Transform the function values 1147 1148 Input Parameters: 1149 + dsp - The PetscDualSpace 1150 . trans - The type of transform 1151 . isInverse - Flag to invert the transform 1152 . fegeom - The cell geometry 1153 . Nv - The number of function samples 1154 . Nc - The number of function components 1155 - vals - The function values 1156 1157 Output Parameter: 1158 . vals - The transformed function values 1159 1160 Level: developer 1161 1162 .seealso: PetscDualSpaceTransformGradient(), PetscDualSpacePullback(), PetscDualSpacePushforward(), PetscDualSpaceTransformType 1163 @*/ 1164 PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) 1165 { 1166 PetscInt dim, v, c; 1167 1168 PetscFunctionBeginHot; 1169 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1170 PetscValidPointer(fegeom, 4); 1171 PetscValidPointer(vals, 7); 1172 dim = dsp->dm->dim; 1173 /* Assume its a vector, otherwise assume its a bunch of scalars */ 1174 if (Nc == 1 || Nc != dim) PetscFunctionReturn(0); 1175 switch (trans) { 1176 case IDENTITY_TRANSFORM: break; 1177 case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */ 1178 if (isInverse) { 1179 for (v = 0; v < Nv; ++v) { 1180 switch (dim) 1181 { 1182 case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->J, 1, &vals[v*Nc], &vals[v*Nc]);break; 1183 case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->J, 1, &vals[v*Nc], &vals[v*Nc]);break; 1184 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1185 } 1186 } 1187 } else { 1188 for (v = 0; v < Nv; ++v) { 1189 switch (dim) 1190 { 1191 case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[v*Nc], &vals[v*Nc]);break; 1192 case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[v*Nc], &vals[v*Nc]);break; 1193 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1194 } 1195 } 1196 } 1197 break; 1198 case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */ 1199 if (isInverse) { 1200 for (v = 0; v < Nv; ++v) { 1201 switch (dim) 1202 { 1203 case 2: DMPlex_Mult2DReal_Internal(fegeom->invJ, 1, &vals[v*Nc], &vals[v*Nc]);break; 1204 case 3: DMPlex_Mult3DReal_Internal(fegeom->invJ, 1, &vals[v*Nc], &vals[v*Nc]);break; 1205 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1206 } 1207 for (c = 0; c < Nc; ++c) vals[v*Nc+c] *= fegeom->detJ[0]; 1208 } 1209 } else { 1210 for (v = 0; v < Nv; ++v) { 1211 switch (dim) 1212 { 1213 case 2: DMPlex_Mult2DReal_Internal(fegeom->J, 1, &vals[v*Nc], &vals[v*Nc]);break; 1214 case 3: DMPlex_Mult3DReal_Internal(fegeom->J, 1, &vals[v*Nc], &vals[v*Nc]);break; 1215 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1216 } 1217 for (c = 0; c < Nc; ++c) vals[v*Nc+c] /= fegeom->detJ[0]; 1218 } 1219 } 1220 break; 1221 } 1222 PetscFunctionReturn(0); 1223 } 1224 /*@C 1225 PetscDualSpaceTransformGradient - Transform the function gradient values 1226 1227 Input Parameters: 1228 + dsp - The PetscDualSpace 1229 . trans - The type of transform 1230 . isInverse - Flag to invert the transform 1231 . fegeom - The cell geometry 1232 . Nv - The number of function gradient samples 1233 . Nc - The number of function components 1234 - vals - The function gradient values 1235 1236 Output Parameter: 1237 . vals - The transformed function values 1238 1239 Level: developer 1240 1241 .seealso: PetscDualSpaceTransform(), PetscDualSpacePullback(), PetscDualSpacePushforward(), PetscDualSpaceTransformType 1242 @*/ 1243 PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) 1244 { 1245 PetscInt dim, v, c, d; 1246 1247 PetscFunctionBeginHot; 1248 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1249 PetscValidPointer(fegeom, 4); 1250 PetscValidPointer(vals, 7); 1251 dim = dsp->dm->dim; 1252 /* Transform gradient */ 1253 for (v = 0; v < Nv; ++v) { 1254 for (c = 0; c < Nc; ++c) { 1255 switch (dim) 1256 { 1257 case 1: vals[(v*Nc+c)*dim] *= fegeom->invJ[0]; 1258 case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v*Nc+c)*dim], &vals[(v*Nc+c)*dim]);break; 1259 case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v*Nc+c)*dim], &vals[(v*Nc+c)*dim]);break; 1260 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1261 } 1262 } 1263 } 1264 /* Assume its a vector, otherwise assume its a bunch of scalars */ 1265 if (Nc == 1 || Nc != dim) PetscFunctionReturn(0); 1266 switch (trans) { 1267 case IDENTITY_TRANSFORM: break; 1268 case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */ 1269 if (isInverse) { 1270 for (v = 0; v < Nv; ++v) { 1271 for (d = 0; d < dim; ++d) { 1272 switch (dim) 1273 { 1274 case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1275 case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1276 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1277 } 1278 } 1279 } 1280 } else { 1281 for (v = 0; v < Nv; ++v) { 1282 for (d = 0; d < dim; ++d) { 1283 switch (dim) 1284 { 1285 case 2: DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1286 case 3: DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1287 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1288 } 1289 } 1290 } 1291 } 1292 break; 1293 case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */ 1294 if (isInverse) { 1295 for (v = 0; v < Nv; ++v) { 1296 for (d = 0; d < dim; ++d) { 1297 switch (dim) 1298 { 1299 case 2: DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1300 case 3: DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1301 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1302 } 1303 for (c = 0; c < Nc; ++c) vals[(v*Nc+c)*dim+d] *= fegeom->detJ[0]; 1304 } 1305 } 1306 } else { 1307 for (v = 0; v < Nv; ++v) { 1308 for (d = 0; d < dim; ++d) { 1309 switch (dim) 1310 { 1311 case 2: DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1312 case 3: DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v*Nc*dim+d], &vals[v*Nc*dim+d]);break; 1313 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %D for transformation", dim); 1314 } 1315 for (c = 0; c < Nc; ++c) vals[(v*Nc+c)*dim+d] /= fegeom->detJ[0]; 1316 } 1317 } 1318 } 1319 break; 1320 } 1321 PetscFunctionReturn(0); 1322 } 1323 1324 /*@C 1325 PetscDualSpacePullback - Transform the given functional so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method. 1326 1327 Input Parameters: 1328 + dsp - The PetscDualSpace 1329 . fegeom - The geometry for this cell 1330 . Nq - The number of function samples 1331 . Nc - The number of function components 1332 - pointEval - The function values 1333 1334 Output Parameter: 1335 . pointEval - The transformed function values 1336 1337 Level: advanced 1338 1339 Note: Functions transform in a complementary way (pushforward) to functionals, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex. 1340 1341 .seealso: PetscDualSpacePushforward(), PetscDualSpaceTransform(), PetscDualSpaceGetDeRahm() 1342 @*/ 1343 PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 1344 { 1345 PetscDualSpaceTransformType trans; 1346 PetscErrorCode ierr; 1347 1348 PetscFunctionBeginHot; 1349 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1350 PetscValidPointer(fegeom, 2); 1351 PetscValidPointer(pointEval, 5); 1352 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 1353 This determines their transformation properties. */ 1354 switch (dsp->k) 1355 { 1356 case 0: /* H^1 point evaluations */ 1357 trans = IDENTITY_TRANSFORM;break; 1358 case 1: /* Hcurl preserves tangential edge traces */ 1359 case 2: 1360 trans = COVARIANT_PIOLA_TRANSFORM;break; 1361 case 3: /* Hdiv preserve normal traces */ 1362 trans = CONTRAVARIANT_PIOLA_TRANSFORM;break; 1363 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %D for transformation", dsp->k); 1364 } 1365 ierr = PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval);CHKERRQ(ierr); 1366 PetscFunctionReturn(0); 1367 } 1368 1369 /*@C 1370 PetscDualSpacePushforward - Transform the given function so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method. 1371 1372 Input Parameters: 1373 + dsp - The PetscDualSpace 1374 . fegeom - The geometry for this cell 1375 . Nq - The number of function samples 1376 . Nc - The number of function components 1377 - pointEval - The function values 1378 1379 Output Parameter: 1380 . pointEval - The transformed function values 1381 1382 Level: advanced 1383 1384 Note: Functionals transform in a complementary way (pullback) to functions, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex. 1385 1386 .seealso: PetscDualSpacePullback(), PetscDualSpaceTransform(), PetscDualSpaceGetDeRahm() 1387 @*/ 1388 PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 1389 { 1390 PetscDualSpaceTransformType trans; 1391 PetscErrorCode ierr; 1392 1393 PetscFunctionBeginHot; 1394 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1395 PetscValidPointer(fegeom, 2); 1396 PetscValidPointer(pointEval, 5); 1397 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 1398 This determines their transformation properties. */ 1399 switch (dsp->k) 1400 { 1401 case 0: /* H^1 point evaluations */ 1402 trans = IDENTITY_TRANSFORM;break; 1403 case 1: /* Hcurl preserves tangential edge traces */ 1404 case 2: 1405 trans = COVARIANT_PIOLA_TRANSFORM;break; 1406 case 3: /* Hdiv preserve normal traces */ 1407 trans = CONTRAVARIANT_PIOLA_TRANSFORM;break; 1408 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %D for transformation", dsp->k); 1409 } 1410 ierr = PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval);CHKERRQ(ierr); 1411 PetscFunctionReturn(0); 1412 } 1413 1414 /*@C 1415 PetscDualSpacePushforwardGradient - Transform the given function gradient so that it operates on real space, rather than the reference element. Operationally, this means that we map the function evaluations depending on continuity requirements of our finite element method. 1416 1417 Input Parameters: 1418 + dsp - The PetscDualSpace 1419 . fegeom - The geometry for this cell 1420 . Nq - The number of function gradient samples 1421 . Nc - The number of function components 1422 - pointEval - The function gradient values 1423 1424 Output Parameter: 1425 . pointEval - The transformed function gradient values 1426 1427 Level: advanced 1428 1429 Note: Functionals transform in a complementary way (pullback) to functions, so that the scalar product is invariant. The type of transform is dependent on the associated k-simplex from the DeRahm complex. 1430 1431 .seealso: PetscDualSpacePushforward(), PPetscDualSpacePullback(), PetscDualSpaceTransform(), PetscDualSpaceGetDeRahm() 1432 @*/PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 1433 { 1434 PetscDualSpaceTransformType trans; 1435 PetscErrorCode ierr; 1436 1437 PetscFunctionBeginHot; 1438 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1439 PetscValidPointer(fegeom, 2); 1440 PetscValidPointer(pointEval, 5); 1441 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 1442 This determines their transformation properties. */ 1443 switch (dsp->k) 1444 { 1445 case 0: /* H^1 point evaluations */ 1446 trans = IDENTITY_TRANSFORM;break; 1447 case 1: /* Hcurl preserves tangential edge traces */ 1448 case 2: 1449 trans = COVARIANT_PIOLA_TRANSFORM;break; 1450 case 3: /* Hdiv preserve normal traces */ 1451 trans = CONTRAVARIANT_PIOLA_TRANSFORM;break; 1452 default: SETERRQ1(PetscObjectComm((PetscObject) dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %D for transformation", dsp->k); 1453 } 1454 ierr = PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval);CHKERRQ(ierr); 1455 PetscFunctionReturn(0); 1456 } 1457