1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/ 2 #include <petscdmplex.h> 3 4 PetscClassId PETSCDUALSPACE_CLASSID = 0; 5 6 PetscLogEvent PETSCDUALSPACE_SetUp; 7 8 PetscFunctionList PetscDualSpaceList = NULL; 9 PetscBool PetscDualSpaceRegisterAllCalled = PETSC_FALSE; 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}, {0,2}. 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 whose sum is at most `max` 23 24 Level: developer 25 26 .seealso: `PetscDualSpaceType`, `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(PETSC_SUCCESS); 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 whose entries are at most `max` 54 55 Level: developer 56 57 .seealso: `PetscDualSpaceType`, `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(PETSC_SUCCESS); 73 } 74 75 /*@C 76 PetscDualSpaceRegister - Adds a new `PetscDualSpaceType` 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 Sample usage: 85 .vb 86 PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate); 87 .ve 88 89 Then, your PetscDualSpace type can be chosen with the procedural interface via 90 .vb 91 PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *); 92 PetscDualSpaceSetType(PetscDualSpace, "my_dual_space"); 93 .ve 94 or at runtime via the option 95 .vb 96 -petscdualspace_type my_dual_space 97 .ve 98 99 Level: advanced 100 101 Note: 102 `PetscDualSpaceRegister()` may be called multiple times to add several user-defined `PetscDualSpace` 103 104 .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceRegisterAll()`, `PetscDualSpaceRegisterDestroy()` 105 @*/ 106 PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace)) 107 { 108 PetscFunctionBegin; 109 PetscCall(PetscFunctionListAdd(&PetscDualSpaceList, sname, function)); 110 PetscFunctionReturn(PETSC_SUCCESS); 111 } 112 113 /*@C 114 PetscDualSpaceSetType - Builds a particular `PetscDualSpace` based on its `PetscDualSpaceType` 115 116 Collective 117 118 Input Parameters: 119 + sp - The `PetscDualSpace` object 120 - name - The kind of space 121 122 Options Database Key: 123 . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types 124 125 Level: intermediate 126 127 .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceGetType()`, `PetscDualSpaceCreate()` 128 @*/ 129 PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name) 130 { 131 PetscErrorCode (*r)(PetscDualSpace); 132 PetscBool match; 133 134 PetscFunctionBegin; 135 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 136 PetscCall(PetscObjectTypeCompare((PetscObject)sp, name, &match)); 137 if (match) PetscFunctionReturn(PETSC_SUCCESS); 138 139 if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll()); 140 PetscCall(PetscFunctionListFind(PetscDualSpaceList, name, &r)); 141 PetscCheck(r, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name); 142 143 PetscTryTypeMethod(sp, destroy); 144 sp->ops->destroy = NULL; 145 146 PetscCall((*r)(sp)); 147 PetscCall(PetscObjectChangeTypeName((PetscObject)sp, name)); 148 PetscFunctionReturn(PETSC_SUCCESS); 149 } 150 151 /*@C 152 PetscDualSpaceGetType - Gets the `PetscDualSpaceType` name (as a string) from the object. 153 154 Not Collective 155 156 Input Parameter: 157 . sp - The `PetscDualSpace` 158 159 Output Parameter: 160 . name - The `PetscDualSpaceType` name 161 162 Level: intermediate 163 164 .seealso: `PetscDualSpace`, `PetscDualSpaceType`, `PetscDualSpaceSetType()`, `PetscDualSpaceCreate()` 165 @*/ 166 PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name) 167 { 168 PetscFunctionBegin; 169 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 170 PetscValidPointer(name, 2); 171 if (!PetscDualSpaceRegisterAllCalled) PetscCall(PetscDualSpaceRegisterAll()); 172 *name = ((PetscObject)sp)->type_name; 173 PetscFunctionReturn(PETSC_SUCCESS); 174 } 175 176 static PetscErrorCode PetscDualSpaceView_ASCII(PetscDualSpace sp, PetscViewer v) 177 { 178 PetscViewerFormat format; 179 PetscInt pdim, f; 180 181 PetscFunctionBegin; 182 PetscCall(PetscDualSpaceGetDimension(sp, &pdim)); 183 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sp, v)); 184 PetscCall(PetscViewerASCIIPushTab(v)); 185 if (sp->k) { 186 PetscCall(PetscViewerASCIIPrintf(v, "Dual space for %" PetscInt_FMT "-forms %swith %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", PetscAbsInt(sp->k), sp->k < 0 ? "(stored in dual form) " : "", sp->Nc, pdim)); 187 } else { 188 PetscCall(PetscViewerASCIIPrintf(v, "Dual space with %" PetscInt_FMT " components, size %" PetscInt_FMT "\n", sp->Nc, pdim)); 189 } 190 PetscTryTypeMethod(sp, view, v); 191 PetscCall(PetscViewerGetFormat(v, &format)); 192 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 193 PetscCall(PetscViewerASCIIPushTab(v)); 194 for (f = 0; f < pdim; ++f) { 195 PetscCall(PetscViewerASCIIPrintf(v, "Dual basis vector %" PetscInt_FMT "\n", f)); 196 PetscCall(PetscViewerASCIIPushTab(v)); 197 PetscCall(PetscQuadratureView(sp->functional[f], v)); 198 PetscCall(PetscViewerASCIIPopTab(v)); 199 } 200 PetscCall(PetscViewerASCIIPopTab(v)); 201 } 202 PetscCall(PetscViewerASCIIPopTab(v)); 203 PetscFunctionReturn(PETSC_SUCCESS); 204 } 205 206 /*@C 207 PetscDualSpaceViewFromOptions - View a `PetscDualSpace` based on values in the options database 208 209 Collective 210 211 Input Parameters: 212 + A - the `PetscDualSpace` object 213 . obj - Optional object, provides the options prefix 214 - name - command line option name 215 216 Level: intermediate 217 218 Note: 219 See `PetscObjectViewFromOptions()` for possible command line values 220 221 .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscObjectViewFromOptions()`, `PetscDualSpaceCreate()` 222 @*/ 223 PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace A, PetscObject obj, const char name[]) 224 { 225 PetscFunctionBegin; 226 PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1); 227 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 228 PetscFunctionReturn(PETSC_SUCCESS); 229 } 230 231 /*@ 232 PetscDualSpaceView - Views a `PetscDualSpace` 233 234 Collective 235 236 Input Parameters: 237 + sp - the `PetscDualSpace` object to view 238 - v - the viewer 239 240 Level: beginner 241 242 .seealso: `PetscViewer`, `PetscDualSpaceDestroy()`, `PetscDualSpace` 243 @*/ 244 PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v) 245 { 246 PetscBool iascii; 247 248 PetscFunctionBegin; 249 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 250 if (v) PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2); 251 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sp), &v)); 252 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii)); 253 if (iascii) PetscCall(PetscDualSpaceView_ASCII(sp, v)); 254 PetscFunctionReturn(PETSC_SUCCESS); 255 } 256 257 /*@ 258 PetscDualSpaceSetFromOptions - sets parameters in a `PetscDualSpace` from the options database 259 260 Collective 261 262 Input Parameter: 263 . sp - the `PetscDualSpace` object to set options for 264 265 Options Database Keys: 266 + -petscdualspace_order <order> - the approximation order of the space 267 . -petscdualspace_form_degree <deg> - the form degree, say 0 for point evaluations, or 2 for area integrals 268 . -petscdualspace_components <c> - the number of components, say d for a vector field 269 . -petscdualspace_refcell <celltype> - Reference cell type name 270 . -petscdualspace_lagrange_continuity - Flag for continuous element 271 . -petscdualspace_lagrange_tensor - Flag for tensor dual space 272 . -petscdualspace_lagrange_trimmed - Flag for trimmed dual space 273 . -petscdualspace_lagrange_node_type <nodetype> - Lagrange node location type 274 . -petscdualspace_lagrange_node_endpoints - Flag for nodes that include endpoints 275 . -petscdualspace_lagrange_node_exponent - Gauss-Jacobi weight function exponent 276 . -petscdualspace_lagrange_use_moments - Use moments (where appropriate) for functionals 277 - -petscdualspace_lagrange_moment_order <order> - Quadrature order for moment functionals 278 279 Level: intermediate 280 281 .seealso: `PetscDualSpaceView()`, `PetscDualSpace`, `PetscObjectSetFromOptions()` 282 @*/ 283 PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp) 284 { 285 DMPolytopeType refCell = DM_POLYTOPE_TRIANGLE; 286 const char *defaultType; 287 char name[256]; 288 PetscBool flg; 289 290 PetscFunctionBegin; 291 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 292 if (!((PetscObject)sp)->type_name) { 293 defaultType = PETSCDUALSPACELAGRANGE; 294 } else { 295 defaultType = ((PetscObject)sp)->type_name; 296 } 297 if (!PetscSpaceRegisterAllCalled) PetscCall(PetscSpaceRegisterAll()); 298 299 PetscObjectOptionsBegin((PetscObject)sp); 300 PetscCall(PetscOptionsFList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, name, 256, &flg)); 301 if (flg) { 302 PetscCall(PetscDualSpaceSetType(sp, name)); 303 } else if (!((PetscObject)sp)->type_name) { 304 PetscCall(PetscDualSpaceSetType(sp, defaultType)); 305 } 306 PetscCall(PetscOptionsBoundedInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL, 0)); 307 PetscCall(PetscOptionsInt("-petscdualspace_form_degree", "The form degree of the dofs", "PetscDualSpaceSetFormDegree", sp->k, &sp->k, NULL)); 308 PetscCall(PetscOptionsBoundedInt("-petscdualspace_components", "The number of components", "PetscDualSpaceSetNumComponents", sp->Nc, &sp->Nc, NULL, 1)); 309 PetscTryTypeMethod(sp, setfromoptions, PetscOptionsObject); 310 PetscCall(PetscOptionsEnum("-petscdualspace_refcell", "Reference cell shape", "PetscDualSpaceSetReferenceCell", DMPolytopeTypes, (PetscEnum)refCell, (PetscEnum *)&refCell, &flg)); 311 if (flg) { 312 DM K; 313 314 PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, refCell, &K)); 315 PetscCall(PetscDualSpaceSetDM(sp, K)); 316 PetscCall(DMDestroy(&K)); 317 } 318 319 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 320 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)sp, PetscOptionsObject)); 321 PetscOptionsEnd(); 322 sp->setfromoptionscalled = PETSC_TRUE; 323 PetscFunctionReturn(PETSC_SUCCESS); 324 } 325 326 /*@ 327 PetscDualSpaceSetUp - Construct a basis for a `PetscDualSpace` 328 329 Collective 330 331 Input Parameter: 332 . sp - the `PetscDualSpace` object to setup 333 334 Level: intermediate 335 336 .seealso: `PetscDualSpaceView()`, `PetscDualSpaceDestroy()`, `PetscDualSpace` 337 @*/ 338 PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp) 339 { 340 PetscFunctionBegin; 341 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 342 if (sp->setupcalled) PetscFunctionReturn(PETSC_SUCCESS); 343 PetscCall(PetscLogEventBegin(PETSCDUALSPACE_SetUp, sp, 0, 0, 0)); 344 sp->setupcalled = PETSC_TRUE; 345 PetscTryTypeMethod(sp, setup); 346 PetscCall(PetscLogEventEnd(PETSCDUALSPACE_SetUp, sp, 0, 0, 0)); 347 if (sp->setfromoptionscalled) PetscCall(PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view")); 348 PetscFunctionReturn(PETSC_SUCCESS); 349 } 350 351 static PetscErrorCode PetscDualSpaceClearDMData_Internal(PetscDualSpace sp, DM dm) 352 { 353 PetscInt pStart = -1, pEnd = -1, depth = -1; 354 355 PetscFunctionBegin; 356 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 357 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 358 PetscCall(DMPlexGetDepth(dm, &depth)); 359 360 if (sp->pointSpaces) { 361 PetscInt i; 362 363 for (i = 0; i < pEnd - pStart; i++) PetscCall(PetscDualSpaceDestroy(&(sp->pointSpaces[i]))); 364 } 365 PetscCall(PetscFree(sp->pointSpaces)); 366 367 if (sp->heightSpaces) { 368 PetscInt i; 369 370 for (i = 0; i <= depth; i++) PetscCall(PetscDualSpaceDestroy(&(sp->heightSpaces[i]))); 371 } 372 PetscCall(PetscFree(sp->heightSpaces)); 373 374 PetscCall(PetscSectionDestroy(&(sp->pointSection))); 375 PetscCall(PetscQuadratureDestroy(&(sp->intNodes))); 376 PetscCall(VecDestroy(&(sp->intDofValues))); 377 PetscCall(VecDestroy(&(sp->intNodeValues))); 378 PetscCall(MatDestroy(&(sp->intMat))); 379 PetscCall(PetscQuadratureDestroy(&(sp->allNodes))); 380 PetscCall(VecDestroy(&(sp->allDofValues))); 381 PetscCall(VecDestroy(&(sp->allNodeValues))); 382 PetscCall(MatDestroy(&(sp->allMat))); 383 PetscCall(PetscFree(sp->numDof)); 384 PetscFunctionReturn(PETSC_SUCCESS); 385 } 386 387 /*@ 388 PetscDualSpaceDestroy - Destroys a `PetscDualSpace` object 389 390 Collective 391 392 Input Parameter: 393 . sp - the `PetscDualSpace` object to destroy 394 395 Level: beginner 396 397 .seealso: `PetscDualSpace`, `PetscDualSpaceView()`, `PetscDualSpace()`, `PetscDualSpaceCreate()` 398 @*/ 399 PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp) 400 { 401 PetscInt dim, f; 402 DM dm; 403 404 PetscFunctionBegin; 405 if (!*sp) PetscFunctionReturn(PETSC_SUCCESS); 406 PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1); 407 408 if (--((PetscObject)(*sp))->refct > 0) { 409 *sp = NULL; 410 PetscFunctionReturn(PETSC_SUCCESS); 411 } 412 ((PetscObject)(*sp))->refct = 0; 413 414 PetscCall(PetscDualSpaceGetDimension(*sp, &dim)); 415 dm = (*sp)->dm; 416 417 PetscTryTypeMethod((*sp), destroy); 418 PetscCall(PetscDualSpaceClearDMData_Internal(*sp, dm)); 419 420 for (f = 0; f < dim; ++f) PetscCall(PetscQuadratureDestroy(&(*sp)->functional[f])); 421 PetscCall(PetscFree((*sp)->functional)); 422 PetscCall(DMDestroy(&(*sp)->dm)); 423 PetscCall(PetscHeaderDestroy(sp)); 424 PetscFunctionReturn(PETSC_SUCCESS); 425 } 426 427 /*@ 428 PetscDualSpaceCreate - Creates an empty `PetscDualSpace` object. The type can then be set with `PetscDualSpaceSetType()`. 429 430 Collective 431 432 Input Parameter: 433 . comm - The communicator for the `PetscDualSpace` object 434 435 Output Parameter: 436 . sp - The `PetscDualSpace` object 437 438 Level: beginner 439 440 .seealso: `PetscDualSpace`, `PetscDualSpaceSetType()`, `PETSCDUALSPACELAGRANGE` 441 @*/ 442 PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp) 443 { 444 PetscDualSpace s; 445 446 PetscFunctionBegin; 447 PetscValidPointer(sp, 2); 448 PetscCall(PetscCitationsRegister(FECitation, &FEcite)); 449 *sp = NULL; 450 PetscCall(PetscFEInitializePackage()); 451 452 PetscCall(PetscHeaderCreate(s, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView)); 453 454 s->order = 0; 455 s->Nc = 1; 456 s->k = 0; 457 s->spdim = -1; 458 s->spintdim = -1; 459 s->uniform = PETSC_TRUE; 460 s->setupcalled = PETSC_FALSE; 461 462 *sp = s; 463 PetscFunctionReturn(PETSC_SUCCESS); 464 } 465 466 /*@ 467 PetscDualSpaceDuplicate - Creates a duplicate `PetscDualSpace` object that is not setup. 468 469 Collective 470 471 Input Parameter: 472 . sp - The original `PetscDualSpace` 473 474 Output Parameter: 475 . spNew - The duplicate `PetscDualSpace` 476 477 Level: beginner 478 479 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `PetscDualSpaceSetType()` 480 @*/ 481 PetscErrorCode PetscDualSpaceDuplicate(PetscDualSpace sp, PetscDualSpace *spNew) 482 { 483 DM dm; 484 PetscDualSpaceType type; 485 const char *name; 486 487 PetscFunctionBegin; 488 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 489 PetscValidPointer(spNew, 2); 490 PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)sp), spNew)); 491 PetscCall(PetscObjectGetName((PetscObject)sp, &name)); 492 PetscCall(PetscObjectSetName((PetscObject)*spNew, name)); 493 PetscCall(PetscDualSpaceGetType(sp, &type)); 494 PetscCall(PetscDualSpaceSetType(*spNew, type)); 495 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 496 PetscCall(PetscDualSpaceSetDM(*spNew, dm)); 497 498 (*spNew)->order = sp->order; 499 (*spNew)->k = sp->k; 500 (*spNew)->Nc = sp->Nc; 501 (*spNew)->uniform = sp->uniform; 502 PetscTryTypeMethod(sp, duplicate, *spNew); 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 /*@ 507 PetscDualSpaceGetDM - Get the `DM` representing the reference cell of a `PetscDualSpace` 508 509 Not Collective 510 511 Input Parameter: 512 . sp - The `PetscDualSpace` 513 514 Output Parameter: 515 . dm - The reference cell, that is a `DM` that consists of a single cell 516 517 Level: intermediate 518 519 .seealso: `PetscDualSpace`, `PetscDualSpaceSetDM()`, `PetscDualSpaceCreate()` 520 @*/ 521 PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm) 522 { 523 PetscFunctionBegin; 524 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 525 PetscValidPointer(dm, 2); 526 *dm = sp->dm; 527 PetscFunctionReturn(PETSC_SUCCESS); 528 } 529 530 /*@ 531 PetscDualSpaceSetDM - Get the `DM` representing the reference cell 532 533 Not Collective 534 535 Input Parameters: 536 + sp - The `PetscDual`Space 537 - dm - The reference cell 538 539 Level: intermediate 540 541 .seealso: `PetscDualSpace`, `DM`, `PetscDualSpaceGetDM()`, `PetscDualSpaceCreate()` 542 @*/ 543 PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm) 544 { 545 PetscFunctionBegin; 546 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 547 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 548 PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change DM after dualspace is set up"); 549 PetscCall(PetscObjectReference((PetscObject)dm)); 550 if (sp->dm && sp->dm != dm) PetscCall(PetscDualSpaceClearDMData_Internal(sp, sp->dm)); 551 PetscCall(DMDestroy(&sp->dm)); 552 sp->dm = dm; 553 PetscFunctionReturn(PETSC_SUCCESS); 554 } 555 556 /*@ 557 PetscDualSpaceGetOrder - Get the order of the dual space 558 559 Not Collective 560 561 Input Parameter: 562 . sp - The `PetscDualSpace` 563 564 Output Parameter: 565 . order - The order 566 567 Level: intermediate 568 569 .seealso: `PetscDualSpace`, `PetscDualSpaceSetOrder()`, `PetscDualSpaceCreate()` 570 @*/ 571 PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order) 572 { 573 PetscFunctionBegin; 574 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 575 PetscValidIntPointer(order, 2); 576 *order = sp->order; 577 PetscFunctionReturn(PETSC_SUCCESS); 578 } 579 580 /*@ 581 PetscDualSpaceSetOrder - Set the order of the dual space 582 583 Not Collective 584 585 Input Parameters: 586 + sp - The `PetscDualSpace` 587 - order - The order 588 589 Level: intermediate 590 591 .seealso: `PetscDualSpace`, `PetscDualSpaceGetOrder()`, `PetscDualSpaceCreate()` 592 @*/ 593 PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order) 594 { 595 PetscFunctionBegin; 596 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 597 PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change order after dualspace is set up"); 598 sp->order = order; 599 PetscFunctionReturn(PETSC_SUCCESS); 600 } 601 602 /*@ 603 PetscDualSpaceGetNumComponents - Return the number of components for this space 604 605 Input Parameter: 606 . sp - The `PetscDualSpace` 607 608 Output Parameter: 609 . Nc - The number of components 610 611 Level: intermediate 612 613 Note: 614 A vector space, for example, will have d components, where d is the spatial dimension 615 616 .seealso: `PetscDualSpaceSetNumComponents()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()`, `PetscDualSpace` 617 @*/ 618 PetscErrorCode PetscDualSpaceGetNumComponents(PetscDualSpace sp, PetscInt *Nc) 619 { 620 PetscFunctionBegin; 621 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 622 PetscValidIntPointer(Nc, 2); 623 *Nc = sp->Nc; 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 /*@ 628 PetscDualSpaceSetNumComponents - Set the number of components for this space 629 630 Input Parameters: 631 + sp - The `PetscDualSpace` 632 - order - The number of components 633 634 Level: intermediate 635 636 .seealso: `PetscDualSpaceGetNumComponents()`, `PetscDualSpaceCreate()`, `PetscDualSpace` 637 @*/ 638 PetscErrorCode PetscDualSpaceSetNumComponents(PetscDualSpace sp, PetscInt Nc) 639 { 640 PetscFunctionBegin; 641 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 642 PetscCheck(!sp->setupcalled, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up"); 643 sp->Nc = Nc; 644 PetscFunctionReturn(PETSC_SUCCESS); 645 } 646 647 /*@ 648 PetscDualSpaceGetFunctional - Get the i-th basis functional in the dual space 649 650 Not Collective 651 652 Input Parameters: 653 + sp - The `PetscDualSpace` 654 - i - The basis number 655 656 Output Parameter: 657 . functional - The basis functional 658 659 Level: intermediate 660 661 .seealso: `PetscDualSpace`, `PetscQuadrature`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceCreate()` 662 @*/ 663 PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional) 664 { 665 PetscInt dim; 666 667 PetscFunctionBegin; 668 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 669 PetscValidPointer(functional, 3); 670 PetscCall(PetscDualSpaceGetDimension(sp, &dim)); 671 PetscCheck(!(i < 0) && !(i >= dim), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Functional index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", i, dim); 672 *functional = sp->functional[i]; 673 PetscFunctionReturn(PETSC_SUCCESS); 674 } 675 676 /*@ 677 PetscDualSpaceGetDimension - Get the dimension of the dual space, i.e. the number of basis functionals 678 679 Not Collective 680 681 Input Parameter: 682 . sp - The `PetscDualSpace` 683 684 Output Parameter: 685 . dim - The dimension 686 687 Level: intermediate 688 689 .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()` 690 @*/ 691 PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim) 692 { 693 PetscFunctionBegin; 694 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 695 PetscValidIntPointer(dim, 2); 696 if (sp->spdim < 0) { 697 PetscSection section; 698 699 PetscCall(PetscDualSpaceGetSection(sp, §ion)); 700 if (section) { 701 PetscCall(PetscSectionGetStorageSize(section, &(sp->spdim))); 702 } else sp->spdim = 0; 703 } 704 *dim = sp->spdim; 705 PetscFunctionReturn(PETSC_SUCCESS); 706 } 707 708 /*@ 709 PetscDualSpaceGetInteriorDimension - Get the interior dimension of the dual space, i.e. the number of basis functionals assigned to the interior of the reference domain 710 711 Not Collective 712 713 Input Parameter: 714 . sp - The `PetscDualSpace` 715 716 Output Parameter: 717 . dim - The dimension 718 719 Level: intermediate 720 721 .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()` 722 @*/ 723 PetscErrorCode PetscDualSpaceGetInteriorDimension(PetscDualSpace sp, PetscInt *intdim) 724 { 725 PetscFunctionBegin; 726 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 727 PetscValidIntPointer(intdim, 2); 728 if (sp->spintdim < 0) { 729 PetscSection section; 730 731 PetscCall(PetscDualSpaceGetSection(sp, §ion)); 732 if (section) { 733 PetscCall(PetscSectionGetConstrainedStorageSize(section, &(sp->spintdim))); 734 } else sp->spintdim = 0; 735 } 736 *intdim = sp->spintdim; 737 PetscFunctionReturn(PETSC_SUCCESS); 738 } 739 740 /*@ 741 PetscDualSpaceGetUniform - Whether this dual space is uniform 742 743 Not Collective 744 745 Input Parameters: 746 . sp - A dual space 747 748 Output Parameters: 749 . uniform - `PETSC_TRUE` if (a) the dual space is the same for each point in a stratum of the reference `DMPLEX`, and 750 (b) every symmetry of each point in the reference `DMPLEX` is also a symmetry of the point's dual space. 751 752 Level: advanced 753 754 Note: 755 All of the usual spaces on simplex or tensor-product elements will be uniform, only reference cells 756 with non-uniform strata (like trianguar-prisms) or anisotropic hp dual spaces will not be uniform. 757 758 .seealso: `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()`, `PetscDualSpaceGetSymmetries()` 759 @*/ 760 PetscErrorCode PetscDualSpaceGetUniform(PetscDualSpace sp, PetscBool *uniform) 761 { 762 PetscFunctionBegin; 763 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 764 PetscValidBoolPointer(uniform, 2); 765 *uniform = sp->uniform; 766 PetscFunctionReturn(PETSC_SUCCESS); 767 } 768 769 /*@C 770 PetscDualSpaceGetNumDof - Get the number of degrees of freedom for each spatial (topological) dimension 771 772 Not Collective 773 774 Input Parameter: 775 . sp - The `PetscDualSpace` 776 777 Output Parameter: 778 . numDof - An array of length dim+1 which holds the number of dofs for each dimension 779 780 Level: intermediate 781 782 .seealso: `PetscDualSpace`, `PetscDualSpaceGetFunctional()`, `PetscDualSpaceCreate()` 783 @*/ 784 PetscErrorCode PetscDualSpaceGetNumDof(PetscDualSpace sp, const PetscInt **numDof) 785 { 786 PetscFunctionBegin; 787 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 788 PetscValidPointer(numDof, 2); 789 PetscCheck(sp->uniform, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "A non-uniform space does not have a fixed number of dofs for each height"); 790 if (!sp->numDof) { 791 DM dm; 792 PetscInt depth, d; 793 PetscSection section; 794 795 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 796 PetscCall(DMPlexGetDepth(dm, &depth)); 797 PetscCall(PetscCalloc1(depth + 1, &(sp->numDof))); 798 PetscCall(PetscDualSpaceGetSection(sp, §ion)); 799 for (d = 0; d <= depth; d++) { 800 PetscInt dStart, dEnd; 801 802 PetscCall(DMPlexGetDepthStratum(dm, d, &dStart, &dEnd)); 803 if (dEnd <= dStart) continue; 804 PetscCall(PetscSectionGetDof(section, dStart, &(sp->numDof[d]))); 805 } 806 } 807 *numDof = sp->numDof; 808 PetscCheck(*numDof, PetscObjectComm((PetscObject)sp), PETSC_ERR_LIB, "Empty numDof[] returned from dual space implementation"); 809 PetscFunctionReturn(PETSC_SUCCESS); 810 } 811 812 /* create the section of the right size and set a permutation for topological ordering */ 813 PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace sp, PetscSection *topSection) 814 { 815 DM dm; 816 PetscInt pStart, pEnd, cStart, cEnd, c, depth, count, i; 817 PetscInt *seen, *perm; 818 PetscSection section; 819 820 PetscFunctionBegin; 821 dm = sp->dm; 822 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, §ion)); 823 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 824 PetscCall(PetscSectionSetChart(section, pStart, pEnd)); 825 PetscCall(PetscCalloc1(pEnd - pStart, &seen)); 826 PetscCall(PetscMalloc1(pEnd - pStart, &perm)); 827 PetscCall(DMPlexGetDepth(dm, &depth)); 828 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 829 for (c = cStart, count = 0; c < cEnd; c++) { 830 PetscInt closureSize = -1, e; 831 PetscInt *closure = NULL; 832 833 perm[count++] = c; 834 seen[c - pStart] = 1; 835 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 836 for (e = 0; e < closureSize; e++) { 837 PetscInt point = closure[2 * e]; 838 839 if (seen[point - pStart]) continue; 840 perm[count++] = point; 841 seen[point - pStart] = 1; 842 } 843 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure)); 844 } 845 PetscCheck(count == pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad topological ordering"); 846 for (i = 0; i < pEnd - pStart; i++) 847 if (perm[i] != i) break; 848 if (i < pEnd - pStart) { 849 IS permIS; 850 851 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd - pStart, perm, PETSC_OWN_POINTER, &permIS)); 852 PetscCall(ISSetPermutation(permIS)); 853 PetscCall(PetscSectionSetPermutation(section, permIS)); 854 PetscCall(ISDestroy(&permIS)); 855 } else { 856 PetscCall(PetscFree(perm)); 857 } 858 PetscCall(PetscFree(seen)); 859 *topSection = section; 860 PetscFunctionReturn(PETSC_SUCCESS); 861 } 862 863 /* mark boundary points and set up */ 864 PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace sp, PetscSection section) 865 { 866 DM dm; 867 DMLabel boundary; 868 PetscInt pStart, pEnd, p; 869 870 PetscFunctionBegin; 871 dm = sp->dm; 872 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "boundary", &boundary)); 873 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 874 PetscCall(DMPlexMarkBoundaryFaces(dm, 1, boundary)); 875 PetscCall(DMPlexLabelComplete(dm, boundary)); 876 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 877 for (p = pStart; p < pEnd; p++) { 878 PetscInt bval; 879 880 PetscCall(DMLabelGetValue(boundary, p, &bval)); 881 if (bval == 1) { 882 PetscInt dof; 883 884 PetscCall(PetscSectionGetDof(section, p, &dof)); 885 PetscCall(PetscSectionSetConstraintDof(section, p, dof)); 886 } 887 } 888 PetscCall(DMLabelDestroy(&boundary)); 889 PetscCall(PetscSectionSetUp(section)); 890 PetscFunctionReturn(PETSC_SUCCESS); 891 } 892 893 /*@ 894 PetscDualSpaceGetSection - Create a `PetscSection` over the reference cell with the layout from this space 895 896 Collective 897 898 Input Parameters: 899 . sp - The `PetscDualSpace` 900 901 Output Parameter: 902 . section - The section 903 904 Level: advanced 905 906 .seealso: `PetscDualSpace`, `PetscSection`, `PetscDualSpaceCreate()`, `DMPLEX` 907 @*/ 908 PetscErrorCode PetscDualSpaceGetSection(PetscDualSpace sp, PetscSection *section) 909 { 910 PetscInt pStart, pEnd, p; 911 912 PetscFunctionBegin; 913 if (!sp->dm) { 914 *section = NULL; 915 PetscFunctionReturn(PETSC_SUCCESS); 916 } 917 if (!sp->pointSection) { 918 /* mark the boundary */ 919 PetscCall(PetscDualSpaceSectionCreate_Internal(sp, &(sp->pointSection))); 920 PetscCall(DMPlexGetChart(sp->dm, &pStart, &pEnd)); 921 for (p = pStart; p < pEnd; p++) { 922 PetscDualSpace psp; 923 924 PetscCall(PetscDualSpaceGetPointSubspace(sp, p, &psp)); 925 if (psp) { 926 PetscInt dof; 927 928 PetscCall(PetscDualSpaceGetInteriorDimension(psp, &dof)); 929 PetscCall(PetscSectionSetDof(sp->pointSection, p, dof)); 930 } 931 } 932 PetscCall(PetscDualSpaceSectionSetUp_Internal(sp, sp->pointSection)); 933 } 934 *section = sp->pointSection; 935 PetscFunctionReturn(PETSC_SUCCESS); 936 } 937 938 /* this assumes that all of the point dual spaces store their interior dofs first, which is true when the point DMs 939 * have one cell */ 940 PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace sp, PetscInt sStart, PetscInt sEnd) 941 { 942 PetscReal *sv0, *v0, *J; 943 PetscSection section; 944 PetscInt dim, s, k; 945 DM dm; 946 947 PetscFunctionBegin; 948 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 949 PetscCall(DMGetDimension(dm, &dim)); 950 PetscCall(PetscDualSpaceGetSection(sp, §ion)); 951 PetscCall(PetscMalloc3(dim, &v0, dim, &sv0, dim * dim, &J)); 952 PetscCall(PetscDualSpaceGetFormDegree(sp, &k)); 953 for (s = sStart; s < sEnd; s++) { 954 PetscReal detJ, hdetJ; 955 PetscDualSpace ssp; 956 PetscInt dof, off, f, sdim; 957 PetscInt i, j; 958 DM sdm; 959 960 PetscCall(PetscDualSpaceGetPointSubspace(sp, s, &ssp)); 961 if (!ssp) continue; 962 PetscCall(PetscSectionGetDof(section, s, &dof)); 963 PetscCall(PetscSectionGetOffset(section, s, &off)); 964 /* get the first vertex of the reference cell */ 965 PetscCall(PetscDualSpaceGetDM(ssp, &sdm)); 966 PetscCall(DMGetDimension(sdm, &sdim)); 967 PetscCall(DMPlexComputeCellGeometryAffineFEM(sdm, 0, sv0, NULL, NULL, &hdetJ)); 968 PetscCall(DMPlexComputeCellGeometryAffineFEM(dm, s, v0, J, NULL, &detJ)); 969 /* compactify Jacobian */ 970 for (i = 0; i < dim; i++) 971 for (j = 0; j < sdim; j++) J[i * sdim + j] = J[i * dim + j]; 972 for (f = 0; f < dof; f++) { 973 PetscQuadrature fn; 974 975 PetscCall(PetscDualSpaceGetFunctional(ssp, f, &fn)); 976 PetscCall(PetscQuadraturePushForward(fn, dim, sv0, v0, J, k, &(sp->functional[off + f]))); 977 } 978 } 979 PetscCall(PetscFree3(v0, sv0, J)); 980 PetscFunctionReturn(PETSC_SUCCESS); 981 } 982 983 /*@C 984 PetscDualSpaceApply - Apply a functional from the dual space basis to an input function 985 986 Input Parameters: 987 + sp - The `PetscDualSpace` object 988 . f - The basis functional index 989 . time - The time 990 . 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) 991 . numComp - The number of components for the function 992 . func - The input function 993 - ctx - A context for the function 994 995 Output Parameter: 996 . value - numComp output values 997 998 Calling Sequence of `func`: 999 .vb 1000 PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx) 1001 .ve 1002 1003 Level: beginner 1004 1005 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1006 @*/ 1007 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) 1008 { 1009 PetscFunctionBegin; 1010 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1011 PetscValidPointer(cgeom, 4); 1012 PetscValidScalarPointer(value, 8); 1013 PetscUseTypeMethod(sp, apply, f, time, cgeom, numComp, func, ctx, value); 1014 PetscFunctionReturn(PETSC_SUCCESS); 1015 } 1016 1017 /*@C 1018 PetscDualSpaceApplyAll - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()` 1019 1020 Input Parameters: 1021 + sp - The `PetscDualSpace` object 1022 - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()` 1023 1024 Output Parameter: 1025 . spValue - The values of all dual space functionals 1026 1027 Level: advanced 1028 1029 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1030 @*/ 1031 PetscErrorCode PetscDualSpaceApplyAll(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) 1032 { 1033 PetscFunctionBegin; 1034 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1035 PetscUseTypeMethod(sp, applyall, pointEval, spValue); 1036 PetscFunctionReturn(PETSC_SUCCESS); 1037 } 1038 1039 /*@C 1040 PetscDualSpaceApplyInterior - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()` 1041 1042 Input Parameters: 1043 + sp - The `PetscDualSpace` object 1044 - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()` 1045 1046 Output Parameter: 1047 . spValue - The values of interior dual space functionals 1048 1049 Level: advanced 1050 1051 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1052 @*/ 1053 PetscErrorCode PetscDualSpaceApplyInterior(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) 1054 { 1055 PetscFunctionBegin; 1056 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1057 PetscUseTypeMethod(sp, applyint, pointEval, spValue); 1058 PetscFunctionReturn(PETSC_SUCCESS); 1059 } 1060 1061 /*@C 1062 PetscDualSpaceApplyDefault - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional. 1063 1064 Input Parameters: 1065 + sp - The `PetscDualSpace` object 1066 . f - The basis functional index 1067 . time - The time 1068 . cgeom - A context with geometric information for this cell, we use v0 (the initial vertex) and J (the Jacobian) 1069 . Nc - The number of components for the function 1070 . func - The input function 1071 - ctx - A context for the function 1072 1073 Output Parameter: 1074 . value - The output value 1075 1076 Calling Sequence of `func`: 1077 .vb 1078 PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[],PetscInt numComponents, PetscScalar values[], void *ctx) 1079 .ve 1080 1081 Level: advanced 1082 1083 Note: 1084 The idea is to evaluate the functional as an integral $ n(f) = \int dx n(x) . f(x) $ where both n and f have Nc components. 1085 1086 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1087 @*/ 1088 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) 1089 { 1090 DM dm; 1091 PetscQuadrature n; 1092 const PetscReal *points, *weights; 1093 PetscReal x[3]; 1094 PetscScalar *val; 1095 PetscInt dim, dE, qNc, c, Nq, q; 1096 PetscBool isAffine; 1097 1098 PetscFunctionBegin; 1099 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1100 PetscValidScalarPointer(value, 8); 1101 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 1102 PetscCall(PetscDualSpaceGetFunctional(sp, f, &n)); 1103 PetscCall(PetscQuadratureGetData(n, &dim, &qNc, &Nq, &points, &weights)); 1104 PetscCheck(dim == cgeom->dim, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature spatial dimension %" PetscInt_FMT " != cell geometry dimension %" PetscInt_FMT, dim, cgeom->dim); 1105 PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc); 1106 PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val)); 1107 *value = 0.0; 1108 isAffine = cgeom->isAffine; 1109 dE = cgeom->dimEmbed; 1110 for (q = 0; q < Nq; ++q) { 1111 if (isAffine) { 1112 CoordinatesRefToReal(dE, cgeom->dim, cgeom->xi, cgeom->v, cgeom->J, &points[q * dim], x); 1113 PetscCall((*func)(dE, time, x, Nc, val, ctx)); 1114 } else { 1115 PetscCall((*func)(dE, time, &cgeom->v[dE * q], Nc, val, ctx)); 1116 } 1117 for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c]; 1118 } 1119 PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val)); 1120 PetscFunctionReturn(PETSC_SUCCESS); 1121 } 1122 1123 /*@C 1124 PetscDualSpaceApplyAllDefault - Apply all functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetAllData()` 1125 1126 Input Parameters: 1127 + sp - The `PetscDualSpace` object 1128 - pointEval - Evaluation at the points returned by `PetscDualSpaceGetAllData()` 1129 1130 Output Parameter: 1131 . spValue - The values of all dual space functionals 1132 1133 Level: advanced 1134 1135 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1136 @*/ 1137 PetscErrorCode PetscDualSpaceApplyAllDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) 1138 { 1139 Vec pointValues, dofValues; 1140 Mat allMat; 1141 1142 PetscFunctionBegin; 1143 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1144 PetscValidScalarPointer(pointEval, 2); 1145 PetscValidScalarPointer(spValue, 3); 1146 PetscCall(PetscDualSpaceGetAllData(sp, NULL, &allMat)); 1147 if (!(sp->allNodeValues)) PetscCall(MatCreateVecs(allMat, &(sp->allNodeValues), NULL)); 1148 pointValues = sp->allNodeValues; 1149 if (!(sp->allDofValues)) PetscCall(MatCreateVecs(allMat, NULL, &(sp->allDofValues))); 1150 dofValues = sp->allDofValues; 1151 PetscCall(VecPlaceArray(pointValues, pointEval)); 1152 PetscCall(VecPlaceArray(dofValues, spValue)); 1153 PetscCall(MatMult(allMat, pointValues, dofValues)); 1154 PetscCall(VecResetArray(dofValues)); 1155 PetscCall(VecResetArray(pointValues)); 1156 PetscFunctionReturn(PETSC_SUCCESS); 1157 } 1158 1159 /*@C 1160 PetscDualSpaceApplyInteriorDefault - Apply interior functionals from the dual space basis to the result of an evaluation at the points returned by `PetscDualSpaceGetInteriorData()` 1161 1162 Input Parameters: 1163 + sp - The `PetscDualSpace` object 1164 - pointEval - Evaluation at the points returned by `PetscDualSpaceGetInteriorData()` 1165 1166 Output Parameter: 1167 . spValue - The values of interior dual space functionals 1168 1169 Level: advanced 1170 1171 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1172 @*/ 1173 PetscErrorCode PetscDualSpaceApplyInteriorDefault(PetscDualSpace sp, const PetscScalar *pointEval, PetscScalar *spValue) 1174 { 1175 Vec pointValues, dofValues; 1176 Mat intMat; 1177 1178 PetscFunctionBegin; 1179 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1180 PetscValidScalarPointer(pointEval, 2); 1181 PetscValidScalarPointer(spValue, 3); 1182 PetscCall(PetscDualSpaceGetInteriorData(sp, NULL, &intMat)); 1183 if (!(sp->intNodeValues)) PetscCall(MatCreateVecs(intMat, &(sp->intNodeValues), NULL)); 1184 pointValues = sp->intNodeValues; 1185 if (!(sp->intDofValues)) PetscCall(MatCreateVecs(intMat, NULL, &(sp->intDofValues))); 1186 dofValues = sp->intDofValues; 1187 PetscCall(VecPlaceArray(pointValues, pointEval)); 1188 PetscCall(VecPlaceArray(dofValues, spValue)); 1189 PetscCall(MatMult(intMat, pointValues, dofValues)); 1190 PetscCall(VecResetArray(dofValues)); 1191 PetscCall(VecResetArray(pointValues)); 1192 PetscFunctionReturn(PETSC_SUCCESS); 1193 } 1194 1195 /*@ 1196 PetscDualSpaceGetAllData - Get all quadrature nodes from this space, and the matrix that sends quadrature node values to degree-of-freedom values 1197 1198 Input Parameter: 1199 . sp - The dualspace 1200 1201 Output Parameters: 1202 + allNodes - A `PetscQuadrature` object containing all evaluation nodes 1203 - allMat - A `Mat` for the node-to-dof transformation 1204 1205 Level: advanced 1206 1207 .seealso: `PetscQuadrature`, `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat` 1208 @*/ 1209 PetscErrorCode PetscDualSpaceGetAllData(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat) 1210 { 1211 PetscFunctionBegin; 1212 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1213 if (allNodes) PetscValidPointer(allNodes, 2); 1214 if (allMat) PetscValidPointer(allMat, 3); 1215 if ((!sp->allNodes || !sp->allMat) && sp->ops->createalldata) { 1216 PetscQuadrature qpoints; 1217 Mat amat; 1218 1219 PetscUseTypeMethod(sp, createalldata, &qpoints, &amat); 1220 PetscCall(PetscQuadratureDestroy(&(sp->allNodes))); 1221 PetscCall(MatDestroy(&(sp->allMat))); 1222 sp->allNodes = qpoints; 1223 sp->allMat = amat; 1224 } 1225 if (allNodes) *allNodes = sp->allNodes; 1226 if (allMat) *allMat = sp->allMat; 1227 PetscFunctionReturn(PETSC_SUCCESS); 1228 } 1229 1230 /*@ 1231 PetscDualSpaceCreateAllDataDefault - Create all evaluation nodes and the node-to-dof matrix by examining functionals 1232 1233 Input Parameter: 1234 . sp - The dualspace 1235 1236 Output Parameters: 1237 + allNodes - A `PetscQuadrature` object containing all evaluation nodes 1238 - allMat - A `Mat` for the node-to-dof transformation 1239 1240 Level: advanced 1241 1242 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()`, `Mat`, `PetscQuadrature` 1243 @*/ 1244 PetscErrorCode PetscDualSpaceCreateAllDataDefault(PetscDualSpace sp, PetscQuadrature *allNodes, Mat *allMat) 1245 { 1246 PetscInt spdim; 1247 PetscInt numPoints, offset; 1248 PetscReal *points; 1249 PetscInt f, dim; 1250 PetscInt Nc, nrows, ncols; 1251 PetscInt maxNumPoints; 1252 PetscQuadrature q; 1253 Mat A; 1254 1255 PetscFunctionBegin; 1256 PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc)); 1257 PetscCall(PetscDualSpaceGetDimension(sp, &spdim)); 1258 if (!spdim) { 1259 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes)); 1260 PetscCall(PetscQuadratureSetData(*allNodes, 0, 0, 0, NULL, NULL)); 1261 } 1262 nrows = spdim; 1263 PetscCall(PetscDualSpaceGetFunctional(sp, 0, &q)); 1264 PetscCall(PetscQuadratureGetData(q, &dim, NULL, &numPoints, NULL, NULL)); 1265 maxNumPoints = numPoints; 1266 for (f = 1; f < spdim; f++) { 1267 PetscInt Np; 1268 1269 PetscCall(PetscDualSpaceGetFunctional(sp, f, &q)); 1270 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL)); 1271 numPoints += Np; 1272 maxNumPoints = PetscMax(maxNumPoints, Np); 1273 } 1274 ncols = numPoints * Nc; 1275 PetscCall(PetscMalloc1(dim * numPoints, &points)); 1276 PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, nrows, ncols, maxNumPoints * Nc, NULL, &A)); 1277 for (f = 0, offset = 0; f < spdim; f++) { 1278 const PetscReal *p, *w; 1279 PetscInt Np, i; 1280 PetscInt fnc; 1281 1282 PetscCall(PetscDualSpaceGetFunctional(sp, f, &q)); 1283 PetscCall(PetscQuadratureGetData(q, NULL, &fnc, &Np, &p, &w)); 1284 PetscCheck(fnc == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "functional component mismatch"); 1285 for (i = 0; i < Np * dim; i++) points[offset * dim + i] = p[i]; 1286 for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(A, f, offset * Nc, w[i], INSERT_VALUES)); 1287 offset += Np; 1288 } 1289 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 1290 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 1291 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allNodes)); 1292 PetscCall(PetscQuadratureSetData(*allNodes, dim, 0, numPoints, points, NULL)); 1293 *allMat = A; 1294 PetscFunctionReturn(PETSC_SUCCESS); 1295 } 1296 1297 /*@ 1298 PetscDualSpaceGetInteriorData - Get all quadrature points necessary to compute the interior degrees of freedom from 1299 this space, as well as the matrix that computes the degrees of freedom from the quadrature values. Degrees of 1300 freedom are interior degrees of freedom if they belong (by `PetscDualSpaceGetSection()`) to interior points in the 1301 reference `DMPLEX`: complementary boundary degrees of freedom are marked as constrained in the section returned by 1302 `PetscDualSpaceGetSection()`). 1303 1304 Input Parameter: 1305 . sp - The dualspace 1306 1307 Output Parameters: 1308 + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom 1309 - intMat - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is 1310 the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section, 1311 npoints is the number of points in intNodes and nc is `PetscDualSpaceGetNumComponents()`. 1312 1313 Level: advanced 1314 1315 .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetDimension()`, `PetscDualSpaceGetNumComponents()`, `PetscQuadratureGetData()` 1316 @*/ 1317 PetscErrorCode PetscDualSpaceGetInteriorData(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat) 1318 { 1319 PetscFunctionBegin; 1320 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1321 if (intNodes) PetscValidPointer(intNodes, 2); 1322 if (intMat) PetscValidPointer(intMat, 3); 1323 if ((!sp->intNodes || !sp->intMat) && sp->ops->createintdata) { 1324 PetscQuadrature qpoints; 1325 Mat imat; 1326 1327 PetscUseTypeMethod(sp, createintdata, &qpoints, &imat); 1328 PetscCall(PetscQuadratureDestroy(&(sp->intNodes))); 1329 PetscCall(MatDestroy(&(sp->intMat))); 1330 sp->intNodes = qpoints; 1331 sp->intMat = imat; 1332 } 1333 if (intNodes) *intNodes = sp->intNodes; 1334 if (intMat) *intMat = sp->intMat; 1335 PetscFunctionReturn(PETSC_SUCCESS); 1336 } 1337 1338 /*@ 1339 PetscDualSpaceCreateInteriorDataDefault - Create quadrature points by examining interior functionals and create the matrix mapping quadrature point values to interior dual space values 1340 1341 Input Parameter: 1342 . sp - The dualspace 1343 1344 Output Parameters: 1345 + intNodes - A `PetscQuadrature` object containing all evaluation points needed to evaluate interior degrees of freedom 1346 - intMat - A matrix that computes dual space values from point values: size [spdim0 x (npoints * nc)], where spdim0 is 1347 the size of the constrained layout (`PetscSectionGetConstrainStorageSize()`) of the dual space section, 1348 npoints is the number of points in allNodes and nc is `PetscDualSpaceGetNumComponents()`. 1349 1350 Level: advanced 1351 1352 .seealso: `PetscDualSpace`, `PetscQuadrature`, `Mat`, `PetscDualSpaceCreate()`, `PetscDualSpaceGetInteriorData()` 1353 @*/ 1354 PetscErrorCode PetscDualSpaceCreateInteriorDataDefault(PetscDualSpace sp, PetscQuadrature *intNodes, Mat *intMat) 1355 { 1356 DM dm; 1357 PetscInt spdim0; 1358 PetscInt Nc; 1359 PetscInt pStart, pEnd, p, f; 1360 PetscSection section; 1361 PetscInt numPoints, offset, matoffset; 1362 PetscReal *points; 1363 PetscInt dim; 1364 PetscInt *nnz; 1365 PetscQuadrature q; 1366 Mat imat; 1367 1368 PetscFunctionBegin; 1369 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1370 PetscCall(PetscDualSpaceGetSection(sp, §ion)); 1371 PetscCall(PetscSectionGetConstrainedStorageSize(section, &spdim0)); 1372 if (!spdim0) { 1373 *intNodes = NULL; 1374 *intMat = NULL; 1375 PetscFunctionReturn(PETSC_SUCCESS); 1376 } 1377 PetscCall(PetscDualSpaceGetNumComponents(sp, &Nc)); 1378 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 1379 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 1380 PetscCall(DMGetDimension(dm, &dim)); 1381 PetscCall(PetscMalloc1(spdim0, &nnz)); 1382 for (p = pStart, f = 0, numPoints = 0; p < pEnd; p++) { 1383 PetscInt dof, cdof, off, d; 1384 1385 PetscCall(PetscSectionGetDof(section, p, &dof)); 1386 PetscCall(PetscSectionGetConstraintDof(section, p, &cdof)); 1387 if (!(dof - cdof)) continue; 1388 PetscCall(PetscSectionGetOffset(section, p, &off)); 1389 for (d = 0; d < dof; d++, off++, f++) { 1390 PetscInt Np; 1391 1392 PetscCall(PetscDualSpaceGetFunctional(sp, off, &q)); 1393 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, NULL, NULL)); 1394 nnz[f] = Np * Nc; 1395 numPoints += Np; 1396 } 1397 } 1398 PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, spdim0, numPoints * Nc, 0, nnz, &imat)); 1399 PetscCall(PetscFree(nnz)); 1400 PetscCall(PetscMalloc1(dim * numPoints, &points)); 1401 for (p = pStart, f = 0, offset = 0, matoffset = 0; p < pEnd; p++) { 1402 PetscInt dof, cdof, off, d; 1403 1404 PetscCall(PetscSectionGetDof(section, p, &dof)); 1405 PetscCall(PetscSectionGetConstraintDof(section, p, &cdof)); 1406 if (!(dof - cdof)) continue; 1407 PetscCall(PetscSectionGetOffset(section, p, &off)); 1408 for (d = 0; d < dof; d++, off++, f++) { 1409 const PetscReal *p; 1410 const PetscReal *w; 1411 PetscInt Np, i; 1412 1413 PetscCall(PetscDualSpaceGetFunctional(sp, off, &q)); 1414 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Np, &p, &w)); 1415 for (i = 0; i < Np * dim; i++) points[offset + i] = p[i]; 1416 for (i = 0; i < Np * Nc; i++) PetscCall(MatSetValue(imat, f, matoffset + i, w[i], INSERT_VALUES)); 1417 offset += Np * dim; 1418 matoffset += Np * Nc; 1419 } 1420 } 1421 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, intNodes)); 1422 PetscCall(PetscQuadratureSetData(*intNodes, dim, 0, numPoints, points, NULL)); 1423 PetscCall(MatAssemblyBegin(imat, MAT_FINAL_ASSEMBLY)); 1424 PetscCall(MatAssemblyEnd(imat, MAT_FINAL_ASSEMBLY)); 1425 *intMat = imat; 1426 PetscFunctionReturn(PETSC_SUCCESS); 1427 } 1428 1429 /*@ 1430 PetscDualSpaceEqual - Determine if two dual spaces are equivalent 1431 1432 Input Parameters: 1433 + A - A `PetscDualSpace` object 1434 - B - Another `PetscDualSpace` object 1435 1436 Output Parameter: 1437 . equal - `PETSC_TRUE` if the dual spaces are equivalent 1438 1439 Level: advanced 1440 1441 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1442 @*/ 1443 PetscErrorCode PetscDualSpaceEqual(PetscDualSpace A, PetscDualSpace B, PetscBool *equal) 1444 { 1445 PetscInt sizeA, sizeB, dimA, dimB; 1446 const PetscInt *dofA, *dofB; 1447 PetscQuadrature quadA, quadB; 1448 Mat matA, matB; 1449 1450 PetscFunctionBegin; 1451 PetscValidHeaderSpecific(A, PETSCDUALSPACE_CLASSID, 1); 1452 PetscValidHeaderSpecific(B, PETSCDUALSPACE_CLASSID, 2); 1453 PetscValidBoolPointer(equal, 3); 1454 *equal = PETSC_FALSE; 1455 PetscCall(PetscDualSpaceGetDimension(A, &sizeA)); 1456 PetscCall(PetscDualSpaceGetDimension(B, &sizeB)); 1457 if (sizeB != sizeA) PetscFunctionReturn(PETSC_SUCCESS); 1458 PetscCall(DMGetDimension(A->dm, &dimA)); 1459 PetscCall(DMGetDimension(B->dm, &dimB)); 1460 if (dimA != dimB) PetscFunctionReturn(PETSC_SUCCESS); 1461 1462 PetscCall(PetscDualSpaceGetNumDof(A, &dofA)); 1463 PetscCall(PetscDualSpaceGetNumDof(B, &dofB)); 1464 for (PetscInt d = 0; d < dimA; d++) { 1465 if (dofA[d] != dofB[d]) PetscFunctionReturn(PETSC_SUCCESS); 1466 } 1467 1468 PetscCall(PetscDualSpaceGetInteriorData(A, &quadA, &matA)); 1469 PetscCall(PetscDualSpaceGetInteriorData(B, &quadB, &matB)); 1470 if (!quadA && !quadB) { 1471 *equal = PETSC_TRUE; 1472 } else if (quadA && quadB) { 1473 PetscCall(PetscQuadratureEqual(quadA, quadB, equal)); 1474 if (*equal == PETSC_FALSE) PetscFunctionReturn(PETSC_SUCCESS); 1475 if (!matA && !matB) PetscFunctionReturn(PETSC_SUCCESS); 1476 if (matA && matB) PetscCall(MatEqual(matA, matB, equal)); 1477 else *equal = PETSC_FALSE; 1478 } 1479 PetscFunctionReturn(PETSC_SUCCESS); 1480 } 1481 1482 /*@C 1483 PetscDualSpaceApplyFVM - Apply a functional from the dual space basis to an input function by assuming a point evaluation functional at the cell centroid. 1484 1485 Input Parameters: 1486 + sp - The `PetscDualSpace` object 1487 . f - The basis functional index 1488 . time - The time 1489 . cgeom - A context with geometric information for this cell, we currently just use the centroid 1490 . Nc - The number of components for the function 1491 . func - The input function 1492 - ctx - A context for the function 1493 1494 Output Parameter: 1495 . value - The output value (scalar) 1496 1497 Calling Sequence of `func`: 1498 .vb 1499 PetscErrorCode func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt numComponents, PetscScalar values[], void *ctx) 1500 .ve 1501 1502 Level: advanced 1503 1504 Note: 1505 The idea is to evaluate the functional as an integral $ n(f) = \int dx n(x) . f(x)$ where both n and f have Nc components. 1506 1507 .seealso: `PetscDualSpace`, `PetscDualSpaceCreate()` 1508 @*/ 1509 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) 1510 { 1511 DM dm; 1512 PetscQuadrature n; 1513 const PetscReal *points, *weights; 1514 PetscScalar *val; 1515 PetscInt dimEmbed, qNc, c, Nq, q; 1516 1517 PetscFunctionBegin; 1518 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1519 PetscValidScalarPointer(value, 8); 1520 PetscCall(PetscDualSpaceGetDM(sp, &dm)); 1521 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 1522 PetscCall(PetscDualSpaceGetFunctional(sp, f, &n)); 1523 PetscCall(PetscQuadratureGetData(n, NULL, &qNc, &Nq, &points, &weights)); 1524 PetscCheck(qNc == Nc, PetscObjectComm((PetscObject)sp), PETSC_ERR_ARG_SIZ, "The quadrature components %" PetscInt_FMT " != function components %" PetscInt_FMT, qNc, Nc); 1525 PetscCall(DMGetWorkArray(dm, Nc, MPIU_SCALAR, &val)); 1526 *value = 0.; 1527 for (q = 0; q < Nq; ++q) { 1528 PetscCall((*func)(dimEmbed, time, cgeom->centroid, Nc, val, ctx)); 1529 for (c = 0; c < Nc; ++c) *value += val[c] * weights[q * Nc + c]; 1530 } 1531 PetscCall(DMRestoreWorkArray(dm, Nc, MPIU_SCALAR, &val)); 1532 PetscFunctionReturn(PETSC_SUCCESS); 1533 } 1534 1535 /*@ 1536 PetscDualSpaceGetHeightSubspace - Get the subset of the dual space basis that is supported on a mesh point of a 1537 given height. This assumes that the reference cell is symmetric over points of this height. 1538 1539 Not Collective 1540 1541 Input Parameters: 1542 + sp - the `PetscDualSpace` object 1543 - height - the height of the mesh point for which the subspace is desired 1544 1545 Output Parameter: 1546 . subsp - the subspace. Note that the functionals in the subspace are with respect to the intrinsic geometry of the 1547 point, which will be of lesser dimension if height > 0. 1548 1549 Level: advanced 1550 1551 Notes: 1552 If the dual space is not defined on mesh points of the given height (e.g. if the space is discontinuous and 1553 pointwise values are not defined on the element boundaries), or if the implementation of `PetscDualSpace` does not 1554 support extracting subspaces, then NULL is returned. 1555 1556 This does not increment the reference count on the returned dual space, and the user should not destroy it. 1557 1558 .seealso: `PetscDualSpace`, `PetscSpaceGetHeightSubspace()`, `PetscDualSpace`, `PetscDualSpaceGetPointSubspace()` 1559 @*/ 1560 PetscErrorCode PetscDualSpaceGetHeightSubspace(PetscDualSpace sp, PetscInt height, PetscDualSpace *subsp) 1561 { 1562 PetscInt depth = -1, cStart, cEnd; 1563 DM dm; 1564 1565 PetscFunctionBegin; 1566 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1567 PetscValidPointer(subsp, 3); 1568 PetscCheck((sp->uniform), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "A non-uniform dual space does not have a single dual space at each height"); 1569 *subsp = NULL; 1570 dm = sp->dm; 1571 PetscCall(DMPlexGetDepth(dm, &depth)); 1572 PetscCheck(height >= 0 && height <= depth, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid height"); 1573 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1574 if (height == 0 && cEnd == cStart + 1) { 1575 *subsp = sp; 1576 PetscFunctionReturn(PETSC_SUCCESS); 1577 } 1578 if (!sp->heightSpaces) { 1579 PetscInt h; 1580 PetscCall(PetscCalloc1(depth + 1, &(sp->heightSpaces))); 1581 1582 for (h = 0; h <= depth; h++) { 1583 if (h == 0 && cEnd == cStart + 1) continue; 1584 if (sp->ops->createheightsubspace) PetscCall((*sp->ops->createheightsubspace)(sp, height, &(sp->heightSpaces[h]))); 1585 else if (sp->pointSpaces) { 1586 PetscInt hStart, hEnd; 1587 1588 PetscCall(DMPlexGetHeightStratum(dm, h, &hStart, &hEnd)); 1589 if (hEnd > hStart) { 1590 const char *name; 1591 1592 PetscCall(PetscObjectReference((PetscObject)(sp->pointSpaces[hStart]))); 1593 if (sp->pointSpaces[hStart]) { 1594 PetscCall(PetscObjectGetName((PetscObject)sp, &name)); 1595 PetscCall(PetscObjectSetName((PetscObject)sp->pointSpaces[hStart], name)); 1596 } 1597 sp->heightSpaces[h] = sp->pointSpaces[hStart]; 1598 } 1599 } 1600 } 1601 } 1602 *subsp = sp->heightSpaces[height]; 1603 PetscFunctionReturn(PETSC_SUCCESS); 1604 } 1605 1606 /*@ 1607 PetscDualSpaceGetPointSubspace - Get the subset of the dual space basis that is supported on a particular mesh point. 1608 1609 Not Collective 1610 1611 Input Parameters: 1612 + sp - the `PetscDualSpace` object 1613 - point - the point (in the dual space's DM) for which the subspace is desired 1614 1615 Output Parameters: 1616 bdsp - the subspace. The functionals in the subspace are with respect to the intrinsic geometry of the 1617 point, which will be of lesser dimension if height > 0. 1618 1619 Level: advanced 1620 1621 Notes: 1622 If the dual space is not defined on the mesh point (e.g. if the space is discontinuous and pointwise values are not 1623 defined on the element boundaries), or if the implementation of `PetscDualSpace` does not support extracting 1624 subspaces, then NULL is returned. 1625 1626 This does not increment the reference count on the returned dual space, and the user should not destroy it. 1627 1628 .seealso: `PetscDualSpace`, `PetscDualSpaceGetHeightSubspace()` 1629 @*/ 1630 PetscErrorCode PetscDualSpaceGetPointSubspace(PetscDualSpace sp, PetscInt point, PetscDualSpace *bdsp) 1631 { 1632 PetscInt pStart = 0, pEnd = 0, cStart, cEnd; 1633 DM dm; 1634 1635 PetscFunctionBegin; 1636 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1637 PetscValidPointer(bdsp, 3); 1638 *bdsp = NULL; 1639 dm = sp->dm; 1640 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1641 PetscCheck(point >= pStart && point <= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid point"); 1642 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 1643 if (point == cStart && cEnd == cStart + 1) { /* the dual space is only equivalent to the dual space on a cell if the reference mesh has just one cell */ 1644 *bdsp = sp; 1645 PetscFunctionReturn(PETSC_SUCCESS); 1646 } 1647 if (!sp->pointSpaces) { 1648 PetscInt p; 1649 PetscCall(PetscCalloc1(pEnd - pStart, &(sp->pointSpaces))); 1650 1651 for (p = 0; p < pEnd - pStart; p++) { 1652 if (p + pStart == cStart && cEnd == cStart + 1) continue; 1653 if (sp->ops->createpointsubspace) PetscCall((*sp->ops->createpointsubspace)(sp, p + pStart, &(sp->pointSpaces[p]))); 1654 else if (sp->heightSpaces || sp->ops->createheightsubspace) { 1655 PetscInt dim, depth, height; 1656 DMLabel label; 1657 1658 PetscCall(DMPlexGetDepth(dm, &dim)); 1659 PetscCall(DMPlexGetDepthLabel(dm, &label)); 1660 PetscCall(DMLabelGetValue(label, p + pStart, &depth)); 1661 height = dim - depth; 1662 PetscCall(PetscDualSpaceGetHeightSubspace(sp, height, &(sp->pointSpaces[p]))); 1663 PetscCall(PetscObjectReference((PetscObject)sp->pointSpaces[p])); 1664 } 1665 } 1666 } 1667 *bdsp = sp->pointSpaces[point - pStart]; 1668 PetscFunctionReturn(PETSC_SUCCESS); 1669 } 1670 1671 /*@C 1672 PetscDualSpaceGetSymmetries - Returns a description of the symmetries of this basis 1673 1674 Not Collective 1675 1676 Input Parameter: 1677 . sp - the `PetscDualSpace` object 1678 1679 Output Parameters: 1680 + perms - Permutations of the interior degrees of freedom, parameterized by the point orientation 1681 - flips - Sign reversal of the interior degrees of freedom, parameterized by the point orientation 1682 1683 Level: developer 1684 1685 Note: 1686 The permutation and flip arrays are organized in the following way 1687 .vb 1688 perms[p][ornt][dof # on point] = new local dof # 1689 flips[p][ornt][dof # on point] = reversal or not 1690 .ve 1691 1692 .seealso: `PetscDualSpace` 1693 @*/ 1694 PetscErrorCode PetscDualSpaceGetSymmetries(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips) 1695 { 1696 PetscFunctionBegin; 1697 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 1698 if (perms) { 1699 PetscValidPointer(perms, 2); 1700 *perms = NULL; 1701 } 1702 if (flips) { 1703 PetscValidPointer(flips, 3); 1704 *flips = NULL; 1705 } 1706 if (sp->ops->getsymmetries) PetscCall((sp->ops->getsymmetries)(sp, perms, flips)); 1707 PetscFunctionReturn(PETSC_SUCCESS); 1708 } 1709 1710 /*@ 1711 PetscDualSpaceGetFormDegree - Get the form degree k for the k-form the describes the pushforwards/pullbacks of this 1712 dual space's functionals. 1713 1714 Input Parameter: 1715 . dsp - The `PetscDualSpace` 1716 1717 Output Parameter: 1718 . k - The *signed* degree k of the k. If k >= 0, this means that the degrees of freedom are k-forms, and are stored 1719 in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms. So for example, 1720 the 1-form basis in 3-D is (dx, dy, dz), and the 2-form basis in 3-D is (dx wedge dy, dx wedge dz, dy wedge dz). 1721 If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the 1722 Hodge star map. So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms 1723 but are stored as 1-forms. 1724 1725 Level: developer 1726 1727 .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType` 1728 @*/ 1729 PetscErrorCode PetscDualSpaceGetFormDegree(PetscDualSpace dsp, PetscInt *k) 1730 { 1731 PetscFunctionBeginHot; 1732 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1733 PetscValidIntPointer(k, 2); 1734 *k = dsp->k; 1735 PetscFunctionReturn(PETSC_SUCCESS); 1736 } 1737 1738 /*@ 1739 PetscDualSpaceSetFormDegree - Set the form degree k for the k-form the describes the pushforwards/pullbacks of this 1740 dual space's functionals. 1741 1742 Input Parameters: 1743 + dsp - The `PetscDualSpace` 1744 - k - The *signed* degree k of the k. If k >= 0, this means that the degrees of freedom are k-forms, and are stored 1745 in lexicographic order according to the basis of k-forms constructed from the wedge product of 1-forms. So for example, 1746 the 1-form basis in 3-D is (dx, dy, dz), and the 2-form basis in 3-D is (dx wedge dy, dx wedge dz, dy wedge dz). 1747 If k < 0, this means that the degrees transform as k-forms, but are stored as (N-k) forms according to the 1748 Hodge star map. So for example if k = -2 and N = 3, this means that the degrees of freedom transform as 2-forms 1749 but are stored as 1-forms. 1750 1751 Level: developer 1752 1753 .seealso: `PetscDualSpace`, `PetscDTAltV`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType` 1754 @*/ 1755 PetscErrorCode PetscDualSpaceSetFormDegree(PetscDualSpace dsp, PetscInt k) 1756 { 1757 PetscInt dim; 1758 1759 PetscFunctionBeginHot; 1760 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1761 PetscCheck(!dsp->setupcalled, PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_WRONGSTATE, "Cannot change number of components after dualspace is set up"); 1762 dim = dsp->dm->dim; 1763 PetscCheck(k >= -dim && k <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported %" PetscInt_FMT "-form on %" PetscInt_FMT "-dimensional reference cell", PetscAbsInt(k), dim); 1764 dsp->k = k; 1765 PetscFunctionReturn(PETSC_SUCCESS); 1766 } 1767 1768 /*@ 1769 PetscDualSpaceGetDeRahm - Get the k-simplex associated with the functionals in this dual space 1770 1771 Input Parameter: 1772 . dsp - The `PetscDualSpace` 1773 1774 Output Parameter: 1775 . k - The simplex dimension 1776 1777 Level: developer 1778 1779 Note: 1780 Currently supported values are 1781 .vb 1782 0: These are H_1 methods that only transform coordinates 1783 1: These are Hcurl methods that transform functions using the covariant Piola transform (COVARIANT_PIOLA_TRANSFORM) 1784 2: These are the same as 1 1785 3: These are Hdiv methods that transform functions using the contravariant Piola transform (CONTRAVARIANT_PIOLA_TRANSFORM) 1786 .ve 1787 1788 .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceTransformType` 1789 @*/ 1790 PetscErrorCode PetscDualSpaceGetDeRahm(PetscDualSpace dsp, PetscInt *k) 1791 { 1792 PetscInt dim; 1793 1794 PetscFunctionBeginHot; 1795 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1796 PetscValidIntPointer(k, 2); 1797 dim = dsp->dm->dim; 1798 if (!dsp->k) *k = IDENTITY_TRANSFORM; 1799 else if (dsp->k == 1) *k = COVARIANT_PIOLA_TRANSFORM; 1800 else if (dsp->k == -(dim - 1)) *k = CONTRAVARIANT_PIOLA_TRANSFORM; 1801 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unsupported transformation"); 1802 PetscFunctionReturn(PETSC_SUCCESS); 1803 } 1804 1805 /*@C 1806 PetscDualSpaceTransform - Transform the function values 1807 1808 Input Parameters: 1809 + dsp - The `PetscDualSpace` 1810 . trans - The type of transform 1811 . isInverse - Flag to invert the transform 1812 . fegeom - The cell geometry 1813 . Nv - The number of function samples 1814 . Nc - The number of function components 1815 - vals - The function values 1816 1817 Output Parameter: 1818 . vals - The transformed function values 1819 1820 Level: intermediate 1821 1822 Note: 1823 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 1824 1825 .seealso: `PetscDualSpace`, `PetscDualSpaceTransformGradient()`, `PetscDualSpaceTransformHessian()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType` 1826 @*/ 1827 PetscErrorCode PetscDualSpaceTransform(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) 1828 { 1829 PetscReal Jstar[9] = {0}; 1830 PetscInt dim, v, c, Nk; 1831 1832 PetscFunctionBeginHot; 1833 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1834 PetscValidPointer(fegeom, 4); 1835 PetscValidScalarPointer(vals, 7); 1836 /* TODO: not handling dimEmbed != dim right now */ 1837 dim = dsp->dm->dim; 1838 /* No change needed for 0-forms */ 1839 if (!dsp->k) PetscFunctionReturn(PETSC_SUCCESS); 1840 PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(dsp->k), &Nk)); 1841 /* TODO: use fegeom->isAffine */ 1842 PetscCall(PetscDTAltVPullbackMatrix(dim, dim, isInverse ? fegeom->J : fegeom->invJ, dsp->k, Jstar)); 1843 for (v = 0; v < Nv; ++v) { 1844 switch (Nk) { 1845 case 1: 1846 for (c = 0; c < Nc; c++) vals[v * Nc + c] *= Jstar[0]; 1847 break; 1848 case 2: 1849 for (c = 0; c < Nc; c += 2) DMPlex_Mult2DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]); 1850 break; 1851 case 3: 1852 for (c = 0; c < Nc; c += 3) DMPlex_Mult3DReal_Internal(Jstar, 1, &vals[v * Nc + c], &vals[v * Nc + c]); 1853 break; 1854 default: 1855 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported form size %" PetscInt_FMT " for transformation", Nk); 1856 } 1857 } 1858 PetscFunctionReturn(PETSC_SUCCESS); 1859 } 1860 1861 /*@C 1862 PetscDualSpaceTransformGradient - Transform the function gradient values 1863 1864 Input Parameters: 1865 + dsp - The `PetscDualSpace` 1866 . trans - The type of transform 1867 . isInverse - Flag to invert the transform 1868 . fegeom - The cell geometry 1869 . Nv - The number of function gradient samples 1870 . Nc - The number of function components 1871 - vals - The function gradient values 1872 1873 Output Parameter: 1874 . vals - The transformed function gradient values 1875 1876 Level: intermediate 1877 1878 Note: 1879 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 1880 1881 .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType` 1882 @*/ 1883 PetscErrorCode PetscDualSpaceTransformGradient(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) 1884 { 1885 const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed; 1886 PetscInt v, c, d; 1887 1888 PetscFunctionBeginHot; 1889 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 1890 PetscValidPointer(fegeom, 4); 1891 PetscValidScalarPointer(vals, 7); 1892 #ifdef PETSC_USE_DEBUG 1893 PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE); 1894 #endif 1895 /* Transform gradient */ 1896 if (dim == dE) { 1897 for (v = 0; v < Nv; ++v) { 1898 for (c = 0; c < Nc; ++c) { 1899 switch (dim) { 1900 case 1: 1901 vals[(v * Nc + c) * dim] *= fegeom->invJ[0]; 1902 break; 1903 case 2: 1904 DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]); 1905 break; 1906 case 3: 1907 DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, 1, &vals[(v * Nc + c) * dim], &vals[(v * Nc + c) * dim]); 1908 break; 1909 default: 1910 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim); 1911 } 1912 } 1913 } 1914 } else { 1915 for (v = 0; v < Nv; ++v) { 1916 for (c = 0; c < Nc; ++c) DMPlex_MultTransposeReal_Internal(fegeom->invJ, dim, dE, 1, &vals[(v * Nc + c) * dE], &vals[(v * Nc + c) * dE]); 1917 } 1918 } 1919 /* Assume its a vector, otherwise assume its a bunch of scalars */ 1920 if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS); 1921 switch (trans) { 1922 case IDENTITY_TRANSFORM: 1923 break; 1924 case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */ 1925 if (isInverse) { 1926 for (v = 0; v < Nv; ++v) { 1927 for (d = 0; d < dim; ++d) { 1928 switch (dim) { 1929 case 2: 1930 DMPlex_MultTranspose2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1931 break; 1932 case 3: 1933 DMPlex_MultTranspose3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1934 break; 1935 default: 1936 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim); 1937 } 1938 } 1939 } 1940 } else { 1941 for (v = 0; v < Nv; ++v) { 1942 for (d = 0; d < dim; ++d) { 1943 switch (dim) { 1944 case 2: 1945 DMPlex_MultTranspose2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1946 break; 1947 case 3: 1948 DMPlex_MultTranspose3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1949 break; 1950 default: 1951 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim); 1952 } 1953 } 1954 } 1955 } 1956 break; 1957 case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */ 1958 if (isInverse) { 1959 for (v = 0; v < Nv; ++v) { 1960 for (d = 0; d < dim; ++d) { 1961 switch (dim) { 1962 case 2: 1963 DMPlex_Mult2DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1964 break; 1965 case 3: 1966 DMPlex_Mult3DReal_Internal(fegeom->invJ, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1967 break; 1968 default: 1969 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim); 1970 } 1971 for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] *= fegeom->detJ[0]; 1972 } 1973 } 1974 } else { 1975 for (v = 0; v < Nv; ++v) { 1976 for (d = 0; d < dim; ++d) { 1977 switch (dim) { 1978 case 2: 1979 DMPlex_Mult2DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1980 break; 1981 case 3: 1982 DMPlex_Mult3DReal_Internal(fegeom->J, dim, &vals[v * Nc * dim + d], &vals[v * Nc * dim + d]); 1983 break; 1984 default: 1985 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim); 1986 } 1987 for (c = 0; c < Nc; ++c) vals[(v * Nc + c) * dim + d] /= fegeom->detJ[0]; 1988 } 1989 } 1990 } 1991 break; 1992 } 1993 PetscFunctionReturn(PETSC_SUCCESS); 1994 } 1995 1996 /*@C 1997 PetscDualSpaceTransformHessian - Transform the function Hessian values 1998 1999 Input Parameters: 2000 + dsp - The `PetscDualSpace` 2001 . trans - The type of transform 2002 . isInverse - Flag to invert the transform 2003 . fegeom - The cell geometry 2004 . Nv - The number of function Hessian samples 2005 . Nc - The number of function components 2006 - vals - The function gradient values 2007 2008 Output Parameter: 2009 . vals - The transformed function Hessian values 2010 2011 Level: intermediate 2012 2013 Note: 2014 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 2015 2016 .seealso: `PetscDualSpace`, `PetscDualSpaceTransform()`, `PetscDualSpacePullback()`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransformType` 2017 @*/ 2018 PetscErrorCode PetscDualSpaceTransformHessian(PetscDualSpace dsp, PetscDualSpaceTransformType trans, PetscBool isInverse, PetscFEGeom *fegeom, PetscInt Nv, PetscInt Nc, PetscScalar vals[]) 2019 { 2020 const PetscInt dim = dsp->dm->dim, dE = fegeom->dimEmbed; 2021 PetscInt v, c; 2022 2023 PetscFunctionBeginHot; 2024 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 2025 PetscValidPointer(fegeom, 4); 2026 PetscValidScalarPointer(vals, 7); 2027 #ifdef PETSC_USE_DEBUG 2028 PetscCheck(dE > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid embedding dimension %" PetscInt_FMT, dE); 2029 #endif 2030 /* Transform Hessian: J^{-T}_{ik} J^{-T}_{jl} H(f)_{kl} = J^{-T}_{ik} H(f)_{kl} J^{-1}_{lj} */ 2031 if (dim == dE) { 2032 for (v = 0; v < Nv; ++v) { 2033 for (c = 0; c < Nc; ++c) { 2034 switch (dim) { 2035 case 1: 2036 vals[(v * Nc + c) * dim * dim] *= PetscSqr(fegeom->invJ[0]); 2037 break; 2038 case 2: 2039 DMPlex_PTAP2DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]); 2040 break; 2041 case 3: 2042 DMPlex_PTAP3DReal_Internal(fegeom->invJ, &vals[(v * Nc + c) * dim * dim], &vals[(v * Nc + c) * dim * dim]); 2043 break; 2044 default: 2045 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported dim %" PetscInt_FMT " for transformation", dim); 2046 } 2047 } 2048 } 2049 } else { 2050 for (v = 0; v < Nv; ++v) { 2051 for (c = 0; c < Nc; ++c) DMPlex_PTAPReal_Internal(fegeom->invJ, dim, dE, &vals[(v * Nc + c) * dE * dE], &vals[(v * Nc + c) * dE * dE]); 2052 } 2053 } 2054 /* Assume its a vector, otherwise assume its a bunch of scalars */ 2055 if (Nc == 1 || Nc != dim) PetscFunctionReturn(PETSC_SUCCESS); 2056 switch (trans) { 2057 case IDENTITY_TRANSFORM: 2058 break; 2059 case COVARIANT_PIOLA_TRANSFORM: /* Covariant Piola mapping $\sigma^*(F) = J^{-T} F \circ \phi^{-1)$ */ 2060 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported"); 2061 case CONTRAVARIANT_PIOLA_TRANSFORM: /* Contravariant Piola mapping $\sigma^*(F) = \frac{1}{|\det J|} J F \circ \phi^{-1}$ */ 2062 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Piola mapping for Hessians not yet supported"); 2063 } 2064 PetscFunctionReturn(PETSC_SUCCESS); 2065 } 2066 2067 /*@C 2068 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. 2069 2070 Input Parameters: 2071 + dsp - The `PetscDualSpace` 2072 . fegeom - The geometry for this cell 2073 . Nq - The number of function samples 2074 . Nc - The number of function components 2075 - pointEval - The function values 2076 2077 Output Parameter: 2078 . pointEval - The transformed function values 2079 2080 Level: advanced 2081 2082 Notes: 2083 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. 2084 2085 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 2086 2087 .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()` 2088 @*/ 2089 PetscErrorCode PetscDualSpacePullback(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 2090 { 2091 PetscDualSpaceTransformType trans; 2092 PetscInt k; 2093 2094 PetscFunctionBeginHot; 2095 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 2096 PetscValidPointer(fegeom, 2); 2097 PetscValidScalarPointer(pointEval, 5); 2098 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 2099 This determines their transformation properties. */ 2100 PetscCall(PetscDualSpaceGetDeRahm(dsp, &k)); 2101 switch (k) { 2102 case 0: /* H^1 point evaluations */ 2103 trans = IDENTITY_TRANSFORM; 2104 break; 2105 case 1: /* Hcurl preserves tangential edge traces */ 2106 trans = COVARIANT_PIOLA_TRANSFORM; 2107 break; 2108 case 2: 2109 case 3: /* Hdiv preserve normal traces */ 2110 trans = CONTRAVARIANT_PIOLA_TRANSFORM; 2111 break; 2112 default: 2113 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k); 2114 } 2115 PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_TRUE, fegeom, Nq, Nc, pointEval)); 2116 PetscFunctionReturn(PETSC_SUCCESS); 2117 } 2118 2119 /*@C 2120 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. 2121 2122 Input Parameters: 2123 + dsp - The `PetscDualSpace` 2124 . fegeom - The geometry for this cell 2125 . Nq - The number of function samples 2126 . Nc - The number of function components 2127 - pointEval - The function values 2128 2129 Output Parameter: 2130 . pointEval - The transformed function values 2131 2132 Level: advanced 2133 2134 Notes: 2135 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. 2136 2137 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 2138 2139 .seealso: `PetscDualSpace`, `PetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()` 2140 @*/ 2141 PetscErrorCode PetscDualSpacePushforward(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 2142 { 2143 PetscDualSpaceTransformType trans; 2144 PetscInt k; 2145 2146 PetscFunctionBeginHot; 2147 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 2148 PetscValidPointer(fegeom, 2); 2149 PetscValidScalarPointer(pointEval, 5); 2150 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 2151 This determines their transformation properties. */ 2152 PetscCall(PetscDualSpaceGetDeRahm(dsp, &k)); 2153 switch (k) { 2154 case 0: /* H^1 point evaluations */ 2155 trans = IDENTITY_TRANSFORM; 2156 break; 2157 case 1: /* Hcurl preserves tangential edge traces */ 2158 trans = COVARIANT_PIOLA_TRANSFORM; 2159 break; 2160 case 2: 2161 case 3: /* Hdiv preserve normal traces */ 2162 trans = CONTRAVARIANT_PIOLA_TRANSFORM; 2163 break; 2164 default: 2165 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k); 2166 } 2167 PetscCall(PetscDualSpaceTransform(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval)); 2168 PetscFunctionReturn(PETSC_SUCCESS); 2169 } 2170 2171 /*@C 2172 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. 2173 2174 Input Parameters: 2175 + dsp - The `PetscDualSpace` 2176 . fegeom - The geometry for this cell 2177 . Nq - The number of function gradient samples 2178 . Nc - The number of function components 2179 - pointEval - The function gradient values 2180 2181 Output Parameter: 2182 . pointEval - The transformed function gradient values 2183 2184 Level: advanced 2185 2186 Notes: 2187 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. 2188 2189 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 2190 2191 .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()` 2192 @*/ 2193 PetscErrorCode PetscDualSpacePushforwardGradient(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 2194 { 2195 PetscDualSpaceTransformType trans; 2196 PetscInt k; 2197 2198 PetscFunctionBeginHot; 2199 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 2200 PetscValidPointer(fegeom, 2); 2201 PetscValidScalarPointer(pointEval, 5); 2202 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 2203 This determines their transformation properties. */ 2204 PetscCall(PetscDualSpaceGetDeRahm(dsp, &k)); 2205 switch (k) { 2206 case 0: /* H^1 point evaluations */ 2207 trans = IDENTITY_TRANSFORM; 2208 break; 2209 case 1: /* Hcurl preserves tangential edge traces */ 2210 trans = COVARIANT_PIOLA_TRANSFORM; 2211 break; 2212 case 2: 2213 case 3: /* Hdiv preserve normal traces */ 2214 trans = CONTRAVARIANT_PIOLA_TRANSFORM; 2215 break; 2216 default: 2217 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k); 2218 } 2219 PetscCall(PetscDualSpaceTransformGradient(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval)); 2220 PetscFunctionReturn(PETSC_SUCCESS); 2221 } 2222 2223 /*@C 2224 PetscDualSpacePushforwardHessian - Transform the given function Hessian 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. 2225 2226 Input Parameters: 2227 + dsp - The `PetscDualSpace` 2228 . fegeom - The geometry for this cell 2229 . Nq - The number of function Hessian samples 2230 . Nc - The number of function components 2231 - pointEval - The function gradient values 2232 2233 Output Parameter: 2234 . pointEval - The transformed function Hessian values 2235 2236 Level: advanced 2237 2238 Notes: 2239 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. 2240 2241 This only handles transformations when the embedding dimension of the geometry in fegeom is the same as the reference dimension. 2242 2243 .seealso: `PetscDualSpace`, `PetscDualSpacePushforward()`, `PPetscDualSpacePullback()`, `PetscDualSpaceTransform()`, `PetscDualSpaceGetDeRahm()` 2244 @*/ 2245 PetscErrorCode PetscDualSpacePushforwardHessian(PetscDualSpace dsp, PetscFEGeom *fegeom, PetscInt Nq, PetscInt Nc, PetscScalar pointEval[]) 2246 { 2247 PetscDualSpaceTransformType trans; 2248 PetscInt k; 2249 2250 PetscFunctionBeginHot; 2251 PetscValidHeaderSpecific(dsp, PETSCDUALSPACE_CLASSID, 1); 2252 PetscValidPointer(fegeom, 2); 2253 PetscValidScalarPointer(pointEval, 5); 2254 /* The dualspace dofs correspond to some simplex in the DeRahm complex, which we label by k. 2255 This determines their transformation properties. */ 2256 PetscCall(PetscDualSpaceGetDeRahm(dsp, &k)); 2257 switch (k) { 2258 case 0: /* H^1 point evaluations */ 2259 trans = IDENTITY_TRANSFORM; 2260 break; 2261 case 1: /* Hcurl preserves tangential edge traces */ 2262 trans = COVARIANT_PIOLA_TRANSFORM; 2263 break; 2264 case 2: 2265 case 3: /* Hdiv preserve normal traces */ 2266 trans = CONTRAVARIANT_PIOLA_TRANSFORM; 2267 break; 2268 default: 2269 SETERRQ(PetscObjectComm((PetscObject)dsp), PETSC_ERR_ARG_OUTOFRANGE, "Unsupported simplex dim %" PetscInt_FMT " for transformation", k); 2270 } 2271 PetscCall(PetscDualSpaceTransformHessian(dsp, trans, PETSC_FALSE, fegeom, Nq, Nc, pointEval)); 2272 PetscFunctionReturn(PETSC_SUCCESS); 2273 } 2274