1 #include <petsc/private/petscfvimpl.h> /*I "petscfv.h" I*/ 2 #include <petscdmplex.h> 3 #include <petscdmplextransform.h> 4 #include <petscds.h> 5 6 PetscClassId PETSCLIMITER_CLASSID = 0; 7 8 PetscFunctionList PetscLimiterList = NULL; 9 PetscBool PetscLimiterRegisterAllCalled = PETSC_FALSE; 10 11 PetscBool Limitercite = PETSC_FALSE; 12 const char LimiterCitation[] = "@article{BergerAftosmisMurman2005,\n" 13 " title = {Analysis of slope limiters on irregular grids},\n" 14 " journal = {AIAA paper},\n" 15 " author = {Marsha Berger and Michael J. Aftosmis and Scott M. Murman},\n" 16 " volume = {490},\n" 17 " year = {2005}\n}\n"; 18 19 /*@C 20 PetscLimiterRegister - Adds a new PetscLimiter implementation 21 22 Not Collective 23 24 Input Parameters: 25 + name - The name of a new user-defined creation routine 26 - create_func - The creation routine itself 27 28 Notes: 29 PetscLimiterRegister() may be called multiple times to add several user-defined PetscLimiters 30 31 Sample usage: 32 .vb 33 PetscLimiterRegister("my_lim", MyPetscLimiterCreate); 34 .ve 35 36 Then, your PetscLimiter type can be chosen with the procedural interface via 37 .vb 38 PetscLimiterCreate(MPI_Comm, PetscLimiter *); 39 PetscLimiterSetType(PetscLimiter, "my_lim"); 40 .ve 41 or at runtime via the option 42 .vb 43 -petsclimiter_type my_lim 44 .ve 45 46 Level: advanced 47 48 .seealso: `PetscLimiterRegisterAll()`, `PetscLimiterRegisterDestroy()` 49 50 @*/ 51 PetscErrorCode PetscLimiterRegister(const char sname[], PetscErrorCode (*function)(PetscLimiter)) 52 { 53 PetscFunctionBegin; 54 PetscCall(PetscFunctionListAdd(&PetscLimiterList, sname, function)); 55 PetscFunctionReturn(0); 56 } 57 58 /*@C 59 PetscLimiterSetType - Builds a particular PetscLimiter 60 61 Collective on lim 62 63 Input Parameters: 64 + lim - The PetscLimiter object 65 - name - The kind of limiter 66 67 Options Database Key: 68 . -petsclimiter_type <type> - Sets the PetscLimiter type; use -help for a list of available types 69 70 Level: intermediate 71 72 .seealso: `PetscLimiterGetType()`, `PetscLimiterCreate()` 73 @*/ 74 PetscErrorCode PetscLimiterSetType(PetscLimiter lim, PetscLimiterType name) 75 { 76 PetscErrorCode (*r)(PetscLimiter); 77 PetscBool match; 78 79 PetscFunctionBegin; 80 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 81 PetscCall(PetscObjectTypeCompare((PetscObject)lim, name, &match)); 82 if (match) PetscFunctionReturn(0); 83 84 PetscCall(PetscLimiterRegisterAll()); 85 PetscCall(PetscFunctionListFind(PetscLimiterList, name, &r)); 86 PetscCheck(r, PetscObjectComm((PetscObject)lim), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscLimiter type: %s", name); 87 88 if (lim->ops->destroy) { 89 PetscUseTypeMethod(lim, destroy); 90 lim->ops->destroy = NULL; 91 } 92 PetscCall((*r)(lim)); 93 PetscCall(PetscObjectChangeTypeName((PetscObject)lim, name)); 94 PetscFunctionReturn(0); 95 } 96 97 /*@C 98 PetscLimiterGetType - Gets the PetscLimiter type name (as a string) from the object. 99 100 Not Collective 101 102 Input Parameter: 103 . lim - The PetscLimiter 104 105 Output Parameter: 106 . name - The PetscLimiter type name 107 108 Level: intermediate 109 110 .seealso: `PetscLimiterSetType()`, `PetscLimiterCreate()` 111 @*/ 112 PetscErrorCode PetscLimiterGetType(PetscLimiter lim, PetscLimiterType *name) 113 { 114 PetscFunctionBegin; 115 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 116 PetscValidPointer(name, 2); 117 PetscCall(PetscLimiterRegisterAll()); 118 *name = ((PetscObject)lim)->type_name; 119 PetscFunctionReturn(0); 120 } 121 122 /*@C 123 PetscLimiterViewFromOptions - View from Options 124 125 Collective on PetscLimiter 126 127 Input Parameters: 128 + A - the PetscLimiter object to view 129 . obj - Optional object 130 - name - command line option 131 132 Level: intermediate 133 .seealso: `PetscLimiter`, `PetscLimiterView`, `PetscObjectViewFromOptions()`, `PetscLimiterCreate()` 134 @*/ 135 PetscErrorCode PetscLimiterViewFromOptions(PetscLimiter A, PetscObject obj, const char name[]) 136 { 137 PetscFunctionBegin; 138 PetscValidHeaderSpecific(A, PETSCLIMITER_CLASSID, 1); 139 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 140 PetscFunctionReturn(0); 141 } 142 143 /*@C 144 PetscLimiterView - Views a PetscLimiter 145 146 Collective on lim 147 148 Input Parameters: 149 + lim - the PetscLimiter object to view 150 - v - the viewer 151 152 Level: beginner 153 154 .seealso: `PetscLimiterDestroy()` 155 @*/ 156 PetscErrorCode PetscLimiterView(PetscLimiter lim, PetscViewer v) 157 { 158 PetscFunctionBegin; 159 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 160 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)lim), &v)); 161 PetscTryTypeMethod(lim, view, v); 162 PetscFunctionReturn(0); 163 } 164 165 /*@ 166 PetscLimiterSetFromOptions - sets parameters in a PetscLimiter from the options database 167 168 Collective on lim 169 170 Input Parameter: 171 . lim - the PetscLimiter object to set options for 172 173 Level: intermediate 174 175 .seealso: `PetscLimiterView()` 176 @*/ 177 PetscErrorCode PetscLimiterSetFromOptions(PetscLimiter lim) 178 { 179 const char *defaultType; 180 char name[256]; 181 PetscBool flg; 182 183 PetscFunctionBegin; 184 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 185 if (!((PetscObject)lim)->type_name) defaultType = PETSCLIMITERSIN; 186 else defaultType = ((PetscObject)lim)->type_name; 187 PetscCall(PetscLimiterRegisterAll()); 188 189 PetscObjectOptionsBegin((PetscObject)lim); 190 PetscCall(PetscOptionsFList("-petsclimiter_type", "Finite volume slope limiter", "PetscLimiterSetType", PetscLimiterList, defaultType, name, 256, &flg)); 191 if (flg) { 192 PetscCall(PetscLimiterSetType(lim, name)); 193 } else if (!((PetscObject)lim)->type_name) { 194 PetscCall(PetscLimiterSetType(lim, defaultType)); 195 } 196 PetscTryTypeMethod(lim, setfromoptions); 197 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 198 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)lim, PetscOptionsObject)); 199 PetscOptionsEnd(); 200 PetscCall(PetscLimiterViewFromOptions(lim, NULL, "-petsclimiter_view")); 201 PetscFunctionReturn(0); 202 } 203 204 /*@C 205 PetscLimiterSetUp - Construct data structures for the PetscLimiter 206 207 Collective on lim 208 209 Input Parameter: 210 . lim - the PetscLimiter object to setup 211 212 Level: intermediate 213 214 .seealso: `PetscLimiterView()`, `PetscLimiterDestroy()` 215 @*/ 216 PetscErrorCode PetscLimiterSetUp(PetscLimiter lim) 217 { 218 PetscFunctionBegin; 219 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 220 PetscTryTypeMethod(lim, setup); 221 PetscFunctionReturn(0); 222 } 223 224 /*@ 225 PetscLimiterDestroy - Destroys a PetscLimiter object 226 227 Collective on lim 228 229 Input Parameter: 230 . lim - the PetscLimiter object to destroy 231 232 Level: beginner 233 234 .seealso: `PetscLimiterView()` 235 @*/ 236 PetscErrorCode PetscLimiterDestroy(PetscLimiter *lim) 237 { 238 PetscFunctionBegin; 239 if (!*lim) PetscFunctionReturn(0); 240 PetscValidHeaderSpecific((*lim), PETSCLIMITER_CLASSID, 1); 241 242 if (--((PetscObject)(*lim))->refct > 0) { 243 *lim = NULL; 244 PetscFunctionReturn(0); 245 } 246 ((PetscObject)(*lim))->refct = 0; 247 248 PetscTryTypeMethod((*lim), destroy); 249 PetscCall(PetscHeaderDestroy(lim)); 250 PetscFunctionReturn(0); 251 } 252 253 /*@ 254 PetscLimiterCreate - Creates an empty PetscLimiter object. The type can then be set with PetscLimiterSetType(). 255 256 Collective 257 258 Input Parameter: 259 . comm - The communicator for the PetscLimiter object 260 261 Output Parameter: 262 . lim - The PetscLimiter object 263 264 Level: beginner 265 266 .seealso: `PetscLimiterSetType()`, `PETSCLIMITERSIN` 267 @*/ 268 PetscErrorCode PetscLimiterCreate(MPI_Comm comm, PetscLimiter *lim) 269 { 270 PetscLimiter l; 271 272 PetscFunctionBegin; 273 PetscValidPointer(lim, 2); 274 PetscCall(PetscCitationsRegister(LimiterCitation, &Limitercite)); 275 *lim = NULL; 276 PetscCall(PetscFVInitializePackage()); 277 278 PetscCall(PetscHeaderCreate(l, PETSCLIMITER_CLASSID, "PetscLimiter", "Finite Volume Slope Limiter", "PetscLimiter", comm, PetscLimiterDestroy, PetscLimiterView)); 279 280 *lim = l; 281 PetscFunctionReturn(0); 282 } 283 284 /*@ 285 PetscLimiterLimit - Limit the flux 286 287 Input Parameters: 288 + lim - The PetscLimiter 289 - flim - The input field 290 291 Output Parameter: 292 . phi - The limited field 293 294 Note: Limiters given in symmetric form following Berger, Aftosmis, and Murman 2005 295 $ The classical flux-limited formulation is psi(r) where 296 $ 297 $ r = (u[0] - u[-1]) / (u[1] - u[0]) 298 $ 299 $ The second order TVD region is bounded by 300 $ 301 $ psi_minmod(r) = min(r,1) and psi_superbee(r) = min(2, 2r, max(1,r)) 302 $ 303 $ where all limiters are implicitly clipped to be non-negative. A more convenient slope-limited form is psi(r) = 304 $ phi(r)(r+1)/2 in which the reconstructed interface values are 305 $ 306 $ u(v) = u[0] + phi(r) (grad u)[0] v 307 $ 308 $ where v is the vector from centroid to quadrature point. In these variables, the usual limiters become 309 $ 310 $ phi_minmod(r) = 2 min(1/(1+r),r/(1+r)) phi_superbee(r) = 2 min(2/(1+r), 2r/(1+r), max(1,r)/(1+r)) 311 $ 312 $ For a nicer symmetric formulation, rewrite in terms of 313 $ 314 $ f = (u[0] - u[-1]) / (u[1] - u[-1]) 315 $ 316 $ where r(f) = f/(1-f). Not that r(1-f) = (1-f)/f = 1/r(f) so the symmetry condition 317 $ 318 $ phi(r) = phi(1/r) 319 $ 320 $ becomes 321 $ 322 $ w(f) = w(1-f). 323 $ 324 $ The limiters below implement this final form w(f). The reference methods are 325 $ 326 $ w_minmod(f) = 2 min(f,(1-f)) w_superbee(r) = 4 min((1-f), f) 327 328 Level: beginner 329 330 .seealso: `PetscLimiterSetType()`, `PetscLimiterCreate()` 331 @*/ 332 PetscErrorCode PetscLimiterLimit(PetscLimiter lim, PetscReal flim, PetscReal *phi) 333 { 334 PetscFunctionBegin; 335 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 336 PetscValidRealPointer(phi, 3); 337 PetscUseTypeMethod(lim, limit, flim, phi); 338 PetscFunctionReturn(0); 339 } 340 341 static PetscErrorCode PetscLimiterDestroy_Sin(PetscLimiter lim) 342 { 343 PetscLimiter_Sin *l = (PetscLimiter_Sin *)lim->data; 344 345 PetscFunctionBegin; 346 PetscCall(PetscFree(l)); 347 PetscFunctionReturn(0); 348 } 349 350 static PetscErrorCode PetscLimiterView_Sin_Ascii(PetscLimiter lim, PetscViewer viewer) 351 { 352 PetscViewerFormat format; 353 354 PetscFunctionBegin; 355 PetscCall(PetscViewerGetFormat(viewer, &format)); 356 PetscCall(PetscViewerASCIIPrintf(viewer, "Sin Slope Limiter:\n")); 357 PetscFunctionReturn(0); 358 } 359 360 static PetscErrorCode PetscLimiterView_Sin(PetscLimiter lim, PetscViewer viewer) 361 { 362 PetscBool iascii; 363 364 PetscFunctionBegin; 365 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 366 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 367 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 368 if (iascii) PetscCall(PetscLimiterView_Sin_Ascii(lim, viewer)); 369 PetscFunctionReturn(0); 370 } 371 372 static PetscErrorCode PetscLimiterLimit_Sin(PetscLimiter lim, PetscReal f, PetscReal *phi) 373 { 374 PetscFunctionBegin; 375 *phi = PetscSinReal(PETSC_PI * PetscMax(0, PetscMin(f, 1))); 376 PetscFunctionReturn(0); 377 } 378 379 static PetscErrorCode PetscLimiterInitialize_Sin(PetscLimiter lim) 380 { 381 PetscFunctionBegin; 382 lim->ops->view = PetscLimiterView_Sin; 383 lim->ops->destroy = PetscLimiterDestroy_Sin; 384 lim->ops->limit = PetscLimiterLimit_Sin; 385 PetscFunctionReturn(0); 386 } 387 388 /*MC 389 PETSCLIMITERSIN = "sin" - A PetscLimiter object 390 391 Level: intermediate 392 393 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 394 M*/ 395 396 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Sin(PetscLimiter lim) 397 { 398 PetscLimiter_Sin *l; 399 400 PetscFunctionBegin; 401 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 402 PetscCall(PetscNew(&l)); 403 lim->data = l; 404 405 PetscCall(PetscLimiterInitialize_Sin(lim)); 406 PetscFunctionReturn(0); 407 } 408 409 static PetscErrorCode PetscLimiterDestroy_Zero(PetscLimiter lim) 410 { 411 PetscLimiter_Zero *l = (PetscLimiter_Zero *)lim->data; 412 413 PetscFunctionBegin; 414 PetscCall(PetscFree(l)); 415 PetscFunctionReturn(0); 416 } 417 418 static PetscErrorCode PetscLimiterView_Zero_Ascii(PetscLimiter lim, PetscViewer viewer) 419 { 420 PetscViewerFormat format; 421 422 PetscFunctionBegin; 423 PetscCall(PetscViewerGetFormat(viewer, &format)); 424 PetscCall(PetscViewerASCIIPrintf(viewer, "Zero Slope Limiter:\n")); 425 PetscFunctionReturn(0); 426 } 427 428 static PetscErrorCode PetscLimiterView_Zero(PetscLimiter lim, PetscViewer viewer) 429 { 430 PetscBool iascii; 431 432 PetscFunctionBegin; 433 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 434 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 435 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 436 if (iascii) PetscCall(PetscLimiterView_Zero_Ascii(lim, viewer)); 437 PetscFunctionReturn(0); 438 } 439 440 static PetscErrorCode PetscLimiterLimit_Zero(PetscLimiter lim, PetscReal f, PetscReal *phi) 441 { 442 PetscFunctionBegin; 443 *phi = 0.0; 444 PetscFunctionReturn(0); 445 } 446 447 static PetscErrorCode PetscLimiterInitialize_Zero(PetscLimiter lim) 448 { 449 PetscFunctionBegin; 450 lim->ops->view = PetscLimiterView_Zero; 451 lim->ops->destroy = PetscLimiterDestroy_Zero; 452 lim->ops->limit = PetscLimiterLimit_Zero; 453 PetscFunctionReturn(0); 454 } 455 456 /*MC 457 PETSCLIMITERZERO = "zero" - A PetscLimiter object 458 459 Level: intermediate 460 461 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 462 M*/ 463 464 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Zero(PetscLimiter lim) 465 { 466 PetscLimiter_Zero *l; 467 468 PetscFunctionBegin; 469 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 470 PetscCall(PetscNew(&l)); 471 lim->data = l; 472 473 PetscCall(PetscLimiterInitialize_Zero(lim)); 474 PetscFunctionReturn(0); 475 } 476 477 static PetscErrorCode PetscLimiterDestroy_None(PetscLimiter lim) 478 { 479 PetscLimiter_None *l = (PetscLimiter_None *)lim->data; 480 481 PetscFunctionBegin; 482 PetscCall(PetscFree(l)); 483 PetscFunctionReturn(0); 484 } 485 486 static PetscErrorCode PetscLimiterView_None_Ascii(PetscLimiter lim, PetscViewer viewer) 487 { 488 PetscViewerFormat format; 489 490 PetscFunctionBegin; 491 PetscCall(PetscViewerGetFormat(viewer, &format)); 492 PetscCall(PetscViewerASCIIPrintf(viewer, "None Slope Limiter:\n")); 493 PetscFunctionReturn(0); 494 } 495 496 static PetscErrorCode PetscLimiterView_None(PetscLimiter lim, PetscViewer viewer) 497 { 498 PetscBool iascii; 499 500 PetscFunctionBegin; 501 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 502 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 503 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 504 if (iascii) PetscCall(PetscLimiterView_None_Ascii(lim, viewer)); 505 PetscFunctionReturn(0); 506 } 507 508 static PetscErrorCode PetscLimiterLimit_None(PetscLimiter lim, PetscReal f, PetscReal *phi) 509 { 510 PetscFunctionBegin; 511 *phi = 1.0; 512 PetscFunctionReturn(0); 513 } 514 515 static PetscErrorCode PetscLimiterInitialize_None(PetscLimiter lim) 516 { 517 PetscFunctionBegin; 518 lim->ops->view = PetscLimiterView_None; 519 lim->ops->destroy = PetscLimiterDestroy_None; 520 lim->ops->limit = PetscLimiterLimit_None; 521 PetscFunctionReturn(0); 522 } 523 524 /*MC 525 PETSCLIMITERNONE = "none" - A PetscLimiter object 526 527 Level: intermediate 528 529 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 530 M*/ 531 532 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_None(PetscLimiter lim) 533 { 534 PetscLimiter_None *l; 535 536 PetscFunctionBegin; 537 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 538 PetscCall(PetscNew(&l)); 539 lim->data = l; 540 541 PetscCall(PetscLimiterInitialize_None(lim)); 542 PetscFunctionReturn(0); 543 } 544 545 static PetscErrorCode PetscLimiterDestroy_Minmod(PetscLimiter lim) 546 { 547 PetscLimiter_Minmod *l = (PetscLimiter_Minmod *)lim->data; 548 549 PetscFunctionBegin; 550 PetscCall(PetscFree(l)); 551 PetscFunctionReturn(0); 552 } 553 554 static PetscErrorCode PetscLimiterView_Minmod_Ascii(PetscLimiter lim, PetscViewer viewer) 555 { 556 PetscViewerFormat format; 557 558 PetscFunctionBegin; 559 PetscCall(PetscViewerGetFormat(viewer, &format)); 560 PetscCall(PetscViewerASCIIPrintf(viewer, "Minmod Slope Limiter:\n")); 561 PetscFunctionReturn(0); 562 } 563 564 static PetscErrorCode PetscLimiterView_Minmod(PetscLimiter lim, PetscViewer viewer) 565 { 566 PetscBool iascii; 567 568 PetscFunctionBegin; 569 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 570 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 571 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 572 if (iascii) PetscCall(PetscLimiterView_Minmod_Ascii(lim, viewer)); 573 PetscFunctionReturn(0); 574 } 575 576 static PetscErrorCode PetscLimiterLimit_Minmod(PetscLimiter lim, PetscReal f, PetscReal *phi) 577 { 578 PetscFunctionBegin; 579 *phi = 2 * PetscMax(0, PetscMin(f, 1 - f)); 580 PetscFunctionReturn(0); 581 } 582 583 static PetscErrorCode PetscLimiterInitialize_Minmod(PetscLimiter lim) 584 { 585 PetscFunctionBegin; 586 lim->ops->view = PetscLimiterView_Minmod; 587 lim->ops->destroy = PetscLimiterDestroy_Minmod; 588 lim->ops->limit = PetscLimiterLimit_Minmod; 589 PetscFunctionReturn(0); 590 } 591 592 /*MC 593 PETSCLIMITERMINMOD = "minmod" - A PetscLimiter object 594 595 Level: intermediate 596 597 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 598 M*/ 599 600 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Minmod(PetscLimiter lim) 601 { 602 PetscLimiter_Minmod *l; 603 604 PetscFunctionBegin; 605 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 606 PetscCall(PetscNew(&l)); 607 lim->data = l; 608 609 PetscCall(PetscLimiterInitialize_Minmod(lim)); 610 PetscFunctionReturn(0); 611 } 612 613 static PetscErrorCode PetscLimiterDestroy_VanLeer(PetscLimiter lim) 614 { 615 PetscLimiter_VanLeer *l = (PetscLimiter_VanLeer *)lim->data; 616 617 PetscFunctionBegin; 618 PetscCall(PetscFree(l)); 619 PetscFunctionReturn(0); 620 } 621 622 static PetscErrorCode PetscLimiterView_VanLeer_Ascii(PetscLimiter lim, PetscViewer viewer) 623 { 624 PetscViewerFormat format; 625 626 PetscFunctionBegin; 627 PetscCall(PetscViewerGetFormat(viewer, &format)); 628 PetscCall(PetscViewerASCIIPrintf(viewer, "Van Leer Slope Limiter:\n")); 629 PetscFunctionReturn(0); 630 } 631 632 static PetscErrorCode PetscLimiterView_VanLeer(PetscLimiter lim, PetscViewer viewer) 633 { 634 PetscBool iascii; 635 636 PetscFunctionBegin; 637 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 638 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 639 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 640 if (iascii) PetscCall(PetscLimiterView_VanLeer_Ascii(lim, viewer)); 641 PetscFunctionReturn(0); 642 } 643 644 static PetscErrorCode PetscLimiterLimit_VanLeer(PetscLimiter lim, PetscReal f, PetscReal *phi) 645 { 646 PetscFunctionBegin; 647 *phi = PetscMax(0, 4 * f * (1 - f)); 648 PetscFunctionReturn(0); 649 } 650 651 static PetscErrorCode PetscLimiterInitialize_VanLeer(PetscLimiter lim) 652 { 653 PetscFunctionBegin; 654 lim->ops->view = PetscLimiterView_VanLeer; 655 lim->ops->destroy = PetscLimiterDestroy_VanLeer; 656 lim->ops->limit = PetscLimiterLimit_VanLeer; 657 PetscFunctionReturn(0); 658 } 659 660 /*MC 661 PETSCLIMITERVANLEER = "vanleer" - A PetscLimiter object 662 663 Level: intermediate 664 665 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 666 M*/ 667 668 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_VanLeer(PetscLimiter lim) 669 { 670 PetscLimiter_VanLeer *l; 671 672 PetscFunctionBegin; 673 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 674 PetscCall(PetscNew(&l)); 675 lim->data = l; 676 677 PetscCall(PetscLimiterInitialize_VanLeer(lim)); 678 PetscFunctionReturn(0); 679 } 680 681 static PetscErrorCode PetscLimiterDestroy_VanAlbada(PetscLimiter lim) 682 { 683 PetscLimiter_VanAlbada *l = (PetscLimiter_VanAlbada *)lim->data; 684 685 PetscFunctionBegin; 686 PetscCall(PetscFree(l)); 687 PetscFunctionReturn(0); 688 } 689 690 static PetscErrorCode PetscLimiterView_VanAlbada_Ascii(PetscLimiter lim, PetscViewer viewer) 691 { 692 PetscViewerFormat format; 693 694 PetscFunctionBegin; 695 PetscCall(PetscViewerGetFormat(viewer, &format)); 696 PetscCall(PetscViewerASCIIPrintf(viewer, "Van Albada Slope Limiter:\n")); 697 PetscFunctionReturn(0); 698 } 699 700 static PetscErrorCode PetscLimiterView_VanAlbada(PetscLimiter lim, PetscViewer viewer) 701 { 702 PetscBool iascii; 703 704 PetscFunctionBegin; 705 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 706 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 707 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 708 if (iascii) PetscCall(PetscLimiterView_VanAlbada_Ascii(lim, viewer)); 709 PetscFunctionReturn(0); 710 } 711 712 static PetscErrorCode PetscLimiterLimit_VanAlbada(PetscLimiter lim, PetscReal f, PetscReal *phi) 713 { 714 PetscFunctionBegin; 715 *phi = PetscMax(0, 2 * f * (1 - f) / (PetscSqr(f) + PetscSqr(1 - f))); 716 PetscFunctionReturn(0); 717 } 718 719 static PetscErrorCode PetscLimiterInitialize_VanAlbada(PetscLimiter lim) 720 { 721 PetscFunctionBegin; 722 lim->ops->view = PetscLimiterView_VanAlbada; 723 lim->ops->destroy = PetscLimiterDestroy_VanAlbada; 724 lim->ops->limit = PetscLimiterLimit_VanAlbada; 725 PetscFunctionReturn(0); 726 } 727 728 /*MC 729 PETSCLIMITERVANALBADA = "vanalbada" - A PetscLimiter object 730 731 Level: intermediate 732 733 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 734 M*/ 735 736 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_VanAlbada(PetscLimiter lim) 737 { 738 PetscLimiter_VanAlbada *l; 739 740 PetscFunctionBegin; 741 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 742 PetscCall(PetscNew(&l)); 743 lim->data = l; 744 745 PetscCall(PetscLimiterInitialize_VanAlbada(lim)); 746 PetscFunctionReturn(0); 747 } 748 749 static PetscErrorCode PetscLimiterDestroy_Superbee(PetscLimiter lim) 750 { 751 PetscLimiter_Superbee *l = (PetscLimiter_Superbee *)lim->data; 752 753 PetscFunctionBegin; 754 PetscCall(PetscFree(l)); 755 PetscFunctionReturn(0); 756 } 757 758 static PetscErrorCode PetscLimiterView_Superbee_Ascii(PetscLimiter lim, PetscViewer viewer) 759 { 760 PetscViewerFormat format; 761 762 PetscFunctionBegin; 763 PetscCall(PetscViewerGetFormat(viewer, &format)); 764 PetscCall(PetscViewerASCIIPrintf(viewer, "Superbee Slope Limiter:\n")); 765 PetscFunctionReturn(0); 766 } 767 768 static PetscErrorCode PetscLimiterView_Superbee(PetscLimiter lim, PetscViewer viewer) 769 { 770 PetscBool iascii; 771 772 PetscFunctionBegin; 773 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 774 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 775 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 776 if (iascii) PetscCall(PetscLimiterView_Superbee_Ascii(lim, viewer)); 777 PetscFunctionReturn(0); 778 } 779 780 static PetscErrorCode PetscLimiterLimit_Superbee(PetscLimiter lim, PetscReal f, PetscReal *phi) 781 { 782 PetscFunctionBegin; 783 *phi = 4 * PetscMax(0, PetscMin(f, 1 - f)); 784 PetscFunctionReturn(0); 785 } 786 787 static PetscErrorCode PetscLimiterInitialize_Superbee(PetscLimiter lim) 788 { 789 PetscFunctionBegin; 790 lim->ops->view = PetscLimiterView_Superbee; 791 lim->ops->destroy = PetscLimiterDestroy_Superbee; 792 lim->ops->limit = PetscLimiterLimit_Superbee; 793 PetscFunctionReturn(0); 794 } 795 796 /*MC 797 PETSCLIMITERSUPERBEE = "superbee" - A PetscLimiter object 798 799 Level: intermediate 800 801 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 802 M*/ 803 804 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_Superbee(PetscLimiter lim) 805 { 806 PetscLimiter_Superbee *l; 807 808 PetscFunctionBegin; 809 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 810 PetscCall(PetscNew(&l)); 811 lim->data = l; 812 813 PetscCall(PetscLimiterInitialize_Superbee(lim)); 814 PetscFunctionReturn(0); 815 } 816 817 static PetscErrorCode PetscLimiterDestroy_MC(PetscLimiter lim) 818 { 819 PetscLimiter_MC *l = (PetscLimiter_MC *)lim->data; 820 821 PetscFunctionBegin; 822 PetscCall(PetscFree(l)); 823 PetscFunctionReturn(0); 824 } 825 826 static PetscErrorCode PetscLimiterView_MC_Ascii(PetscLimiter lim, PetscViewer viewer) 827 { 828 PetscViewerFormat format; 829 830 PetscFunctionBegin; 831 PetscCall(PetscViewerGetFormat(viewer, &format)); 832 PetscCall(PetscViewerASCIIPrintf(viewer, "MC Slope Limiter:\n")); 833 PetscFunctionReturn(0); 834 } 835 836 static PetscErrorCode PetscLimiterView_MC(PetscLimiter lim, PetscViewer viewer) 837 { 838 PetscBool iascii; 839 840 PetscFunctionBegin; 841 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 842 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 843 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 844 if (iascii) PetscCall(PetscLimiterView_MC_Ascii(lim, viewer)); 845 PetscFunctionReturn(0); 846 } 847 848 /* aka Barth-Jespersen */ 849 static PetscErrorCode PetscLimiterLimit_MC(PetscLimiter lim, PetscReal f, PetscReal *phi) 850 { 851 PetscFunctionBegin; 852 *phi = PetscMin(1, 4 * PetscMax(0, PetscMin(f, 1 - f))); 853 PetscFunctionReturn(0); 854 } 855 856 static PetscErrorCode PetscLimiterInitialize_MC(PetscLimiter lim) 857 { 858 PetscFunctionBegin; 859 lim->ops->view = PetscLimiterView_MC; 860 lim->ops->destroy = PetscLimiterDestroy_MC; 861 lim->ops->limit = PetscLimiterLimit_MC; 862 PetscFunctionReturn(0); 863 } 864 865 /*MC 866 PETSCLIMITERMC = "mc" - A PetscLimiter object 867 868 Level: intermediate 869 870 .seealso: `PetscLimiterType`, `PetscLimiterCreate()`, `PetscLimiterSetType()` 871 M*/ 872 873 PETSC_EXTERN PetscErrorCode PetscLimiterCreate_MC(PetscLimiter lim) 874 { 875 PetscLimiter_MC *l; 876 877 PetscFunctionBegin; 878 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 1); 879 PetscCall(PetscNew(&l)); 880 lim->data = l; 881 882 PetscCall(PetscLimiterInitialize_MC(lim)); 883 PetscFunctionReturn(0); 884 } 885 886 PetscClassId PETSCFV_CLASSID = 0; 887 888 PetscFunctionList PetscFVList = NULL; 889 PetscBool PetscFVRegisterAllCalled = PETSC_FALSE; 890 891 /*@C 892 PetscFVRegister - Adds a new PetscFV implementation 893 894 Not Collective 895 896 Input Parameters: 897 + name - The name of a new user-defined creation routine 898 - create_func - The creation routine itself 899 900 Notes: 901 PetscFVRegister() may be called multiple times to add several user-defined PetscFVs 902 903 Sample usage: 904 .vb 905 PetscFVRegister("my_fv", MyPetscFVCreate); 906 .ve 907 908 Then, your PetscFV type can be chosen with the procedural interface via 909 .vb 910 PetscFVCreate(MPI_Comm, PetscFV *); 911 PetscFVSetType(PetscFV, "my_fv"); 912 .ve 913 or at runtime via the option 914 .vb 915 -petscfv_type my_fv 916 .ve 917 918 Level: advanced 919 920 .seealso: `PetscFVRegisterAll()`, `PetscFVRegisterDestroy()` 921 922 @*/ 923 PetscErrorCode PetscFVRegister(const char sname[], PetscErrorCode (*function)(PetscFV)) 924 { 925 PetscFunctionBegin; 926 PetscCall(PetscFunctionListAdd(&PetscFVList, sname, function)); 927 PetscFunctionReturn(0); 928 } 929 930 /*@C 931 PetscFVSetType - Builds a particular PetscFV 932 933 Collective on fvm 934 935 Input Parameters: 936 + fvm - The PetscFV object 937 - name - The kind of FVM space 938 939 Options Database Key: 940 . -petscfv_type <type> - Sets the PetscFV type; use -help for a list of available types 941 942 Level: intermediate 943 944 .seealso: `PetscFVGetType()`, `PetscFVCreate()` 945 @*/ 946 PetscErrorCode PetscFVSetType(PetscFV fvm, PetscFVType name) 947 { 948 PetscErrorCode (*r)(PetscFV); 949 PetscBool match; 950 951 PetscFunctionBegin; 952 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 953 PetscCall(PetscObjectTypeCompare((PetscObject)fvm, name, &match)); 954 if (match) PetscFunctionReturn(0); 955 956 PetscCall(PetscFVRegisterAll()); 957 PetscCall(PetscFunctionListFind(PetscFVList, name, &r)); 958 PetscCheck(r, PetscObjectComm((PetscObject)fvm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscFV type: %s", name); 959 960 PetscTryTypeMethod(fvm, destroy); 961 fvm->ops->destroy = NULL; 962 963 PetscCall((*r)(fvm)); 964 PetscCall(PetscObjectChangeTypeName((PetscObject)fvm, name)); 965 PetscFunctionReturn(0); 966 } 967 968 /*@C 969 PetscFVGetType - Gets the PetscFV type name (as a string) from the object. 970 971 Not Collective 972 973 Input Parameter: 974 . fvm - The PetscFV 975 976 Output Parameter: 977 . name - The PetscFV type name 978 979 Level: intermediate 980 981 .seealso: `PetscFVSetType()`, `PetscFVCreate()` 982 @*/ 983 PetscErrorCode PetscFVGetType(PetscFV fvm, PetscFVType *name) 984 { 985 PetscFunctionBegin; 986 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 987 PetscValidPointer(name, 2); 988 PetscCall(PetscFVRegisterAll()); 989 *name = ((PetscObject)fvm)->type_name; 990 PetscFunctionReturn(0); 991 } 992 993 /*@C 994 PetscFVViewFromOptions - View from Options 995 996 Collective on PetscFV 997 998 Input Parameters: 999 + A - the PetscFV object 1000 . obj - Optional object 1001 - name - command line option 1002 1003 Level: intermediate 1004 .seealso: `PetscFV`, `PetscFVView`, `PetscObjectViewFromOptions()`, `PetscFVCreate()` 1005 @*/ 1006 PetscErrorCode PetscFVViewFromOptions(PetscFV A, PetscObject obj, const char name[]) 1007 { 1008 PetscFunctionBegin; 1009 PetscValidHeaderSpecific(A, PETSCFV_CLASSID, 1); 1010 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 1011 PetscFunctionReturn(0); 1012 } 1013 1014 /*@C 1015 PetscFVView - Views a PetscFV 1016 1017 Collective on fvm 1018 1019 Input Parameters: 1020 + fvm - the PetscFV object to view 1021 - v - the viewer 1022 1023 Level: beginner 1024 1025 .seealso: `PetscFVDestroy()` 1026 @*/ 1027 PetscErrorCode PetscFVView(PetscFV fvm, PetscViewer v) 1028 { 1029 PetscFunctionBegin; 1030 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1031 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)fvm), &v)); 1032 PetscTryTypeMethod(fvm, view, v); 1033 PetscFunctionReturn(0); 1034 } 1035 1036 /*@ 1037 PetscFVSetFromOptions - sets parameters in a PetscFV from the options database 1038 1039 Collective on fvm 1040 1041 Input Parameter: 1042 . fvm - the PetscFV object to set options for 1043 1044 Options Database Key: 1045 . -petscfv_compute_gradients <bool> - Determines whether cell gradients are calculated 1046 1047 Level: intermediate 1048 1049 .seealso: `PetscFVView()` 1050 @*/ 1051 PetscErrorCode PetscFVSetFromOptions(PetscFV fvm) 1052 { 1053 const char *defaultType; 1054 char name[256]; 1055 PetscBool flg; 1056 1057 PetscFunctionBegin; 1058 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1059 if (!((PetscObject)fvm)->type_name) defaultType = PETSCFVUPWIND; 1060 else defaultType = ((PetscObject)fvm)->type_name; 1061 PetscCall(PetscFVRegisterAll()); 1062 1063 PetscObjectOptionsBegin((PetscObject)fvm); 1064 PetscCall(PetscOptionsFList("-petscfv_type", "Finite volume discretization", "PetscFVSetType", PetscFVList, defaultType, name, 256, &flg)); 1065 if (flg) { 1066 PetscCall(PetscFVSetType(fvm, name)); 1067 } else if (!((PetscObject)fvm)->type_name) { 1068 PetscCall(PetscFVSetType(fvm, defaultType)); 1069 } 1070 PetscCall(PetscOptionsBool("-petscfv_compute_gradients", "Compute cell gradients", "PetscFVSetComputeGradients", fvm->computeGradients, &fvm->computeGradients, NULL)); 1071 PetscTryTypeMethod(fvm, setfromoptions); 1072 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 1073 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)fvm, PetscOptionsObject)); 1074 PetscCall(PetscLimiterSetFromOptions(fvm->limiter)); 1075 PetscOptionsEnd(); 1076 PetscCall(PetscFVViewFromOptions(fvm, NULL, "-petscfv_view")); 1077 PetscFunctionReturn(0); 1078 } 1079 1080 /*@ 1081 PetscFVSetUp - Construct data structures for the PetscFV 1082 1083 Collective on fvm 1084 1085 Input Parameter: 1086 . fvm - the PetscFV object to setup 1087 1088 Level: intermediate 1089 1090 .seealso: `PetscFVView()`, `PetscFVDestroy()` 1091 @*/ 1092 PetscErrorCode PetscFVSetUp(PetscFV fvm) 1093 { 1094 PetscFunctionBegin; 1095 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1096 PetscCall(PetscLimiterSetUp(fvm->limiter)); 1097 PetscTryTypeMethod(fvm, setup); 1098 PetscFunctionReturn(0); 1099 } 1100 1101 /*@ 1102 PetscFVDestroy - Destroys a PetscFV object 1103 1104 Collective on fvm 1105 1106 Input Parameter: 1107 . fvm - the PetscFV object to destroy 1108 1109 Level: beginner 1110 1111 .seealso: `PetscFVView()` 1112 @*/ 1113 PetscErrorCode PetscFVDestroy(PetscFV *fvm) 1114 { 1115 PetscInt i; 1116 1117 PetscFunctionBegin; 1118 if (!*fvm) PetscFunctionReturn(0); 1119 PetscValidHeaderSpecific((*fvm), PETSCFV_CLASSID, 1); 1120 1121 if (--((PetscObject)(*fvm))->refct > 0) { 1122 *fvm = NULL; 1123 PetscFunctionReturn(0); 1124 } 1125 ((PetscObject)(*fvm))->refct = 0; 1126 1127 for (i = 0; i < (*fvm)->numComponents; i++) PetscCall(PetscFree((*fvm)->componentNames[i])); 1128 PetscCall(PetscFree((*fvm)->componentNames)); 1129 PetscCall(PetscLimiterDestroy(&(*fvm)->limiter)); 1130 PetscCall(PetscDualSpaceDestroy(&(*fvm)->dualSpace)); 1131 PetscCall(PetscFree((*fvm)->fluxWork)); 1132 PetscCall(PetscQuadratureDestroy(&(*fvm)->quadrature)); 1133 PetscCall(PetscTabulationDestroy(&(*fvm)->T)); 1134 1135 PetscTryTypeMethod((*fvm), destroy); 1136 PetscCall(PetscHeaderDestroy(fvm)); 1137 PetscFunctionReturn(0); 1138 } 1139 1140 /*@ 1141 PetscFVCreate - Creates an empty PetscFV object. The type can then be set with PetscFVSetType(). 1142 1143 Collective 1144 1145 Input Parameter: 1146 . comm - The communicator for the PetscFV object 1147 1148 Output Parameter: 1149 . fvm - The PetscFV object 1150 1151 Level: beginner 1152 1153 .seealso: `PetscFVSetType()`, `PETSCFVUPWIND` 1154 @*/ 1155 PetscErrorCode PetscFVCreate(MPI_Comm comm, PetscFV *fvm) 1156 { 1157 PetscFV f; 1158 1159 PetscFunctionBegin; 1160 PetscValidPointer(fvm, 2); 1161 *fvm = NULL; 1162 PetscCall(PetscFVInitializePackage()); 1163 1164 PetscCall(PetscHeaderCreate(f, PETSCFV_CLASSID, "PetscFV", "Finite Volume", "PetscFV", comm, PetscFVDestroy, PetscFVView)); 1165 PetscCall(PetscMemzero(f->ops, sizeof(struct _PetscFVOps))); 1166 1167 PetscCall(PetscLimiterCreate(comm, &f->limiter)); 1168 f->numComponents = 1; 1169 f->dim = 0; 1170 f->computeGradients = PETSC_FALSE; 1171 f->fluxWork = NULL; 1172 PetscCall(PetscCalloc1(f->numComponents, &f->componentNames)); 1173 1174 *fvm = f; 1175 PetscFunctionReturn(0); 1176 } 1177 1178 /*@ 1179 PetscFVSetLimiter - Set the limiter object 1180 1181 Logically collective on fvm 1182 1183 Input Parameters: 1184 + fvm - the PetscFV object 1185 - lim - The PetscLimiter 1186 1187 Level: intermediate 1188 1189 .seealso: `PetscFVGetLimiter()` 1190 @*/ 1191 PetscErrorCode PetscFVSetLimiter(PetscFV fvm, PetscLimiter lim) 1192 { 1193 PetscFunctionBegin; 1194 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1195 PetscValidHeaderSpecific(lim, PETSCLIMITER_CLASSID, 2); 1196 PetscCall(PetscLimiterDestroy(&fvm->limiter)); 1197 PetscCall(PetscObjectReference((PetscObject)lim)); 1198 fvm->limiter = lim; 1199 PetscFunctionReturn(0); 1200 } 1201 1202 /*@ 1203 PetscFVGetLimiter - Get the limiter object 1204 1205 Not collective 1206 1207 Input Parameter: 1208 . fvm - the PetscFV object 1209 1210 Output Parameter: 1211 . lim - The PetscLimiter 1212 1213 Level: intermediate 1214 1215 .seealso: `PetscFVSetLimiter()` 1216 @*/ 1217 PetscErrorCode PetscFVGetLimiter(PetscFV fvm, PetscLimiter *lim) 1218 { 1219 PetscFunctionBegin; 1220 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1221 PetscValidPointer(lim, 2); 1222 *lim = fvm->limiter; 1223 PetscFunctionReturn(0); 1224 } 1225 1226 /*@ 1227 PetscFVSetNumComponents - Set the number of field components 1228 1229 Logically collective on fvm 1230 1231 Input Parameters: 1232 + fvm - the PetscFV object 1233 - comp - The number of components 1234 1235 Level: intermediate 1236 1237 .seealso: `PetscFVGetNumComponents()` 1238 @*/ 1239 PetscErrorCode PetscFVSetNumComponents(PetscFV fvm, PetscInt comp) 1240 { 1241 PetscFunctionBegin; 1242 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1243 if (fvm->numComponents != comp) { 1244 PetscInt i; 1245 1246 for (i = 0; i < fvm->numComponents; i++) PetscCall(PetscFree(fvm->componentNames[i])); 1247 PetscCall(PetscFree(fvm->componentNames)); 1248 PetscCall(PetscCalloc1(comp, &fvm->componentNames)); 1249 } 1250 fvm->numComponents = comp; 1251 PetscCall(PetscFree(fvm->fluxWork)); 1252 PetscCall(PetscMalloc1(comp, &fvm->fluxWork)); 1253 PetscFunctionReturn(0); 1254 } 1255 1256 /*@ 1257 PetscFVGetNumComponents - Get the number of field components 1258 1259 Not collective 1260 1261 Input Parameter: 1262 . fvm - the PetscFV object 1263 1264 Output Parameter: 1265 , comp - The number of components 1266 1267 Level: intermediate 1268 1269 .seealso: `PetscFVSetNumComponents()` 1270 @*/ 1271 PetscErrorCode PetscFVGetNumComponents(PetscFV fvm, PetscInt *comp) 1272 { 1273 PetscFunctionBegin; 1274 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1275 PetscValidIntPointer(comp, 2); 1276 *comp = fvm->numComponents; 1277 PetscFunctionReturn(0); 1278 } 1279 1280 /*@C 1281 PetscFVSetComponentName - Set the name of a component (used in output and viewing) 1282 1283 Logically collective on fvm 1284 Input Parameters: 1285 + fvm - the PetscFV object 1286 . comp - the component number 1287 - name - the component name 1288 1289 Level: intermediate 1290 1291 .seealso: `PetscFVGetComponentName()` 1292 @*/ 1293 PetscErrorCode PetscFVSetComponentName(PetscFV fvm, PetscInt comp, const char *name) 1294 { 1295 PetscFunctionBegin; 1296 PetscCall(PetscFree(fvm->componentNames[comp])); 1297 PetscCall(PetscStrallocpy(name, &fvm->componentNames[comp])); 1298 PetscFunctionReturn(0); 1299 } 1300 1301 /*@C 1302 PetscFVGetComponentName - Get the name of a component (used in output and viewing) 1303 1304 Logically collective on fvm 1305 Input Parameters: 1306 + fvm - the PetscFV object 1307 - comp - the component number 1308 1309 Output Parameter: 1310 . name - the component name 1311 1312 Level: intermediate 1313 1314 .seealso: `PetscFVSetComponentName()` 1315 @*/ 1316 PetscErrorCode PetscFVGetComponentName(PetscFV fvm, PetscInt comp, const char **name) 1317 { 1318 PetscFunctionBegin; 1319 *name = fvm->componentNames[comp]; 1320 PetscFunctionReturn(0); 1321 } 1322 1323 /*@ 1324 PetscFVSetSpatialDimension - Set the spatial dimension 1325 1326 Logically collective on fvm 1327 1328 Input Parameters: 1329 + fvm - the PetscFV object 1330 - dim - The spatial dimension 1331 1332 Level: intermediate 1333 1334 .seealso: `PetscFVGetSpatialDimension()` 1335 @*/ 1336 PetscErrorCode PetscFVSetSpatialDimension(PetscFV fvm, PetscInt dim) 1337 { 1338 PetscFunctionBegin; 1339 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1340 fvm->dim = dim; 1341 PetscFunctionReturn(0); 1342 } 1343 1344 /*@ 1345 PetscFVGetSpatialDimension - Get the spatial dimension 1346 1347 Logically collective on fvm 1348 1349 Input Parameter: 1350 . fvm - the PetscFV object 1351 1352 Output Parameter: 1353 . dim - The spatial dimension 1354 1355 Level: intermediate 1356 1357 .seealso: `PetscFVSetSpatialDimension()` 1358 @*/ 1359 PetscErrorCode PetscFVGetSpatialDimension(PetscFV fvm, PetscInt *dim) 1360 { 1361 PetscFunctionBegin; 1362 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1363 PetscValidIntPointer(dim, 2); 1364 *dim = fvm->dim; 1365 PetscFunctionReturn(0); 1366 } 1367 1368 /*@ 1369 PetscFVSetComputeGradients - Toggle computation of cell gradients 1370 1371 Logically collective on fvm 1372 1373 Input Parameters: 1374 + fvm - the PetscFV object 1375 - computeGradients - Flag to compute cell gradients 1376 1377 Level: intermediate 1378 1379 .seealso: `PetscFVGetComputeGradients()` 1380 @*/ 1381 PetscErrorCode PetscFVSetComputeGradients(PetscFV fvm, PetscBool computeGradients) 1382 { 1383 PetscFunctionBegin; 1384 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1385 fvm->computeGradients = computeGradients; 1386 PetscFunctionReturn(0); 1387 } 1388 1389 /*@ 1390 PetscFVGetComputeGradients - Return flag for computation of cell gradients 1391 1392 Not collective 1393 1394 Input Parameter: 1395 . fvm - the PetscFV object 1396 1397 Output Parameter: 1398 . computeGradients - Flag to compute cell gradients 1399 1400 Level: intermediate 1401 1402 .seealso: `PetscFVSetComputeGradients()` 1403 @*/ 1404 PetscErrorCode PetscFVGetComputeGradients(PetscFV fvm, PetscBool *computeGradients) 1405 { 1406 PetscFunctionBegin; 1407 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1408 PetscValidBoolPointer(computeGradients, 2); 1409 *computeGradients = fvm->computeGradients; 1410 PetscFunctionReturn(0); 1411 } 1412 1413 /*@ 1414 PetscFVSetQuadrature - Set the quadrature object 1415 1416 Logically collective on fvm 1417 1418 Input Parameters: 1419 + fvm - the PetscFV object 1420 - q - The PetscQuadrature 1421 1422 Level: intermediate 1423 1424 .seealso: `PetscFVGetQuadrature()` 1425 @*/ 1426 PetscErrorCode PetscFVSetQuadrature(PetscFV fvm, PetscQuadrature q) 1427 { 1428 PetscFunctionBegin; 1429 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1430 PetscCall(PetscQuadratureDestroy(&fvm->quadrature)); 1431 PetscCall(PetscObjectReference((PetscObject)q)); 1432 fvm->quadrature = q; 1433 PetscFunctionReturn(0); 1434 } 1435 1436 /*@ 1437 PetscFVGetQuadrature - Get the quadrature object 1438 1439 Not collective 1440 1441 Input Parameter: 1442 . fvm - the PetscFV object 1443 1444 Output Parameter: 1445 . lim - The PetscQuadrature 1446 1447 Level: intermediate 1448 1449 .seealso: `PetscFVSetQuadrature()` 1450 @*/ 1451 PetscErrorCode PetscFVGetQuadrature(PetscFV fvm, PetscQuadrature *q) 1452 { 1453 PetscFunctionBegin; 1454 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1455 PetscValidPointer(q, 2); 1456 if (!fvm->quadrature) { 1457 /* Create default 1-point quadrature */ 1458 PetscReal *points, *weights; 1459 1460 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &fvm->quadrature)); 1461 PetscCall(PetscCalloc1(fvm->dim, &points)); 1462 PetscCall(PetscMalloc1(1, &weights)); 1463 weights[0] = 1.0; 1464 PetscCall(PetscQuadratureSetData(fvm->quadrature, fvm->dim, 1, 1, points, weights)); 1465 } 1466 *q = fvm->quadrature; 1467 PetscFunctionReturn(0); 1468 } 1469 1470 /*@ 1471 PetscFVGetDualSpace - Returns the PetscDualSpace used to define the inner product 1472 1473 Not collective 1474 1475 Input Parameter: 1476 . fvm - The PetscFV object 1477 1478 Output Parameter: 1479 . sp - The PetscDualSpace object 1480 1481 Note: A simple dual space is provided automatically, and the user typically will not need to override it. 1482 1483 Level: intermediate 1484 1485 .seealso: `PetscFVCreate()` 1486 @*/ 1487 PetscErrorCode PetscFVGetDualSpace(PetscFV fvm, PetscDualSpace *sp) 1488 { 1489 PetscFunctionBegin; 1490 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1491 PetscValidPointer(sp, 2); 1492 if (!fvm->dualSpace) { 1493 DM K; 1494 PetscInt dim, Nc, c; 1495 1496 PetscCall(PetscFVGetSpatialDimension(fvm, &dim)); 1497 PetscCall(PetscFVGetNumComponents(fvm, &Nc)); 1498 PetscCall(PetscDualSpaceCreate(PetscObjectComm((PetscObject)fvm), &fvm->dualSpace)); 1499 PetscCall(PetscDualSpaceSetType(fvm->dualSpace, PETSCDUALSPACESIMPLE)); 1500 PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, PETSC_FALSE), &K)); 1501 PetscCall(PetscDualSpaceSetNumComponents(fvm->dualSpace, Nc)); 1502 PetscCall(PetscDualSpaceSetDM(fvm->dualSpace, K)); 1503 PetscCall(DMDestroy(&K)); 1504 PetscCall(PetscDualSpaceSimpleSetDimension(fvm->dualSpace, Nc)); 1505 /* Should we be using PetscFVGetQuadrature() here? */ 1506 for (c = 0; c < Nc; ++c) { 1507 PetscQuadrature qc; 1508 PetscReal *points, *weights; 1509 1510 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &qc)); 1511 PetscCall(PetscCalloc1(dim, &points)); 1512 PetscCall(PetscCalloc1(Nc, &weights)); 1513 weights[c] = 1.0; 1514 PetscCall(PetscQuadratureSetData(qc, dim, Nc, 1, points, weights)); 1515 PetscCall(PetscDualSpaceSimpleSetFunctional(fvm->dualSpace, c, qc)); 1516 PetscCall(PetscQuadratureDestroy(&qc)); 1517 } 1518 PetscCall(PetscDualSpaceSetUp(fvm->dualSpace)); 1519 } 1520 *sp = fvm->dualSpace; 1521 PetscFunctionReturn(0); 1522 } 1523 1524 /*@ 1525 PetscFVSetDualSpace - Sets the PetscDualSpace used to define the inner product 1526 1527 Not collective 1528 1529 Input Parameters: 1530 + fvm - The PetscFV object 1531 - sp - The PetscDualSpace object 1532 1533 Level: intermediate 1534 1535 Note: A simple dual space is provided automatically, and the user typically will not need to override it. 1536 1537 .seealso: `PetscFVCreate()` 1538 @*/ 1539 PetscErrorCode PetscFVSetDualSpace(PetscFV fvm, PetscDualSpace sp) 1540 { 1541 PetscFunctionBegin; 1542 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1543 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 2); 1544 PetscCall(PetscDualSpaceDestroy(&fvm->dualSpace)); 1545 fvm->dualSpace = sp; 1546 PetscCall(PetscObjectReference((PetscObject)fvm->dualSpace)); 1547 PetscFunctionReturn(0); 1548 } 1549 1550 /*@C 1551 PetscFVGetCellTabulation - Returns the tabulation of the basis functions at the quadrature points 1552 1553 Not collective 1554 1555 Input Parameter: 1556 . fvm - The PetscFV object 1557 1558 Output Parameter: 1559 . T - The basis function values and derivatives at quadrature points 1560 1561 Note: 1562 $ T->T[0] = B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c 1563 $ T->T[1] = D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d 1564 $ T->T[2] = H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e 1565 1566 Level: intermediate 1567 1568 .seealso: `PetscFEGetCellTabulation()`, `PetscFVCreateTabulation()`, `PetscFVGetQuadrature()`, `PetscQuadratureGetData()` 1569 @*/ 1570 PetscErrorCode PetscFVGetCellTabulation(PetscFV fvm, PetscTabulation *T) 1571 { 1572 PetscInt npoints; 1573 const PetscReal *points; 1574 1575 PetscFunctionBegin; 1576 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1577 PetscValidPointer(T, 2); 1578 PetscCall(PetscQuadratureGetData(fvm->quadrature, NULL, NULL, &npoints, &points, NULL)); 1579 if (!fvm->T) PetscCall(PetscFVCreateTabulation(fvm, 1, npoints, points, 1, &fvm->T)); 1580 *T = fvm->T; 1581 PetscFunctionReturn(0); 1582 } 1583 1584 /*@C 1585 PetscFVCreateTabulation - Tabulates the basis functions, and perhaps derivatives, at the points provided. 1586 1587 Not collective 1588 1589 Input Parameters: 1590 + fvm - The PetscFV object 1591 . nrepl - The number of replicas 1592 . npoints - The number of tabulation points in a replica 1593 . points - The tabulation point coordinates 1594 - K - The order of derivative to tabulate 1595 1596 Output Parameter: 1597 . T - The basis function values and derivative at tabulation points 1598 1599 Note: 1600 $ T->T[0] = B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c 1601 $ T->T[1] = D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d 1602 $ T->T[2] = H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e 1603 1604 Level: intermediate 1605 1606 .seealso: `PetscFECreateTabulation()`, `PetscTabulationDestroy()`, `PetscFEGetCellTabulation()` 1607 @*/ 1608 PetscErrorCode PetscFVCreateTabulation(PetscFV fvm, PetscInt nrepl, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation *T) 1609 { 1610 PetscInt pdim = 1; /* Dimension of approximation space P */ 1611 PetscInt cdim; /* Spatial dimension */ 1612 PetscInt Nc; /* Field components */ 1613 PetscInt k, p, d, c, e; 1614 1615 PetscFunctionBegin; 1616 if (!npoints || K < 0) { 1617 *T = NULL; 1618 PetscFunctionReturn(0); 1619 } 1620 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1621 PetscValidRealPointer(points, 4); 1622 PetscValidPointer(T, 6); 1623 PetscCall(PetscFVGetSpatialDimension(fvm, &cdim)); 1624 PetscCall(PetscFVGetNumComponents(fvm, &Nc)); 1625 PetscCall(PetscMalloc1(1, T)); 1626 (*T)->K = !cdim ? 0 : K; 1627 (*T)->Nr = nrepl; 1628 (*T)->Np = npoints; 1629 (*T)->Nb = pdim; 1630 (*T)->Nc = Nc; 1631 (*T)->cdim = cdim; 1632 PetscCall(PetscMalloc1((*T)->K + 1, &(*T)->T)); 1633 for (k = 0; k <= (*T)->K; ++k) PetscCall(PetscMalloc1(nrepl * npoints * pdim * Nc * PetscPowInt(cdim, k), &(*T)->T[k])); 1634 if (K >= 0) { 1635 for (p = 0; p < nrepl * npoints; ++p) 1636 for (d = 0; d < pdim; ++d) 1637 for (c = 0; c < Nc; ++c) (*T)->T[0][(p * pdim + d) * Nc + c] = 1.0; 1638 } 1639 if (K >= 1) { 1640 for (p = 0; p < nrepl * npoints; ++p) 1641 for (d = 0; d < pdim; ++d) 1642 for (c = 0; c < Nc; ++c) 1643 for (e = 0; e < cdim; ++e) (*T)->T[1][((p * pdim + d) * Nc + c) * cdim + e] = 0.0; 1644 } 1645 if (K >= 2) { 1646 for (p = 0; p < nrepl * npoints; ++p) 1647 for (d = 0; d < pdim; ++d) 1648 for (c = 0; c < Nc; ++c) 1649 for (e = 0; e < cdim * cdim; ++e) (*T)->T[2][((p * pdim + d) * Nc + c) * cdim * cdim + e] = 0.0; 1650 } 1651 PetscFunctionReturn(0); 1652 } 1653 1654 /*@C 1655 PetscFVComputeGradient - Compute the gradient reconstruction matrix for a given cell 1656 1657 Input Parameters: 1658 + fvm - The PetscFV object 1659 . numFaces - The number of cell faces which are not constrained 1660 - dx - The vector from the cell centroid to the neighboring cell centroid for each face 1661 1662 Level: advanced 1663 1664 .seealso: `PetscFVCreate()` 1665 @*/ 1666 PetscErrorCode PetscFVComputeGradient(PetscFV fvm, PetscInt numFaces, PetscScalar dx[], PetscScalar grad[]) 1667 { 1668 PetscFunctionBegin; 1669 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1670 PetscTryTypeMethod(fvm, computegradient, numFaces, dx, grad); 1671 PetscFunctionReturn(0); 1672 } 1673 1674 /*@C 1675 PetscFVIntegrateRHSFunction - Produce the cell residual vector for a chunk of elements by quadrature integration 1676 1677 Not collective 1678 1679 Input Parameters: 1680 + fvm - The PetscFV object for the field being integrated 1681 . prob - The PetscDS specifing the discretizations and continuum functions 1682 . field - The field being integrated 1683 . Nf - The number of faces in the chunk 1684 . fgeom - The face geometry for each face in the chunk 1685 . neighborVol - The volume for each pair of cells in the chunk 1686 . uL - The state from the cell on the left 1687 - uR - The state from the cell on the right 1688 1689 Output Parameters: 1690 + fluxL - the left fluxes for each face 1691 - fluxR - the right fluxes for each face 1692 1693 Level: developer 1694 1695 .seealso: `PetscFVCreate()` 1696 @*/ 1697 PetscErrorCode PetscFVIntegrateRHSFunction(PetscFV fvm, PetscDS prob, PetscInt field, PetscInt Nf, PetscFVFaceGeom *fgeom, PetscReal *neighborVol, PetscScalar uL[], PetscScalar uR[], PetscScalar fluxL[], PetscScalar fluxR[]) 1698 { 1699 PetscFunctionBegin; 1700 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1701 PetscTryTypeMethod(fvm, integraterhsfunction, prob, field, Nf, fgeom, neighborVol, uL, uR, fluxL, fluxR); 1702 PetscFunctionReturn(0); 1703 } 1704 1705 /*@ 1706 PetscFVRefine - Create a "refined" PetscFV object that refines the reference cell into smaller copies. This is typically used 1707 to precondition a higher order method with a lower order method on a refined mesh having the same number of dofs (but more 1708 sparsity). It is also used to create an interpolation between regularly refined meshes. 1709 1710 Input Parameter: 1711 . fv - The initial PetscFV 1712 1713 Output Parameter: 1714 . fvRef - The refined PetscFV 1715 1716 Level: advanced 1717 1718 .seealso: `PetscFVType`, `PetscFVCreate()`, `PetscFVSetType()` 1719 @*/ 1720 PetscErrorCode PetscFVRefine(PetscFV fv, PetscFV *fvRef) 1721 { 1722 PetscDualSpace Q, Qref; 1723 DM K, Kref; 1724 PetscQuadrature q, qref; 1725 DMPolytopeType ct; 1726 DMPlexTransform tr; 1727 PetscReal *v0; 1728 PetscReal *jac, *invjac; 1729 PetscInt numComp, numSubelements, s; 1730 1731 PetscFunctionBegin; 1732 PetscCall(PetscFVGetDualSpace(fv, &Q)); 1733 PetscCall(PetscFVGetQuadrature(fv, &q)); 1734 PetscCall(PetscDualSpaceGetDM(Q, &K)); 1735 /* Create dual space */ 1736 PetscCall(PetscDualSpaceDuplicate(Q, &Qref)); 1737 PetscCall(DMRefine(K, PetscObjectComm((PetscObject)fv), &Kref)); 1738 PetscCall(PetscDualSpaceSetDM(Qref, Kref)); 1739 PetscCall(DMDestroy(&Kref)); 1740 PetscCall(PetscDualSpaceSetUp(Qref)); 1741 /* Create volume */ 1742 PetscCall(PetscFVCreate(PetscObjectComm((PetscObject)fv), fvRef)); 1743 PetscCall(PetscFVSetDualSpace(*fvRef, Qref)); 1744 PetscCall(PetscFVGetNumComponents(fv, &numComp)); 1745 PetscCall(PetscFVSetNumComponents(*fvRef, numComp)); 1746 PetscCall(PetscFVSetUp(*fvRef)); 1747 /* Create quadrature */ 1748 PetscCall(DMPlexGetCellType(K, 0, &ct)); 1749 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &tr)); 1750 PetscCall(DMPlexTransformSetType(tr, DMPLEXREFINEREGULAR)); 1751 PetscCall(DMPlexRefineRegularGetAffineTransforms(tr, ct, &numSubelements, &v0, &jac, &invjac)); 1752 PetscCall(PetscQuadratureExpandComposite(q, numSubelements, v0, jac, &qref)); 1753 PetscCall(PetscDualSpaceSimpleSetDimension(Qref, numSubelements)); 1754 for (s = 0; s < numSubelements; ++s) { 1755 PetscQuadrature qs; 1756 const PetscReal *points, *weights; 1757 PetscReal *p, *w; 1758 PetscInt dim, Nc, npoints, np; 1759 1760 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &qs)); 1761 PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights)); 1762 np = npoints / numSubelements; 1763 PetscCall(PetscMalloc1(np * dim, &p)); 1764 PetscCall(PetscMalloc1(np * Nc, &w)); 1765 PetscCall(PetscArraycpy(p, &points[s * np * dim], np * dim)); 1766 PetscCall(PetscArraycpy(w, &weights[s * np * Nc], np * Nc)); 1767 PetscCall(PetscQuadratureSetData(qs, dim, Nc, np, p, w)); 1768 PetscCall(PetscDualSpaceSimpleSetFunctional(Qref, s, qs)); 1769 PetscCall(PetscQuadratureDestroy(&qs)); 1770 } 1771 PetscCall(PetscFVSetQuadrature(*fvRef, qref)); 1772 PetscCall(DMPlexTransformDestroy(&tr)); 1773 PetscCall(PetscQuadratureDestroy(&qref)); 1774 PetscCall(PetscDualSpaceDestroy(&Qref)); 1775 PetscFunctionReturn(0); 1776 } 1777 1778 static PetscErrorCode PetscFVDestroy_Upwind(PetscFV fvm) 1779 { 1780 PetscFV_Upwind *b = (PetscFV_Upwind *)fvm->data; 1781 1782 PetscFunctionBegin; 1783 PetscCall(PetscFree(b)); 1784 PetscFunctionReturn(0); 1785 } 1786 1787 static PetscErrorCode PetscFVView_Upwind_Ascii(PetscFV fv, PetscViewer viewer) 1788 { 1789 PetscInt Nc, c; 1790 PetscViewerFormat format; 1791 1792 PetscFunctionBegin; 1793 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1794 PetscCall(PetscViewerGetFormat(viewer, &format)); 1795 PetscCall(PetscViewerASCIIPrintf(viewer, "Upwind Finite Volume:\n")); 1796 PetscCall(PetscViewerASCIIPrintf(viewer, " num components: %" PetscInt_FMT "\n", Nc)); 1797 for (c = 0; c < Nc; c++) { 1798 if (fv->componentNames[c]) PetscCall(PetscViewerASCIIPrintf(viewer, " component %" PetscInt_FMT ": %s\n", c, fv->componentNames[c])); 1799 } 1800 PetscFunctionReturn(0); 1801 } 1802 1803 static PetscErrorCode PetscFVView_Upwind(PetscFV fv, PetscViewer viewer) 1804 { 1805 PetscBool iascii; 1806 1807 PetscFunctionBegin; 1808 PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 1); 1809 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1810 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1811 if (iascii) PetscCall(PetscFVView_Upwind_Ascii(fv, viewer)); 1812 PetscFunctionReturn(0); 1813 } 1814 1815 static PetscErrorCode PetscFVSetUp_Upwind(PetscFV fvm) 1816 { 1817 PetscFunctionBegin; 1818 PetscFunctionReturn(0); 1819 } 1820 1821 /* 1822 neighborVol[f*2+0] contains the left geom 1823 neighborVol[f*2+1] contains the right geom 1824 */ 1825 static PetscErrorCode PetscFVIntegrateRHSFunction_Upwind(PetscFV fvm, PetscDS prob, PetscInt field, PetscInt Nf, PetscFVFaceGeom *fgeom, PetscReal *neighborVol, PetscScalar uL[], PetscScalar uR[], PetscScalar fluxL[], PetscScalar fluxR[]) 1826 { 1827 void (*riemann)(PetscInt, PetscInt, const PetscReal[], const PetscReal[], const PetscScalar[], const PetscScalar[], PetscInt, const PetscScalar[], PetscScalar[], void *); 1828 void *rctx; 1829 PetscScalar *flux = fvm->fluxWork; 1830 const PetscScalar *constants; 1831 PetscInt dim, numConstants, pdim, totDim, Nc, off, f, d; 1832 1833 PetscFunctionBegin; 1834 PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 1835 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 1836 PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 1837 PetscCall(PetscDSGetRiemannSolver(prob, field, &riemann)); 1838 PetscCall(PetscDSGetContext(prob, field, &rctx)); 1839 PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 1840 PetscCall(PetscFVGetSpatialDimension(fvm, &dim)); 1841 PetscCall(PetscFVGetNumComponents(fvm, &pdim)); 1842 for (f = 0; f < Nf; ++f) { 1843 (*riemann)(dim, pdim, fgeom[f].centroid, fgeom[f].normal, &uL[f * Nc], &uR[f * Nc], numConstants, constants, flux, rctx); 1844 for (d = 0; d < pdim; ++d) { 1845 fluxL[f * totDim + off + d] = flux[d] / neighborVol[f * 2 + 0]; 1846 fluxR[f * totDim + off + d] = flux[d] / neighborVol[f * 2 + 1]; 1847 } 1848 } 1849 PetscFunctionReturn(0); 1850 } 1851 1852 static PetscErrorCode PetscFVInitialize_Upwind(PetscFV fvm) 1853 { 1854 PetscFunctionBegin; 1855 fvm->ops->setfromoptions = NULL; 1856 fvm->ops->setup = PetscFVSetUp_Upwind; 1857 fvm->ops->view = PetscFVView_Upwind; 1858 fvm->ops->destroy = PetscFVDestroy_Upwind; 1859 fvm->ops->integraterhsfunction = PetscFVIntegrateRHSFunction_Upwind; 1860 PetscFunctionReturn(0); 1861 } 1862 1863 /*MC 1864 PETSCFVUPWIND = "upwind" - A PetscFV object 1865 1866 Level: intermediate 1867 1868 .seealso: `PetscFVType`, `PetscFVCreate()`, `PetscFVSetType()` 1869 M*/ 1870 1871 PETSC_EXTERN PetscErrorCode PetscFVCreate_Upwind(PetscFV fvm) 1872 { 1873 PetscFV_Upwind *b; 1874 1875 PetscFunctionBegin; 1876 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 1877 PetscCall(PetscNew(&b)); 1878 fvm->data = b; 1879 1880 PetscCall(PetscFVInitialize_Upwind(fvm)); 1881 PetscFunctionReturn(0); 1882 } 1883 1884 #include <petscblaslapack.h> 1885 1886 static PetscErrorCode PetscFVDestroy_LeastSquares(PetscFV fvm) 1887 { 1888 PetscFV_LeastSquares *ls = (PetscFV_LeastSquares *)fvm->data; 1889 1890 PetscFunctionBegin; 1891 PetscCall(PetscObjectComposeFunction((PetscObject)fvm, "PetscFVLeastSquaresSetMaxFaces_C", NULL)); 1892 PetscCall(PetscFree4(ls->B, ls->Binv, ls->tau, ls->work)); 1893 PetscCall(PetscFree(ls)); 1894 PetscFunctionReturn(0); 1895 } 1896 1897 static PetscErrorCode PetscFVView_LeastSquares_Ascii(PetscFV fv, PetscViewer viewer) 1898 { 1899 PetscInt Nc, c; 1900 PetscViewerFormat format; 1901 1902 PetscFunctionBegin; 1903 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1904 PetscCall(PetscViewerGetFormat(viewer, &format)); 1905 PetscCall(PetscViewerASCIIPrintf(viewer, "Finite Volume with Least Squares Reconstruction:\n")); 1906 PetscCall(PetscViewerASCIIPrintf(viewer, " num components: %" PetscInt_FMT "\n", Nc)); 1907 for (c = 0; c < Nc; c++) { 1908 if (fv->componentNames[c]) PetscCall(PetscViewerASCIIPrintf(viewer, " component %" PetscInt_FMT ": %s\n", c, fv->componentNames[c])); 1909 } 1910 PetscFunctionReturn(0); 1911 } 1912 1913 static PetscErrorCode PetscFVView_LeastSquares(PetscFV fv, PetscViewer viewer) 1914 { 1915 PetscBool iascii; 1916 1917 PetscFunctionBegin; 1918 PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 1); 1919 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1920 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 1921 if (iascii) PetscCall(PetscFVView_LeastSquares_Ascii(fv, viewer)); 1922 PetscFunctionReturn(0); 1923 } 1924 1925 static PetscErrorCode PetscFVSetUp_LeastSquares(PetscFV fvm) 1926 { 1927 PetscFunctionBegin; 1928 PetscFunctionReturn(0); 1929 } 1930 1931 /* Overwrites A. Can only handle full-rank problems with m>=n */ 1932 static PetscErrorCode PetscFVLeastSquaresPseudoInverse_Static(PetscInt m, PetscInt mstride, PetscInt n, PetscScalar *A, PetscScalar *Ainv, PetscScalar *tau, PetscInt worksize, PetscScalar *work) 1933 { 1934 PetscBool debug = PETSC_FALSE; 1935 PetscBLASInt M, N, K, lda, ldb, ldwork, info; 1936 PetscScalar *R, *Q, *Aback, Alpha; 1937 1938 PetscFunctionBegin; 1939 if (debug) { 1940 PetscCall(PetscMalloc1(m * n, &Aback)); 1941 PetscCall(PetscArraycpy(Aback, A, m * n)); 1942 } 1943 1944 PetscCall(PetscBLASIntCast(m, &M)); 1945 PetscCall(PetscBLASIntCast(n, &N)); 1946 PetscCall(PetscBLASIntCast(mstride, &lda)); 1947 PetscCall(PetscBLASIntCast(worksize, &ldwork)); 1948 PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 1949 PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&M, &N, A, &lda, tau, work, &ldwork, &info)); 1950 PetscCall(PetscFPTrapPop()); 1951 PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xGEQRF error"); 1952 R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */ 1953 1954 /* Extract an explicit representation of Q */ 1955 Q = Ainv; 1956 PetscCall(PetscArraycpy(Q, A, mstride * n)); 1957 K = N; /* full rank */ 1958 PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&M, &N, &K, Q, &lda, tau, work, &ldwork, &info)); 1959 PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xORGQR/xUNGQR error"); 1960 1961 /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */ 1962 Alpha = 1.0; 1963 ldb = lda; 1964 BLAStrsm_("Right", "Upper", "ConjugateTranspose", "NotUnitTriangular", &M, &N, &Alpha, R, &lda, Q, &ldb); 1965 /* Ainv is Q, overwritten with inverse */ 1966 1967 if (debug) { /* Check that pseudo-inverse worked */ 1968 PetscScalar Beta = 0.0; 1969 PetscBLASInt ldc; 1970 K = N; 1971 ldc = N; 1972 BLASgemm_("ConjugateTranspose", "Normal", &N, &K, &M, &Alpha, Ainv, &lda, Aback, &ldb, &Beta, work, &ldc); 1973 PetscCall(PetscScalarView(n * n, work, PETSC_VIEWER_STDOUT_SELF)); 1974 PetscCall(PetscFree(Aback)); 1975 } 1976 PetscFunctionReturn(0); 1977 } 1978 1979 /* Overwrites A. Can handle degenerate problems and m<n. */ 1980 static PetscErrorCode PetscFVLeastSquaresPseudoInverseSVD_Static(PetscInt m, PetscInt mstride, PetscInt n, PetscScalar *A, PetscScalar *Ainv, PetscScalar *tau, PetscInt worksize, PetscScalar *work) 1981 { 1982 PetscScalar *Brhs; 1983 PetscScalar *tmpwork; 1984 PetscReal rcond; 1985 #if defined(PETSC_USE_COMPLEX) 1986 PetscInt rworkSize; 1987 PetscReal *rwork; 1988 #endif 1989 PetscInt i, j, maxmn; 1990 PetscBLASInt M, N, lda, ldb, ldwork; 1991 PetscBLASInt nrhs, irank, info; 1992 1993 PetscFunctionBegin; 1994 /* initialize to identity */ 1995 tmpwork = work; 1996 Brhs = Ainv; 1997 maxmn = PetscMax(m, n); 1998 for (j = 0; j < maxmn; j++) { 1999 for (i = 0; i < maxmn; i++) Brhs[i + j * maxmn] = 1.0 * (i == j); 2000 } 2001 2002 PetscCall(PetscBLASIntCast(m, &M)); 2003 PetscCall(PetscBLASIntCast(n, &N)); 2004 PetscCall(PetscBLASIntCast(mstride, &lda)); 2005 PetscCall(PetscBLASIntCast(maxmn, &ldb)); 2006 PetscCall(PetscBLASIntCast(worksize, &ldwork)); 2007 rcond = -1; 2008 nrhs = M; 2009 #if defined(PETSC_USE_COMPLEX) 2010 rworkSize = 5 * PetscMin(M, N); 2011 PetscCall(PetscMalloc1(rworkSize, &rwork)); 2012 PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 2013 PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&M, &N, &nrhs, A, &lda, Brhs, &ldb, (PetscReal *)tau, &rcond, &irank, tmpwork, &ldwork, rwork, &info)); 2014 PetscCall(PetscFPTrapPop()); 2015 PetscCall(PetscFree(rwork)); 2016 #else 2017 nrhs = M; 2018 PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 2019 PetscCallBLAS("LAPACKgelss", LAPACKgelss_(&M, &N, &nrhs, A, &lda, Brhs, &ldb, (PetscReal *)tau, &rcond, &irank, tmpwork, &ldwork, &info)); 2020 PetscCall(PetscFPTrapPop()); 2021 #endif 2022 PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xGELSS error"); 2023 /* The following check should be turned into a diagnostic as soon as someone wants to do this intentionally */ 2024 PetscCheck(irank >= PetscMin(M, N), PETSC_COMM_SELF, PETSC_ERR_USER, "Rank deficient least squares fit, indicates an isolated cell with two colinear points"); 2025 PetscFunctionReturn(0); 2026 } 2027 2028 #if 0 2029 static PetscErrorCode PetscFVLeastSquaresDebugCell_Static(PetscFV fvm, PetscInt cell, DM dm, DM dmFace, PetscScalar *fgeom, DM dmCell, PetscScalar *cgeom) 2030 { 2031 PetscReal grad[2] = {0, 0}; 2032 const PetscInt *faces; 2033 PetscInt numFaces, f; 2034 2035 PetscFunctionBegin; 2036 PetscCall(DMPlexGetConeSize(dm, cell, &numFaces)); 2037 PetscCall(DMPlexGetCone(dm, cell, &faces)); 2038 for (f = 0; f < numFaces; ++f) { 2039 const PetscInt *fcells; 2040 const CellGeom *cg1; 2041 const FaceGeom *fg; 2042 2043 PetscCall(DMPlexGetSupport(dm, faces[f], &fcells)); 2044 PetscCall(DMPlexPointLocalRead(dmFace, faces[f], fgeom, &fg)); 2045 for (i = 0; i < 2; ++i) { 2046 PetscScalar du; 2047 2048 if (fcells[i] == c) continue; 2049 PetscCall(DMPlexPointLocalRead(dmCell, fcells[i], cgeom, &cg1)); 2050 du = cg1->centroid[0] + 3*cg1->centroid[1] - (cg->centroid[0] + 3*cg->centroid[1]); 2051 grad[0] += fg->grad[!i][0] * du; 2052 grad[1] += fg->grad[!i][1] * du; 2053 } 2054 } 2055 PetscCall(PetscPrintf(PETSC_COMM_SELF, "cell[%d] grad (%g, %g)\n", cell, grad[0], grad[1])); 2056 PetscFunctionReturn(0); 2057 } 2058 #endif 2059 2060 /* 2061 PetscFVComputeGradient - Compute the gradient reconstruction matrix for a given cell 2062 2063 Input Parameters: 2064 + fvm - The PetscFV object 2065 . numFaces - The number of cell faces which are not constrained 2066 . dx - The vector from the cell centroid to the neighboring cell centroid for each face 2067 2068 Level: developer 2069 2070 .seealso: `PetscFVCreate()` 2071 */ 2072 static PetscErrorCode PetscFVComputeGradient_LeastSquares(PetscFV fvm, PetscInt numFaces, const PetscScalar dx[], PetscScalar grad[]) 2073 { 2074 PetscFV_LeastSquares *ls = (PetscFV_LeastSquares *)fvm->data; 2075 const PetscBool useSVD = PETSC_TRUE; 2076 const PetscInt maxFaces = ls->maxFaces; 2077 PetscInt dim, f, d; 2078 2079 PetscFunctionBegin; 2080 if (numFaces > maxFaces) { 2081 PetscCheck(maxFaces >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Reconstruction has not been initialized, call PetscFVLeastSquaresSetMaxFaces()"); 2082 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input faces %" PetscInt_FMT " > %" PetscInt_FMT " maxfaces", numFaces, maxFaces); 2083 } 2084 PetscCall(PetscFVGetSpatialDimension(fvm, &dim)); 2085 for (f = 0; f < numFaces; ++f) { 2086 for (d = 0; d < dim; ++d) ls->B[d * maxFaces + f] = dx[f * dim + d]; 2087 } 2088 /* Overwrites B with garbage, returns Binv in row-major format */ 2089 if (useSVD) { 2090 PetscInt maxmn = PetscMax(numFaces, dim); 2091 PetscCall(PetscFVLeastSquaresPseudoInverseSVD_Static(numFaces, maxFaces, dim, ls->B, ls->Binv, ls->tau, ls->workSize, ls->work)); 2092 /* Binv shaped in column-major, coldim=maxmn.*/ 2093 for (f = 0; f < numFaces; ++f) { 2094 for (d = 0; d < dim; ++d) grad[f * dim + d] = ls->Binv[d + maxmn * f]; 2095 } 2096 } else { 2097 PetscCall(PetscFVLeastSquaresPseudoInverse_Static(numFaces, maxFaces, dim, ls->B, ls->Binv, ls->tau, ls->workSize, ls->work)); 2098 /* Binv shaped in row-major, rowdim=maxFaces.*/ 2099 for (f = 0; f < numFaces; ++f) { 2100 for (d = 0; d < dim; ++d) grad[f * dim + d] = ls->Binv[d * maxFaces + f]; 2101 } 2102 } 2103 PetscFunctionReturn(0); 2104 } 2105 2106 /* 2107 neighborVol[f*2+0] contains the left geom 2108 neighborVol[f*2+1] contains the right geom 2109 */ 2110 static PetscErrorCode PetscFVIntegrateRHSFunction_LeastSquares(PetscFV fvm, PetscDS prob, PetscInt field, PetscInt Nf, PetscFVFaceGeom *fgeom, PetscReal *neighborVol, PetscScalar uL[], PetscScalar uR[], PetscScalar fluxL[], PetscScalar fluxR[]) 2111 { 2112 void (*riemann)(PetscInt, PetscInt, const PetscReal[], const PetscReal[], const PetscScalar[], const PetscScalar[], PetscInt, const PetscScalar[], PetscScalar[], void *); 2113 void *rctx; 2114 PetscScalar *flux = fvm->fluxWork; 2115 const PetscScalar *constants; 2116 PetscInt dim, numConstants, pdim, Nc, totDim, off, f, d; 2117 2118 PetscFunctionBegin; 2119 PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 2120 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2121 PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 2122 PetscCall(PetscDSGetRiemannSolver(prob, field, &riemann)); 2123 PetscCall(PetscDSGetContext(prob, field, &rctx)); 2124 PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2125 PetscCall(PetscFVGetSpatialDimension(fvm, &dim)); 2126 PetscCall(PetscFVGetNumComponents(fvm, &pdim)); 2127 for (f = 0; f < Nf; ++f) { 2128 (*riemann)(dim, pdim, fgeom[f].centroid, fgeom[f].normal, &uL[f * Nc], &uR[f * Nc], numConstants, constants, flux, rctx); 2129 for (d = 0; d < pdim; ++d) { 2130 fluxL[f * totDim + off + d] = flux[d] / neighborVol[f * 2 + 0]; 2131 fluxR[f * totDim + off + d] = flux[d] / neighborVol[f * 2 + 1]; 2132 } 2133 } 2134 PetscFunctionReturn(0); 2135 } 2136 2137 static PetscErrorCode PetscFVLeastSquaresSetMaxFaces_LS(PetscFV fvm, PetscInt maxFaces) 2138 { 2139 PetscFV_LeastSquares *ls = (PetscFV_LeastSquares *)fvm->data; 2140 PetscInt dim, m, n, nrhs, minmn, maxmn; 2141 2142 PetscFunctionBegin; 2143 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 2144 PetscCall(PetscFVGetSpatialDimension(fvm, &dim)); 2145 PetscCall(PetscFree4(ls->B, ls->Binv, ls->tau, ls->work)); 2146 ls->maxFaces = maxFaces; 2147 m = ls->maxFaces; 2148 n = dim; 2149 nrhs = ls->maxFaces; 2150 minmn = PetscMin(m, n); 2151 maxmn = PetscMax(m, n); 2152 ls->workSize = 3 * minmn + PetscMax(2 * minmn, PetscMax(maxmn, nrhs)); /* required by LAPACK */ 2153 PetscCall(PetscMalloc4(m * n, &ls->B, maxmn * maxmn, &ls->Binv, minmn, &ls->tau, ls->workSize, &ls->work)); 2154 PetscFunctionReturn(0); 2155 } 2156 2157 PetscErrorCode PetscFVInitialize_LeastSquares(PetscFV fvm) 2158 { 2159 PetscFunctionBegin; 2160 fvm->ops->setfromoptions = NULL; 2161 fvm->ops->setup = PetscFVSetUp_LeastSquares; 2162 fvm->ops->view = PetscFVView_LeastSquares; 2163 fvm->ops->destroy = PetscFVDestroy_LeastSquares; 2164 fvm->ops->computegradient = PetscFVComputeGradient_LeastSquares; 2165 fvm->ops->integraterhsfunction = PetscFVIntegrateRHSFunction_LeastSquares; 2166 PetscFunctionReturn(0); 2167 } 2168 2169 /*MC 2170 PETSCFVLEASTSQUARES = "leastsquares" - A PetscFV object 2171 2172 Level: intermediate 2173 2174 .seealso: `PetscFVType`, `PetscFVCreate()`, `PetscFVSetType()` 2175 M*/ 2176 2177 PETSC_EXTERN PetscErrorCode PetscFVCreate_LeastSquares(PetscFV fvm) 2178 { 2179 PetscFV_LeastSquares *ls; 2180 2181 PetscFunctionBegin; 2182 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 2183 PetscCall(PetscNew(&ls)); 2184 fvm->data = ls; 2185 2186 ls->maxFaces = -1; 2187 ls->workSize = -1; 2188 ls->B = NULL; 2189 ls->Binv = NULL; 2190 ls->tau = NULL; 2191 ls->work = NULL; 2192 2193 PetscCall(PetscFVSetComputeGradients(fvm, PETSC_TRUE)); 2194 PetscCall(PetscFVInitialize_LeastSquares(fvm)); 2195 PetscCall(PetscObjectComposeFunction((PetscObject)fvm, "PetscFVLeastSquaresSetMaxFaces_C", PetscFVLeastSquaresSetMaxFaces_LS)); 2196 PetscFunctionReturn(0); 2197 } 2198 2199 /*@ 2200 PetscFVLeastSquaresSetMaxFaces - Set the maximum number of cell faces for gradient reconstruction 2201 2202 Not collective 2203 2204 Input parameters: 2205 + fvm - The PetscFV object 2206 - maxFaces - The maximum number of cell faces 2207 2208 Level: intermediate 2209 2210 .seealso: `PetscFVCreate()`, `PETSCFVLEASTSQUARES` 2211 @*/ 2212 PetscErrorCode PetscFVLeastSquaresSetMaxFaces(PetscFV fvm, PetscInt maxFaces) 2213 { 2214 PetscFunctionBegin; 2215 PetscValidHeaderSpecific(fvm, PETSCFV_CLASSID, 1); 2216 PetscTryMethod(fvm, "PetscFVLeastSquaresSetMaxFaces_C", (PetscFV, PetscInt), (fvm, maxFaces)); 2217 PetscFunctionReturn(0); 2218 } 2219