1 #include <petscvec.h> 2 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/ 3 #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/ 4 #include <petsc/private/petscdsimpl.h> /*I "petscds.h" I*/ 5 #include <petscdmplex.h> 6 #include <petscdmfield.h> 7 #include <petscsf.h> 8 #include <petscds.h> 9 10 #ifdef PETSC_HAVE_LIBCEED 11 #include <petscfeceed.h> 12 #endif 13 14 #if !defined(PETSC_HAVE_WINDOWS_COMPILERS) 15 #include <petsc/private/valgrind/memcheck.h> 16 #endif 17 18 PetscClassId DM_CLASSID; 19 PetscClassId DMLABEL_CLASSID; 20 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_AdaptInterpolator; 21 22 const char *const DMBoundaryTypes[] = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL}; 23 const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "INVALID", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "INVALID", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType", "DM_BC_", NULL}; 24 const char *const DMPolytopeTypes[] = {"vertex", "segment", "tensor_segment", "triangle", "quadrilateral", "tensor_quad", "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", 25 "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown", "invalid", "DMPolytopeType", "DM_POLYTOPE_", NULL}; 26 const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL}; 27 28 /*@ 29 DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the 30 algebraic solvers, time integrators, and optimization algorithms. 31 32 Collective 33 34 Input Parameter: 35 . comm - The communicator for the `DM` object 36 37 Output Parameter: 38 . dm - The `DM` object 39 40 Level: beginner 41 42 Notes: 43 See `DMType` for a brief summary of available `DM`. 44 45 The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an 46 error when you try to use the dm. 47 48 .seealso: `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK` 49 @*/ 50 PetscErrorCode DMCreate(MPI_Comm comm, DM *dm) 51 { 52 DM v; 53 PetscDS ds; 54 55 PetscFunctionBegin; 56 PetscValidPointer(dm, 2); 57 *dm = NULL; 58 PetscCall(DMInitializePackage()); 59 60 PetscCall(PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView)); 61 62 v->setupcalled = PETSC_FALSE; 63 v->setfromoptionscalled = PETSC_FALSE; 64 v->ltogmap = NULL; 65 v->bind_below = 0; 66 v->bs = 1; 67 v->coloringtype = IS_COLORING_GLOBAL; 68 PetscCall(PetscSFCreate(comm, &v->sf)); 69 PetscCall(PetscSFCreate(comm, &v->sectionSF)); 70 v->labels = NULL; 71 v->adjacency[0] = PETSC_FALSE; 72 v->adjacency[1] = PETSC_TRUE; 73 v->depthLabel = NULL; 74 v->celltypeLabel = NULL; 75 v->localSection = NULL; 76 v->globalSection = NULL; 77 v->defaultConstraint.section = NULL; 78 v->defaultConstraint.mat = NULL; 79 v->defaultConstraint.bias = NULL; 80 v->coordinates[0].dim = PETSC_DEFAULT; 81 v->coordinates[1].dim = PETSC_DEFAULT; 82 v->sparseLocalize = PETSC_TRUE; 83 v->dim = PETSC_DETERMINE; 84 { 85 PetscInt i; 86 for (i = 0; i < 10; ++i) { 87 v->nullspaceConstructors[i] = NULL; 88 v->nearnullspaceConstructors[i] = NULL; 89 } 90 } 91 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 92 PetscCall(DMSetRegionDS(v, NULL, NULL, ds)); 93 PetscCall(PetscDSDestroy(&ds)); 94 PetscCall(PetscHMapAuxCreate(&v->auxData)); 95 v->dmBC = NULL; 96 v->coarseMesh = NULL; 97 v->outputSequenceNum = -1; 98 v->outputSequenceVal = 0.0; 99 PetscCall(DMSetVecType(v, VECSTANDARD)); 100 PetscCall(DMSetMatType(v, MATAIJ)); 101 102 *dm = v; 103 PetscFunctionReturn(0); 104 } 105 106 /*@ 107 DMClone - Creates a `DM` object with the same topology as the original. 108 109 Collective 110 111 Input Parameter: 112 . dm - The original `DM` object 113 114 Output Parameter: 115 . newdm - The new `DM` object 116 117 Level: beginner 118 119 Notes: 120 For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example, 121 `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not 122 share the `PetscSection` of the original `DM`. 123 124 The clone is considered set up if the original has been set up. 125 126 Use `DMConvert()` for a general way to create new `DM` from a given `DM` 127 128 .seealso: `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMSetType()`, `DMConvert()` 129 130 @*/ 131 PetscErrorCode DMClone(DM dm, DM *newdm) 132 { 133 PetscSF sf; 134 Vec coords; 135 void *ctx; 136 PetscInt dim, cdim, i; 137 138 PetscFunctionBegin; 139 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 140 PetscValidPointer(newdm, 2); 141 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), newdm)); 142 PetscCall(DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL)); 143 (*newdm)->leveldown = dm->leveldown; 144 (*newdm)->levelup = dm->levelup; 145 (*newdm)->prealloc_only = dm->prealloc_only; 146 PetscCall(PetscFree((*newdm)->vectype)); 147 PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype)); 148 PetscCall(PetscFree((*newdm)->mattype)); 149 PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype)); 150 PetscCall(DMGetDimension(dm, &dim)); 151 PetscCall(DMSetDimension(*newdm, dim)); 152 PetscTryTypeMethod(dm, clone, newdm); 153 (*newdm)->setupcalled = dm->setupcalled; 154 PetscCall(DMGetPointSF(dm, &sf)); 155 PetscCall(DMSetPointSF(*newdm, sf)); 156 PetscCall(DMGetApplicationContext(dm, &ctx)); 157 PetscCall(DMSetApplicationContext(*newdm, ctx)); 158 for (i = 0; i < 2; ++i) { 159 if (dm->coordinates[i].dm) { 160 DM ncdm; 161 PetscSection cs; 162 PetscInt pEnd = -1, pEndMax = -1; 163 164 PetscCall(DMGetLocalSection(dm->coordinates[i].dm, &cs)); 165 if (cs) PetscCall(PetscSectionGetChart(cs, NULL, &pEnd)); 166 PetscCallMPI(MPI_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 167 if (pEndMax >= 0) { 168 PetscCall(DMClone(dm->coordinates[i].dm, &ncdm)); 169 PetscCall(DMCopyDisc(dm->coordinates[i].dm, ncdm)); 170 PetscCall(DMSetLocalSection(ncdm, cs)); 171 if (i) PetscCall(DMSetCellCoordinateDM(*newdm, ncdm)); 172 else PetscCall(DMSetCoordinateDM(*newdm, ncdm)); 173 PetscCall(DMDestroy(&ncdm)); 174 } 175 } 176 } 177 PetscCall(DMGetCoordinateDim(dm, &cdim)); 178 PetscCall(DMSetCoordinateDim(*newdm, cdim)); 179 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 180 if (coords) { 181 PetscCall(DMSetCoordinatesLocal(*newdm, coords)); 182 } else { 183 PetscCall(DMGetCoordinates(dm, &coords)); 184 if (coords) PetscCall(DMSetCoordinates(*newdm, coords)); 185 } 186 PetscCall(DMGetCellCoordinatesLocal(dm, &coords)); 187 if (coords) { 188 PetscCall(DMSetCellCoordinatesLocal(*newdm, coords)); 189 } else { 190 PetscCall(DMGetCellCoordinates(dm, &coords)); 191 if (coords) PetscCall(DMSetCellCoordinates(*newdm, coords)); 192 } 193 { 194 const PetscReal *maxCell, *Lstart, *L; 195 196 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 197 PetscCall(DMSetPeriodicity(*newdm, maxCell, Lstart, L)); 198 } 199 { 200 PetscBool useCone, useClosure; 201 202 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure)); 203 PetscCall(DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure)); 204 } 205 PetscFunctionReturn(0); 206 } 207 208 /*@C 209 DMSetVecType - Sets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()` 210 211 Logically Collective on da 212 213 Input Parameters: 214 + da - initial distributed array 215 - ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL` 216 217 Options Database: 218 . -dm_vec_type ctype - the type of vector to create 219 220 Level: intermediate 221 222 .seealso: `DMCreate()`, `DMDestroy()`, `DM`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`, 223 `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()` 224 @*/ 225 PetscErrorCode DMSetVecType(DM da, VecType ctype) 226 { 227 PetscFunctionBegin; 228 PetscValidHeaderSpecific(da, DM_CLASSID, 1); 229 PetscCall(PetscFree(da->vectype)); 230 PetscCall(PetscStrallocpy(ctype, (char **)&da->vectype)); 231 PetscFunctionReturn(0); 232 } 233 234 /*@C 235 DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()` 236 237 Logically Collective on da 238 239 Input Parameter: 240 . da - initial distributed array 241 242 Output Parameter: 243 . ctype - the vector type 244 245 Level: intermediate 246 247 .seealso: `DMCreate()`, `DMDestroy()`, `DM`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()` 248 @*/ 249 PetscErrorCode DMGetVecType(DM da, VecType *ctype) 250 { 251 PetscFunctionBegin; 252 PetscValidHeaderSpecific(da, DM_CLASSID, 1); 253 *ctype = da->vectype; 254 PetscFunctionReturn(0); 255 } 256 257 /*@ 258 VecGetDM - Gets the `DM` defining the data layout of the vector 259 260 Not collective 261 262 Input Parameter: 263 . v - The `Vec` 264 265 Output Parameter: 266 . dm - The `DM` 267 268 Level: intermediate 269 270 Note: 271 A `Vec` may not have a `DM` associated with it. 272 273 .seealso: `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()` 274 @*/ 275 PetscErrorCode VecGetDM(Vec v, DM *dm) 276 { 277 PetscFunctionBegin; 278 PetscValidHeaderSpecific(v, VEC_CLASSID, 1); 279 PetscValidPointer(dm, 2); 280 PetscCall(PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm)); 281 PetscFunctionReturn(0); 282 } 283 284 /*@ 285 VecSetDM - Sets the `DM` defining the data layout of the vector. 286 287 Not collective 288 289 Input Parameters: 290 + v - The `Vec` 291 - dm - The `DM` 292 293 Note: 294 This is rarely used, generally one uses `DMGetLocalVector()` or `DMGetGlobalVector()` to create a vector associated with a given `DM` 295 296 This is NOT the same as `DMCreateGlobalVector()` since it does not change the view methods or perform other customization, but merely sets the `DM` member. 297 298 Level: developer 299 300 .seealso: `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()` 301 @*/ 302 PetscErrorCode VecSetDM(Vec v, DM dm) 303 { 304 PetscFunctionBegin; 305 PetscValidHeaderSpecific(v, VEC_CLASSID, 1); 306 if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 307 PetscCall(PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm)); 308 PetscFunctionReturn(0); 309 } 310 311 /*@C 312 DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM` 313 314 Logically Collective on dm 315 316 Input Parameters: 317 + dm - the `DM` context 318 - ctype - the matrix type 319 320 Options Database: 321 . -dm_is_coloring_type - global or local 322 323 Level: intermediate 324 325 .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`, 326 `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL` 327 @*/ 328 PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype) 329 { 330 PetscFunctionBegin; 331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 332 dm->coloringtype = ctype; 333 PetscFunctionReturn(0); 334 } 335 336 /*@C 337 DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM` 338 339 Logically Collective on dm 340 341 Input Parameter: 342 . dm - the `DM` context 343 344 Output Parameter: 345 . ctype - the matrix type 346 347 Options Database: 348 . -dm_is_coloring_type - global or local 349 350 Level: intermediate 351 352 .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`, 353 `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL` 354 @*/ 355 PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype) 356 { 357 PetscFunctionBegin; 358 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 359 *ctype = dm->coloringtype; 360 PetscFunctionReturn(0); 361 } 362 363 /*@C 364 DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()` 365 366 Logically Collective on dm 367 368 Input Parameters: 369 + dm - the `DM` context 370 - ctype - the matrix type, for example `MATMPIAIJ` 371 372 Options Database: 373 . -dm_mat_type ctype - the type of the matrix to create, for example mpiaij 374 375 Level: intermediate 376 377 .seealso: `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`, `DMSetMatType()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()` 378 @*/ 379 PetscErrorCode DMSetMatType(DM dm, MatType ctype) 380 { 381 PetscFunctionBegin; 382 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 383 PetscCall(PetscFree(dm->mattype)); 384 PetscCall(PetscStrallocpy(ctype, (char **)&dm->mattype)); 385 PetscFunctionReturn(0); 386 } 387 388 /*@C 389 DMGetMatType - Gets the type of matrix created with `DMCreateMatrix()` 390 391 Logically Collective on dm 392 393 Input Parameter: 394 . dm - the `DM` context 395 396 Output Parameter: 397 . ctype - the matrix type 398 399 Level: intermediate 400 401 .seealso: `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`, `DMSetMatType()`, `DMGetMatType()` 402 @*/ 403 PetscErrorCode DMGetMatType(DM dm, MatType *ctype) 404 { 405 PetscFunctionBegin; 406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 407 *ctype = dm->mattype; 408 PetscFunctionReturn(0); 409 } 410 411 /*@ 412 MatGetDM - Gets the `DM` defining the data layout of the matrix 413 414 Not collective 415 416 Input Parameter: 417 . A - The `Mat` 418 419 Output Parameter: 420 . dm - The `DM` 421 422 Level: intermediate 423 424 Note: 425 A matrix may not have a `DM` associated with it 426 427 Developer Note: 428 Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with the `Mat` through a `PetscObjectCompose()` operation 429 430 .seealso: `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()` 431 @*/ 432 PetscErrorCode MatGetDM(Mat A, DM *dm) 433 { 434 PetscFunctionBegin; 435 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 436 PetscValidPointer(dm, 2); 437 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm)); 438 PetscFunctionReturn(0); 439 } 440 441 /*@ 442 MatSetDM - Sets the `DM` defining the data layout of the matrix 443 444 Not collective 445 446 Input Parameters: 447 + A - The Mat 448 - dm - The DM 449 450 Level: developer 451 452 Note: 453 This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM` 454 455 Developer Note: 456 Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with 457 the `Mat` through a `PetscObjectCompose()` operation 458 459 .seealso: `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()` 460 @*/ 461 PetscErrorCode MatSetDM(Mat A, DM dm) 462 { 463 PetscFunctionBegin; 464 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 465 if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 466 PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm)); 467 PetscFunctionReturn(0); 468 } 469 470 /*@C 471 DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database 472 473 Logically Collective on dm 474 475 Input Parameters: 476 + da - the `DM` context 477 - prefix - the prefix to prepend 478 479 Notes: 480 A hyphen (-) must NOT be given at the beginning of the prefix name. 481 The first character of all runtime options is AUTOMATICALLY the hyphen. 482 483 Level: advanced 484 485 .seealso: `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()` 486 @*/ 487 PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[]) 488 { 489 PetscFunctionBegin; 490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 491 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix)); 492 if (dm->sf) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix)); 493 if (dm->sectionSF) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix)); 494 PetscFunctionReturn(0); 495 } 496 497 /*@C 498 DMAppendOptionsPrefix - Appends an additional string to an already exising prefix used for searching for 499 `DM` options in the options database. 500 501 Logically Collective on dm 502 503 Input Parameters: 504 + dm - the `DM` context 505 - prefix - the string to append to the current prefix 506 507 Notes: 508 If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called. 509 A hyphen (-) must NOT be given at the beginning of the prefix name. 510 The first character of all runtime options is AUTOMATICALLY the hyphen. 511 512 Level: advanced 513 514 .seealso: `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()` 515 @*/ 516 PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[]) 517 { 518 PetscFunctionBegin; 519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 520 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix)); 521 PetscFunctionReturn(0); 522 } 523 524 /*@C 525 DMGetOptionsPrefix - Gets the prefix used for searching for all 526 DM options in the options database. 527 528 Not Collective 529 530 Input Parameters: 531 . dm - the `DM` context 532 533 Output Parameters: 534 . prefix - pointer to the prefix string used is returned 535 536 Fortran Note: 537 On the fortran side, the user should pass in a string 'prefix' of 538 sufficient length to hold the prefix. 539 540 Level: advanced 541 542 .seealso: `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()` 543 @*/ 544 PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[]) 545 { 546 PetscFunctionBegin; 547 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 548 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, prefix)); 549 PetscFunctionReturn(0); 550 } 551 552 static PetscErrorCode DMCountNonCyclicReferences(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct) 553 { 554 PetscInt refct = ((PetscObject)dm)->refct; 555 556 PetscFunctionBegin; 557 *ncrefct = 0; 558 if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) { 559 refct--; 560 if (recurseCoarse) { 561 PetscInt coarseCount; 562 563 PetscCall(DMCountNonCyclicReferences(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount)); 564 refct += coarseCount; 565 } 566 } 567 if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) { 568 refct--; 569 if (recurseFine) { 570 PetscInt fineCount; 571 572 PetscCall(DMCountNonCyclicReferences(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount)); 573 refct += fineCount; 574 } 575 } 576 *ncrefct = refct; 577 PetscFunctionReturn(0); 578 } 579 580 PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm) 581 { 582 DMLabelLink next = dm->labels; 583 584 PetscFunctionBegin; 585 /* destroy the labels */ 586 while (next) { 587 DMLabelLink tmp = next->next; 588 589 if (next->label == dm->depthLabel) dm->depthLabel = NULL; 590 if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL; 591 PetscCall(DMLabelDestroy(&next->label)); 592 PetscCall(PetscFree(next)); 593 next = tmp; 594 } 595 dm->labels = NULL; 596 PetscFunctionReturn(0); 597 } 598 599 PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c) 600 { 601 PetscFunctionBegin; 602 c->dim = PETSC_DEFAULT; 603 PetscCall(DMDestroy(&c->dm)); 604 PetscCall(VecDestroy(&c->x)); 605 PetscCall(VecDestroy(&c->xl)); 606 PetscCall(DMFieldDestroy(&c->field)); 607 PetscFunctionReturn(0); 608 } 609 610 /*@C 611 DMDestroy - Destroys a `DM`. 612 613 Collective on dm 614 615 Input Parameter: 616 . dm - the `DM` object to destroy 617 618 Level: developer 619 620 .seealso: `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()` 621 622 @*/ 623 PetscErrorCode DMDestroy(DM *dm) 624 { 625 PetscInt cnt; 626 DMNamedVecLink nlink, nnext; 627 628 PetscFunctionBegin; 629 if (!*dm) PetscFunctionReturn(0); 630 PetscValidHeaderSpecific((*dm), DM_CLASSID, 1); 631 632 /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */ 633 PetscCall(DMCountNonCyclicReferences(*dm, PETSC_TRUE, PETSC_TRUE, &cnt)); 634 --((PetscObject)(*dm))->refct; 635 if (--cnt > 0) { 636 *dm = NULL; 637 PetscFunctionReturn(0); 638 } 639 if (((PetscObject)(*dm))->refct < 0) PetscFunctionReturn(0); 640 ((PetscObject)(*dm))->refct = 0; 641 642 PetscCall(DMClearGlobalVectors(*dm)); 643 PetscCall(DMClearLocalVectors(*dm)); 644 645 nnext = (*dm)->namedglobal; 646 (*dm)->namedglobal = NULL; 647 for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named vectors */ 648 nnext = nlink->next; 649 PetscCheck(nlink->status == DMVEC_STATUS_IN, ((PetscObject)*dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "DM still has Vec named '%s' checked out", nlink->name); 650 PetscCall(PetscFree(nlink->name)); 651 PetscCall(VecDestroy(&nlink->X)); 652 PetscCall(PetscFree(nlink)); 653 } 654 nnext = (*dm)->namedlocal; 655 (*dm)->namedlocal = NULL; 656 for (nlink = nnext; nlink; nlink = nnext) { /* Destroy the named local vectors */ 657 nnext = nlink->next; 658 PetscCheck(nlink->status == DMVEC_STATUS_IN, ((PetscObject)*dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "DM still has Vec named '%s' checked out", nlink->name); 659 PetscCall(PetscFree(nlink->name)); 660 PetscCall(VecDestroy(&nlink->X)); 661 PetscCall(PetscFree(nlink)); 662 } 663 664 /* Destroy the list of hooks */ 665 { 666 DMCoarsenHookLink link, next; 667 for (link = (*dm)->coarsenhook; link; link = next) { 668 next = link->next; 669 PetscCall(PetscFree(link)); 670 } 671 (*dm)->coarsenhook = NULL; 672 } 673 { 674 DMRefineHookLink link, next; 675 for (link = (*dm)->refinehook; link; link = next) { 676 next = link->next; 677 PetscCall(PetscFree(link)); 678 } 679 (*dm)->refinehook = NULL; 680 } 681 { 682 DMSubDomainHookLink link, next; 683 for (link = (*dm)->subdomainhook; link; link = next) { 684 next = link->next; 685 PetscCall(PetscFree(link)); 686 } 687 (*dm)->subdomainhook = NULL; 688 } 689 { 690 DMGlobalToLocalHookLink link, next; 691 for (link = (*dm)->gtolhook; link; link = next) { 692 next = link->next; 693 PetscCall(PetscFree(link)); 694 } 695 (*dm)->gtolhook = NULL; 696 } 697 { 698 DMLocalToGlobalHookLink link, next; 699 for (link = (*dm)->ltoghook; link; link = next) { 700 next = link->next; 701 PetscCall(PetscFree(link)); 702 } 703 (*dm)->ltoghook = NULL; 704 } 705 /* Destroy the work arrays */ 706 { 707 DMWorkLink link, next; 708 PetscCheck(!(*dm)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out"); 709 for (link = (*dm)->workin; link; link = next) { 710 next = link->next; 711 PetscCall(PetscFree(link->mem)); 712 PetscCall(PetscFree(link)); 713 } 714 (*dm)->workin = NULL; 715 } 716 /* destroy the labels */ 717 PetscCall(DMDestroyLabelLinkList_Internal(*dm)); 718 /* destroy the fields */ 719 PetscCall(DMClearFields(*dm)); 720 /* destroy the boundaries */ 721 { 722 DMBoundary next = (*dm)->boundary; 723 while (next) { 724 DMBoundary b = next; 725 726 next = b->next; 727 PetscCall(PetscFree(b)); 728 } 729 } 730 731 PetscCall(PetscObjectDestroy(&(*dm)->dmksp)); 732 PetscCall(PetscObjectDestroy(&(*dm)->dmsnes)); 733 PetscCall(PetscObjectDestroy(&(*dm)->dmts)); 734 735 if ((*dm)->ctx && (*dm)->ctxdestroy) PetscCall((*(*dm)->ctxdestroy)(&(*dm)->ctx)); 736 PetscCall(MatFDColoringDestroy(&(*dm)->fd)); 737 PetscCall(ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap)); 738 PetscCall(PetscFree((*dm)->vectype)); 739 PetscCall(PetscFree((*dm)->mattype)); 740 741 PetscCall(PetscSectionDestroy(&(*dm)->localSection)); 742 PetscCall(PetscSectionDestroy(&(*dm)->globalSection)); 743 PetscCall(PetscLayoutDestroy(&(*dm)->map)); 744 PetscCall(PetscSectionDestroy(&(*dm)->defaultConstraint.section)); 745 PetscCall(MatDestroy(&(*dm)->defaultConstraint.mat)); 746 PetscCall(PetscSFDestroy(&(*dm)->sf)); 747 PetscCall(PetscSFDestroy(&(*dm)->sectionSF)); 748 if ((*dm)->useNatural) { 749 if ((*dm)->sfNatural) PetscCall(PetscSFDestroy(&(*dm)->sfNatural)); 750 PetscCall(PetscObjectDereference((PetscObject)(*dm)->sfMigration)); 751 } 752 { 753 Vec *auxData; 754 PetscInt n, i, off = 0; 755 756 PetscCall(PetscHMapAuxGetSize((*dm)->auxData, &n)); 757 PetscCall(PetscMalloc1(n, &auxData)); 758 PetscCall(PetscHMapAuxGetVals((*dm)->auxData, &off, auxData)); 759 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 760 PetscCall(PetscFree(auxData)); 761 PetscCall(PetscHMapAuxDestroy(&(*dm)->auxData)); 762 } 763 if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) PetscCall(DMSetFineDM((*dm)->coarseMesh, NULL)); 764 765 PetscCall(DMDestroy(&(*dm)->coarseMesh)); 766 if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) PetscCall(DMSetCoarseDM((*dm)->fineMesh, NULL)); 767 PetscCall(DMDestroy(&(*dm)->fineMesh)); 768 PetscCall(PetscFree((*dm)->Lstart)); 769 PetscCall(PetscFree((*dm)->L)); 770 PetscCall(PetscFree((*dm)->maxCell)); 771 PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[0])); 772 PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[1])); 773 if ((*dm)->transformDestroy) PetscCall((*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx)); 774 PetscCall(DMDestroy(&(*dm)->transformDM)); 775 PetscCall(VecDestroy(&(*dm)->transform)); 776 777 PetscCall(DMClearDS(*dm)); 778 PetscCall(DMDestroy(&(*dm)->dmBC)); 779 /* if memory was published with SAWs then destroy it */ 780 PetscCall(PetscObjectSAWsViewOff((PetscObject)*dm)); 781 782 if ((*dm)->ops->destroy) PetscCall((*(*dm)->ops->destroy)(*dm)); 783 PetscCall(DMMonitorCancel(*dm)); 784 #ifdef PETSC_HAVE_LIBCEED 785 PetscCallCEED(CeedElemRestrictionDestroy(&(*dm)->ceedERestrict)); 786 PetscCallCEED(CeedDestroy(&(*dm)->ceed)); 787 #endif 788 /* We do not destroy (*dm)->data here so that we can reference count backend objects */ 789 PetscCall(PetscHeaderDestroy(dm)); 790 PetscFunctionReturn(0); 791 } 792 793 /*@ 794 DMSetUp - sets up the data structures inside a `DM` object 795 796 Collective on dm 797 798 Input Parameter: 799 . dm - the `DM` object to setup 800 801 Level: intermediate 802 803 Note: 804 This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM` 805 806 .seealso: `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()` 807 808 @*/ 809 PetscErrorCode DMSetUp(DM dm) 810 { 811 PetscFunctionBegin; 812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 813 if (dm->setupcalled) PetscFunctionReturn(0); 814 PetscTryTypeMethod(dm, setup); 815 dm->setupcalled = PETSC_TRUE; 816 PetscFunctionReturn(0); 817 } 818 819 /*@ 820 DMSetFromOptions - sets parameters in a `DM` from the options database 821 822 Collective on dm 823 824 Input Parameter: 825 . dm - the `DM` object to set options for 826 827 Options Database: 828 + -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros 829 . -dm_vec_type <type> - type of vector to create inside `DM` 830 . -dm_mat_type <type> - type of matrix to create inside `DM` 831 . -dm_is_coloring_type - <global or local> 832 - -dm_bind_below <n> - bind (force execution on CPU) for `Vec` and `Mat` objects with local size (number of vector entries or matrix rows) below n; currently only supported for `DMDA` 833 834 DMPLEX Specific creation options 835 + -dm_plex_filename <str> - File containing a mesh 836 . -dm_plex_boundary_filename <str> - File containing a mesh boundary 837 . -dm_plex_name <str> - Name of the mesh in the file 838 . -dm_plex_shape <shape> - The domain shape, such as `DM_SHAPE_BOX`, `DM_SHAPE_SPHERE`, etc. 839 . -dm_plex_cell <ct> - Cell shape 840 . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain 841 . -dm_plex_dim <dim> - Set the topological dimension 842 . -dm_plex_simplex <bool> - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements 843 . -dm_plex_interpolate <bool> - `PETSC_TRUE` turns on topological interpolation (creating edges and faces) 844 . -dm_plex_scale <sc> - Scale factor for mesh coordinates 845 . -dm_plex_box_faces <m,n,p> - Number of faces along each dimension 846 . -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box 847 . -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box 848 . -dm_plex_box_bd <bx,by,bz> - Specify the `DMBoundaryType `for each direction 849 . -dm_plex_sphere_radius <r> - The sphere radius 850 . -dm_plex_ball_radius <r> - Radius of the ball 851 . -dm_plex_cylinder_bd <bz> - Boundary type in the z direction 852 . -dm_plex_cylinder_num_wedges <n> - Number of wedges around the cylinder 853 . -dm_plex_reorder <order> - Reorder the mesh using the specified algorithm 854 . -dm_refine_pre <n> - The number of refinements before distribution 855 . -dm_refine_uniform_pre <bool> - Flag for uniform refinement before distribution 856 . -dm_refine_volume_limit_pre <v> - The maximum cell volume after refinement before distribution 857 . -dm_refine <n> - The number of refinements after distribution 858 . -dm_extrude <l> - Activate extrusion and specify the number of layers to extrude 859 . -dm_plex_transform_extrude_thickness <t> - The total thickness of extruded layers 860 . -dm_plex_transform_extrude_use_tensor <bool> - Use tensor cells when extruding 861 . -dm_plex_transform_extrude_symmetric <bool> - Extrude layers symmetrically about the surface 862 . -dm_plex_transform_extrude_normal <n0,...,nd> - Specify the extrusion direction 863 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer 864 . -dm_plex_create_fv_ghost_cells - Flag to create finite volume ghost cells on the boundary 865 . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary 866 . -dm_distribute <bool> - Flag to redistribute a mesh among processes 867 . -dm_distribute_overlap <n> - The size of the overlap halo 868 . -dm_plex_adj_cone <bool> - Set adjacency direction 869 - -dm_plex_adj_closure <bool> - Set adjacency size 870 871 DMPLEX Specific Checks 872 + -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()` 873 . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()` 874 . -dm_plex_check_faces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - `DMPlexCheckFaces()` 875 . -dm_plex_check_geometry - Check that cells have positive volume - `DMPlexCheckGeometry()` 876 . -dm_plex_check_pointsf - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()` 877 . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()` 878 - -dm_plex_check_all - Perform all the checks above 879 880 Level: intermediate 881 882 .seealso: `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, 883 `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`, 884 `DMSetOptionsPrefix()`, `DM`, `DMType`, `DMPLEX`, `DMDA` 885 886 @*/ 887 PetscErrorCode DMSetFromOptions(DM dm) 888 { 889 char typeName[256]; 890 PetscBool flg; 891 892 PetscFunctionBegin; 893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 894 dm->setfromoptionscalled = PETSC_TRUE; 895 if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf)); 896 if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF)); 897 PetscObjectOptionsBegin((PetscObject)dm); 898 PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL)); 899 PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg)); 900 if (flg) PetscCall(DMSetVecType(dm, typeName)); 901 PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg)); 902 if (flg) PetscCall(DMSetMatType(dm, typeName)); 903 PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL)); 904 PetscCall(PetscOptionsInt("-dm_bind_below", "Set the size threshold (in entries) below which the Vec is bound to the CPU", "VecBindToCPU", dm->bind_below, &dm->bind_below, &flg)); 905 PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject); 906 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 907 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject)); 908 PetscOptionsEnd(); 909 PetscFunctionReturn(0); 910 } 911 912 /*@C 913 DMViewFromOptions - View a `DM` in a particular way based on a request in the options database 914 915 Collective on dm 916 917 Input Parameters: 918 + dm - the `DM` object 919 . obj - optional object that provides the prefix for the options database (if NULL then the prefix in obj is used) 920 - optionname - option string that is used to activate viewing 921 922 Level: intermediate 923 924 Note: 925 See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed 926 927 .seealso: `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`, `PetscObjectViewFromOptions()` 928 @*/ 929 PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[]) 930 { 931 PetscFunctionBegin; 932 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 933 PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name)); 934 PetscFunctionReturn(0); 935 } 936 937 /*@C 938 DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or 939 save the `DM` in a binary file to be loaded later or create a visualization of the `DM` 940 941 Collective on dm 942 943 Input Parameters: 944 + dm - the `DM` object to view 945 - v - the viewer 946 947 Notes: 948 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` one can save multiple `DMPLEX` 949 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 950 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 951 952 Level: beginner 953 954 .seealso: `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat`(), `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()` 955 956 @*/ 957 PetscErrorCode DMView(DM dm, PetscViewer v) 958 { 959 PetscBool isbinary; 960 PetscMPIInt size; 961 PetscViewerFormat format; 962 963 PetscFunctionBegin; 964 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 965 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v)); 966 PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2); 967 /* Ideally, we would like to have this test on. 968 However, it currently breaks socket viz via GLVis. 969 During DMView(parallel_mesh,glvis_viewer), each 970 process opens a sequential ASCII socket to visualize 971 the local mesh, and PetscObjectView(dm,local_socket) 972 is internally called inside VecView_GLVis, incurring 973 in an error here */ 974 /* PetscCheckSameComm(dm,1,v,2); */ 975 PetscCall(PetscViewerCheckWritable(v)); 976 977 PetscCall(PetscViewerGetFormat(v, &format)); 978 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 979 if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(0); 980 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v)); 981 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary)); 982 if (isbinary) { 983 PetscInt classid = DM_FILE_CLASSID; 984 char type[256]; 985 986 PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT)); 987 PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, 256)); 988 PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR)); 989 } 990 PetscTryTypeMethod(dm, view, v); 991 PetscFunctionReturn(0); 992 } 993 994 /*@ 995 DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks, 996 that is it has no ghost locations. 997 998 Collective on dm 999 1000 Input Parameter: 1001 . dm - the `DM` object 1002 1003 Output Parameter: 1004 . vec - the global vector 1005 1006 Level: beginner 1007 1008 .seealso: `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, 1009 `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()` 1010 1011 @*/ 1012 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec) 1013 { 1014 PetscFunctionBegin; 1015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1016 PetscValidPointer(vec, 2); 1017 PetscUseTypeMethod(dm, createglobalvector, vec); 1018 if (PetscDefined(USE_DEBUG)) { 1019 DM vdm; 1020 1021 PetscCall(VecGetDM(*vec, &vdm)); 1022 PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name); 1023 } 1024 PetscFunctionReturn(0); 1025 } 1026 1027 /*@ 1028 DMCreateLocalVector - Creates a local vector from a `DM` object. 1029 1030 Not Collective 1031 1032 Input Parameter: 1033 . dm - the `DM` object 1034 1035 Output Parameter: 1036 . vec - the local vector 1037 1038 Level: beginner 1039 1040 Notes: 1041 A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations. 1042 1043 .seealso: `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()` 1044 `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()` 1045 1046 @*/ 1047 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec) 1048 { 1049 PetscFunctionBegin; 1050 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1051 PetscValidPointer(vec, 2); 1052 PetscUseTypeMethod(dm, createlocalvector, vec); 1053 if (PetscDefined(USE_DEBUG)) { 1054 DM vdm; 1055 1056 PetscCall(VecGetDM(*vec, &vdm)); 1057 PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name); 1058 } 1059 PetscFunctionReturn(0); 1060 } 1061 1062 /*@ 1063 DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`. 1064 1065 Collective on dm 1066 1067 Input Parameter: 1068 . dm - the `DM` that provides the mapping 1069 1070 Output Parameter: 1071 . ltog - the mapping 1072 1073 Level: advanced 1074 1075 Notes: 1076 The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()` 1077 1078 Vectors obtained with `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do 1079 need to use this function with those objects. 1080 1081 This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`. 1082 1083 .seealso: `DMCreateLocalVector()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`, 1084 `DMCreateMatrix()` 1085 @*/ 1086 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog) 1087 { 1088 PetscInt bs = -1, bsLocal[2], bsMinMax[2]; 1089 1090 PetscFunctionBegin; 1091 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1092 PetscValidPointer(ltog, 2); 1093 if (!dm->ltogmap) { 1094 PetscSection section, sectionGlobal; 1095 1096 PetscCall(DMGetLocalSection(dm, §ion)); 1097 if (section) { 1098 const PetscInt *cdofs; 1099 PetscInt *ltog; 1100 PetscInt pStart, pEnd, n, p, k, l; 1101 1102 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 1103 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 1104 PetscCall(PetscSectionGetStorageSize(section, &n)); 1105 PetscCall(PetscMalloc1(n, <og)); /* We want the local+overlap size */ 1106 for (p = pStart, l = 0; p < pEnd; ++p) { 1107 PetscInt bdof, cdof, dof, off, c, cind; 1108 1109 /* Should probably use constrained dofs */ 1110 PetscCall(PetscSectionGetDof(section, p, &dof)); 1111 PetscCall(PetscSectionGetConstraintDof(section, p, &cdof)); 1112 PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs)); 1113 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off)); 1114 /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */ 1115 bdof = cdof && (dof - cdof) ? 1 : dof; 1116 if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof); 1117 1118 for (c = 0, cind = 0; c < dof; ++c, ++l) { 1119 if (cind < cdof && c == cdofs[cind]) { 1120 ltog[l] = off < 0 ? off - c : -(off + c + 1); 1121 cind++; 1122 } else { 1123 ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind; 1124 } 1125 } 1126 } 1127 /* Must have same blocksize on all procs (some might have no points) */ 1128 bsLocal[0] = bs < 0 ? PETSC_MAX_INT : bs; 1129 bsLocal[1] = bs; 1130 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 1131 if (bsMinMax[0] != bsMinMax[1]) { 1132 bs = 1; 1133 } else { 1134 bs = bsMinMax[0]; 1135 } 1136 bs = bs < 0 ? 1 : bs; 1137 /* Must reduce indices by blocksize */ 1138 if (bs > 1) { 1139 for (l = 0, k = 0; l < n; l += bs, ++k) { 1140 // Integer division of negative values truncates toward zero(!), not toward negative infinity 1141 ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1); 1142 } 1143 n /= bs; 1144 } 1145 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap)); 1146 } else PetscUseTypeMethod(dm, getlocaltoglobalmapping); 1147 } 1148 *ltog = dm->ltogmap; 1149 PetscFunctionReturn(0); 1150 } 1151 1152 /*@ 1153 DMGetBlockSize - Gets the inherent block size associated with a `DM` 1154 1155 Not Collective 1156 1157 Input Parameter: 1158 . dm - the `DM` with block structure 1159 1160 Output Parameter: 1161 . bs - the block size, 1 implies no exploitable block structure 1162 1163 Level: intermediate 1164 1165 Note: 1166 This might be the number of degrees of freedom at each grid point for a structured grid. 1167 1168 Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but 1169 rather different locations in the vectors may have a different block size. 1170 1171 .seealso: `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()` 1172 @*/ 1173 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs) 1174 { 1175 PetscFunctionBegin; 1176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1177 PetscValidIntPointer(bs, 2); 1178 PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet"); 1179 *bs = dm->bs; 1180 PetscFunctionReturn(0); 1181 } 1182 1183 /*@C 1184 DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by 1185 `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`. 1186 1187 Collective on dmc 1188 1189 Input Parameters: 1190 + dmc - the `DM` object 1191 - dmf - the second, finer `DM` object 1192 1193 Output Parameters: 1194 + mat - the interpolation 1195 - vec - the scaling (optional), see `DMCreateInterpolationScale()` 1196 1197 Level: developer 1198 1199 Notes: 1200 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by 1201 DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation. 1202 1203 For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate 1204 vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic. 1205 1206 .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()` 1207 1208 @*/ 1209 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec) 1210 { 1211 PetscFunctionBegin; 1212 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1213 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1214 PetscValidPointer(mat, 3); 1215 PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0)); 1216 PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec); 1217 PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0)); 1218 PetscFunctionReturn(0); 1219 } 1220 1221 /*@ 1222 DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is the transpose of the interpolation between the `DM`. 1223 xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual) restriction. In other words xcoarse is the coarse 1224 representation of xfine. 1225 1226 Input Parameters: 1227 + dac - `DM` that defines a coarse mesh 1228 . daf - `DM` that defines a fine mesh 1229 - mat - the restriction (or interpolation operator) from fine to coarse 1230 1231 Output Parameter: 1232 . scale - the scaled vector 1233 1234 Level: advanced 1235 1236 Developer Notes: 1237 If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()` 1238 on the restriction/interpolation operator to set the bindingpropagates flag to true. 1239 1240 .seealso: `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, DMCreateRestriction()`, `DMCreateGlobalVector()` 1241 1242 @*/ 1243 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale) 1244 { 1245 Vec fine; 1246 PetscScalar one = 1.0; 1247 #if defined(PETSC_HAVE_CUDA) 1248 PetscBool bindingpropagates, isbound; 1249 #endif 1250 1251 PetscFunctionBegin; 1252 PetscCall(DMCreateGlobalVector(daf, &fine)); 1253 PetscCall(DMCreateGlobalVector(dac, scale)); 1254 PetscCall(VecSet(fine, one)); 1255 #if defined(PETSC_HAVE_CUDA) 1256 /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well. 1257 * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL, 1258 * we'll need to do it for that case, too.*/ 1259 PetscCall(VecGetBindingPropagates(fine, &bindingpropagates)); 1260 if (bindingpropagates) { 1261 PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE)); 1262 PetscCall(VecBoundToCPU(fine, &isbound)); 1263 PetscCall(MatBindToCPU(mat, isbound)); 1264 } 1265 #endif 1266 PetscCall(MatRestrict(mat, fine, *scale)); 1267 PetscCall(VecDestroy(&fine)); 1268 PetscCall(VecReciprocal(*scale)); 1269 PetscFunctionReturn(0); 1270 } 1271 1272 /*@ 1273 DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by 1274 `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`. 1275 1276 Collective on dmc 1277 1278 Input Parameters: 1279 + dmc - the `DM` object 1280 - dmf - the second, finer `DM` object 1281 1282 Output Parameter: 1283 . mat - the restriction 1284 1285 Level: developer 1286 1287 Note: 1288 This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that 1289 matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object. 1290 1291 .seealso: `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()` 1292 1293 @*/ 1294 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat) 1295 { 1296 PetscFunctionBegin; 1297 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1298 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1299 PetscValidPointer(mat, 3); 1300 PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0)); 1301 PetscUseTypeMethod(dmc, createrestriction, dmf, mat); 1302 PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0)); 1303 PetscFunctionReturn(0); 1304 } 1305 1306 /*@ 1307 DMCreateInjection - Gets injection matrix between two `DM` objects. This is an operator that applied to a vector obtained with 1308 `DMCreateGlobalVector()` on the fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting the values 1309 on the coarse grid points. This compares to the operator obtained by `DMCreateRestriction()` or the transpose of the operator obtained 1310 by `DMCreateInterpolation()` that uses a "local weighted average" of the values around the coarse grid point as the coarse grid value. 1311 1312 Collective on dac 1313 1314 Input Parameters: 1315 + dac - the `DM` object 1316 - daf - the second, finer `DM` object 1317 1318 Output Parameter: 1319 . mat - the injection 1320 1321 Level: developer 1322 1323 Note: 1324 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by 1325 `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection. 1326 1327 .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`, 1328 `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()` 1329 1330 @*/ 1331 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat) 1332 { 1333 PetscFunctionBegin; 1334 PetscValidHeaderSpecific(dac, DM_CLASSID, 1); 1335 PetscValidHeaderSpecific(daf, DM_CLASSID, 2); 1336 PetscValidPointer(mat, 3); 1337 PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0)); 1338 PetscUseTypeMethod(dac, createinjection, daf, mat); 1339 PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0)); 1340 PetscFunctionReturn(0); 1341 } 1342 1343 /*@ 1344 DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a 1345 a Galerkin finite element model on the `DM` 1346 1347 Collective on dac 1348 1349 Input Parameters: 1350 + dmc - the target `DM` object 1351 - dmf - the source `DM` object 1352 1353 Output Parameter: 1354 . mat - the mass matrix 1355 1356 Level: developer 1357 1358 Notes: 1359 For `DMPLEX` the finite element model for the `DM` must have been already provided. 1360 1361 if dmc is dmf then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()` 1362 1363 .seealso: `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()` 1364 @*/ 1365 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat) 1366 { 1367 PetscFunctionBegin; 1368 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1369 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1370 PetscValidPointer(mat, 3); 1371 PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, 0, 0, 0, 0)); 1372 PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat); 1373 PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, 0, 0, 0, 0)); 1374 PetscFunctionReturn(0); 1375 } 1376 1377 /*@ 1378 DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM` 1379 1380 Collective on dm 1381 1382 Input Parameter: 1383 . dm - the `DM` object 1384 1385 Output Parameter: 1386 . lm - the lumped mass matrix, which is a diagonal matrix, represented as a vector 1387 1388 Level: developer 1389 1390 Note: 1391 See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix. 1392 1393 .seealso: `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()` 1394 @*/ 1395 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *lm) 1396 { 1397 PetscFunctionBegin; 1398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1399 PetscValidPointer(lm, 2); 1400 PetscUseTypeMethod(dm, createmassmatrixlumped, lm); 1401 PetscFunctionReturn(0); 1402 } 1403 1404 /*@ 1405 DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization 1406 of a PDE on the `DM`. 1407 1408 Collective on dm 1409 1410 Input Parameters: 1411 + dm - the `DM` object 1412 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL` 1413 1414 Output Parameter: 1415 . coloring - the coloring 1416 1417 Notes: 1418 Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the 1419 matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors). 1420 1421 This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()` 1422 1423 Level: developer 1424 1425 .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()` 1426 1427 @*/ 1428 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring) 1429 { 1430 PetscFunctionBegin; 1431 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1432 PetscValidPointer(coloring, 3); 1433 PetscUseTypeMethod(dm, getcoloring, ctype, coloring); 1434 PetscFunctionReturn(0); 1435 } 1436 1437 /*@ 1438 DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator. 1439 1440 Collective on dm 1441 1442 Input Parameter: 1443 . dm - the `DM` object 1444 1445 Output Parameter: 1446 . mat - the empty Jacobian 1447 1448 Level: beginner 1449 1450 Options Database Keys: 1451 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros 1452 1453 Notes: 1454 This properly preallocates the number of nonzeros in the sparse matrix so you 1455 do not need to do it yourself. 1456 1457 By default it also sets the nonzero structure and puts in the zero entries. To prevent setting 1458 the nonzero pattern call `DMSetMatrixPreallocateOnly()` 1459 1460 For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used 1461 internally by PETSc. 1462 1463 For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because 1464 `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute 1465 1466 .seealso: `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()` 1467 1468 @*/ 1469 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat) 1470 { 1471 PetscFunctionBegin; 1472 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1473 PetscValidPointer(mat, 2); 1474 PetscCall(MatInitializePackage()); 1475 PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0)); 1476 PetscUseTypeMethod(dm, creatematrix, mat); 1477 if (PetscDefined(USE_DEBUG)) { 1478 DM mdm; 1479 1480 PetscCall(MatGetDM(*mat, &mdm)); 1481 PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name); 1482 } 1483 /* Handle nullspace and near nullspace */ 1484 if (dm->Nf) { 1485 MatNullSpace nullSpace; 1486 PetscInt Nf, f; 1487 1488 PetscCall(DMGetNumFields(dm, &Nf)); 1489 for (f = 0; f < Nf; ++f) { 1490 if (dm->nullspaceConstructors[f]) { 1491 PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace)); 1492 PetscCall(MatSetNullSpace(*mat, nullSpace)); 1493 PetscCall(MatNullSpaceDestroy(&nullSpace)); 1494 break; 1495 } 1496 } 1497 for (f = 0; f < Nf; ++f) { 1498 if (dm->nearnullspaceConstructors[f]) { 1499 PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace)); 1500 PetscCall(MatSetNearNullSpace(*mat, nullSpace)); 1501 PetscCall(MatNullSpaceDestroy(&nullSpace)); 1502 } 1503 } 1504 } 1505 PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0)); 1506 PetscFunctionReturn(0); 1507 } 1508 1509 /*@ 1510 DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and `ISLocalToGlobalMapping` will be 1511 properly set, but the data structures to store values in the matrices will not be preallocated. This is most useful to reduce initialization costs when 1512 `MatSetPreallocationCOO()` and `MatSetValuesCOO()` will be used. 1513 1514 Logically Collective on dm 1515 1516 Input Parameters: 1517 + dm - the `DM` 1518 - skip - `PETSC_TRUE` to skip preallocation 1519 1520 Level: developer 1521 1522 .seealso: `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()` 1523 @*/ 1524 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip) 1525 { 1526 PetscFunctionBegin; 1527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1528 dm->prealloc_skip = skip; 1529 PetscFunctionReturn(0); 1530 } 1531 1532 /*@ 1533 DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly 1534 preallocated but the nonzero structure and zero values will not be set. 1535 1536 Logically Collective on dm 1537 1538 Input Parameters: 1539 + dm - the `DM` 1540 - only - `PETSC_TRUE` if only want preallocation 1541 1542 Level: developer 1543 1544 Options Database Keys: 1545 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros 1546 1547 .seealso: `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()` 1548 @*/ 1549 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only) 1550 { 1551 PetscFunctionBegin; 1552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1553 dm->prealloc_only = only; 1554 PetscFunctionReturn(0); 1555 } 1556 1557 /*@ 1558 DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix structure will be created 1559 but the array for numerical values will not be allocated. 1560 1561 Logically Collective on dm 1562 1563 Input Parameters: 1564 + dm - the `DM` 1565 - only - `PETSC_TRUE` if you only want matrix stucture 1566 1567 Level: developer 1568 1569 .seealso: `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()` 1570 @*/ 1571 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only) 1572 { 1573 PetscFunctionBegin; 1574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1575 dm->structure_only = only; 1576 PetscFunctionReturn(0); 1577 } 1578 1579 /*@C 1580 DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()` 1581 1582 Not Collective 1583 1584 Input Parameters: 1585 + dm - the `DM` object 1586 . count - The minimum size 1587 - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, or MPIU_INT) 1588 1589 Output Parameter: 1590 . array - the work array 1591 1592 Level: developer 1593 1594 Note: 1595 A `DM` may stash the array between instantations so using this routine may be more efficient than calling `PetscMalloc()` 1596 1597 The array may contain nonzero values 1598 1599 .seealso: `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()` 1600 @*/ 1601 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem) 1602 { 1603 DMWorkLink link; 1604 PetscMPIInt dsize; 1605 1606 PetscFunctionBegin; 1607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1608 PetscValidPointer(mem, 4); 1609 if (dm->workin) { 1610 link = dm->workin; 1611 dm->workin = dm->workin->next; 1612 } else { 1613 PetscCall(PetscNew(&link)); 1614 } 1615 PetscCallMPI(MPI_Type_size(dtype, &dsize)); 1616 if (((size_t)dsize * count) > link->bytes) { 1617 PetscCall(PetscFree(link->mem)); 1618 PetscCall(PetscMalloc(dsize * count, &link->mem)); 1619 link->bytes = dsize * count; 1620 } 1621 link->next = dm->workout; 1622 dm->workout = link; 1623 #if defined(__MEMCHECK_H) && (defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) || defined(PLAT_amd64_darwin)) 1624 VALGRIND_MAKE_MEM_NOACCESS((char *)link->mem + (size_t)dsize * count, link->bytes - (size_t)dsize * count); 1625 VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize * count); 1626 #endif 1627 *(void **)mem = link->mem; 1628 PetscFunctionReturn(0); 1629 } 1630 1631 /*@C 1632 DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()` 1633 1634 Not Collective 1635 1636 Input Parameters: 1637 + dm - the `DM` object 1638 . count - The minimum size 1639 - dtype - MPI data type, often MPIU_REAL, MPIU_SCALAR, MPIU_INT 1640 1641 Output Parameter: 1642 . array - the work array 1643 1644 Level: developer 1645 1646 Developer Notes: 1647 count and dtype are ignored, they are only needed for `DMGetWorkArray()` 1648 1649 .seealso: `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()` 1650 @*/ 1651 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem) 1652 { 1653 DMWorkLink *p, link; 1654 1655 PetscFunctionBegin; 1656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1657 PetscValidPointer(mem, 4); 1658 for (p = &dm->workout; (link = *p); p = &link->next) { 1659 if (link->mem == *(void **)mem) { 1660 *p = link->next; 1661 link->next = dm->workin; 1662 dm->workin = link; 1663 *(void **)mem = NULL; 1664 PetscFunctionReturn(0); 1665 } 1666 } 1667 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out"); 1668 } 1669 1670 /*@C 1671 DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces 1672 are joined or split, such as in `DMCreateSubDM()` 1673 1674 Logically collective on dm 1675 1676 Input Parameters: 1677 + dm - The `DM` 1678 . field - The field number for the nullspace 1679 - nullsp - A callback to create the nullspace 1680 1681 Calling sequence of nullsp: 1682 .vb 1683 PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace) 1684 .ve 1685 + dm - The present `DM` 1686 . origField - The field number given above, in the original `DM` 1687 . field - The field number in dm 1688 - nullSpace - The nullspace for the given field 1689 1690 Level: intermediate 1691 1692 Fortran Notes: 1693 This function is not available from Fortran. 1694 1695 .seealso: `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 1696 @*/ 1697 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *)) 1698 { 1699 PetscFunctionBegin; 1700 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1701 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1702 dm->nullspaceConstructors[field] = nullsp; 1703 PetscFunctionReturn(0); 1704 } 1705 1706 /*@C 1707 DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()` 1708 1709 Not collective 1710 1711 Input Parameters: 1712 + dm - The `DM` 1713 - field - The field number for the nullspace 1714 1715 Output Parameter: 1716 . nullsp - A callback to create the nullspace 1717 1718 Calling sequence of nullsp: 1719 .vb 1720 PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace) 1721 .ve 1722 + dm - The present DM 1723 . origField - The field number given above, in the original DM 1724 . field - The field number in dm 1725 - nullSpace - The nullspace for the given field 1726 1727 Fortran Note: 1728 This function is not available from Fortran. 1729 1730 Level: intermediate 1731 1732 .seealso: `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 1733 @*/ 1734 PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *)) 1735 { 1736 PetscFunctionBegin; 1737 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1738 PetscValidPointer(nullsp, 3); 1739 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1740 *nullsp = dm->nullspaceConstructors[field]; 1741 PetscFunctionReturn(0); 1742 } 1743 1744 /*@C 1745 DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()` 1746 1747 Logically collective on dm 1748 1749 Input Parameters: 1750 + dm - The `DM` 1751 . field - The field number for the nullspace 1752 - nullsp - A callback to create the near-nullspace 1753 1754 Calling sequence of nullsp: 1755 .vb 1756 PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace) 1757 .ve 1758 + dm - The present `DM` 1759 . origField - The field number given above, in the original `DM` 1760 . field - The field number in dm 1761 - nullSpace - The nullspace for the given field 1762 1763 Fortran Note: 1764 This function is not available from Fortran. 1765 1766 Level: intermediate 1767 1768 .seealso: `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`, 1769 `MatNullSpace` 1770 @*/ 1771 PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM, PetscInt, PetscInt, MatNullSpace *)) 1772 { 1773 PetscFunctionBegin; 1774 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1775 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1776 dm->nearnullspaceConstructors[field] = nullsp; 1777 PetscFunctionReturn(0); 1778 } 1779 1780 /*@C 1781 DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()` 1782 1783 Not collective 1784 1785 Input Parameters: 1786 + dm - The `DM` 1787 - field - The field number for the nullspace 1788 1789 Output Parameter: 1790 . nullsp - A callback to create the near-nullspace 1791 1792 Calling sequence of nullsp: 1793 .vb 1794 PetscErrorCode nullsp(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace) 1795 .ve 1796 + dm - The present `DM` 1797 . origField - The field number given above, in the original `DM` 1798 . field - The field number in dm 1799 - nullSpace - The nullspace for the given field 1800 1801 Fortran Note: 1802 This function is not available from Fortran. 1803 1804 Level: intermediate 1805 1806 .seealso: `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, 1807 `MatNullSpace`, `DMCreateSuperDM()` 1808 @*/ 1809 PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM, PetscInt, PetscInt, MatNullSpace *)) 1810 { 1811 PetscFunctionBegin; 1812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1813 PetscValidPointer(nullsp, 3); 1814 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1815 *nullsp = dm->nearnullspaceConstructors[field]; 1816 PetscFunctionReturn(0); 1817 } 1818 1819 /*@C 1820 DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()` 1821 1822 Not collective 1823 1824 Input Parameter: 1825 . dm - the `DM` object 1826 1827 Output Parameters: 1828 + numFields - The number of fields (or NULL if not requested) 1829 . fieldNames - The number of each field (or NULL if not requested) 1830 - fields - The global indices for each field (or NULL if not requested) 1831 1832 Level: intermediate 1833 1834 Note: 1835 The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with 1836 `PetscFree()`, every entry of fields should be destroyed with `ISDestroy()`, and both arrays should be freed with 1837 `PetscFree()`. 1838 1839 Fortran Note: 1840 Not available in Fortran. 1841 1842 Developer Note: 1843 It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should 1844 likely be removed. 1845 1846 .seealso: `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, 1847 `DMCreateFieldDecomposition()` 1848 @*/ 1849 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields) 1850 { 1851 PetscSection section, sectionGlobal; 1852 1853 PetscFunctionBegin; 1854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1855 if (numFields) { 1856 PetscValidIntPointer(numFields, 2); 1857 *numFields = 0; 1858 } 1859 if (fieldNames) { 1860 PetscValidPointer(fieldNames, 3); 1861 *fieldNames = NULL; 1862 } 1863 if (fields) { 1864 PetscValidPointer(fields, 4); 1865 *fields = NULL; 1866 } 1867 PetscCall(DMGetLocalSection(dm, §ion)); 1868 if (section) { 1869 PetscInt *fieldSizes, *fieldNc, **fieldIndices; 1870 PetscInt nF, f, pStart, pEnd, p; 1871 1872 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 1873 PetscCall(PetscSectionGetNumFields(section, &nF)); 1874 PetscCall(PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices)); 1875 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 1876 for (f = 0; f < nF; ++f) { 1877 fieldSizes[f] = 0; 1878 PetscCall(PetscSectionGetFieldComponents(section, f, &fieldNc[f])); 1879 } 1880 for (p = pStart; p < pEnd; ++p) { 1881 PetscInt gdof; 1882 1883 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 1884 if (gdof > 0) { 1885 for (f = 0; f < nF; ++f) { 1886 PetscInt fdof, fcdof, fpdof; 1887 1888 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 1889 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 1890 fpdof = fdof - fcdof; 1891 if (fpdof && fpdof != fieldNc[f]) { 1892 /* Layout does not admit a pointwise block size */ 1893 fieldNc[f] = 1; 1894 } 1895 fieldSizes[f] += fpdof; 1896 } 1897 } 1898 } 1899 for (f = 0; f < nF; ++f) { 1900 PetscCall(PetscMalloc1(fieldSizes[f], &fieldIndices[f])); 1901 fieldSizes[f] = 0; 1902 } 1903 for (p = pStart; p < pEnd; ++p) { 1904 PetscInt gdof, goff; 1905 1906 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 1907 if (gdof > 0) { 1908 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff)); 1909 for (f = 0; f < nF; ++f) { 1910 PetscInt fdof, fcdof, fc; 1911 1912 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 1913 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 1914 for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++; 1915 } 1916 } 1917 } 1918 if (numFields) *numFields = nF; 1919 if (fieldNames) { 1920 PetscCall(PetscMalloc1(nF, fieldNames)); 1921 for (f = 0; f < nF; ++f) { 1922 const char *fieldName; 1923 1924 PetscCall(PetscSectionGetFieldName(section, f, &fieldName)); 1925 PetscCall(PetscStrallocpy(fieldName, (char **)&(*fieldNames)[f])); 1926 } 1927 } 1928 if (fields) { 1929 PetscCall(PetscMalloc1(nF, fields)); 1930 for (f = 0; f < nF; ++f) { 1931 PetscInt bs, in[2], out[2]; 1932 1933 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f])); 1934 in[0] = -fieldNc[f]; 1935 in[1] = fieldNc[f]; 1936 PetscCall(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 1937 bs = (-out[0] == out[1]) ? out[1] : 1; 1938 PetscCall(ISSetBlockSize((*fields)[f], bs)); 1939 } 1940 } 1941 PetscCall(PetscFree3(fieldSizes, fieldNc, fieldIndices)); 1942 } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields); 1943 PetscFunctionReturn(0); 1944 } 1945 1946 /*@C 1947 DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems 1948 corresponding to different fields: each `IS` contains the global indices of the dofs of the 1949 corresponding field, defined by `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem. 1950 The same as `DMCreateFieldIS()` but also returns a `DM` for each field. 1951 1952 Not collective 1953 1954 Input Parameter: 1955 . dm - the `DM` object 1956 1957 Output Parameters: 1958 + len - The number of fields (or NULL if not requested) 1959 . namelist - The name for each field (or NULL if not requested) 1960 . islist - The global indices for each field (or NULL if not requested) 1961 - dmlist - The `DM`s for each field subproblem (or NULL, if not requested; if NULL is returned, no `DM`s are defined) 1962 1963 Level: intermediate 1964 1965 Note: 1966 The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with 1967 `PetscFree()`, every entry of is should be destroyed with `ISDestroy()`, every entry of dm should be destroyed with `DMDestroy()`, 1968 and all of the arrays should be freed with `PetscFree()`. 1969 1970 Fortran Note: 1971 Not available in Fortran. 1972 1973 Developer Note: 1974 It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing. 1975 1976 .seealso: `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()` 1977 @*/ 1978 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist) 1979 { 1980 PetscFunctionBegin; 1981 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1982 if (len) { 1983 PetscValidIntPointer(len, 2); 1984 *len = 0; 1985 } 1986 if (namelist) { 1987 PetscValidPointer(namelist, 3); 1988 *namelist = NULL; 1989 } 1990 if (islist) { 1991 PetscValidPointer(islist, 4); 1992 *islist = NULL; 1993 } 1994 if (dmlist) { 1995 PetscValidPointer(dmlist, 5); 1996 *dmlist = NULL; 1997 } 1998 /* 1999 Is it a good idea to apply the following check across all impls? 2000 Perhaps some impls can have a well-defined decomposition before DMSetUp? 2001 This, however, follows the general principle that accessors are not well-behaved until the object is set up. 2002 */ 2003 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp"); 2004 if (!dm->ops->createfielddecomposition) { 2005 PetscSection section; 2006 PetscInt numFields, f; 2007 2008 PetscCall(DMGetLocalSection(dm, §ion)); 2009 if (section) PetscCall(PetscSectionGetNumFields(section, &numFields)); 2010 if (section && numFields && dm->ops->createsubdm) { 2011 if (len) *len = numFields; 2012 if (namelist) PetscCall(PetscMalloc1(numFields, namelist)); 2013 if (islist) PetscCall(PetscMalloc1(numFields, islist)); 2014 if (dmlist) PetscCall(PetscMalloc1(numFields, dmlist)); 2015 for (f = 0; f < numFields; ++f) { 2016 const char *fieldName; 2017 2018 PetscCall(DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL)); 2019 if (namelist) { 2020 PetscCall(PetscSectionGetFieldName(section, f, &fieldName)); 2021 PetscCall(PetscStrallocpy(fieldName, (char **)&(*namelist)[f])); 2022 } 2023 } 2024 } else { 2025 PetscCall(DMCreateFieldIS(dm, len, namelist, islist)); 2026 /* By default there are no DMs associated with subproblems. */ 2027 if (dmlist) *dmlist = NULL; 2028 } 2029 } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist); 2030 PetscFunctionReturn(0); 2031 } 2032 2033 /*@C 2034 DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in. 2035 The fields are defined by DMCreateFieldIS(). 2036 2037 Not collective 2038 2039 Input Parameters: 2040 + dm - The `DM `object 2041 . numFields - The number of fields to select 2042 - fields - The field numbers of the selected fields 2043 2044 Output Parameters: 2045 + is - The global indices for all the degrees of freedom in the new sub `DM` 2046 - subdm - The `DM` for the subproblem 2047 2048 Note: 2049 You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed 2050 2051 Level: intermediate 2052 2053 .seealso: `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `DM`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()` 2054 @*/ 2055 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 2056 { 2057 PetscFunctionBegin; 2058 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2059 PetscValidIntPointer(fields, 3); 2060 if (is) PetscValidPointer(is, 4); 2061 if (subdm) PetscValidPointer(subdm, 5); 2062 PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm); 2063 PetscFunctionReturn(0); 2064 } 2065 2066 /*@C 2067 DMCreateSuperDM - Returns an arrays of `IS` and `DM` encapsulating a superproblem defined by multiple `DM`s passed in. 2068 2069 Not collective 2070 2071 Input Parameters: 2072 + dms - The `DM` objects 2073 - n - The number of `DM`s 2074 2075 Output Parameters: 2076 + is - The global indices for each of subproblem within the super `DM`, or NULL 2077 - superdm - The `DM` for the superproblem 2078 2079 Note: 2080 You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed 2081 2082 Level: intermediate 2083 2084 .seealso: `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()` 2085 @*/ 2086 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS **is, DM *superdm) 2087 { 2088 PetscInt i; 2089 2090 PetscFunctionBegin; 2091 PetscValidPointer(dms, 1); 2092 for (i = 0; i < n; ++i) PetscValidHeaderSpecific(dms[i], DM_CLASSID, 1); 2093 if (is) PetscValidPointer(is, 3); 2094 PetscValidPointer(superdm, 4); 2095 PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %" PetscInt_FMT, n); 2096 if (n) { 2097 DM dm = dms[0]; 2098 PetscCall((*dm->ops->createsuperdm)(dms, n, is, superdm)); 2099 } 2100 PetscFunctionReturn(0); 2101 } 2102 2103 /*@C 2104 DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a problem into subproblems 2105 corresponding to restrictions to pairs of nested subdomains: each `IS` contains the global 2106 indices of the dofs of the corresponding subdomains with in the dofs of the original `DM`. 2107 The inner subdomains conceptually define a nonoverlapping covering, while outer subdomains can overlap. 2108 The optional list of `DM`s define a `DM` for each subproblem. 2109 2110 Not collective 2111 2112 Input Parameter: 2113 . dm - the `DM` object 2114 2115 Output Parameters: 2116 + n - The number of subproblems in the domain decomposition (or NULL if not requested) 2117 . namelist - The name for each subdomain (or NULL if not requested) 2118 . innerislist - The global indices for each inner subdomain (or NULL, if not requested) 2119 . outerislist - The global indices for each outer subdomain (or NULL, if not requested) 2120 - dmlist - The `DM`s for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no `DM`s are defined) 2121 2122 Level: intermediate 2123 2124 Note: 2125 The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with 2126 `PetscFree()`, every entry of is should be destroyed with `ISDestroy()`, every entry of dm should be destroyed with `DMDestroy()`, 2127 and all of the arrays should be freed with `PetscFree()`. 2128 2129 Questions: 2130 The dmlist is for the inner subdomains or the outer subdomains or all subdomains? 2131 2132 .seealso: `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldDecomposition()` 2133 @*/ 2134 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist) 2135 { 2136 DMSubDomainHookLink link; 2137 PetscInt i, l; 2138 2139 PetscFunctionBegin; 2140 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2141 if (n) { 2142 PetscValidIntPointer(n, 2); 2143 *n = 0; 2144 } 2145 if (namelist) { 2146 PetscValidPointer(namelist, 3); 2147 *namelist = NULL; 2148 } 2149 if (innerislist) { 2150 PetscValidPointer(innerislist, 4); 2151 *innerislist = NULL; 2152 } 2153 if (outerislist) { 2154 PetscValidPointer(outerislist, 5); 2155 *outerislist = NULL; 2156 } 2157 if (dmlist) { 2158 PetscValidPointer(dmlist, 6); 2159 *dmlist = NULL; 2160 } 2161 /* 2162 Is it a good idea to apply the following check across all impls? 2163 Perhaps some impls can have a well-defined decomposition before DMSetUp? 2164 This, however, follows the general principle that accessors are not well-behaved until the object is set up. 2165 */ 2166 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp"); 2167 if (dm->ops->createdomaindecomposition) { 2168 PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist); 2169 /* copy subdomain hooks and context over to the subdomain DMs */ 2170 if (dmlist && *dmlist) { 2171 for (i = 0; i < l; i++) { 2172 for (link = dm->subdomainhook; link; link = link->next) { 2173 if (link->ddhook) PetscCall((*link->ddhook)(dm, (*dmlist)[i], link->ctx)); 2174 } 2175 if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx; 2176 } 2177 } 2178 if (n) *n = l; 2179 } 2180 PetscFunctionReturn(0); 2181 } 2182 2183 /*@C 2184 DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector 2185 2186 Not collective 2187 2188 Input Parameters: 2189 + dm - the `DM` object 2190 . n - the number of subdomain scatters 2191 - subdms - the local subdomains 2192 2193 Output Parameters: 2194 + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain 2195 . oscat - scatter from global vector to overlapping global vector entries on subdomain 2196 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts) 2197 2198 Note: 2199 This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution 2200 of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets 2201 of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of 2202 solution and residual data. 2203 2204 Questions: 2205 Can the subdms input be anything or are they exactly the `DM` obtained from `DMCreateDomainDecomposition()`? 2206 2207 Level: developer 2208 2209 .seealso: `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()` 2210 @*/ 2211 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter **iscat, VecScatter **oscat, VecScatter **gscat) 2212 { 2213 PetscFunctionBegin; 2214 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2215 PetscValidPointer(subdms, 3); 2216 PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat); 2217 PetscFunctionReturn(0); 2218 } 2219 2220 /*@ 2221 DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh 2222 2223 Collective on dm 2224 2225 Input Parameters: 2226 + dm - the `DM` object 2227 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`) 2228 2229 Output Parameter: 2230 . dmf - the refined `D`M, or NULL 2231 2232 Options Database Keys: 2233 . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex 2234 2235 Note: 2236 If no refinement was done, the return value is NULL 2237 2238 Level: developer 2239 2240 .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 2241 @*/ 2242 PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf) 2243 { 2244 DMRefineHookLink link; 2245 2246 PetscFunctionBegin; 2247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2248 PetscCall(PetscLogEventBegin(DM_Refine, dm, 0, 0, 0)); 2249 PetscUseTypeMethod(dm, refine, comm, dmf); 2250 if (*dmf) { 2251 (*dmf)->ops->creatematrix = dm->ops->creatematrix; 2252 2253 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf)); 2254 2255 (*dmf)->ctx = dm->ctx; 2256 (*dmf)->leveldown = dm->leveldown; 2257 (*dmf)->levelup = dm->levelup + 1; 2258 2259 PetscCall(DMSetMatType(*dmf, dm->mattype)); 2260 for (link = dm->refinehook; link; link = link->next) { 2261 if (link->refinehook) PetscCall((*link->refinehook)(dm, *dmf, link->ctx)); 2262 } 2263 } 2264 PetscCall(PetscLogEventEnd(DM_Refine, dm, 0, 0, 0)); 2265 PetscFunctionReturn(0); 2266 } 2267 2268 /*@C 2269 DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid 2270 2271 Logically Collective on coarse 2272 2273 Input Parameters: 2274 + coarse - `DM` on which to run a hook when interpolating to a finer level 2275 . refinehook - function to run when setting up the finer level 2276 . interphook - function to run to update data on finer levels (once per `SNESSolve`()) 2277 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 2278 2279 Calling sequence of refinehook: 2280 $ refinehook(DM coarse,DM fine,void *ctx); 2281 2282 + coarse - coarse level `DM` 2283 . fine - fine level `DM` to interpolate problem to 2284 - ctx - optional user-defined function context 2285 2286 Calling sequence for interphook: 2287 $ interphook(DM coarse,Mat interp,DM fine,void *ctx) 2288 2289 + coarse - coarse level `DM` 2290 . interp - matrix interpolating a coarse-level solution to the finer grid 2291 . fine - fine level `DM` to update 2292 - ctx - optional user-defined function context 2293 2294 Level: advanced 2295 2296 Notes: 2297 This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be 2298 passed to fine grids while grid sequencing. 2299 2300 The actual interpolation is done when `DMInterpolate()` is called. 2301 2302 If this function is called multiple times, the hooks will be run in the order they are added. 2303 2304 Fortran Note: 2305 This function is not available from Fortran. 2306 2307 .seealso: `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2308 @*/ 2309 PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx) 2310 { 2311 DMRefineHookLink link, *p; 2312 2313 PetscFunctionBegin; 2314 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1); 2315 for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */ 2316 if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(0); 2317 } 2318 PetscCall(PetscNew(&link)); 2319 link->refinehook = refinehook; 2320 link->interphook = interphook; 2321 link->ctx = ctx; 2322 link->next = NULL; 2323 *p = link; 2324 PetscFunctionReturn(0); 2325 } 2326 2327 /*@C 2328 DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating 2329 a nonlinear problem to a finer grid 2330 2331 Logically Collective on coarse 2332 2333 Input Parameters: 2334 + coarse - the `DM` on which to run a hook when restricting to a coarser level 2335 . refinehook - function to run when setting up a finer level 2336 . interphook - function to run to update data on finer levels 2337 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 2338 2339 Level: advanced 2340 2341 Note: 2342 This function does nothing if the hook is not in the list. 2343 2344 Fortran Note: 2345 This function is not available from Fortran. 2346 2347 .seealso: `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2348 @*/ 2349 PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx) 2350 { 2351 DMRefineHookLink link, *p; 2352 2353 PetscFunctionBegin; 2354 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1); 2355 for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */ 2356 if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) { 2357 link = *p; 2358 *p = link->next; 2359 PetscCall(PetscFree(link)); 2360 break; 2361 } 2362 } 2363 PetscFunctionReturn(0); 2364 } 2365 2366 /*@ 2367 DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()` 2368 2369 Collective if any hooks are 2370 2371 Input Parameters: 2372 + coarse - coarser `DM` to use as a base 2373 . interp - interpolation matrix, apply using `MatInterpolate()` 2374 - fine - finer `DM` to update 2375 2376 Level: developer 2377 2378 Developer Note: 2379 This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an 2380 an API with consistent terminology. 2381 2382 .seealso: `DM`, `DMRefineHookAdd()`, `MatInterpolate()` 2383 @*/ 2384 PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine) 2385 { 2386 DMRefineHookLink link; 2387 2388 PetscFunctionBegin; 2389 for (link = fine->refinehook; link; link = link->next) { 2390 if (link->interphook) PetscCall((*link->interphook)(coarse, interp, fine, link->ctx)); 2391 } 2392 PetscFunctionReturn(0); 2393 } 2394 2395 /*@ 2396 DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh. 2397 2398 Collective on dm 2399 2400 Input Parameters: 2401 + coarse - coarse `DM` 2402 . fine - fine `DM` 2403 . interp - (optional) the matrix computed by `DMCreateInterpolation()`. Implementations may not need this, but if it 2404 is available it can avoid some recomputation. If it is provided, `MatInterpolate()` will be used if 2405 the coarse `DM` does not have a specialized implementation. 2406 - coarseSol - solution on the coarse mesh 2407 2408 Output Parameter: 2409 . fineSol - the interpolation of coarseSol to the fine mesh 2410 2411 Level: developer 2412 2413 Note: 2414 This function exists because the interpolation of a solution vector between meshes is not always a linear 2415 map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed 2416 out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using 2417 slope-limiting reconstruction. 2418 2419 Developer Note: 2420 This doesn't just interpolate "solutions" so its API name is questionable. 2421 2422 .seealso: `DMInterpolate()`, `DMCreateInterpolation()` 2423 @*/ 2424 PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 2425 { 2426 PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL; 2427 2428 PetscFunctionBegin; 2429 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1); 2430 if (interp) PetscValidHeaderSpecific(interp, MAT_CLASSID, 3); 2431 PetscValidHeaderSpecific(coarseSol, VEC_CLASSID, 4); 2432 PetscValidHeaderSpecific(fineSol, VEC_CLASSID, 5); 2433 2434 PetscCall(PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol)); 2435 if (interpsol) { 2436 PetscCall((*interpsol)(coarse, fine, interp, coarseSol, fineSol)); 2437 } else if (interp) { 2438 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 2439 } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name); 2440 PetscFunctionReturn(0); 2441 } 2442 2443 /*@ 2444 DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`. 2445 2446 Not Collective 2447 2448 Input Parameter: 2449 . dm - the `DM` object 2450 2451 Output Parameter: 2452 . level - number of refinements 2453 2454 Level: developer 2455 2456 Note: 2457 This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver. 2458 2459 .seealso: `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 2460 2461 @*/ 2462 PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level) 2463 { 2464 PetscFunctionBegin; 2465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2466 *level = dm->levelup; 2467 PetscFunctionReturn(0); 2468 } 2469 2470 /*@ 2471 DMSetRefineLevel - Sets the number of refinements that have generated this `DM`. 2472 2473 Not Collective 2474 2475 Input Parameters: 2476 + dm - the `DM` object 2477 - level - number of refinements 2478 2479 Level: advanced 2480 2481 Notes: 2482 This value is used by `PCMG` to determine how many multigrid levels to use 2483 2484 The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine. 2485 2486 .seealso: `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 2487 2488 @*/ 2489 PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level) 2490 { 2491 PetscFunctionBegin; 2492 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2493 dm->levelup = level; 2494 PetscFunctionReturn(0); 2495 } 2496 2497 /*@ 2498 DMExtrude - Extrude a `DM` object from a surface 2499 2500 Collective on dm 2501 2502 Input Parameters: 2503 + dm - the `DM` object 2504 - layers - the number of extruded cell layers 2505 2506 Output Parameter: 2507 . dme - the extruded `DM`, or NULL 2508 2509 Note: 2510 If no extrusion was done, the return value is NULL 2511 2512 Level: developer 2513 2514 .seealso: `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()` 2515 @*/ 2516 PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme) 2517 { 2518 PetscFunctionBegin; 2519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2520 PetscUseTypeMethod(dm, extrude, layers, dme); 2521 if (*dme) { 2522 (*dme)->ops->creatematrix = dm->ops->creatematrix; 2523 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme)); 2524 (*dme)->ctx = dm->ctx; 2525 PetscCall(DMSetMatType(*dme, dm->mattype)); 2526 } 2527 PetscFunctionReturn(0); 2528 } 2529 2530 PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm) 2531 { 2532 PetscFunctionBegin; 2533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2534 PetscValidPointer(tdm, 2); 2535 *tdm = dm->transformDM; 2536 PetscFunctionReturn(0); 2537 } 2538 2539 PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv) 2540 { 2541 PetscFunctionBegin; 2542 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2543 PetscValidPointer(tv, 2); 2544 *tv = dm->transform; 2545 PetscFunctionReturn(0); 2546 } 2547 2548 /*@ 2549 DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors 2550 2551 Input Parameter: 2552 . dm - The DM 2553 2554 Output Parameter: 2555 . flg - PETSC_TRUE if a basis transformation should be done 2556 2557 Level: developer 2558 2559 .seealso: `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()` 2560 @*/ 2561 PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg) 2562 { 2563 Vec tv; 2564 2565 PetscFunctionBegin; 2566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2567 PetscValidBoolPointer(flg, 2); 2568 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 2569 *flg = tv ? PETSC_TRUE : PETSC_FALSE; 2570 PetscFunctionReturn(0); 2571 } 2572 2573 PetscErrorCode DMConstructBasisTransform_Internal(DM dm) 2574 { 2575 PetscSection s, ts; 2576 PetscScalar *ta; 2577 PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof; 2578 2579 PetscFunctionBegin; 2580 PetscCall(DMGetCoordinateDim(dm, &cdim)); 2581 PetscCall(DMGetLocalSection(dm, &s)); 2582 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2583 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2584 PetscCall(DMClone(dm, &dm->transformDM)); 2585 PetscCall(DMGetLocalSection(dm->transformDM, &ts)); 2586 PetscCall(PetscSectionSetNumFields(ts, Nf)); 2587 PetscCall(PetscSectionSetChart(ts, pStart, pEnd)); 2588 for (f = 0; f < Nf; ++f) { 2589 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 2590 /* We could start to label fields by their transformation properties */ 2591 if (Nc != cdim) continue; 2592 for (p = pStart; p < pEnd; ++p) { 2593 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 2594 if (!dof) continue; 2595 PetscCall(PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim))); 2596 PetscCall(PetscSectionAddDof(ts, p, PetscSqr(cdim))); 2597 } 2598 } 2599 PetscCall(PetscSectionSetUp(ts)); 2600 PetscCall(DMCreateLocalVector(dm->transformDM, &dm->transform)); 2601 PetscCall(VecGetArray(dm->transform, &ta)); 2602 for (p = pStart; p < pEnd; ++p) { 2603 for (f = 0; f < Nf; ++f) { 2604 PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 2605 if (dof) { 2606 PetscReal x[3] = {0.0, 0.0, 0.0}; 2607 PetscScalar *tva; 2608 const PetscScalar *A; 2609 2610 /* TODO Get quadrature point for this dual basis vector for coordinate */ 2611 PetscCall((*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx)); 2612 PetscCall(DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva)); 2613 PetscCall(PetscArraycpy(tva, A, PetscSqr(cdim))); 2614 } 2615 } 2616 } 2617 PetscCall(VecRestoreArray(dm->transform, &ta)); 2618 PetscFunctionReturn(0); 2619 } 2620 2621 PetscErrorCode DMCopyTransform(DM dm, DM newdm) 2622 { 2623 PetscFunctionBegin; 2624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2625 PetscValidHeaderSpecific(newdm, DM_CLASSID, 2); 2626 newdm->transformCtx = dm->transformCtx; 2627 newdm->transformSetUp = dm->transformSetUp; 2628 newdm->transformDestroy = NULL; 2629 newdm->transformGetMatrix = dm->transformGetMatrix; 2630 if (newdm->transformSetUp) PetscCall(DMConstructBasisTransform_Internal(newdm)); 2631 PetscFunctionReturn(0); 2632 } 2633 2634 /*@C 2635 DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called 2636 2637 Logically Collective on dm 2638 2639 Input Parameters: 2640 + dm - the `DM` 2641 . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()` 2642 . endhook - function to run after `DMGlobalToLocalEnd()` has completed 2643 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 2644 2645 Calling sequence for beginhook: 2646 $ beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx) 2647 2648 + dm - global DM 2649 . g - global vector 2650 . mode - mode 2651 . l - local vector 2652 - ctx - optional user-defined function context 2653 2654 Calling sequence for endhook: 2655 $ endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx) 2656 2657 + global - global DM 2658 - ctx - optional user-defined function context 2659 2660 Level: advanced 2661 2662 Note: 2663 The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector. 2664 2665 .seealso: `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2666 @*/ 2667 PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx) 2668 { 2669 DMGlobalToLocalHookLink link, *p; 2670 2671 PetscFunctionBegin; 2672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2673 for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */ 2674 PetscCall(PetscNew(&link)); 2675 link->beginhook = beginhook; 2676 link->endhook = endhook; 2677 link->ctx = ctx; 2678 link->next = NULL; 2679 *p = link; 2680 PetscFunctionReturn(0); 2681 } 2682 2683 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx) 2684 { 2685 Mat cMat; 2686 Vec cVec, cBias; 2687 PetscSection section, cSec; 2688 PetscInt pStart, pEnd, p, dof; 2689 2690 PetscFunctionBegin; 2691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2692 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias)); 2693 if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) { 2694 PetscInt nRows; 2695 2696 PetscCall(MatGetSize(cMat, &nRows, NULL)); 2697 if (nRows <= 0) PetscFunctionReturn(0); 2698 PetscCall(DMGetLocalSection(dm, §ion)); 2699 PetscCall(MatCreateVecs(cMat, NULL, &cVec)); 2700 PetscCall(MatMult(cMat, l, cVec)); 2701 if (cBias) PetscCall(VecAXPY(cVec, 1., cBias)); 2702 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 2703 for (p = pStart; p < pEnd; p++) { 2704 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 2705 if (dof) { 2706 PetscScalar *vals; 2707 PetscCall(VecGetValuesSection(cVec, cSec, p, &vals)); 2708 PetscCall(VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES)); 2709 } 2710 } 2711 PetscCall(VecDestroy(&cVec)); 2712 } 2713 PetscFunctionReturn(0); 2714 } 2715 2716 /*@ 2717 DMGlobalToLocal - update local vectors from global vector 2718 2719 Neighbor-wise Collective on dm 2720 2721 Input Parameters: 2722 + dm - the `DM` object 2723 . g - the global vector 2724 . mode - `INSERT_VALUES` or `ADD_VALUES` 2725 - l - the local vector 2726 2727 Notes: 2728 The communication involved in this update can be overlapped with computation by instead using 2729 `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`. 2730 2731 `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process. 2732 2733 Level: beginner 2734 2735 .seealso: `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, 2736 `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, 2737 `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()` 2738 2739 @*/ 2740 PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l) 2741 { 2742 PetscFunctionBegin; 2743 PetscCall(DMGlobalToLocalBegin(dm, g, mode, l)); 2744 PetscCall(DMGlobalToLocalEnd(dm, g, mode, l)); 2745 PetscFunctionReturn(0); 2746 } 2747 2748 /*@ 2749 DMGlobalToLocalBegin - Begins updating local vectors from global vector 2750 2751 Neighbor-wise Collective on dm 2752 2753 Input Parameters: 2754 + dm - the `DM` object 2755 . g - the global vector 2756 . mode - `INSERT_VALUES` or `ADD_VALUES` 2757 - l - the local vector 2758 2759 Level: intermediate 2760 2761 Notes: 2762 The operation is completed with `DMGlobalToLocalEnd()` 2763 2764 One can perform local computations between the `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()` to overlap communication and computation 2765 2766 `DMGlobalToLocal()` is a short form of `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()` 2767 2768 `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process. 2769 2770 .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()` 2771 2772 @*/ 2773 PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l) 2774 { 2775 PetscSF sf; 2776 DMGlobalToLocalHookLink link; 2777 2778 PetscFunctionBegin; 2779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2780 for (link = dm->gtolhook; link; link = link->next) { 2781 if (link->beginhook) PetscCall((*link->beginhook)(dm, g, mode, l, link->ctx)); 2782 } 2783 PetscCall(DMGetSectionSF(dm, &sf)); 2784 if (sf) { 2785 const PetscScalar *gArray; 2786 PetscScalar *lArray; 2787 PetscMemType lmtype, gmtype; 2788 2789 PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode); 2790 PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype)); 2791 PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype)); 2792 PetscCall(PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE)); 2793 PetscCall(VecRestoreArrayAndMemType(l, &lArray)); 2794 PetscCall(VecRestoreArrayReadAndMemType(g, &gArray)); 2795 } else { 2796 PetscCall((*dm->ops->globaltolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l)); 2797 } 2798 PetscFunctionReturn(0); 2799 } 2800 2801 /*@ 2802 DMGlobalToLocalEnd - Ends updating local vectors from global vector 2803 2804 Neighbor-wise Collective on dm 2805 2806 Input Parameters: 2807 + dm - the `DM` object 2808 . g - the global vector 2809 . mode - `INSERT_VALUES` or `ADD_VALUES` 2810 - l - the local vector 2811 2812 Level: intermediate 2813 2814 Note: 2815 See `DMGlobalToLocalBegin()` for details. 2816 2817 .seealso: `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()` 2818 2819 @*/ 2820 PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l) 2821 { 2822 PetscSF sf; 2823 const PetscScalar *gArray; 2824 PetscScalar *lArray; 2825 PetscBool transform; 2826 DMGlobalToLocalHookLink link; 2827 PetscMemType lmtype, gmtype; 2828 2829 PetscFunctionBegin; 2830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2831 PetscCall(DMGetSectionSF(dm, &sf)); 2832 PetscCall(DMHasBasisTransform(dm, &transform)); 2833 if (sf) { 2834 PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode); 2835 2836 PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype)); 2837 PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype)); 2838 PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE)); 2839 PetscCall(VecRestoreArrayAndMemType(l, &lArray)); 2840 PetscCall(VecRestoreArrayReadAndMemType(g, &gArray)); 2841 if (transform) PetscCall(DMPlexGlobalToLocalBasis(dm, l)); 2842 } else { 2843 PetscCall((*dm->ops->globaltolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l)); 2844 } 2845 PetscCall(DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL)); 2846 for (link = dm->gtolhook; link; link = link->next) { 2847 if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx)); 2848 } 2849 PetscFunctionReturn(0); 2850 } 2851 2852 /*@C 2853 DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called 2854 2855 Logically Collective on dm 2856 2857 Input Parameters: 2858 + dm - the `DM` 2859 . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()` 2860 . endhook - function to run after `DMLocalToGlobalEnd()` has completed 2861 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 2862 2863 Calling sequence for beginhook: 2864 $ beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx) 2865 2866 + dm - global `DM` 2867 . l - local vector 2868 . mode - mode 2869 . g - global vector 2870 - ctx - optional user-defined function context 2871 2872 Calling sequence for endhook: 2873 $ endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx) 2874 2875 + global - global `DM` 2876 . l - local vector 2877 . mode - mode 2878 . g - global vector 2879 - ctx - optional user-defined function context 2880 2881 Level: advanced 2882 2883 .seealso: `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2884 @*/ 2885 PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM, Vec, InsertMode, Vec, void *), PetscErrorCode (*endhook)(DM, Vec, InsertMode, Vec, void *), void *ctx) 2886 { 2887 DMLocalToGlobalHookLink link, *p; 2888 2889 PetscFunctionBegin; 2890 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2891 for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */ 2892 PetscCall(PetscNew(&link)); 2893 link->beginhook = beginhook; 2894 link->endhook = endhook; 2895 link->ctx = ctx; 2896 link->next = NULL; 2897 *p = link; 2898 PetscFunctionReturn(0); 2899 } 2900 2901 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx) 2902 { 2903 Mat cMat; 2904 Vec cVec; 2905 PetscSection section, cSec; 2906 PetscInt pStart, pEnd, p, dof; 2907 2908 PetscFunctionBegin; 2909 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2910 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 2911 if (cMat && (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES)) { 2912 PetscInt nRows; 2913 2914 PetscCall(MatGetSize(cMat, &nRows, NULL)); 2915 if (nRows <= 0) PetscFunctionReturn(0); 2916 PetscCall(DMGetLocalSection(dm, §ion)); 2917 PetscCall(MatCreateVecs(cMat, NULL, &cVec)); 2918 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 2919 for (p = pStart; p < pEnd; p++) { 2920 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 2921 if (dof) { 2922 PetscInt d; 2923 PetscScalar *vals; 2924 PetscCall(VecGetValuesSection(l, section, p, &vals)); 2925 PetscCall(VecSetValuesSection(cVec, cSec, p, vals, mode)); 2926 /* for this to be the true transpose, we have to zero the values that 2927 * we just extracted */ 2928 for (d = 0; d < dof; d++) vals[d] = 0.; 2929 } 2930 } 2931 PetscCall(MatMultTransposeAdd(cMat, cVec, l, l)); 2932 PetscCall(VecDestroy(&cVec)); 2933 } 2934 PetscFunctionReturn(0); 2935 } 2936 /*@ 2937 DMLocalToGlobal - updates global vectors from local vectors 2938 2939 Neighbor-wise Collective on dm 2940 2941 Input Parameters: 2942 + dm - the `DM` object 2943 . l - the local vector 2944 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point. 2945 - g - the global vector 2946 2947 Notes: 2948 The communication involved in this update can be overlapped with computation by using 2949 `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`. 2950 2951 In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation. 2952 2953 `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one. 2954 2955 Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process 2956 2957 Level: beginner 2958 2959 .seealso: `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()` 2960 2961 @*/ 2962 PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g) 2963 { 2964 PetscFunctionBegin; 2965 PetscCall(DMLocalToGlobalBegin(dm, l, mode, g)); 2966 PetscCall(DMLocalToGlobalEnd(dm, l, mode, g)); 2967 PetscFunctionReturn(0); 2968 } 2969 2970 /*@ 2971 DMLocalToGlobalBegin - begins updating global vectors from local vectors 2972 2973 Neighbor-wise Collective on dm 2974 2975 Input Parameters: 2976 + dm - the `DM` object 2977 . l - the local vector 2978 . mode - `if INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point. 2979 - g - the global vector 2980 2981 Notes: 2982 In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation. 2983 2984 `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one. 2985 2986 Use `DMLocalToGlobalEnd()` to complete the communication process. 2987 2988 `DMLocalToGlobal()` is a short form of `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()` 2989 2990 `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process. 2991 2992 Level: intermediate 2993 2994 .seealso: `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()` 2995 2996 @*/ 2997 PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g) 2998 { 2999 PetscSF sf; 3000 PetscSection s, gs; 3001 DMLocalToGlobalHookLink link; 3002 Vec tmpl; 3003 const PetscScalar *lArray; 3004 PetscScalar *gArray; 3005 PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE; 3006 PetscMemType lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST; 3007 3008 PetscFunctionBegin; 3009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3010 for (link = dm->ltoghook; link; link = link->next) { 3011 if (link->beginhook) PetscCall((*link->beginhook)(dm, l, mode, g, link->ctx)); 3012 } 3013 PetscCall(DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL)); 3014 PetscCall(DMGetSectionSF(dm, &sf)); 3015 PetscCall(DMGetLocalSection(dm, &s)); 3016 switch (mode) { 3017 case INSERT_VALUES: 3018 case INSERT_ALL_VALUES: 3019 case INSERT_BC_VALUES: 3020 isInsert = PETSC_TRUE; 3021 break; 3022 case ADD_VALUES: 3023 case ADD_ALL_VALUES: 3024 case ADD_BC_VALUES: 3025 isInsert = PETSC_FALSE; 3026 break; 3027 default: 3028 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode); 3029 } 3030 if ((sf && !isInsert) || (s && isInsert)) { 3031 PetscCall(DMHasBasisTransform(dm, &transform)); 3032 if (transform) { 3033 PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3034 PetscCall(VecCopy(l, tmpl)); 3035 PetscCall(DMPlexLocalToGlobalBasis(dm, tmpl)); 3036 PetscCall(VecGetArrayRead(tmpl, &lArray)); 3037 } else if (isInsert) { 3038 PetscCall(VecGetArrayRead(l, &lArray)); 3039 } else { 3040 PetscCall(VecGetArrayReadAndMemType(l, &lArray, &lmtype)); 3041 l_inplace = PETSC_TRUE; 3042 } 3043 if (s && isInsert) { 3044 PetscCall(VecGetArray(g, &gArray)); 3045 } else { 3046 PetscCall(VecGetArrayAndMemType(g, &gArray, &gmtype)); 3047 g_inplace = PETSC_TRUE; 3048 } 3049 if (sf && !isInsert) { 3050 PetscCall(PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM)); 3051 } else if (s && isInsert) { 3052 PetscInt gStart, pStart, pEnd, p; 3053 3054 PetscCall(DMGetGlobalSection(dm, &gs)); 3055 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 3056 PetscCall(VecGetOwnershipRange(g, &gStart, NULL)); 3057 for (p = pStart; p < pEnd; ++p) { 3058 PetscInt dof, gdof, cdof, gcdof, off, goff, d, e; 3059 3060 PetscCall(PetscSectionGetDof(s, p, &dof)); 3061 PetscCall(PetscSectionGetDof(gs, p, &gdof)); 3062 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 3063 PetscCall(PetscSectionGetConstraintDof(gs, p, &gcdof)); 3064 PetscCall(PetscSectionGetOffset(s, p, &off)); 3065 PetscCall(PetscSectionGetOffset(gs, p, &goff)); 3066 /* Ignore off-process data and points with no global data */ 3067 if (!gdof || goff < 0) continue; 3068 PetscCheck(dof == gdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof); 3069 /* If no constraints are enforced in the global vector */ 3070 if (!gcdof) { 3071 for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d]; 3072 /* If constraints are enforced in the global vector */ 3073 } else if (cdof == gcdof) { 3074 const PetscInt *cdofs; 3075 PetscInt cind = 0; 3076 3077 PetscCall(PetscSectionGetConstraintIndices(s, p, &cdofs)); 3078 for (d = 0, e = 0; d < dof; ++d) { 3079 if ((cind < cdof) && (d == cdofs[cind])) { 3080 ++cind; 3081 continue; 3082 } 3083 gArray[goff - gStart + e++] = lArray[off + d]; 3084 } 3085 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof); 3086 } 3087 } 3088 if (g_inplace) { 3089 PetscCall(VecRestoreArrayAndMemType(g, &gArray)); 3090 } else { 3091 PetscCall(VecRestoreArray(g, &gArray)); 3092 } 3093 if (transform) { 3094 PetscCall(VecRestoreArrayRead(tmpl, &lArray)); 3095 PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3096 } else if (l_inplace) { 3097 PetscCall(VecRestoreArrayReadAndMemType(l, &lArray)); 3098 } else { 3099 PetscCall(VecRestoreArrayRead(l, &lArray)); 3100 } 3101 } else { 3102 PetscCall((*dm->ops->localtoglobalbegin)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g)); 3103 } 3104 PetscFunctionReturn(0); 3105 } 3106 3107 /*@ 3108 DMLocalToGlobalEnd - updates global vectors from local vectors 3109 3110 Neighbor-wise Collective on dm 3111 3112 Input Parameters: 3113 + dm - the `DM` object 3114 . l - the local vector 3115 . mode - `INSERT_VALUES` or `ADD_VALUES` 3116 - g - the global vector 3117 3118 Level: intermediate 3119 3120 Note: 3121 See `DMLocalToGlobalBegin()` for full details 3122 3123 .seealso: `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalEnd()` 3124 3125 @*/ 3126 PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g) 3127 { 3128 PetscSF sf; 3129 PetscSection s; 3130 DMLocalToGlobalHookLink link; 3131 PetscBool isInsert, transform; 3132 3133 PetscFunctionBegin; 3134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3135 PetscCall(DMGetSectionSF(dm, &sf)); 3136 PetscCall(DMGetLocalSection(dm, &s)); 3137 switch (mode) { 3138 case INSERT_VALUES: 3139 case INSERT_ALL_VALUES: 3140 isInsert = PETSC_TRUE; 3141 break; 3142 case ADD_VALUES: 3143 case ADD_ALL_VALUES: 3144 isInsert = PETSC_FALSE; 3145 break; 3146 default: 3147 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode); 3148 } 3149 if (sf && !isInsert) { 3150 const PetscScalar *lArray; 3151 PetscScalar *gArray; 3152 Vec tmpl; 3153 3154 PetscCall(DMHasBasisTransform(dm, &transform)); 3155 if (transform) { 3156 PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3157 PetscCall(VecGetArrayRead(tmpl, &lArray)); 3158 } else { 3159 PetscCall(VecGetArrayReadAndMemType(l, &lArray, NULL)); 3160 } 3161 PetscCall(VecGetArrayAndMemType(g, &gArray, NULL)); 3162 PetscCall(PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM)); 3163 if (transform) { 3164 PetscCall(VecRestoreArrayRead(tmpl, &lArray)); 3165 PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3166 } else { 3167 PetscCall(VecRestoreArrayReadAndMemType(l, &lArray)); 3168 } 3169 PetscCall(VecRestoreArrayAndMemType(g, &gArray)); 3170 } else if (s && isInsert) { 3171 } else { 3172 PetscCall((*dm->ops->localtoglobalend)(dm, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g)); 3173 } 3174 for (link = dm->ltoghook; link; link = link->next) { 3175 if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx)); 3176 } 3177 PetscFunctionReturn(0); 3178 } 3179 3180 /*@ 3181 DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include ghost points 3182 that contain irrelevant values) to another local vector where the ghost 3183 points in the second are set correctly from values on other MPI ranks. Must be followed by `DMLocalToLocalEnd()`. 3184 3185 Neighbor-wise Collective on dm 3186 3187 Input Parameters: 3188 + dm - the `DM` object 3189 . g - the original local vector 3190 - mode - one of `INSERT_VALUES` or `ADD_VALUES` 3191 3192 Output Parameter: 3193 . l - the local vector with correct ghost values 3194 3195 Level: intermediate 3196 3197 .seealso: `DMLocalToLocalEnd(), `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalEnd()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()` 3198 3199 @*/ 3200 PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l) 3201 { 3202 PetscFunctionBegin; 3203 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3204 PetscCall((*dm->ops->localtolocalbegin)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l)); 3205 PetscFunctionReturn(0); 3206 } 3207 3208 /*@ 3209 DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost 3210 points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`. 3211 3212 Neighbor-wise Collective on dm 3213 3214 Input Parameters: 3215 + da - the `DM` object 3216 . g - the original local vector 3217 - mode - one of `INSERT_VALUES` or `ADD_VALUES` 3218 3219 Output Parameter: 3220 . l - the local vector with correct ghost values 3221 3222 Level: intermediate 3223 3224 .seealso: `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMLocalToLocalBegin()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()` 3225 3226 @*/ 3227 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l) 3228 { 3229 PetscFunctionBegin; 3230 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3231 PetscCall((*dm->ops->localtolocalend)(dm, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l)); 3232 PetscFunctionReturn(0); 3233 } 3234 3235 /*@ 3236 DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh 3237 3238 Collective on dm 3239 3240 Input Parameters: 3241 + dm - the `DM` object 3242 - comm - the communicator to contain the new `DM` object (or MPI_COMM_NULL) 3243 3244 Output Parameter: 3245 . dmc - the coarsened `DM` 3246 3247 Level: developer 3248 3249 .seealso: `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3250 3251 @*/ 3252 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc) 3253 { 3254 DMCoarsenHookLink link; 3255 3256 PetscFunctionBegin; 3257 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3258 PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0)); 3259 PetscUseTypeMethod(dm, coarsen, comm, dmc); 3260 if (*dmc) { 3261 (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */ 3262 PetscCall(DMSetCoarseDM(dm, *dmc)); 3263 (*dmc)->ops->creatematrix = dm->ops->creatematrix; 3264 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc)); 3265 (*dmc)->ctx = dm->ctx; 3266 (*dmc)->levelup = dm->levelup; 3267 (*dmc)->leveldown = dm->leveldown + 1; 3268 PetscCall(DMSetMatType(*dmc, dm->mattype)); 3269 for (link = dm->coarsenhook; link; link = link->next) { 3270 if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx)); 3271 } 3272 } 3273 PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0)); 3274 PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced"); 3275 PetscFunctionReturn(0); 3276 } 3277 3278 /*@C 3279 DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid 3280 3281 Logically Collective on fine 3282 3283 Input Parameters: 3284 + fine - `DM` on which to run a hook when restricting to a coarser level 3285 . coarsenhook - function to run when setting up a coarser level 3286 . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`) 3287 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 3288 3289 Calling sequence of coarsenhook: 3290 $ coarsenhook(DM fine,DM coarse,void *ctx); 3291 3292 + fine - fine level `DM` 3293 . coarse - coarse level `DM` to restrict problem to 3294 - ctx - optional user-defined function context 3295 3296 Calling sequence for restricthook: 3297 $ restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx) 3298 $ 3299 + fine - fine level `DM` 3300 . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation 3301 . rscale - scaling vector for restriction 3302 . inject - matrix restricting by injection 3303 . coarse - coarse level DM to update 3304 - ctx - optional user-defined function context 3305 3306 Level: advanced 3307 3308 Notes: 3309 This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`. 3310 3311 If this function is called multiple times, the hooks will be run in the order they are added. 3312 3313 In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to 3314 extract the finest level information from its context (instead of from the `SNES`). 3315 3316 The hooks are automatically called by `DMRestrict()` 3317 3318 Fortran Note: 3319 This function is not available from Fortran. 3320 3321 .seealso: `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 3322 @*/ 3323 PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx) 3324 { 3325 DMCoarsenHookLink link, *p; 3326 3327 PetscFunctionBegin; 3328 PetscValidHeaderSpecific(fine, DM_CLASSID, 1); 3329 for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */ 3330 if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(0); 3331 } 3332 PetscCall(PetscNew(&link)); 3333 link->coarsenhook = coarsenhook; 3334 link->restricthook = restricthook; 3335 link->ctx = ctx; 3336 link->next = NULL; 3337 *p = link; 3338 PetscFunctionReturn(0); 3339 } 3340 3341 /*@C 3342 DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()` 3343 3344 Logically Collective on fine 3345 3346 Input Parameters: 3347 + fine - `DM` on which to run a hook when restricting to a coarser level 3348 . coarsenhook - function to run when setting up a coarser level 3349 . restricthook - function to run to update data on coarser levels 3350 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 3351 3352 Level: advanced 3353 3354 Note: 3355 This function does nothing if the hook is not in the list. 3356 3357 Fortran Note: 3358 This function is not available from Fortran. 3359 3360 .seealso: `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 3361 @*/ 3362 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx) 3363 { 3364 DMCoarsenHookLink link, *p; 3365 3366 PetscFunctionBegin; 3367 PetscValidHeaderSpecific(fine, DM_CLASSID, 1); 3368 for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */ 3369 if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) { 3370 link = *p; 3371 *p = link->next; 3372 PetscCall(PetscFree(link)); 3373 break; 3374 } 3375 } 3376 PetscFunctionReturn(0); 3377 } 3378 3379 /*@ 3380 DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()` 3381 3382 Collective if any hooks are 3383 3384 Input Parameters: 3385 + fine - finer `DM` from which the data is obtained 3386 . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation 3387 . rscale - scaling vector for restriction 3388 . inject - injection matrix, also use `MatRestrict()` 3389 - coarse - coarser DM to update 3390 3391 Level: developer 3392 3393 Developer Note: 3394 Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better 3395 3396 .seealso: `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()` 3397 @*/ 3398 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse) 3399 { 3400 DMCoarsenHookLink link; 3401 3402 PetscFunctionBegin; 3403 for (link = fine->coarsenhook; link; link = link->next) { 3404 if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx)); 3405 } 3406 PetscFunctionReturn(0); 3407 } 3408 3409 /*@C 3410 DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid 3411 3412 Logically Collective on global 3413 3414 Input Parameters: 3415 + global - global `DM` 3416 . ddhook - function to run to pass data to the decomposition `DM` upon its creation 3417 . restricthook - function to run to update data on block solve (at the beginning of the block solve) 3418 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 3419 3420 Calling sequence for ddhook: 3421 $ ddhook(DM global,DM block,void *ctx) 3422 3423 + global - global `DM` 3424 . block - block `DM` 3425 - ctx - optional user-defined function context 3426 3427 Calling sequence for restricthook: 3428 $ restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx) 3429 3430 + global - global `DM` 3431 . out - scatter to the outer (with ghost and overlap points) block vector 3432 . in - scatter to block vector values only owned locally 3433 . block - block `DM` 3434 - ctx - optional user-defined function context 3435 3436 Level: advanced 3437 3438 Notes: 3439 This function is only needed if auxiliary data needs to be set up on subdomain `DM`s. 3440 3441 If this function is called multiple times, the hooks will be run in the order they are added. 3442 3443 In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to 3444 extract the global information from its context (instead of from the `SNES`). 3445 3446 Fortran Note: 3447 This function is not available from Fortran. 3448 3449 .seealso: `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 3450 @*/ 3451 PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx) 3452 { 3453 DMSubDomainHookLink link, *p; 3454 3455 PetscFunctionBegin; 3456 PetscValidHeaderSpecific(global, DM_CLASSID, 1); 3457 for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */ 3458 if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(0); 3459 } 3460 PetscCall(PetscNew(&link)); 3461 link->restricthook = restricthook; 3462 link->ddhook = ddhook; 3463 link->ctx = ctx; 3464 link->next = NULL; 3465 *p = link; 3466 PetscFunctionReturn(0); 3467 } 3468 3469 /*@C 3470 DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to the coarse grid 3471 3472 Logically Collective on global 3473 3474 Input Parameters: 3475 + global - global `DM` 3476 . ddhook - function to run to pass data to the decomposition `DM` upon its creation 3477 . restricthook - function to run to update data on block solve (at the beginning of the block solve) 3478 - ctx - [optional] user-defined context for provide data for the hooks (may be NULL) 3479 3480 Level: advanced 3481 3482 Fortran Note: 3483 This function is not available from Fortran. 3484 3485 .seealso: `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 3486 @*/ 3487 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx) 3488 { 3489 DMSubDomainHookLink link, *p; 3490 3491 PetscFunctionBegin; 3492 PetscValidHeaderSpecific(global, DM_CLASSID, 1); 3493 for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */ 3494 if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) { 3495 link = *p; 3496 *p = link->next; 3497 PetscCall(PetscFree(link)); 3498 break; 3499 } 3500 } 3501 PetscFunctionReturn(0); 3502 } 3503 3504 /*@ 3505 DMSubDomainRestrict - restricts user-defined problem data to a block `DM` by running hooks registered by `DMSubDomainHookAdd()` 3506 3507 Collective if any hooks are 3508 3509 Input Parameters: 3510 + fine - finer `DM` to use as a base 3511 . oscatter - scatter from domain global vector filling subdomain global vector with overlap 3512 . gscatter - scatter from domain global vector filling subdomain local vector with ghosts 3513 - coarse - coarser `DM` to update 3514 3515 Level: developer 3516 3517 .seealso: `DMCoarsenHookAdd()`, `MatRestrict()` 3518 @*/ 3519 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm) 3520 { 3521 DMSubDomainHookLink link; 3522 3523 PetscFunctionBegin; 3524 for (link = global->subdomainhook; link; link = link->next) { 3525 if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx)); 3526 } 3527 PetscFunctionReturn(0); 3528 } 3529 3530 /*@ 3531 DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`. 3532 3533 Not Collective 3534 3535 Input Parameter: 3536 . dm - the `DM` object 3537 3538 Output Parameter: 3539 . level - number of coarsenings 3540 3541 Level: developer 3542 3543 .seealso: `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3544 3545 @*/ 3546 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level) 3547 { 3548 PetscFunctionBegin; 3549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3550 PetscValidIntPointer(level, 2); 3551 *level = dm->leveldown; 3552 PetscFunctionReturn(0); 3553 } 3554 3555 /*@ 3556 DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`. 3557 3558 Collective on dm 3559 3560 Input Parameters: 3561 + dm - the `DM` object 3562 - level - number of coarsenings 3563 3564 Level: developer 3565 3566 Note: 3567 This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()` 3568 3569 .seealso: `DMSetCoarsenLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3570 @*/ 3571 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level) 3572 { 3573 PetscFunctionBegin; 3574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3575 dm->leveldown = level; 3576 PetscFunctionReturn(0); 3577 } 3578 3579 /*@C 3580 DMRefineHierarchy - Refines a `DM` object, all levels at once 3581 3582 Collective on dm 3583 3584 Input Parameters: 3585 + dm - the `DM` object 3586 - nlevels - the number of levels of refinement 3587 3588 Output Parameter: 3589 . dmf - the refined `DM` hierarchy 3590 3591 Level: developer 3592 3593 .seealso: `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3594 3595 @*/ 3596 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[]) 3597 { 3598 PetscFunctionBegin; 3599 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3600 PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative"); 3601 if (nlevels == 0) PetscFunctionReturn(0); 3602 PetscValidPointer(dmf, 3); 3603 if (dm->ops->refinehierarchy) { 3604 PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf); 3605 } else if (dm->ops->refine) { 3606 PetscInt i; 3607 3608 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0])); 3609 for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i])); 3610 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No RefineHierarchy for this DM yet"); 3611 PetscFunctionReturn(0); 3612 } 3613 3614 /*@C 3615 DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once 3616 3617 Collective on dm 3618 3619 Input Parameters: 3620 + dm - the `DM` object 3621 - nlevels - the number of levels of coarsening 3622 3623 Output Parameter: 3624 . dmc - the coarsened `DM` hierarchy 3625 3626 Level: developer 3627 3628 .seealso: `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3629 3630 @*/ 3631 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[]) 3632 { 3633 PetscFunctionBegin; 3634 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3635 PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative"); 3636 if (nlevels == 0) PetscFunctionReturn(0); 3637 PetscValidPointer(dmc, 3); 3638 if (dm->ops->coarsenhierarchy) { 3639 PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc); 3640 } else if (dm->ops->coarsen) { 3641 PetscInt i; 3642 3643 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0])); 3644 for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i])); 3645 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No CoarsenHierarchy for this DM yet"); 3646 PetscFunctionReturn(0); 3647 } 3648 3649 /*@C 3650 DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed 3651 3652 Logically Collective if the function is collective 3653 3654 Input Parameters: 3655 + dm - the `DM` object 3656 - destroy - the destroy function 3657 3658 Level: intermediate 3659 3660 .seealso: `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()` 3661 3662 @*/ 3663 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **)) 3664 { 3665 PetscFunctionBegin; 3666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3667 dm->ctxdestroy = destroy; 3668 PetscFunctionReturn(0); 3669 } 3670 3671 /*@ 3672 DMSetApplicationContext - Set a user context into a `DM` object 3673 3674 Not Collective 3675 3676 Input Parameters: 3677 + dm - the `DM` object 3678 - ctx - the user context 3679 3680 Level: intermediate 3681 3682 Note: 3683 A user context is a way to pass problem specific information that is accessable whenever the `DM` is available 3684 3685 .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()` 3686 3687 @*/ 3688 PetscErrorCode DMSetApplicationContext(DM dm, void *ctx) 3689 { 3690 PetscFunctionBegin; 3691 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3692 dm->ctx = ctx; 3693 PetscFunctionReturn(0); 3694 } 3695 3696 /*@ 3697 DMGetApplicationContext - Gets a user context from a `DM` object 3698 3699 Not Collective 3700 3701 Input Parameter: 3702 . dm - the `DM` object 3703 3704 Output Parameter: 3705 . ctx - the user context 3706 3707 Level: intermediate 3708 3709 Note: 3710 A user context is a way to pass problem specific information that is accessable whenever the `DM` is available 3711 3712 .seealso: `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()` 3713 3714 @*/ 3715 PetscErrorCode DMGetApplicationContext(DM dm, void *ctx) 3716 { 3717 PetscFunctionBegin; 3718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3719 *(void **)ctx = dm->ctx; 3720 PetscFunctionReturn(0); 3721 } 3722 3723 /*@C 3724 DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`. 3725 3726 Logically Collective on dm 3727 3728 Input Parameters: 3729 + dm - the DM object 3730 - f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set) 3731 3732 Level: intermediate 3733 3734 .seealso: `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`, 3735 `DMSetJacobian()` 3736 3737 @*/ 3738 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec)) 3739 { 3740 PetscFunctionBegin; 3741 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3742 dm->ops->computevariablebounds = f; 3743 PetscFunctionReturn(0); 3744 } 3745 3746 /*@ 3747 DMHasVariableBounds - does the `DM` object have a variable bounds function? 3748 3749 Not Collective 3750 3751 Input Parameter: 3752 . dm - the `DM` object to destroy 3753 3754 Output Parameter: 3755 . flg - `PETSC_TRUE` if the variable bounds function exists 3756 3757 Level: developer 3758 3759 .seealso: `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()` 3760 3761 @*/ 3762 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg) 3763 { 3764 PetscFunctionBegin; 3765 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3766 PetscValidBoolPointer(flg, 2); 3767 *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE; 3768 PetscFunctionReturn(0); 3769 } 3770 3771 /*@C 3772 DMComputeVariableBounds - compute variable bounds used by `SNESVI`. 3773 3774 Logically Collective on dm 3775 3776 Input Parameter: 3777 . dm - the `DM` object 3778 3779 Output parameters: 3780 + xl - lower bound 3781 - xu - upper bound 3782 3783 Level: advanced 3784 3785 Notes: 3786 This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds() 3787 3788 .seealso: `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()` 3789 3790 @*/ 3791 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu) 3792 { 3793 PetscFunctionBegin; 3794 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3795 PetscValidHeaderSpecific(xl, VEC_CLASSID, 2); 3796 PetscValidHeaderSpecific(xu, VEC_CLASSID, 3); 3797 PetscUseTypeMethod(dm, computevariablebounds, xl, xu); 3798 PetscFunctionReturn(0); 3799 } 3800 3801 /*@ 3802 DMHasColoring - does the `DM` object have a method of providing a coloring? 3803 3804 Not Collective 3805 3806 Input Parameter: 3807 . dm - the DM object 3808 3809 Output Parameter: 3810 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`. 3811 3812 Level: developer 3813 3814 .seealso: `DMCreateColoring()` 3815 3816 @*/ 3817 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg) 3818 { 3819 PetscFunctionBegin; 3820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3821 PetscValidBoolPointer(flg, 2); 3822 *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE; 3823 PetscFunctionReturn(0); 3824 } 3825 3826 /*@ 3827 DMHasCreateRestriction - does the `DM` object have a method of providing a restriction? 3828 3829 Not Collective 3830 3831 Input Parameter: 3832 . dm - the `DM` object 3833 3834 Output Parameter: 3835 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`. 3836 3837 Level: developer 3838 3839 .seealso: `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()` 3840 3841 @*/ 3842 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg) 3843 { 3844 PetscFunctionBegin; 3845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3846 PetscValidBoolPointer(flg, 2); 3847 *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE; 3848 PetscFunctionReturn(0); 3849 } 3850 3851 /*@ 3852 DMHasCreateInjection - does the `DM` object have a method of providing an injection? 3853 3854 Not Collective 3855 3856 Input Parameter: 3857 . dm - the `DM` object 3858 3859 Output Parameter: 3860 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`. 3861 3862 Level: developer 3863 3864 .seealso: `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()` 3865 3866 @*/ 3867 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg) 3868 { 3869 PetscFunctionBegin; 3870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3871 PetscValidBoolPointer(flg, 2); 3872 if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg); 3873 else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE; 3874 PetscFunctionReturn(0); 3875 } 3876 3877 PetscFunctionList DMList = NULL; 3878 PetscBool DMRegisterAllCalled = PETSC_FALSE; 3879 3880 /*@C 3881 DMSetType - Builds a `DM`, for a particular `DM` implementation. 3882 3883 Collective on dm 3884 3885 Input Parameters: 3886 + dm - The `DM` object 3887 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX` 3888 3889 Options Database Key: 3890 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types 3891 3892 Level: intermediate 3893 3894 Note: 3895 Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPLEXCreateBoxMesh()` 3896 3897 .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()` 3898 @*/ 3899 PetscErrorCode DMSetType(DM dm, DMType method) 3900 { 3901 PetscErrorCode (*r)(DM); 3902 PetscBool match; 3903 3904 PetscFunctionBegin; 3905 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3906 PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match)); 3907 if (match) PetscFunctionReturn(0); 3908 3909 PetscCall(DMRegisterAll()); 3910 PetscCall(PetscFunctionListFind(DMList, method, &r)); 3911 PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method); 3912 3913 PetscTryTypeMethod(dm, destroy); 3914 PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops))); 3915 PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method)); 3916 PetscCall((*r)(dm)); 3917 PetscFunctionReturn(0); 3918 } 3919 3920 /*@C 3921 DMGetType - Gets the `DM` type name (as a string) from the `DM`. 3922 3923 Not Collective 3924 3925 Input Parameter: 3926 . dm - The `DM` 3927 3928 Output Parameter: 3929 . type - The `DMType` name 3930 3931 Level: intermediate 3932 3933 .seealso: `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()` 3934 @*/ 3935 PetscErrorCode DMGetType(DM dm, DMType *type) 3936 { 3937 PetscFunctionBegin; 3938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3939 PetscValidPointer(type, 2); 3940 PetscCall(DMRegisterAll()); 3941 *type = ((PetscObject)dm)->type_name; 3942 PetscFunctionReturn(0); 3943 } 3944 3945 /*@C 3946 DMConvert - Converts a `DM` to another `DM`, either of the same or different type. 3947 3948 Collective on dm 3949 3950 Input Parameters: 3951 + dm - the `DM` 3952 - newtype - new `DM` type (use "same" for the same type) 3953 3954 Output Parameter: 3955 . M - pointer to new `DM` 3956 3957 Notes: 3958 Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential, 3959 the MPI communicator of the generated `DM` is always the same as the communicator 3960 of the input `DM`. 3961 3962 Level: intermediate 3963 3964 .seealso: `DM`, `DMSetType()`, `DMCreate()`, `DMClone()` 3965 @*/ 3966 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M) 3967 { 3968 DM B; 3969 char convname[256]; 3970 PetscBool sametype /*, issame */; 3971 3972 PetscFunctionBegin; 3973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3974 PetscValidType(dm, 1); 3975 PetscValidPointer(M, 3); 3976 PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype)); 3977 /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */ 3978 if (sametype) { 3979 *M = dm; 3980 PetscCall(PetscObjectReference((PetscObject)dm)); 3981 PetscFunctionReturn(0); 3982 } else { 3983 PetscErrorCode (*conv)(DM, DMType, DM *) = NULL; 3984 3985 /* 3986 Order of precedence: 3987 1) See if a specialized converter is known to the current DM. 3988 2) See if a specialized converter is known to the desired DM class. 3989 3) See if a good general converter is registered for the desired class 3990 4) See if a good general converter is known for the current matrix. 3991 5) Use a really basic converter. 3992 */ 3993 3994 /* 1) See if a specialized converter is known to the current DM and the desired class */ 3995 PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname))); 3996 PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname))); 3997 PetscCall(PetscStrlcat(convname, "_", sizeof(convname))); 3998 PetscCall(PetscStrlcat(convname, newtype, sizeof(convname))); 3999 PetscCall(PetscStrlcat(convname, "_C", sizeof(convname))); 4000 PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv)); 4001 if (conv) goto foundconv; 4002 4003 /* 2) See if a specialized converter is known to the desired DM class. */ 4004 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B)); 4005 PetscCall(DMSetType(B, newtype)); 4006 PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname))); 4007 PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname))); 4008 PetscCall(PetscStrlcat(convname, "_", sizeof(convname))); 4009 PetscCall(PetscStrlcat(convname, newtype, sizeof(convname))); 4010 PetscCall(PetscStrlcat(convname, "_C", sizeof(convname))); 4011 PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv)); 4012 if (conv) { 4013 PetscCall(DMDestroy(&B)); 4014 goto foundconv; 4015 } 4016 4017 #if 0 4018 /* 3) See if a good general converter is registered for the desired class */ 4019 conv = B->ops->convertfrom; 4020 PetscCall(DMDestroy(&B)); 4021 if (conv) goto foundconv; 4022 4023 /* 4) See if a good general converter is known for the current matrix */ 4024 if (dm->ops->convert) { 4025 conv = dm->ops->convert; 4026 } 4027 if (conv) goto foundconv; 4028 #endif 4029 4030 /* 5) Use a really basic converter. */ 4031 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype); 4032 4033 foundconv: 4034 PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0)); 4035 PetscCall((*conv)(dm, newtype, M)); 4036 /* Things that are independent of DM type: We should consult DMClone() here */ 4037 { 4038 const PetscReal *maxCell, *Lstart, *L; 4039 4040 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 4041 PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L)); 4042 (*M)->prealloc_only = dm->prealloc_only; 4043 PetscCall(PetscFree((*M)->vectype)); 4044 PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype)); 4045 PetscCall(PetscFree((*M)->mattype)); 4046 PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype)); 4047 } 4048 PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0)); 4049 } 4050 PetscCall(PetscObjectStateIncrease((PetscObject)*M)); 4051 PetscFunctionReturn(0); 4052 } 4053 4054 /*--------------------------------------------------------------------------------------------------------------------*/ 4055 4056 /*@C 4057 DMRegister - Adds a new `DM` type implementation 4058 4059 Not Collective 4060 4061 Input Parameters: 4062 + name - The name of a new user-defined creation routine 4063 - create_func - The creation routine itself 4064 4065 Notes: 4066 DMRegister() may be called multiple times to add several user-defined `DM`s 4067 4068 Sample usage: 4069 .vb 4070 DMRegister("my_da", MyDMCreate); 4071 .ve 4072 4073 Then, your DM type can be chosen with the procedural interface via 4074 .vb 4075 DMCreate(MPI_Comm, DM *); 4076 DMSetType(DM,"my_da"); 4077 .ve 4078 or at runtime via the option 4079 .vb 4080 -da_type my_da 4081 .ve 4082 4083 Level: advanced 4084 4085 .seealso: `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()` 4086 4087 @*/ 4088 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM)) 4089 { 4090 PetscFunctionBegin; 4091 PetscCall(DMInitializePackage()); 4092 PetscCall(PetscFunctionListAdd(&DMList, sname, function)); 4093 PetscFunctionReturn(0); 4094 } 4095 4096 /*@C 4097 DMLoad - Loads a DM that has been stored in binary with `DMView()`. 4098 4099 Collective on viewer 4100 4101 Input Parameters: 4102 + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or 4103 some related function before a call to `DMLoad()`. 4104 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or 4105 `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()` 4106 4107 Level: intermediate 4108 4109 Notes: 4110 The type is determined by the data in the file, any type set into the DM before this call is ignored. 4111 4112 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 4113 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 4114 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 4115 4116 Notes for advanced users: 4117 Most users should not need to know the details of the binary storage 4118 format, since `DMLoad()` and `DMView()` completely hide these details. 4119 But for anyone who's interested, the standard binary matrix storage 4120 format is 4121 .vb 4122 has not yet been determined 4123 .ve 4124 4125 .seealso: `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()` 4126 @*/ 4127 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer) 4128 { 4129 PetscBool isbinary, ishdf5; 4130 4131 PetscFunctionBegin; 4132 PetscValidHeaderSpecific(newdm, DM_CLASSID, 1); 4133 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 4134 PetscCall(PetscViewerCheckReadable(viewer)); 4135 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 4136 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 4137 PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0)); 4138 if (isbinary) { 4139 PetscInt classid; 4140 char type[256]; 4141 4142 PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT)); 4143 PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %d", (int)classid); 4144 PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR)); 4145 PetscCall(DMSetType(newdm, type)); 4146 PetscTryTypeMethod(newdm, load, viewer); 4147 } else if (ishdf5) { 4148 PetscTryTypeMethod(newdm, load, viewer); 4149 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()"); 4150 PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0)); 4151 PetscFunctionReturn(0); 4152 } 4153 4154 /******************************** FEM Support **********************************/ 4155 4156 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[]) 4157 { 4158 PetscInt f; 4159 4160 PetscFunctionBegin; 4161 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name)); 4162 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]))); 4163 PetscFunctionReturn(0); 4164 } 4165 4166 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[]) 4167 { 4168 PetscInt f, g; 4169 4170 PetscFunctionBegin; 4171 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name)); 4172 for (f = 0; f < rows; ++f) { 4173 PetscCall(PetscPrintf(PETSC_COMM_SELF, " |")); 4174 for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g]))); 4175 PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n")); 4176 } 4177 PetscFunctionReturn(0); 4178 } 4179 4180 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X) 4181 { 4182 PetscInt localSize, bs; 4183 PetscMPIInt size; 4184 Vec x, xglob; 4185 const PetscScalar *xarray; 4186 4187 PetscFunctionBegin; 4188 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 4189 PetscCall(VecDuplicate(X, &x)); 4190 PetscCall(VecCopy(X, x)); 4191 PetscCall(VecChop(x, tol)); 4192 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name)); 4193 if (size > 1) { 4194 PetscCall(VecGetLocalSize(x, &localSize)); 4195 PetscCall(VecGetArrayRead(x, &xarray)); 4196 PetscCall(VecGetBlockSize(x, &bs)); 4197 PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob)); 4198 } else { 4199 xglob = x; 4200 } 4201 PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm)))); 4202 if (size > 1) { 4203 PetscCall(VecDestroy(&xglob)); 4204 PetscCall(VecRestoreArrayRead(x, &xarray)); 4205 } 4206 PetscCall(VecDestroy(&x)); 4207 PetscFunctionReturn(0); 4208 } 4209 4210 /*@ 4211 DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`. This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12 4212 4213 Input Parameter: 4214 . dm - The `DM` 4215 4216 Output Parameter: 4217 . section - The `PetscSection` 4218 4219 Options Database Keys: 4220 . -dm_petscsection_view - View the `PetscSection` created by the `DM` 4221 4222 Level: advanced 4223 4224 Notes: 4225 Use `DMGetLocalSection()` in new code. 4226 4227 This gets a borrowed reference, so the user should not destroy this `PetscSection`. 4228 4229 .seealso: `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()` 4230 @*/ 4231 PetscErrorCode DMGetSection(DM dm, PetscSection *section) 4232 { 4233 PetscFunctionBegin; 4234 PetscCall(DMGetLocalSection(dm, section)); 4235 PetscFunctionReturn(0); 4236 } 4237 4238 /*@ 4239 DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`. 4240 4241 Input Parameter: 4242 . dm - The `DM` 4243 4244 Output Parameter: 4245 . section - The `PetscSection` 4246 4247 Options Database Keys: 4248 . -dm_petscsection_view - View the section created by the `DM` 4249 4250 Level: intermediate 4251 4252 Note: 4253 This gets a borrowed reference, so the user should not destroy this `PetscSection`. 4254 4255 .seealso: `DMSetLocalSection()`, `DMGetGlobalSection()` 4256 @*/ 4257 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section) 4258 { 4259 PetscFunctionBegin; 4260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4261 PetscValidPointer(section, 2); 4262 if (!dm->localSection && dm->ops->createlocalsection) { 4263 PetscInt d; 4264 4265 if (dm->setfromoptionscalled) { 4266 PetscObject obj = (PetscObject)dm; 4267 PetscViewer viewer; 4268 PetscViewerFormat format; 4269 PetscBool flg; 4270 4271 PetscCall(PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg)); 4272 if (flg) PetscCall(PetscViewerPushFormat(viewer, format)); 4273 for (d = 0; d < dm->Nds; ++d) { 4274 PetscCall(PetscDSSetFromOptions(dm->probs[d].ds)); 4275 if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer)); 4276 } 4277 if (flg) { 4278 PetscCall(PetscViewerFlush(viewer)); 4279 PetscCall(PetscViewerPopFormat(viewer)); 4280 PetscCall(PetscViewerDestroy(&viewer)); 4281 } 4282 } 4283 PetscUseTypeMethod(dm, createlocalsection); 4284 if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view")); 4285 } 4286 *section = dm->localSection; 4287 PetscFunctionReturn(0); 4288 } 4289 4290 /*@ 4291 DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`. This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12 4292 4293 Input Parameters: 4294 + dm - The `DM` 4295 - section - The `PetscSection` 4296 4297 Level: advanced 4298 4299 Notes: 4300 Use `DMSetLocalSection()` in new code. 4301 4302 Any existing `PetscSection` will be destroyed 4303 4304 .seealso: `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()` 4305 @*/ 4306 PetscErrorCode DMSetSection(DM dm, PetscSection section) 4307 { 4308 PetscFunctionBegin; 4309 PetscCall(DMSetLocalSection(dm, section)); 4310 PetscFunctionReturn(0); 4311 } 4312 4313 /*@ 4314 DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`. 4315 4316 Input Parameters: 4317 + dm - The `DM` 4318 - section - The `PetscSection` 4319 4320 Level: intermediate 4321 4322 Note: 4323 Any existing Section will be destroyed 4324 4325 .seealso: `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()` 4326 @*/ 4327 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section) 4328 { 4329 PetscInt numFields = 0; 4330 PetscInt f; 4331 4332 PetscFunctionBegin; 4333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4334 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4335 PetscCall(PetscObjectReference((PetscObject)section)); 4336 PetscCall(PetscSectionDestroy(&dm->localSection)); 4337 dm->localSection = section; 4338 if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields)); 4339 if (numFields) { 4340 PetscCall(DMSetNumFields(dm, numFields)); 4341 for (f = 0; f < numFields; ++f) { 4342 PetscObject disc; 4343 const char *name; 4344 4345 PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name)); 4346 PetscCall(DMGetField(dm, f, NULL, &disc)); 4347 PetscCall(PetscObjectSetName(disc, name)); 4348 } 4349 } 4350 /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */ 4351 PetscCall(PetscSectionDestroy(&dm->globalSection)); 4352 PetscFunctionReturn(0); 4353 } 4354 4355 /*@ 4356 DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation. 4357 4358 not collective 4359 4360 Input Parameter: 4361 . dm - The `DM` 4362 4363 Output Parameters: 4364 + section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section. Returns NULL if there are no local constraints. 4365 . mat - The `Mat` that interpolates local constraints: its width should be the layout size of the default section. Returns NULL if there are no local constraints. 4366 - bias - Vector containing bias to be added to constrained dofs 4367 4368 Level: advanced 4369 4370 Note: 4371 This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`. 4372 4373 .seealso: `DMSetDefaultConstraints()` 4374 @*/ 4375 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias) 4376 { 4377 PetscFunctionBegin; 4378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4379 if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints); 4380 if (section) *section = dm->defaultConstraint.section; 4381 if (mat) *mat = dm->defaultConstraint.mat; 4382 if (bias) *bias = dm->defaultConstraint.bias; 4383 PetscFunctionReturn(0); 4384 } 4385 4386 /*@ 4387 DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation. 4388 4389 If a constraint matrix is specified, then it is applied during `DMGlobalToLocalEnd()` when mode is `INSERT_VALUES`, `INSERT_BC_VALUES`, or `INSERT_ALL_VALUES`. Without a constraint matrix, the local vector l returned by `DMGlobalToLocalEnd()` contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l + bias, l[s[i]] = c[i], where the scatter s is defined by the `PetscSection` returned by `DMGetDefaultConstraints()`. 4390 4391 If a constraint matrix is specified, then its adjoint is applied during `DMLocalToGlobalBegin()` when mode is `ADD_VALUES`, `ADD_BC_VALUES`, or `ADD_ALL_VALUES`. Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above. Any bias, if specified, is ignored when accumulating. 4392 4393 collective on dm 4394 4395 Input Parameters: 4396 + dm - The `DM` 4397 . section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 4398 . mat - The `Mat` that interpolates local constraints: its width should be the layout size of the default section: NULL indicates no constraints. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 4399 - bias - A bias vector to be added to constrained values in the local vector. NULL indicates no bias. Must have a local communicator (`PETSC_COMM_SELF` or derivative). 4400 4401 Level: advanced 4402 4403 Note: 4404 This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them. 4405 4406 .seealso: `DMGetDefaultConstraints()` 4407 @*/ 4408 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias) 4409 { 4410 PetscMPIInt result; 4411 4412 PetscFunctionBegin; 4413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4414 if (section) { 4415 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4416 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result)); 4417 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator"); 4418 } 4419 if (mat) { 4420 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3); 4421 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result)); 4422 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator"); 4423 } 4424 if (bias) { 4425 PetscValidHeaderSpecific(bias, VEC_CLASSID, 4); 4426 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result)); 4427 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator"); 4428 } 4429 PetscCall(PetscObjectReference((PetscObject)section)); 4430 PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section)); 4431 dm->defaultConstraint.section = section; 4432 PetscCall(PetscObjectReference((PetscObject)mat)); 4433 PetscCall(MatDestroy(&dm->defaultConstraint.mat)); 4434 dm->defaultConstraint.mat = mat; 4435 PetscCall(PetscObjectReference((PetscObject)bias)); 4436 PetscCall(VecDestroy(&dm->defaultConstraint.bias)); 4437 dm->defaultConstraint.bias = bias; 4438 PetscFunctionReturn(0); 4439 } 4440 4441 #if defined(PETSC_USE_DEBUG) 4442 /* 4443 DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent. 4444 4445 Input Parameters: 4446 + dm - The `DM` 4447 . localSection - `PetscSection` describing the local data layout 4448 - globalSection - `PetscSection` describing the global data layout 4449 4450 Level: intermediate 4451 4452 .seealso: `DMGetSectionSF()`, `DMSetSectionSF()` 4453 */ 4454 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection) 4455 { 4456 MPI_Comm comm; 4457 PetscLayout layout; 4458 const PetscInt *ranges; 4459 PetscInt pStart, pEnd, p, nroots; 4460 PetscMPIInt size, rank; 4461 PetscBool valid = PETSC_TRUE, gvalid; 4462 4463 PetscFunctionBegin; 4464 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4465 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4466 PetscCallMPI(MPI_Comm_size(comm, &size)); 4467 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 4468 PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd)); 4469 PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots)); 4470 PetscCall(PetscLayoutCreate(comm, &layout)); 4471 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 4472 PetscCall(PetscLayoutSetLocalSize(layout, nroots)); 4473 PetscCall(PetscLayoutSetUp(layout)); 4474 PetscCall(PetscLayoutGetRanges(layout, &ranges)); 4475 for (p = pStart; p < pEnd; ++p) { 4476 PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d; 4477 4478 PetscCall(PetscSectionGetDof(localSection, p, &dof)); 4479 PetscCall(PetscSectionGetOffset(localSection, p, &off)); 4480 PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof)); 4481 PetscCall(PetscSectionGetDof(globalSection, p, &gdof)); 4482 PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof)); 4483 PetscCall(PetscSectionGetOffset(globalSection, p, &goff)); 4484 if (!gdof) continue; /* Censored point */ 4485 if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) { 4486 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof)); 4487 valid = PETSC_FALSE; 4488 } 4489 if (gcdof && (gcdof != cdof)) { 4490 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof)); 4491 valid = PETSC_FALSE; 4492 } 4493 if (gdof < 0) { 4494 gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof; 4495 for (d = 0; d < gsize; ++d) { 4496 PetscInt offset = -(goff + 1) + d, r; 4497 4498 PetscCall(PetscFindInt(offset, size + 1, ranges, &r)); 4499 if (r < 0) r = -(r + 2); 4500 if ((r < 0) || (r >= size)) { 4501 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff)); 4502 valid = PETSC_FALSE; 4503 break; 4504 } 4505 } 4506 } 4507 } 4508 PetscCall(PetscLayoutDestroy(&layout)); 4509 PetscCall(PetscSynchronizedFlush(comm, NULL)); 4510 PetscCall(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm)); 4511 if (!gvalid) { 4512 PetscCall(DMView(dm, NULL)); 4513 SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections"); 4514 } 4515 PetscFunctionReturn(0); 4516 } 4517 #endif 4518 4519 /*@ 4520 DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`. 4521 4522 Collective on dm 4523 4524 Input Parameter: 4525 . dm - The `DM` 4526 4527 Output Parameter: 4528 . section - The `PetscSection` 4529 4530 Level: intermediate 4531 4532 Note: 4533 This gets a borrowed reference, so the user should not destroy this `PetscSection`. 4534 4535 .seealso: `DMSetLocalSection()`, `DMGetLocalSection()` 4536 @*/ 4537 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section) 4538 { 4539 PetscFunctionBegin; 4540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4541 PetscValidPointer(section, 2); 4542 if (!dm->globalSection) { 4543 PetscSection s; 4544 4545 PetscCall(DMGetLocalSection(dm, &s)); 4546 PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection"); 4547 PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection"); 4548 PetscCall(PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection)); 4549 PetscCall(PetscLayoutDestroy(&dm->map)); 4550 PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map)); 4551 PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view")); 4552 } 4553 *section = dm->globalSection; 4554 PetscFunctionReturn(0); 4555 } 4556 4557 /*@ 4558 DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`. 4559 4560 Input Parameters: 4561 + dm - The `DM` 4562 - section - The PetscSection, or NULL 4563 4564 Level: intermediate 4565 4566 Note: 4567 Any existing `PetscSection` will be destroyed 4568 4569 .seealso: `DMGetGlobalSection()`, `DMSetLocalSection()` 4570 @*/ 4571 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section) 4572 { 4573 PetscFunctionBegin; 4574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4575 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4576 PetscCall(PetscObjectReference((PetscObject)section)); 4577 PetscCall(PetscSectionDestroy(&dm->globalSection)); 4578 dm->globalSection = section; 4579 #if defined(PETSC_USE_DEBUG) 4580 if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section)); 4581 #endif 4582 PetscFunctionReturn(0); 4583 } 4584 4585 /*@ 4586 DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set, 4587 it is created from the default `PetscSection` layouts in the `DM`. 4588 4589 Input Parameter: 4590 . dm - The `DM` 4591 4592 Output Parameter: 4593 . sf - The `PetscSF` 4594 4595 Level: intermediate 4596 4597 Note: 4598 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4599 4600 .seealso: `DMSetSectionSF()`, `DMCreateSectionSF()` 4601 @*/ 4602 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf) 4603 { 4604 PetscInt nroots; 4605 4606 PetscFunctionBegin; 4607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4608 PetscValidPointer(sf, 2); 4609 if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF)); 4610 PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL)); 4611 if (nroots < 0) { 4612 PetscSection section, gSection; 4613 4614 PetscCall(DMGetLocalSection(dm, §ion)); 4615 if (section) { 4616 PetscCall(DMGetGlobalSection(dm, &gSection)); 4617 PetscCall(DMCreateSectionSF(dm, section, gSection)); 4618 } else { 4619 *sf = NULL; 4620 PetscFunctionReturn(0); 4621 } 4622 } 4623 *sf = dm->sectionSF; 4624 PetscFunctionReturn(0); 4625 } 4626 4627 /*@ 4628 DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM` 4629 4630 Input Parameters: 4631 + dm - The `DM` 4632 - sf - The `PetscSF` 4633 4634 Level: intermediate 4635 4636 Note: 4637 Any previous `PetscSF` is destroyed 4638 4639 .seealso: `DMGetSectionSF()`, `DMCreateSectionSF()` 4640 @*/ 4641 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf) 4642 { 4643 PetscFunctionBegin; 4644 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4645 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4646 PetscCall(PetscObjectReference((PetscObject)sf)); 4647 PetscCall(PetscSFDestroy(&dm->sectionSF)); 4648 dm->sectionSF = sf; 4649 PetscFunctionReturn(0); 4650 } 4651 4652 /*@C 4653 DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s 4654 describing the data layout. 4655 4656 Input Parameters: 4657 + dm - The `DM` 4658 . localSection - `PetscSection` describing the local data layout 4659 - globalSection - `PetscSection` describing the global data layout 4660 4661 Level: developer 4662 4663 Note: 4664 One usually uses `DMGetSectionSF()` to obtain the `PetscSF` 4665 4666 Developer Note: 4667 Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF` 4668 directly into the `DM`, perhaps this function should not take the local and global sections as 4669 input and should just obtain them from the `DM`? 4670 4671 .seealso: `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 4672 @*/ 4673 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection) 4674 { 4675 PetscFunctionBegin; 4676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4677 PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection)); 4678 PetscFunctionReturn(0); 4679 } 4680 4681 /*@ 4682 DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`. 4683 4684 Not collective but the resulting `PetscSF` is collective 4685 4686 Input Parameter: 4687 . dm - The `DM` 4688 4689 Output Parameter: 4690 . sf - The `PetscSF` 4691 4692 Level: intermediate 4693 4694 Note: 4695 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4696 4697 .seealso: `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4698 @*/ 4699 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf) 4700 { 4701 PetscFunctionBegin; 4702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4703 PetscValidPointer(sf, 2); 4704 *sf = dm->sf; 4705 PetscFunctionReturn(0); 4706 } 4707 4708 /*@ 4709 DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`. 4710 4711 Collective on dm 4712 4713 Input Parameters: 4714 + dm - The `DM` 4715 - sf - The` PetscSF` 4716 4717 Level: intermediate 4718 4719 .seealso: `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4720 @*/ 4721 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf) 4722 { 4723 PetscFunctionBegin; 4724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4725 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4726 PetscCall(PetscObjectReference((PetscObject)sf)); 4727 PetscCall(PetscSFDestroy(&dm->sf)); 4728 dm->sf = sf; 4729 PetscFunctionReturn(0); 4730 } 4731 4732 /*@ 4733 DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering 4734 4735 Input Parameter: 4736 . dm - The `DM` 4737 4738 Output Parameter: 4739 . sf - The `PetscSF` 4740 4741 Level: intermediate 4742 4743 Note: 4744 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4745 4746 .seealso: `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4747 @*/ 4748 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf) 4749 { 4750 PetscFunctionBegin; 4751 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4752 PetscValidPointer(sf, 2); 4753 *sf = dm->sfNatural; 4754 PetscFunctionReturn(0); 4755 } 4756 4757 /*@ 4758 DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering 4759 4760 Input Parameters: 4761 + dm - The DM 4762 - sf - The PetscSF 4763 4764 Level: intermediate 4765 4766 .seealso: `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4767 @*/ 4768 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf) 4769 { 4770 PetscFunctionBegin; 4771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4772 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4773 PetscCall(PetscObjectReference((PetscObject)sf)); 4774 PetscCall(PetscSFDestroy(&dm->sfNatural)); 4775 dm->sfNatural = sf; 4776 PetscFunctionReturn(0); 4777 } 4778 4779 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc) 4780 { 4781 PetscClassId id; 4782 4783 PetscFunctionBegin; 4784 PetscCall(PetscObjectGetClassId(disc, &id)); 4785 if (id == PETSCFE_CLASSID) { 4786 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4787 } else if (id == PETSCFV_CLASSID) { 4788 PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE)); 4789 } else { 4790 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4791 } 4792 PetscFunctionReturn(0); 4793 } 4794 4795 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew) 4796 { 4797 RegionField *tmpr; 4798 PetscInt Nf = dm->Nf, f; 4799 4800 PetscFunctionBegin; 4801 if (Nf >= NfNew) PetscFunctionReturn(0); 4802 PetscCall(PetscMalloc1(NfNew, &tmpr)); 4803 for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f]; 4804 for (f = Nf; f < NfNew; ++f) { 4805 tmpr[f].disc = NULL; 4806 tmpr[f].label = NULL; 4807 tmpr[f].avoidTensor = PETSC_FALSE; 4808 } 4809 PetscCall(PetscFree(dm->fields)); 4810 dm->Nf = NfNew; 4811 dm->fields = tmpr; 4812 PetscFunctionReturn(0); 4813 } 4814 4815 /*@ 4816 DMClearFields - Remove all fields from the DM 4817 4818 Logically collective on dm 4819 4820 Input Parameter: 4821 . dm - The DM 4822 4823 Level: intermediate 4824 4825 .seealso: `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()` 4826 @*/ 4827 PetscErrorCode DMClearFields(DM dm) 4828 { 4829 PetscInt f; 4830 4831 PetscFunctionBegin; 4832 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4833 for (f = 0; f < dm->Nf; ++f) { 4834 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 4835 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 4836 } 4837 PetscCall(PetscFree(dm->fields)); 4838 dm->fields = NULL; 4839 dm->Nf = 0; 4840 PetscFunctionReturn(0); 4841 } 4842 4843 /*@ 4844 DMGetNumFields - Get the number of fields in the DM 4845 4846 Not collective 4847 4848 Input Parameter: 4849 . dm - The DM 4850 4851 Output Parameter: 4852 . Nf - The number of fields 4853 4854 Level: intermediate 4855 4856 .seealso: `DMSetNumFields()`, `DMSetField()` 4857 @*/ 4858 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields) 4859 { 4860 PetscFunctionBegin; 4861 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4862 PetscValidIntPointer(numFields, 2); 4863 *numFields = dm->Nf; 4864 PetscFunctionReturn(0); 4865 } 4866 4867 /*@ 4868 DMSetNumFields - Set the number of fields in the DM 4869 4870 Logically collective on dm 4871 4872 Input Parameters: 4873 + dm - The DM 4874 - Nf - The number of fields 4875 4876 Level: intermediate 4877 4878 .seealso: `DMGetNumFields()`, `DMSetField()` 4879 @*/ 4880 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields) 4881 { 4882 PetscInt Nf, f; 4883 4884 PetscFunctionBegin; 4885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4886 PetscCall(DMGetNumFields(dm, &Nf)); 4887 for (f = Nf; f < numFields; ++f) { 4888 PetscContainer obj; 4889 4890 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj)); 4891 PetscCall(DMAddField(dm, NULL, (PetscObject)obj)); 4892 PetscCall(PetscContainerDestroy(&obj)); 4893 } 4894 PetscFunctionReturn(0); 4895 } 4896 4897 /*@ 4898 DMGetField - Return the `DMLabel` and discretization object for a given `DM` field 4899 4900 Not collective 4901 4902 Input Parameters: 4903 + dm - The `DM` 4904 - f - The field number 4905 4906 Output Parameters: 4907 + label - The label indicating the support of the field, or NULL for the entire mesh (pass in NULL if not needed) 4908 - disc - The discretization object (pass in NULL if not needed) 4909 4910 Level: intermediate 4911 4912 .seealso: `DMAddField()`, `DMSetField()` 4913 @*/ 4914 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc) 4915 { 4916 PetscFunctionBegin; 4917 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4918 PetscValidPointer(disc, 4); 4919 PetscCheck((f >= 0) && (f < dm->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, dm->Nf); 4920 if (label) *label = dm->fields[f].label; 4921 if (disc) *disc = dm->fields[f].disc; 4922 PetscFunctionReturn(0); 4923 } 4924 4925 /* Does not clear the DS */ 4926 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc) 4927 { 4928 PetscFunctionBegin; 4929 PetscCall(DMFieldEnlarge_Static(dm, f + 1)); 4930 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 4931 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 4932 dm->fields[f].label = label; 4933 dm->fields[f].disc = disc; 4934 PetscCall(PetscObjectReference((PetscObject)label)); 4935 PetscCall(PetscObjectReference((PetscObject)disc)); 4936 PetscFunctionReturn(0); 4937 } 4938 4939 /*@ 4940 DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles 4941 the field numbering. 4942 4943 Logically collective on dm 4944 4945 Input Parameters: 4946 + dm - The `DM` 4947 . f - The field number 4948 . label - The label indicating the support of the field, or NULL for the entire mesh 4949 - disc - The discretization object 4950 4951 Level: intermediate 4952 4953 .seealso: `DMAddField()`, `DMGetField()` 4954 @*/ 4955 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc) 4956 { 4957 PetscFunctionBegin; 4958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4959 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 4960 PetscValidHeader(disc, 4); 4961 PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f); 4962 PetscCall(DMSetField_Internal(dm, f, label, disc)); 4963 PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc)); 4964 PetscCall(DMClearDS(dm)); 4965 PetscFunctionReturn(0); 4966 } 4967 4968 /*@ 4969 DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities) 4970 and a discretization object that defines the function space associated with those points. 4971 4972 Logically collective on dm 4973 4974 Input Parameters: 4975 + dm - The `DM` 4976 . label - The label indicating the support of the field, or NULL for the entire mesh 4977 - disc - The discretization object 4978 4979 Level: intermediate 4980 4981 Notes: 4982 The label already exists or will be added to the `DM` with `DMSetLabel()`. 4983 4984 For example, a piecewise continous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions 4985 within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the 4986 geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`. 4987 4988 .seealso: `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE` 4989 @*/ 4990 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc) 4991 { 4992 PetscInt Nf = dm->Nf; 4993 4994 PetscFunctionBegin; 4995 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4996 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 4997 PetscValidHeader(disc, 3); 4998 PetscCall(DMFieldEnlarge_Static(dm, Nf + 1)); 4999 dm->fields[Nf].label = label; 5000 dm->fields[Nf].disc = disc; 5001 PetscCall(PetscObjectReference((PetscObject)label)); 5002 PetscCall(PetscObjectReference((PetscObject)disc)); 5003 PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc)); 5004 PetscCall(DMClearDS(dm)); 5005 PetscFunctionReturn(0); 5006 } 5007 5008 /*@ 5009 DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells 5010 5011 Logically collective on dm 5012 5013 Input Parameters: 5014 + dm - The `DM` 5015 . f - The field index 5016 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells 5017 5018 Level: intermediate 5019 5020 .seealso: `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()` 5021 @*/ 5022 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor) 5023 { 5024 PetscFunctionBegin; 5025 PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf); 5026 dm->fields[f].avoidTensor = avoidTensor; 5027 PetscFunctionReturn(0); 5028 } 5029 5030 /*@ 5031 DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells 5032 5033 Not collective 5034 5035 Input Parameters: 5036 + dm - The `DM` 5037 - f - The field index 5038 5039 Output Parameter: 5040 . avoidTensor - The flag to avoid defining the field on tensor cells 5041 5042 Level: intermediate 5043 5044 .seealso: `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()` 5045 @*/ 5046 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor) 5047 { 5048 PetscFunctionBegin; 5049 PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf); 5050 *avoidTensor = dm->fields[f].avoidTensor; 5051 PetscFunctionReturn(0); 5052 } 5053 5054 /*@ 5055 DMCopyFields - Copy the discretizations for the `DM` into another `DM` 5056 5057 Collective on dm 5058 5059 Input Parameter: 5060 . dm - The `DM` 5061 5062 Output Parameter: 5063 . newdm - The `DM` 5064 5065 Level: advanced 5066 5067 .seealso: `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()` 5068 @*/ 5069 PetscErrorCode DMCopyFields(DM dm, DM newdm) 5070 { 5071 PetscInt Nf, f; 5072 5073 PetscFunctionBegin; 5074 if (dm == newdm) PetscFunctionReturn(0); 5075 PetscCall(DMGetNumFields(dm, &Nf)); 5076 PetscCall(DMClearFields(newdm)); 5077 for (f = 0; f < Nf; ++f) { 5078 DMLabel label; 5079 PetscObject field; 5080 PetscBool useCone, useClosure; 5081 5082 PetscCall(DMGetField(dm, f, &label, &field)); 5083 PetscCall(DMSetField(newdm, f, label, field)); 5084 PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure)); 5085 PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure)); 5086 } 5087 PetscFunctionReturn(0); 5088 } 5089 5090 /*@ 5091 DMGetAdjacency - Returns the flags for determining variable influence 5092 5093 Not collective 5094 5095 Input Parameters: 5096 + dm - The DM object 5097 - f - The field number, or PETSC_DEFAULT for the default adjacency 5098 5099 Output Parameters: 5100 + useCone - Flag for variable influence starting with the cone operation 5101 - useClosure - Flag for variable influence using transitive closure 5102 5103 Notes: 5104 $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5105 $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5106 $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5107 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5108 5109 Level: developer 5110 5111 .seealso: `DMSetAdjacency()`, `DMGetField()`, `DMSetField()` 5112 @*/ 5113 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure) 5114 { 5115 PetscFunctionBegin; 5116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5117 if (useCone) PetscValidBoolPointer(useCone, 3); 5118 if (useClosure) PetscValidBoolPointer(useClosure, 4); 5119 if (f < 0) { 5120 if (useCone) *useCone = dm->adjacency[0]; 5121 if (useClosure) *useClosure = dm->adjacency[1]; 5122 } else { 5123 PetscInt Nf; 5124 5125 PetscCall(DMGetNumFields(dm, &Nf)); 5126 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5127 if (useCone) *useCone = dm->fields[f].adjacency[0]; 5128 if (useClosure) *useClosure = dm->fields[f].adjacency[1]; 5129 } 5130 PetscFunctionReturn(0); 5131 } 5132 5133 /*@ 5134 DMSetAdjacency - Set the flags for determining variable influence 5135 5136 Not collective 5137 5138 Input Parameters: 5139 + dm - The DM object 5140 . f - The field number 5141 . useCone - Flag for variable influence starting with the cone operation 5142 - useClosure - Flag for variable influence using transitive closure 5143 5144 Notes: 5145 $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5146 $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5147 $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5148 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5149 5150 Level: developer 5151 5152 .seealso: `DMGetAdjacency()`, `DMGetField()`, `DMSetField()` 5153 @*/ 5154 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure) 5155 { 5156 PetscFunctionBegin; 5157 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5158 if (f < 0) { 5159 dm->adjacency[0] = useCone; 5160 dm->adjacency[1] = useClosure; 5161 } else { 5162 PetscInt Nf; 5163 5164 PetscCall(DMGetNumFields(dm, &Nf)); 5165 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5166 dm->fields[f].adjacency[0] = useCone; 5167 dm->fields[f].adjacency[1] = useClosure; 5168 } 5169 PetscFunctionReturn(0); 5170 } 5171 5172 /*@ 5173 DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined 5174 5175 Not collective 5176 5177 Input Parameter: 5178 . dm - The DM object 5179 5180 Output Parameters: 5181 + useCone - Flag for variable influence starting with the cone operation 5182 - useClosure - Flag for variable influence using transitive closure 5183 5184 Notes: 5185 $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5186 $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5187 $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5188 5189 Level: developer 5190 5191 .seealso: `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5192 @*/ 5193 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure) 5194 { 5195 PetscInt Nf; 5196 5197 PetscFunctionBegin; 5198 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5199 if (useCone) PetscValidBoolPointer(useCone, 2); 5200 if (useClosure) PetscValidBoolPointer(useClosure, 3); 5201 PetscCall(DMGetNumFields(dm, &Nf)); 5202 if (!Nf) { 5203 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5204 } else { 5205 PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure)); 5206 } 5207 PetscFunctionReturn(0); 5208 } 5209 5210 /*@ 5211 DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined 5212 5213 Not collective 5214 5215 Input Parameters: 5216 + dm - The DM object 5217 . useCone - Flag for variable influence starting with the cone operation 5218 - useClosure - Flag for variable influence using transitive closure 5219 5220 Notes: 5221 $ FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5222 $ FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5223 $ FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5224 5225 Level: developer 5226 5227 .seealso: `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5228 @*/ 5229 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure) 5230 { 5231 PetscInt Nf; 5232 5233 PetscFunctionBegin; 5234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5235 PetscCall(DMGetNumFields(dm, &Nf)); 5236 if (!Nf) { 5237 PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5238 } else { 5239 PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure)); 5240 } 5241 PetscFunctionReturn(0); 5242 } 5243 5244 PetscErrorCode DMCompleteBCLabels_Internal(DM dm) 5245 { 5246 DM plex; 5247 DMLabel *labels, *glabels; 5248 const char **names; 5249 char *sendNames, *recvNames; 5250 PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m; 5251 size_t len; 5252 MPI_Comm comm; 5253 PetscMPIInt rank, size, p, *counts, *displs; 5254 5255 PetscFunctionBegin; 5256 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5257 PetscCallMPI(MPI_Comm_size(comm, &size)); 5258 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5259 PetscCall(DMGetNumDS(dm, &Nds)); 5260 for (s = 0; s < Nds; ++s) { 5261 PetscDS dsBC; 5262 PetscInt numBd; 5263 5264 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC)); 5265 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5266 maxLabels += numBd; 5267 } 5268 PetscCall(PetscCalloc1(maxLabels, &labels)); 5269 /* Get list of labels to be completed */ 5270 for (s = 0; s < Nds; ++s) { 5271 PetscDS dsBC; 5272 PetscInt numBd, bd; 5273 5274 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC)); 5275 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5276 for (bd = 0; bd < numBd; ++bd) { 5277 DMLabel label; 5278 PetscInt field; 5279 PetscObject obj; 5280 PetscClassId id; 5281 5282 PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 5283 PetscCall(DMGetField(dm, field, NULL, &obj)); 5284 PetscCall(PetscObjectGetClassId(obj, &id)); 5285 if (!(id == PETSCFE_CLASSID) || !label) continue; 5286 for (l = 0; l < Nl; ++l) 5287 if (labels[l] == label) break; 5288 if (l == Nl) labels[Nl++] = label; 5289 } 5290 } 5291 /* Get label names */ 5292 PetscCall(PetscMalloc1(Nl, &names)); 5293 for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l])); 5294 for (l = 0; l < Nl; ++l) { 5295 PetscCall(PetscStrlen(names[l], &len)); 5296 maxLen = PetscMax(maxLen, (PetscInt)len + 2); 5297 } 5298 PetscCall(PetscFree(labels)); 5299 PetscCallMPI(MPI_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm)); 5300 PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames)); 5301 for (l = 0; l < Nl; ++l) PetscCall(PetscStrcpy(&sendNames[gmaxLen * l], names[l])); 5302 PetscCall(PetscFree(names)); 5303 /* Put all names on all processes */ 5304 PetscCall(PetscCalloc2(size, &counts, size + 1, &displs)); 5305 PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm)); 5306 for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p]; 5307 gNl = displs[size]; 5308 for (p = 0; p < size; ++p) { 5309 counts[p] *= gmaxLen; 5310 displs[p] *= gmaxLen; 5311 } 5312 PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels)); 5313 PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm)); 5314 PetscCall(PetscFree2(counts, displs)); 5315 PetscCall(PetscFree(sendNames)); 5316 for (l = 0, gl = 0; l < gNl; ++l) { 5317 PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl])); 5318 PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank); 5319 for (m = 0; m < gl; ++m) 5320 if (glabels[m] == glabels[gl]) continue; 5321 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5322 PetscCall(DMPlexLabelComplete(plex, glabels[gl])); 5323 PetscCall(DMDestroy(&plex)); 5324 ++gl; 5325 } 5326 PetscCall(PetscFree2(recvNames, glabels)); 5327 PetscFunctionReturn(0); 5328 } 5329 5330 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew) 5331 { 5332 DMSpace *tmpd; 5333 PetscInt Nds = dm->Nds, s; 5334 5335 PetscFunctionBegin; 5336 if (Nds >= NdsNew) PetscFunctionReturn(0); 5337 PetscCall(PetscMalloc1(NdsNew, &tmpd)); 5338 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s]; 5339 for (s = Nds; s < NdsNew; ++s) { 5340 tmpd[s].ds = NULL; 5341 tmpd[s].label = NULL; 5342 tmpd[s].fields = NULL; 5343 } 5344 PetscCall(PetscFree(dm->probs)); 5345 dm->Nds = NdsNew; 5346 dm->probs = tmpd; 5347 PetscFunctionReturn(0); 5348 } 5349 5350 /*@ 5351 DMGetNumDS - Get the number of discrete systems in the DM 5352 5353 Not collective 5354 5355 Input Parameter: 5356 . dm - The DM 5357 5358 Output Parameter: 5359 . Nds - The number of PetscDS objects 5360 5361 Level: intermediate 5362 5363 .seealso: `DMGetDS()`, `DMGetCellDS()` 5364 @*/ 5365 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds) 5366 { 5367 PetscFunctionBegin; 5368 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5369 PetscValidIntPointer(Nds, 2); 5370 *Nds = dm->Nds; 5371 PetscFunctionReturn(0); 5372 } 5373 5374 /*@ 5375 DMClearDS - Remove all discrete systems from the DM 5376 5377 Logically collective on dm 5378 5379 Input Parameter: 5380 . dm - The DM 5381 5382 Level: intermediate 5383 5384 .seealso: `DMGetNumDS()`, `DMGetDS()`, `DMSetField()` 5385 @*/ 5386 PetscErrorCode DMClearDS(DM dm) 5387 { 5388 PetscInt s; 5389 5390 PetscFunctionBegin; 5391 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5392 for (s = 0; s < dm->Nds; ++s) { 5393 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5394 PetscCall(DMLabelDestroy(&dm->probs[s].label)); 5395 PetscCall(ISDestroy(&dm->probs[s].fields)); 5396 } 5397 PetscCall(PetscFree(dm->probs)); 5398 dm->probs = NULL; 5399 dm->Nds = 0; 5400 PetscFunctionReturn(0); 5401 } 5402 5403 /*@ 5404 DMGetDS - Get the default PetscDS 5405 5406 Not collective 5407 5408 Input Parameter: 5409 . dm - The DM 5410 5411 Output Parameter: 5412 . prob - The default PetscDS 5413 5414 Level: intermediate 5415 5416 .seealso: `DMGetCellDS()`, `DMGetRegionDS()` 5417 @*/ 5418 PetscErrorCode DMGetDS(DM dm, PetscDS *prob) 5419 { 5420 PetscFunctionBeginHot; 5421 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5422 PetscValidPointer(prob, 2); 5423 if (dm->Nds <= 0) { 5424 PetscDS ds; 5425 5426 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 5427 PetscCall(DMSetRegionDS(dm, NULL, NULL, ds)); 5428 PetscCall(PetscDSDestroy(&ds)); 5429 } 5430 *prob = dm->probs[0].ds; 5431 PetscFunctionReturn(0); 5432 } 5433 5434 /*@ 5435 DMGetCellDS - Get the PetscDS defined on a given cell 5436 5437 Not collective 5438 5439 Input Parameters: 5440 + dm - The DM 5441 - point - Cell for the DS 5442 5443 Output Parameter: 5444 . prob - The PetscDS defined on the given cell 5445 5446 Level: developer 5447 5448 .seealso: `DMGetDS()`, `DMSetRegionDS()` 5449 @*/ 5450 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob) 5451 { 5452 PetscDS probDef = NULL; 5453 PetscInt s; 5454 5455 PetscFunctionBeginHot; 5456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5457 PetscValidPointer(prob, 3); 5458 PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point); 5459 *prob = NULL; 5460 for (s = 0; s < dm->Nds; ++s) { 5461 PetscInt val; 5462 5463 if (!dm->probs[s].label) { 5464 probDef = dm->probs[s].ds; 5465 } else { 5466 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val)); 5467 if (val >= 0) { 5468 *prob = dm->probs[s].ds; 5469 break; 5470 } 5471 } 5472 } 5473 if (!*prob) *prob = probDef; 5474 PetscFunctionReturn(0); 5475 } 5476 5477 /*@ 5478 DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel 5479 5480 Not collective 5481 5482 Input Parameters: 5483 + dm - The DM 5484 - label - The DMLabel defining the mesh region, or NULL for the entire mesh 5485 5486 Output Parameters: 5487 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL 5488 - prob - The PetscDS defined on the given region, or NULL 5489 5490 Note: 5491 If a non-NULL label is given, but there is no PetscDS on that specific label, 5492 the PetscDS for the full domain (if present) is returned. Returns with 5493 fields=NULL and prob=NULL if there is no PetscDS for the full domain. 5494 5495 Level: advanced 5496 5497 .seealso: `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5498 @*/ 5499 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds) 5500 { 5501 PetscInt Nds = dm->Nds, s; 5502 5503 PetscFunctionBegin; 5504 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5505 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5506 if (fields) { 5507 PetscValidPointer(fields, 3); 5508 *fields = NULL; 5509 } 5510 if (ds) { 5511 PetscValidPointer(ds, 4); 5512 *ds = NULL; 5513 } 5514 for (s = 0; s < Nds; ++s) { 5515 if (dm->probs[s].label == label || !dm->probs[s].label) { 5516 if (fields) *fields = dm->probs[s].fields; 5517 if (ds) *ds = dm->probs[s].ds; 5518 if (dm->probs[s].label) PetscFunctionReturn(0); 5519 } 5520 } 5521 PetscFunctionReturn(0); 5522 } 5523 5524 /*@ 5525 DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel` 5526 5527 Collective on dm 5528 5529 Input Parameters: 5530 + dm - The `DM` 5531 . label - The `DMLabel` defining the mesh region, or NULL for the entire mesh 5532 . fields - The IS containing the `DM` field numbers for the fields in this `PetscDS`, or NULL for all fields 5533 - prob - The `PetscDS` defined on the given region 5534 5535 Note: 5536 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced, 5537 the fields argument is ignored. 5538 5539 Level: advanced 5540 5541 .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()` 5542 @*/ 5543 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds) 5544 { 5545 PetscInt Nds = dm->Nds, s; 5546 5547 PetscFunctionBegin; 5548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5549 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5550 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4); 5551 for (s = 0; s < Nds; ++s) { 5552 if (dm->probs[s].label == label) { 5553 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5554 dm->probs[s].ds = ds; 5555 PetscFunctionReturn(0); 5556 } 5557 } 5558 PetscCall(DMDSEnlarge_Static(dm, Nds + 1)); 5559 PetscCall(PetscObjectReference((PetscObject)label)); 5560 PetscCall(PetscObjectReference((PetscObject)fields)); 5561 PetscCall(PetscObjectReference((PetscObject)ds)); 5562 if (!label) { 5563 /* Put the NULL label at the front, so it is returned as the default */ 5564 for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s]; 5565 Nds = 0; 5566 } 5567 dm->probs[Nds].label = label; 5568 dm->probs[Nds].fields = fields; 5569 dm->probs[Nds].ds = ds; 5570 PetscFunctionReturn(0); 5571 } 5572 5573 /*@ 5574 DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number 5575 5576 Not collective 5577 5578 Input Parameters: 5579 + dm - The DM 5580 - num - The region number, in [0, Nds) 5581 5582 Output Parameters: 5583 + label - The region label, or NULL 5584 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL 5585 - ds - The PetscDS defined on the given region, or NULL 5586 5587 Level: advanced 5588 5589 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5590 @*/ 5591 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds) 5592 { 5593 PetscInt Nds; 5594 5595 PetscFunctionBegin; 5596 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5597 PetscCall(DMGetNumDS(dm, &Nds)); 5598 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5599 if (label) { 5600 PetscValidPointer(label, 3); 5601 *label = dm->probs[num].label; 5602 } 5603 if (fields) { 5604 PetscValidPointer(fields, 4); 5605 *fields = dm->probs[num].fields; 5606 } 5607 if (ds) { 5608 PetscValidPointer(ds, 5); 5609 *ds = dm->probs[num].ds; 5610 } 5611 PetscFunctionReturn(0); 5612 } 5613 5614 /*@ 5615 DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number 5616 5617 Not collective 5618 5619 Input Parameters: 5620 + dm - The DM 5621 . num - The region number, in [0, Nds) 5622 . label - The region label, or NULL 5623 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting 5624 - ds - The PetscDS defined on the given region, or NULL to prevent setting 5625 5626 Level: advanced 5627 5628 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5629 @*/ 5630 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds) 5631 { 5632 PetscInt Nds; 5633 5634 PetscFunctionBegin; 5635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5636 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5637 PetscCall(DMGetNumDS(dm, &Nds)); 5638 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5639 PetscCall(PetscObjectReference((PetscObject)label)); 5640 PetscCall(DMLabelDestroy(&dm->probs[num].label)); 5641 dm->probs[num].label = label; 5642 if (fields) { 5643 PetscValidHeaderSpecific(fields, IS_CLASSID, 4); 5644 PetscCall(PetscObjectReference((PetscObject)fields)); 5645 PetscCall(ISDestroy(&dm->probs[num].fields)); 5646 dm->probs[num].fields = fields; 5647 } 5648 if (ds) { 5649 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5); 5650 PetscCall(PetscObjectReference((PetscObject)ds)); 5651 PetscCall(PetscDSDestroy(&dm->probs[num].ds)); 5652 dm->probs[num].ds = ds; 5653 } 5654 PetscFunctionReturn(0); 5655 } 5656 5657 /*@ 5658 DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found. 5659 5660 Not collective 5661 5662 Input Parameters: 5663 + dm - The DM 5664 - ds - The PetscDS defined on the given region 5665 5666 Output Parameter: 5667 . num - The region number, in [0, Nds), or -1 if not found 5668 5669 Level: advanced 5670 5671 .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5672 @*/ 5673 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num) 5674 { 5675 PetscInt Nds, n; 5676 5677 PetscFunctionBegin; 5678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5679 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2); 5680 PetscValidIntPointer(num, 3); 5681 PetscCall(DMGetNumDS(dm, &Nds)); 5682 for (n = 0; n < Nds; ++n) 5683 if (ds == dm->probs[n].ds) break; 5684 if (n >= Nds) *num = -1; 5685 else *num = n; 5686 PetscFunctionReturn(0); 5687 } 5688 5689 /*@C 5690 DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh 5691 5692 Not collective 5693 5694 Input Parameters: 5695 + dm - The `DM` 5696 . Nc - The number of components for the field 5697 . prefix - The options prefix for the output `PetscFE`, or NULL 5698 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree 5699 5700 Output Parameter: 5701 . fem - The `PetscFE` 5702 5703 Note: 5704 This is a convenience method that just calls `PetscFECreateByCell()` underneath. 5705 5706 Level: intermediate 5707 5708 .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()` 5709 @*/ 5710 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem) 5711 { 5712 DMPolytopeType ct; 5713 PetscInt dim, cStart; 5714 5715 PetscFunctionBegin; 5716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5717 PetscValidLogicalCollectiveInt(dm, Nc, 2); 5718 if (prefix) PetscValidCharPointer(prefix, 3); 5719 PetscValidLogicalCollectiveInt(dm, qorder, 4); 5720 PetscValidPointer(fem, 5); 5721 PetscCall(DMGetDimension(dm, &dim)); 5722 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 5723 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 5724 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem)); 5725 PetscFunctionReturn(0); 5726 } 5727 5728 /*@ 5729 DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM` 5730 5731 Collective on dm 5732 5733 Input Parameter: 5734 . dm - The `DM` 5735 5736 Options Database Keys: 5737 . -dm_petscds_view - View all the `PetscDS` objects in this `DM` 5738 5739 Note: 5740 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. 5741 5742 Level: intermediate 5743 5744 .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 5745 @*/ 5746 PetscErrorCode DMCreateDS(DM dm) 5747 { 5748 MPI_Comm comm; 5749 PetscDS dsDef; 5750 DMLabel *labelSet; 5751 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k; 5752 PetscBool doSetup = PETSC_TRUE, flg; 5753 5754 PetscFunctionBegin; 5755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5756 if (!dm->fields) PetscFunctionReturn(0); 5757 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5758 PetscCall(DMGetCoordinateDim(dm, &dE)); 5759 /* Determine how many regions we have */ 5760 PetscCall(PetscMalloc1(Nf, &labelSet)); 5761 Nl = 0; 5762 Ndef = 0; 5763 for (f = 0; f < Nf; ++f) { 5764 DMLabel label = dm->fields[f].label; 5765 PetscInt l; 5766 5767 #ifdef PETSC_HAVE_LIBCEED 5768 /* Move CEED context to discretizations */ 5769 { 5770 PetscClassId id; 5771 5772 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id)); 5773 if (id == PETSCFE_CLASSID) { 5774 Ceed ceed; 5775 5776 PetscCall(DMGetCeed(dm, &ceed)); 5777 PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed)); 5778 } 5779 } 5780 #endif 5781 if (!label) { 5782 ++Ndef; 5783 continue; 5784 } 5785 for (l = 0; l < Nl; ++l) 5786 if (label == labelSet[l]) break; 5787 if (l < Nl) continue; 5788 labelSet[Nl++] = label; 5789 } 5790 /* Create default DS if there are no labels to intersect with */ 5791 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef)); 5792 if (!dsDef && Ndef && !Nl) { 5793 IS fields; 5794 PetscInt *fld, nf; 5795 5796 for (f = 0, nf = 0; f < Nf; ++f) 5797 if (!dm->fields[f].label) ++nf; 5798 PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS"); 5799 PetscCall(PetscMalloc1(nf, &fld)); 5800 for (f = 0, nf = 0; f < Nf; ++f) 5801 if (!dm->fields[f].label) fld[nf++] = f; 5802 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5803 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5804 PetscCall(ISSetType(fields, ISGENERAL)); 5805 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5806 5807 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5808 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef)); 5809 PetscCall(PetscDSDestroy(&dsDef)); 5810 PetscCall(ISDestroy(&fields)); 5811 } 5812 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef)); 5813 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5814 /* Intersect labels with default fields */ 5815 if (Ndef && Nl) { 5816 DM plex; 5817 DMLabel cellLabel; 5818 IS fieldIS, allcellIS, defcellIS = NULL; 5819 PetscInt *fields; 5820 const PetscInt *cells; 5821 PetscInt depth, nf = 0, n, c; 5822 5823 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5824 PetscCall(DMPlexGetDepth(plex, &depth)); 5825 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS)); 5826 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS)); 5827 /* TODO This looks like it only works for one label */ 5828 for (l = 0; l < Nl; ++l) { 5829 DMLabel label = labelSet[l]; 5830 IS pointIS; 5831 5832 PetscCall(ISDestroy(&defcellIS)); 5833 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 5834 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS)); 5835 PetscCall(ISDestroy(&pointIS)); 5836 } 5837 PetscCall(ISDestroy(&allcellIS)); 5838 5839 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel)); 5840 PetscCall(ISGetLocalSize(defcellIS, &n)); 5841 PetscCall(ISGetIndices(defcellIS, &cells)); 5842 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1)); 5843 PetscCall(ISRestoreIndices(defcellIS, &cells)); 5844 PetscCall(ISDestroy(&defcellIS)); 5845 PetscCall(DMPlexLabelComplete(plex, cellLabel)); 5846 5847 PetscCall(PetscMalloc1(Ndef, &fields)); 5848 for (f = 0; f < Nf; ++f) 5849 if (!dm->fields[f].label) fields[nf++] = f; 5850 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS)); 5851 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_")); 5852 PetscCall(ISSetType(fieldIS, ISGENERAL)); 5853 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER)); 5854 5855 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5856 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef)); 5857 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5858 PetscCall(DMLabelDestroy(&cellLabel)); 5859 PetscCall(PetscDSDestroy(&dsDef)); 5860 PetscCall(ISDestroy(&fieldIS)); 5861 PetscCall(DMDestroy(&plex)); 5862 } 5863 /* Create label DSes 5864 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS 5865 */ 5866 /* TODO Should check that labels are disjoint */ 5867 for (l = 0; l < Nl; ++l) { 5868 DMLabel label = labelSet[l]; 5869 PetscDS ds; 5870 IS fields; 5871 PetscInt *fld, nf; 5872 5873 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 5874 for (f = 0, nf = 0; f < Nf; ++f) 5875 if (label == dm->fields[f].label || !dm->fields[f].label) ++nf; 5876 PetscCall(PetscMalloc1(nf, &fld)); 5877 for (f = 0, nf = 0; f < Nf; ++f) 5878 if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f; 5879 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5880 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5881 PetscCall(ISSetType(fields, ISGENERAL)); 5882 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5883 PetscCall(DMSetRegionDS(dm, label, fields, ds)); 5884 PetscCall(ISDestroy(&fields)); 5885 PetscCall(PetscDSSetCoordinateDimension(ds, dE)); 5886 { 5887 DMPolytopeType ct; 5888 PetscInt lStart, lEnd; 5889 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive; 5890 5891 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd)); 5892 if (lStart >= 0) { 5893 PetscCall(DMPlexGetCellType(dm, lStart, &ct)); 5894 switch (ct) { 5895 case DM_POLYTOPE_POINT_PRISM_TENSOR: 5896 case DM_POLYTOPE_SEG_PRISM_TENSOR: 5897 case DM_POLYTOPE_TRI_PRISM_TENSOR: 5898 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 5899 isCohesiveLocal = PETSC_TRUE; 5900 break; 5901 default: 5902 break; 5903 } 5904 } 5905 PetscCallMPI(MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm)); 5906 for (f = 0, nf = 0; f < Nf; ++f) { 5907 if (label == dm->fields[f].label || !dm->fields[f].label) { 5908 if (label == dm->fields[f].label) { 5909 PetscCall(PetscDSSetDiscretization(ds, nf, NULL)); 5910 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive)); 5911 } 5912 ++nf; 5913 } 5914 } 5915 } 5916 PetscCall(PetscDSDestroy(&ds)); 5917 } 5918 PetscCall(PetscFree(labelSet)); 5919 /* Set fields in DSes */ 5920 for (s = 0; s < dm->Nds; ++s) { 5921 PetscDS ds = dm->probs[s].ds; 5922 IS fields = dm->probs[s].fields; 5923 const PetscInt *fld; 5924 PetscInt nf, dsnf; 5925 PetscBool isCohesive; 5926 5927 PetscCall(PetscDSGetNumFields(ds, &dsnf)); 5928 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 5929 PetscCall(ISGetLocalSize(fields, &nf)); 5930 PetscCall(ISGetIndices(fields, &fld)); 5931 for (f = 0; f < nf; ++f) { 5932 PetscObject disc = dm->fields[fld[f]].disc; 5933 PetscBool isCohesiveField; 5934 PetscClassId id; 5935 5936 /* Handle DS with no fields */ 5937 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 5938 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */ 5939 if (isCohesive && !isCohesiveField) PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&disc)); 5940 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 5941 /* We allow people to have placeholder fields and construct the Section by hand */ 5942 PetscCall(PetscObjectGetClassId(disc, &id)); 5943 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE; 5944 } 5945 PetscCall(ISRestoreIndices(fields, &fld)); 5946 } 5947 /* Allow k-jet tabulation */ 5948 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg)); 5949 if (flg) { 5950 for (s = 0; s < dm->Nds; ++s) { 5951 PetscDS ds = dm->probs[s].ds; 5952 PetscInt Nf, f; 5953 5954 PetscCall(PetscDSGetNumFields(ds, &Nf)); 5955 for (f = 0; f < Nf; ++f) PetscCall(PetscDSSetJetDegree(ds, f, k)); 5956 } 5957 } 5958 /* Setup DSes */ 5959 if (doSetup) { 5960 for (s = 0; s < dm->Nds; ++s) PetscCall(PetscDSSetUp(dm->probs[s].ds)); 5961 } 5962 PetscFunctionReturn(0); 5963 } 5964 5965 /*@ 5966 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information. 5967 5968 Collective on `DM` 5969 5970 Input Parameters: 5971 + dm - The `DM` 5972 - time - The time 5973 5974 Output Parameters: 5975 + u - The vector will be filled with exact solution values, or NULL 5976 - u_t - The vector will be filled with the time derivative of exact solution values, or NULL 5977 5978 Note: 5979 The user must call `PetscDSSetExactSolution()` before using this routine 5980 5981 Level: developer 5982 5983 .seealso: `PetscDSSetExactSolution()` 5984 @*/ 5985 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 5986 { 5987 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 5988 void **ectxs; 5989 PetscInt Nf, Nds, s; 5990 5991 PetscFunctionBegin; 5992 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5993 if (u) PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 5994 if (u_t) PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 5995 PetscCall(DMGetNumFields(dm, &Nf)); 5996 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 5997 PetscCall(DMGetNumDS(dm, &Nds)); 5998 for (s = 0; s < Nds; ++s) { 5999 PetscDS ds; 6000 DMLabel label; 6001 IS fieldIS; 6002 const PetscInt *fields, id = 1; 6003 PetscInt dsNf, f; 6004 6005 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 6006 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 6007 PetscCall(ISGetIndices(fieldIS, &fields)); 6008 PetscCall(PetscArrayzero(exacts, Nf)); 6009 PetscCall(PetscArrayzero(ectxs, Nf)); 6010 if (u) { 6011 for (f = 0; f < dsNf; ++f) { 6012 const PetscInt field = fields[f]; 6013 PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field])); 6014 } 6015 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6016 if (label) { 6017 PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u)); 6018 } else { 6019 PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u)); 6020 } 6021 } 6022 if (u_t) { 6023 PetscCall(PetscArrayzero(exacts, Nf)); 6024 PetscCall(PetscArrayzero(ectxs, Nf)); 6025 for (f = 0; f < dsNf; ++f) { 6026 const PetscInt field = fields[f]; 6027 PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field])); 6028 } 6029 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6030 if (label) { 6031 PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t)); 6032 } else { 6033 PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t)); 6034 } 6035 } 6036 } 6037 if (u) { 6038 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution")); 6039 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_")); 6040 } 6041 if (u_t) { 6042 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative")); 6043 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_")); 6044 } 6045 PetscCall(PetscFree2(exacts, ectxs)); 6046 PetscFunctionReturn(0); 6047 } 6048 6049 PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds) 6050 { 6051 PetscDS dsNew; 6052 DSBoundary b; 6053 PetscInt cdim, Nf, f, d; 6054 PetscBool isCohesive; 6055 void *ctx; 6056 6057 PetscFunctionBegin; 6058 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew)); 6059 PetscCall(PetscDSCopyConstants(ds, dsNew)); 6060 PetscCall(PetscDSCopyExactSolutions(ds, dsNew)); 6061 PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew)); 6062 PetscCall(PetscDSCopyEquations(ds, dsNew)); 6063 PetscCall(PetscDSGetNumFields(ds, &Nf)); 6064 for (f = 0; f < Nf; ++f) { 6065 PetscCall(PetscDSGetContext(ds, f, &ctx)); 6066 PetscCall(PetscDSSetContext(dsNew, f, ctx)); 6067 PetscCall(PetscDSGetCohesive(ds, f, &isCohesive)); 6068 PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive)); 6069 PetscCall(PetscDSGetJetDegree(ds, f, &d)); 6070 PetscCall(PetscDSSetJetDegree(dsNew, f, d)); 6071 } 6072 if (Nf) { 6073 PetscCall(PetscDSGetCoordinateDimension(ds, &cdim)); 6074 PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim)); 6075 } 6076 PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew)); 6077 for (b = dsNew->boundary; b; b = b->next) { 6078 PetscCall(DMGetLabel(dm, b->lname, &b->label)); 6079 /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */ 6080 //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name); 6081 } 6082 6083 PetscCall(DMSetRegionDS(dm, label, fields, dsNew)); 6084 PetscCall(PetscDSDestroy(&dsNew)); 6085 PetscFunctionReturn(0); 6086 } 6087 6088 /*@ 6089 DMCopyDS - Copy the discrete systems for the `DM` into another `DM` 6090 6091 Collective on dm 6092 6093 Input Parameter: 6094 . dm - The `DM` 6095 6096 Output Parameter: 6097 . newdm - The `DM` 6098 6099 Level: advanced 6100 6101 .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 6102 @*/ 6103 PetscErrorCode DMCopyDS(DM dm, DM newdm) 6104 { 6105 PetscInt Nds, s; 6106 6107 PetscFunctionBegin; 6108 if (dm == newdm) PetscFunctionReturn(0); 6109 PetscCall(DMGetNumDS(dm, &Nds)); 6110 PetscCall(DMClearDS(newdm)); 6111 for (s = 0; s < Nds; ++s) { 6112 DMLabel label; 6113 IS fields; 6114 PetscDS ds, newds; 6115 PetscInt Nbd, bd; 6116 6117 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds)); 6118 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 6119 PetscCall(DMTransferDS_Internal(newdm, label, fields, ds)); 6120 /* Commplete new labels in the new DS */ 6121 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds)); 6122 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 6123 for (bd = 0; bd < Nbd; ++bd) { 6124 PetscWeakForm wf; 6125 DMLabel label; 6126 PetscInt field; 6127 6128 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 6129 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 6130 } 6131 } 6132 PetscCall(DMCompleteBCLabels_Internal(newdm)); 6133 PetscFunctionReturn(0); 6134 } 6135 6136 /*@ 6137 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM` 6138 6139 Collective on dm 6140 6141 Input Parameter: 6142 . dm - The `DM` 6143 6144 Output Parameter: 6145 . newdm - The `DM` 6146 6147 Level: advanced 6148 6149 Developer Note: 6150 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation 6151 6152 .seealso: `DMCopyFields()`, `DMCopyDS()` 6153 @*/ 6154 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6155 { 6156 PetscFunctionBegin; 6157 PetscCall(DMCopyFields(dm, newdm)); 6158 PetscCall(DMCopyDS(dm, newdm)); 6159 PetscFunctionReturn(0); 6160 } 6161 6162 /*@ 6163 DMGetDimension - Return the topological dimension of the `DM` 6164 6165 Not collective 6166 6167 Input Parameter: 6168 . dm - The `DM` 6169 6170 Output Parameter: 6171 . dim - The topological dimension 6172 6173 Level: beginner 6174 6175 .seealso: `DMSetDimension()`, `DMCreate()` 6176 @*/ 6177 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6178 { 6179 PetscFunctionBegin; 6180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6181 PetscValidIntPointer(dim, 2); 6182 *dim = dm->dim; 6183 PetscFunctionReturn(0); 6184 } 6185 6186 /*@ 6187 DMSetDimension - Set the topological dimension of the `DM` 6188 6189 Collective on dm 6190 6191 Input Parameters: 6192 + dm - The `DM` 6193 - dim - The topological dimension 6194 6195 Level: beginner 6196 6197 .seealso: `DMGetDimension()`, `DMCreate()` 6198 @*/ 6199 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6200 { 6201 PetscDS ds; 6202 PetscInt Nds, n; 6203 6204 PetscFunctionBegin; 6205 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6206 PetscValidLogicalCollectiveInt(dm, dim, 2); 6207 dm->dim = dim; 6208 if (dm->dim >= 0) { 6209 PetscCall(DMGetNumDS(dm, &Nds)); 6210 for (n = 0; n < Nds; ++n) { 6211 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds)); 6212 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6213 } 6214 } 6215 PetscFunctionReturn(0); 6216 } 6217 6218 /*@ 6219 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6220 6221 Collective on dm 6222 6223 Input Parameters: 6224 + dm - the `DM` 6225 - dim - the dimension 6226 6227 Output Parameters: 6228 + pStart - The first point of the given dimension 6229 - pEnd - The first point following points of the given dimension 6230 6231 Note: 6232 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6233 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6234 then the interval is empty. 6235 6236 Level: intermediate 6237 6238 .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 6239 @*/ 6240 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6241 { 6242 PetscInt d; 6243 6244 PetscFunctionBegin; 6245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6246 PetscCall(DMGetDimension(dm, &d)); 6247 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6248 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd); 6249 PetscFunctionReturn(0); 6250 } 6251 6252 /*@ 6253 DMGetOutputDM - Retrieve the `DM` associated with the layout for output 6254 6255 Collective on dm 6256 6257 Input Parameter: 6258 . dm - The original `DM` 6259 6260 Output Parameter: 6261 . odm - The `DM` which provides the layout for output 6262 6263 Level: intermediate 6264 6265 Note: 6266 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary 6267 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the 6268 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof. 6269 6270 .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()` 6271 @*/ 6272 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 6273 { 6274 PetscSection section; 6275 PetscBool hasConstraints, ghasConstraints; 6276 6277 PetscFunctionBegin; 6278 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6279 PetscValidPointer(odm, 2); 6280 PetscCall(DMGetLocalSection(dm, §ion)); 6281 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 6282 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 6283 if (!ghasConstraints) { 6284 *odm = dm; 6285 PetscFunctionReturn(0); 6286 } 6287 if (!dm->dmBC) { 6288 PetscSection newSection, gsection; 6289 PetscSF sf; 6290 6291 PetscCall(DMClone(dm, &dm->dmBC)); 6292 PetscCall(DMCopyDisc(dm, dm->dmBC)); 6293 PetscCall(PetscSectionClone(section, &newSection)); 6294 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 6295 PetscCall(PetscSectionDestroy(&newSection)); 6296 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 6297 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 6298 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 6299 PetscCall(PetscSectionDestroy(&gsection)); 6300 } 6301 *odm = dm->dmBC; 6302 PetscFunctionReturn(0); 6303 } 6304 6305 /*@ 6306 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 6307 6308 Input Parameter: 6309 . dm - The original `DM` 6310 6311 Output Parameters: 6312 + num - The output sequence number 6313 - val - The output sequence value 6314 6315 Level: intermediate 6316 6317 Note: 6318 This is intended for output that should appear in sequence, for instance 6319 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6320 6321 Developer Note: 6322 The `DM` serves as a convenient place to store the current iteration value. The iteration is not 6323 not directly related to the `DM`. 6324 6325 .seealso: `VecView()` 6326 @*/ 6327 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 6328 { 6329 PetscFunctionBegin; 6330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6331 if (num) { 6332 PetscValidIntPointer(num, 2); 6333 *num = dm->outputSequenceNum; 6334 } 6335 if (val) { 6336 PetscValidRealPointer(val, 3); 6337 *val = dm->outputSequenceVal; 6338 } 6339 PetscFunctionReturn(0); 6340 } 6341 6342 /*@ 6343 DMSetOutputSequenceNumber - Set the sequence number/value for output 6344 6345 Input Parameters: 6346 + dm - The original `DM` 6347 . num - The output sequence number 6348 - val - The output sequence value 6349 6350 Level: intermediate 6351 6352 Note: 6353 This is intended for output that should appear in sequence, for instance 6354 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6355 6356 .seealso: `VecView()` 6357 @*/ 6358 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 6359 { 6360 PetscFunctionBegin; 6361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6362 dm->outputSequenceNum = num; 6363 dm->outputSequenceVal = val; 6364 PetscFunctionReturn(0); 6365 } 6366 6367 /*@C 6368 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer` 6369 6370 Input Parameters: 6371 + dm - The original `DM` 6372 . name - The sequence name 6373 - num - The output sequence number 6374 6375 Output Parameter: 6376 . val - The output sequence value 6377 6378 Level: intermediate 6379 6380 Note: 6381 This is intended for output that should appear in sequence, for instance 6382 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6383 6384 Developer Note: 6385 It is unclear at the user API level why a `DM` is needed as input 6386 6387 .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6388 @*/ 6389 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val) 6390 { 6391 PetscBool ishdf5; 6392 6393 PetscFunctionBegin; 6394 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6395 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6396 PetscValidRealPointer(val, 5); 6397 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6398 if (ishdf5) { 6399 #if defined(PETSC_HAVE_HDF5) 6400 PetscScalar value; 6401 6402 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 6403 *val = PetscRealPart(value); 6404 #endif 6405 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6406 PetscFunctionReturn(0); 6407 } 6408 6409 /*@ 6410 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6411 6412 Not collective 6413 6414 Input Parameter: 6415 . dm - The `DM` 6416 6417 Output Parameter: 6418 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6419 6420 Level: beginner 6421 6422 .seealso: `DMSetUseNatural()`, `DMCreate()` 6423 @*/ 6424 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6425 { 6426 PetscFunctionBegin; 6427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6428 PetscValidBoolPointer(useNatural, 2); 6429 *useNatural = dm->useNatural; 6430 PetscFunctionReturn(0); 6431 } 6432 6433 /*@ 6434 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6435 6436 Collective on dm 6437 6438 Input Parameters: 6439 + dm - The `DM` 6440 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6441 6442 Note: 6443 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6444 6445 Level: beginner 6446 6447 .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6448 @*/ 6449 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6450 { 6451 PetscFunctionBegin; 6452 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6453 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6454 dm->useNatural = useNatural; 6455 PetscFunctionReturn(0); 6456 } 6457 6458 /*@C 6459 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6460 6461 Not Collective 6462 6463 Input Parameters: 6464 + dm - The `DM` object 6465 - name - The label name 6466 6467 Level: intermediate 6468 6469 .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6470 @*/ 6471 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6472 { 6473 PetscBool flg; 6474 DMLabel label; 6475 6476 PetscFunctionBegin; 6477 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6478 PetscValidCharPointer(name, 2); 6479 PetscCall(DMHasLabel(dm, name, &flg)); 6480 if (!flg) { 6481 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6482 PetscCall(DMAddLabel(dm, label)); 6483 PetscCall(DMLabelDestroy(&label)); 6484 } 6485 PetscFunctionReturn(0); 6486 } 6487 6488 /*@C 6489 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6490 6491 Not Collective 6492 6493 Input Parameters: 6494 + dm - The `DM` object 6495 . l - The index for the label 6496 - name - The label name 6497 6498 Level: intermediate 6499 6500 .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6501 @*/ 6502 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6503 { 6504 DMLabelLink orig, prev = NULL; 6505 DMLabel label; 6506 PetscInt Nl, m; 6507 PetscBool flg, match; 6508 const char *lname; 6509 6510 PetscFunctionBegin; 6511 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6512 PetscValidCharPointer(name, 3); 6513 PetscCall(DMHasLabel(dm, name, &flg)); 6514 if (!flg) { 6515 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6516 PetscCall(DMAddLabel(dm, label)); 6517 PetscCall(DMLabelDestroy(&label)); 6518 } 6519 PetscCall(DMGetNumLabels(dm, &Nl)); 6520 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6521 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6522 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6523 PetscCall(PetscStrcmp(name, lname, &match)); 6524 if (match) break; 6525 } 6526 if (m == l) PetscFunctionReturn(0); 6527 if (!m) dm->labels = orig->next; 6528 else prev->next = orig->next; 6529 if (!l) { 6530 orig->next = dm->labels; 6531 dm->labels = orig; 6532 } else { 6533 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next) 6534 ; 6535 orig->next = prev->next; 6536 prev->next = orig; 6537 } 6538 PetscFunctionReturn(0); 6539 } 6540 6541 /*@C 6542 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6543 6544 Not Collective 6545 6546 Input Parameters: 6547 + dm - The `DM` object 6548 . name - The label name 6549 - point - The mesh point 6550 6551 Output Parameter: 6552 . value - The label value for this point, or -1 if the point is not in the label 6553 6554 Level: beginner 6555 6556 .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6557 @*/ 6558 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6559 { 6560 DMLabel label; 6561 6562 PetscFunctionBegin; 6563 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6564 PetscValidCharPointer(name, 2); 6565 PetscCall(DMGetLabel(dm, name, &label)); 6566 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6567 PetscCall(DMLabelGetValue(label, point, value)); 6568 PetscFunctionReturn(0); 6569 } 6570 6571 /*@C 6572 DMSetLabelValue - Add a point to a `DMLabel` with given value 6573 6574 Not Collective 6575 6576 Input Parameters: 6577 + dm - The `DM` object 6578 . name - The label name 6579 . point - The mesh point 6580 - value - The label value for this point 6581 6582 Output Parameter: 6583 6584 Level: beginner 6585 6586 .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6587 @*/ 6588 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6589 { 6590 DMLabel label; 6591 6592 PetscFunctionBegin; 6593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6594 PetscValidCharPointer(name, 2); 6595 PetscCall(DMGetLabel(dm, name, &label)); 6596 if (!label) { 6597 PetscCall(DMCreateLabel(dm, name)); 6598 PetscCall(DMGetLabel(dm, name, &label)); 6599 } 6600 PetscCall(DMLabelSetValue(label, point, value)); 6601 PetscFunctionReturn(0); 6602 } 6603 6604 /*@C 6605 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6606 6607 Not Collective 6608 6609 Input Parameters: 6610 + dm - The `DM` object 6611 . name - The label name 6612 . point - The mesh point 6613 - value - The label value for this point 6614 6615 Level: beginner 6616 6617 .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6618 @*/ 6619 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6620 { 6621 DMLabel label; 6622 6623 PetscFunctionBegin; 6624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6625 PetscValidCharPointer(name, 2); 6626 PetscCall(DMGetLabel(dm, name, &label)); 6627 if (!label) PetscFunctionReturn(0); 6628 PetscCall(DMLabelClearValue(label, point, value)); 6629 PetscFunctionReturn(0); 6630 } 6631 6632 /*@C 6633 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6634 6635 Not Collective 6636 6637 Input Parameters: 6638 + dm - The `DM` object 6639 - name - The label name 6640 6641 Output Parameter: 6642 . size - The number of different integer ids, or 0 if the label does not exist 6643 6644 Level: beginner 6645 6646 Developer Note: 6647 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6648 6649 .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6650 @*/ 6651 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6652 { 6653 DMLabel label; 6654 6655 PetscFunctionBegin; 6656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6657 PetscValidCharPointer(name, 2); 6658 PetscValidIntPointer(size, 3); 6659 PetscCall(DMGetLabel(dm, name, &label)); 6660 *size = 0; 6661 if (!label) PetscFunctionReturn(0); 6662 PetscCall(DMLabelGetNumValues(label, size)); 6663 PetscFunctionReturn(0); 6664 } 6665 6666 /*@C 6667 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6668 6669 Not Collective 6670 6671 Input Parameters: 6672 + mesh - The `DM` object 6673 - name - The label name 6674 6675 Output Parameter: 6676 . ids - The integer ids, or NULL if the label does not exist 6677 6678 Level: beginner 6679 6680 .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()` 6681 @*/ 6682 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6683 { 6684 DMLabel label; 6685 6686 PetscFunctionBegin; 6687 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6688 PetscValidCharPointer(name, 2); 6689 PetscValidPointer(ids, 3); 6690 PetscCall(DMGetLabel(dm, name, &label)); 6691 *ids = NULL; 6692 if (label) { 6693 PetscCall(DMLabelGetValueIS(label, ids)); 6694 } else { 6695 /* returning an empty IS */ 6696 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 6697 } 6698 PetscFunctionReturn(0); 6699 } 6700 6701 /*@C 6702 DMGetStratumSize - Get the number of points in a label stratum 6703 6704 Not Collective 6705 6706 Input Parameters: 6707 + dm - The `DM` object 6708 . name - The label name 6709 - value - The stratum value 6710 6711 Output Parameter: 6712 . size - The number of points, also called the stratum size 6713 6714 Level: beginner 6715 6716 .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 6717 @*/ 6718 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 6719 { 6720 DMLabel label; 6721 6722 PetscFunctionBegin; 6723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6724 PetscValidCharPointer(name, 2); 6725 PetscValidIntPointer(size, 4); 6726 PetscCall(DMGetLabel(dm, name, &label)); 6727 *size = 0; 6728 if (!label) PetscFunctionReturn(0); 6729 PetscCall(DMLabelGetStratumSize(label, value, size)); 6730 PetscFunctionReturn(0); 6731 } 6732 6733 /*@C 6734 DMGetStratumIS - Get the points in a label stratum 6735 6736 Not Collective 6737 6738 Input Parameters: 6739 + dm - The `DM` object 6740 . name - The label name 6741 - value - The stratum value 6742 6743 Output Parameter: 6744 . points - The stratum points, or NULL if the label does not exist or does not have that value 6745 6746 Level: beginner 6747 6748 .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()` 6749 @*/ 6750 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 6751 { 6752 DMLabel label; 6753 6754 PetscFunctionBegin; 6755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6756 PetscValidCharPointer(name, 2); 6757 PetscValidPointer(points, 4); 6758 PetscCall(DMGetLabel(dm, name, &label)); 6759 *points = NULL; 6760 if (!label) PetscFunctionReturn(0); 6761 PetscCall(DMLabelGetStratumIS(label, value, points)); 6762 PetscFunctionReturn(0); 6763 } 6764 6765 /*@C 6766 DMSetStratumIS - Set the points in a label stratum 6767 6768 Not Collective 6769 6770 Input Parameters: 6771 + dm - The `DM` object 6772 . name - The label name 6773 . value - The stratum value 6774 - points - The stratum points 6775 6776 Level: beginner 6777 6778 .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 6779 @*/ 6780 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 6781 { 6782 DMLabel label; 6783 6784 PetscFunctionBegin; 6785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6786 PetscValidCharPointer(name, 2); 6787 PetscValidPointer(points, 4); 6788 PetscCall(DMGetLabel(dm, name, &label)); 6789 if (!label) PetscFunctionReturn(0); 6790 PetscCall(DMLabelSetStratumIS(label, value, points)); 6791 PetscFunctionReturn(0); 6792 } 6793 6794 /*@C 6795 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 6796 6797 Not Collective 6798 6799 Input Parameters: 6800 + dm - The `DM` object 6801 . name - The label name 6802 - value - The label value for this point 6803 6804 Output Parameter: 6805 6806 Level: beginner 6807 6808 .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6809 @*/ 6810 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 6811 { 6812 DMLabel label; 6813 6814 PetscFunctionBegin; 6815 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6816 PetscValidCharPointer(name, 2); 6817 PetscCall(DMGetLabel(dm, name, &label)); 6818 if (!label) PetscFunctionReturn(0); 6819 PetscCall(DMLabelClearStratum(label, value)); 6820 PetscFunctionReturn(0); 6821 } 6822 6823 /*@ 6824 DMGetNumLabels - Return the number of labels defined by on the `DM` 6825 6826 Not Collective 6827 6828 Input Parameter: 6829 . dm - The `DM` object 6830 6831 Output Parameter: 6832 . numLabels - the number of Labels 6833 6834 Level: intermediate 6835 6836 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6837 @*/ 6838 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 6839 { 6840 DMLabelLink next = dm->labels; 6841 PetscInt n = 0; 6842 6843 PetscFunctionBegin; 6844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6845 PetscValidIntPointer(numLabels, 2); 6846 while (next) { 6847 ++n; 6848 next = next->next; 6849 } 6850 *numLabels = n; 6851 PetscFunctionReturn(0); 6852 } 6853 6854 /*@C 6855 DMGetLabelName - Return the name of nth label 6856 6857 Not Collective 6858 6859 Input Parameters: 6860 + dm - The `DM` object 6861 - n - the label number 6862 6863 Output Parameter: 6864 . name - the label name 6865 6866 Level: intermediate 6867 6868 Developer Note: 6869 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 6870 6871 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6872 @*/ 6873 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name) 6874 { 6875 DMLabelLink next = dm->labels; 6876 PetscInt l = 0; 6877 6878 PetscFunctionBegin; 6879 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6880 PetscValidPointer(name, 3); 6881 while (next) { 6882 if (l == n) { 6883 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 6884 PetscFunctionReturn(0); 6885 } 6886 ++l; 6887 next = next->next; 6888 } 6889 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 6890 } 6891 6892 /*@C 6893 DMHasLabel - Determine whether the `DM` has a label of a given name 6894 6895 Not Collective 6896 6897 Input Parameters: 6898 + dm - The `DM` object 6899 - name - The label name 6900 6901 Output Parameter: 6902 . hasLabel - `PETSC_TRUE` if the label is present 6903 6904 Level: intermediate 6905 6906 .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6907 @*/ 6908 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 6909 { 6910 DMLabelLink next = dm->labels; 6911 const char *lname; 6912 6913 PetscFunctionBegin; 6914 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6915 PetscValidCharPointer(name, 2); 6916 PetscValidBoolPointer(hasLabel, 3); 6917 *hasLabel = PETSC_FALSE; 6918 while (next) { 6919 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 6920 PetscCall(PetscStrcmp(name, lname, hasLabel)); 6921 if (*hasLabel) break; 6922 next = next->next; 6923 } 6924 PetscFunctionReturn(0); 6925 } 6926 6927 /*@C 6928 DMGetLabel - Return the label of a given name, or NULL, from a `DM` 6929 6930 Not Collective 6931 6932 Input Parameters: 6933 + dm - The `DM` object 6934 - name - The label name 6935 6936 Output Parameter: 6937 . label - The `DMLabel`, or NULL if the label is absent 6938 6939 Default labels in a `DMPLEX`: 6940 + "depth" - Holds the depth (co-dimension) of each mesh point 6941 . "celltype" - Holds the topological type of each cell 6942 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 6943 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 6944 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 6945 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 6946 6947 Level: intermediate 6948 6949 .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 6950 @*/ 6951 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 6952 { 6953 DMLabelLink next = dm->labels; 6954 PetscBool hasLabel; 6955 const char *lname; 6956 6957 PetscFunctionBegin; 6958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6959 PetscValidCharPointer(name, 2); 6960 PetscValidPointer(label, 3); 6961 *label = NULL; 6962 while (next) { 6963 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 6964 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 6965 if (hasLabel) { 6966 *label = next->label; 6967 break; 6968 } 6969 next = next->next; 6970 } 6971 PetscFunctionReturn(0); 6972 } 6973 6974 /*@C 6975 DMGetLabelByNum - Return the nth label on a `DM` 6976 6977 Not Collective 6978 6979 Input Parameters: 6980 + dm - The `DM` object 6981 - n - the label number 6982 6983 Output Parameter: 6984 . label - the label 6985 6986 Level: intermediate 6987 6988 .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6989 @*/ 6990 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 6991 { 6992 DMLabelLink next = dm->labels; 6993 PetscInt l = 0; 6994 6995 PetscFunctionBegin; 6996 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6997 PetscValidPointer(label, 3); 6998 while (next) { 6999 if (l == n) { 7000 *label = next->label; 7001 PetscFunctionReturn(0); 7002 } 7003 ++l; 7004 next = next->next; 7005 } 7006 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7007 } 7008 7009 /*@C 7010 DMAddLabel - Add the label to this `DM` 7011 7012 Not Collective 7013 7014 Input Parameters: 7015 + dm - The `DM` object 7016 - label - The `DMLabel` 7017 7018 Level: developer 7019 7020 .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7021 @*/ 7022 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7023 { 7024 DMLabelLink l, *p, tmpLabel; 7025 PetscBool hasLabel; 7026 const char *lname; 7027 PetscBool flg; 7028 7029 PetscFunctionBegin; 7030 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7031 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7032 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7033 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7034 PetscCall(PetscCalloc1(1, &tmpLabel)); 7035 tmpLabel->label = label; 7036 tmpLabel->output = PETSC_TRUE; 7037 for (p = &dm->labels; (l = *p); p = &l->next) { } 7038 *p = tmpLabel; 7039 PetscCall(PetscObjectReference((PetscObject)label)); 7040 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7041 if (flg) dm->depthLabel = label; 7042 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7043 if (flg) dm->celltypeLabel = label; 7044 PetscFunctionReturn(0); 7045 } 7046 7047 /*@C 7048 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7049 7050 Not Collective 7051 7052 Input Parameters: 7053 + dm - The `DM` object 7054 - label - The `DMLabel`, having the same name, to substitute 7055 7056 Default labels in a `DMPLEX`: 7057 + "depth" - Holds the depth (co-dimension) of each mesh point 7058 . "celltype" - Holds the topological type of each cell 7059 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7060 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7061 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7062 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7063 7064 Level: intermediate 7065 7066 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7067 @*/ 7068 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7069 { 7070 DMLabelLink next = dm->labels; 7071 PetscBool hasLabel, flg; 7072 const char *name, *lname; 7073 7074 PetscFunctionBegin; 7075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7076 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7077 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7078 while (next) { 7079 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7080 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7081 if (hasLabel) { 7082 PetscCall(PetscObjectReference((PetscObject)label)); 7083 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7084 if (flg) dm->depthLabel = label; 7085 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7086 if (flg) dm->celltypeLabel = label; 7087 PetscCall(DMLabelDestroy(&next->label)); 7088 next->label = label; 7089 break; 7090 } 7091 next = next->next; 7092 } 7093 PetscFunctionReturn(0); 7094 } 7095 7096 /*@C 7097 DMRemoveLabel - Remove the label given by name from this `DM` 7098 7099 Not Collective 7100 7101 Input Parameters: 7102 + dm - The `DM` object 7103 - name - The label name 7104 7105 Output Parameter: 7106 . label - The `DMLabel`, or NULL if the label is absent. Pass in NULL to call `DMLabelDestroy()` on the label, otherwise the 7107 caller is responsible for calling `DMLabelDestroy()`. 7108 7109 Level: developer 7110 7111 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7112 @*/ 7113 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7114 { 7115 DMLabelLink link, *pnext; 7116 PetscBool hasLabel; 7117 const char *lname; 7118 7119 PetscFunctionBegin; 7120 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7121 PetscValidCharPointer(name, 2); 7122 if (label) { 7123 PetscValidPointer(label, 3); 7124 *label = NULL; 7125 } 7126 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7127 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7128 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7129 if (hasLabel) { 7130 *pnext = link->next; /* Remove from list */ 7131 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7132 if (hasLabel) dm->depthLabel = NULL; 7133 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7134 if (hasLabel) dm->celltypeLabel = NULL; 7135 if (label) *label = link->label; 7136 else PetscCall(DMLabelDestroy(&link->label)); 7137 PetscCall(PetscFree(link)); 7138 break; 7139 } 7140 } 7141 PetscFunctionReturn(0); 7142 } 7143 7144 /*@ 7145 DMRemoveLabelBySelf - Remove the label from this `DM` 7146 7147 Not Collective 7148 7149 Input Parameters: 7150 + dm - The `DM` object 7151 . label - The `DMLabel` to be removed from the `DM` 7152 - failNotFound - Should it fail if the label is not found in the DM? 7153 7154 Level: developer 7155 7156 Note: 7157 Only exactly the same instance is removed if found, name match is ignored. 7158 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7159 *label nullified. 7160 7161 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7162 @*/ 7163 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7164 { 7165 DMLabelLink link, *pnext; 7166 PetscBool hasLabel = PETSC_FALSE; 7167 7168 PetscFunctionBegin; 7169 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7170 PetscValidPointer(label, 2); 7171 if (!*label && !failNotFound) PetscFunctionReturn(0); 7172 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7173 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7174 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7175 if (*label == link->label) { 7176 hasLabel = PETSC_TRUE; 7177 *pnext = link->next; /* Remove from list */ 7178 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7179 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7180 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7181 PetscCall(DMLabelDestroy(&link->label)); 7182 PetscCall(PetscFree(link)); 7183 break; 7184 } 7185 } 7186 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7187 PetscFunctionReturn(0); 7188 } 7189 7190 /*@C 7191 DMGetLabelOutput - Get the output flag for a given label 7192 7193 Not Collective 7194 7195 Input Parameters: 7196 + dm - The `DM` object 7197 - name - The label name 7198 7199 Output Parameter: 7200 . output - The flag for output 7201 7202 Level: developer 7203 7204 .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7205 @*/ 7206 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7207 { 7208 DMLabelLink next = dm->labels; 7209 const char *lname; 7210 7211 PetscFunctionBegin; 7212 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7213 PetscValidCharPointer(name, 2); 7214 PetscValidBoolPointer(output, 3); 7215 while (next) { 7216 PetscBool flg; 7217 7218 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7219 PetscCall(PetscStrcmp(name, lname, &flg)); 7220 if (flg) { 7221 *output = next->output; 7222 PetscFunctionReturn(0); 7223 } 7224 next = next->next; 7225 } 7226 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7227 } 7228 7229 /*@C 7230 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7231 7232 Not Collective 7233 7234 Input Parameters: 7235 + dm - The `DM` object 7236 . name - The label name 7237 - output - `PETSC_TRUE` to save the label to the viewer 7238 7239 Level: developer 7240 7241 .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7242 @*/ 7243 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7244 { 7245 DMLabelLink next = dm->labels; 7246 const char *lname; 7247 7248 PetscFunctionBegin; 7249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7250 PetscValidCharPointer(name, 2); 7251 while (next) { 7252 PetscBool flg; 7253 7254 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7255 PetscCall(PetscStrcmp(name, lname, &flg)); 7256 if (flg) { 7257 next->output = output; 7258 PetscFunctionReturn(0); 7259 } 7260 next = next->next; 7261 } 7262 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7263 } 7264 7265 /*@ 7266 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7267 7268 Collective on dmA 7269 7270 Input Parameters: 7271 + dmA - The `DM` object with initial labels 7272 . dmB - The `DM` object to which labels are copied 7273 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7274 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7275 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7276 7277 Level: intermediate 7278 7279 Note: 7280 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7281 7282 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7283 @*/ 7284 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7285 { 7286 DMLabel label, labelNew, labelOld; 7287 const char *name; 7288 PetscBool flg; 7289 DMLabelLink link; 7290 7291 PetscFunctionBegin; 7292 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7293 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7294 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7295 PetscValidLogicalCollectiveBool(dmA, all, 4); 7296 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7297 if (dmA == dmB) PetscFunctionReturn(0); 7298 for (link = dmA->labels; link; link = link->next) { 7299 label = link->label; 7300 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7301 if (!all) { 7302 PetscCall(PetscStrcmp(name, "depth", &flg)); 7303 if (flg) continue; 7304 PetscCall(PetscStrcmp(name, "dim", &flg)); 7305 if (flg) continue; 7306 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7307 if (flg) continue; 7308 } 7309 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7310 if (labelOld) { 7311 switch (emode) { 7312 case DM_COPY_LABELS_KEEP: 7313 continue; 7314 case DM_COPY_LABELS_REPLACE: 7315 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7316 break; 7317 case DM_COPY_LABELS_FAIL: 7318 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7319 default: 7320 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7321 } 7322 } 7323 if (mode == PETSC_COPY_VALUES) { 7324 PetscCall(DMLabelDuplicate(label, &labelNew)); 7325 } else { 7326 labelNew = label; 7327 } 7328 PetscCall(DMAddLabel(dmB, labelNew)); 7329 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7330 } 7331 PetscFunctionReturn(0); 7332 } 7333 7334 /*@C 7335 DMCompareLabels - Compare labels of two `DMPLEX` meshes 7336 7337 Collective 7338 7339 Input Parameters: 7340 + dm0 - First `DM` object 7341 - dm1 - Second `DM` object 7342 7343 Output Parameters 7344 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 7345 - message - (Optional) Message describing the difference, or NULL if there is no difference 7346 7347 Level: intermediate 7348 7349 Notes: 7350 The output flag equal will be the same on all processes. 7351 7352 If equal is passed as NULL and difference is found, an error is thrown on all processes. 7353 7354 Make sure to pass equal is NULL on all processes or none of them. 7355 7356 The output message is set independently on each rank. 7357 7358 message must be freed with `PetscFree()` 7359 7360 If message is passed as NULL and a difference is found, the difference description is printed to stderr in synchronized manner. 7361 7362 Make sure to pass message as NULL on all processes or no processes. 7363 7364 Labels are matched by name. If the number of labels and their names are equal, 7365 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7366 7367 Fortran Note: 7368 This function is not available from Fortran. 7369 7370 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7371 @*/ 7372 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 7373 { 7374 PetscInt n, i; 7375 char msg[PETSC_MAX_PATH_LEN] = ""; 7376 PetscBool eq; 7377 MPI_Comm comm; 7378 PetscMPIInt rank; 7379 7380 PetscFunctionBegin; 7381 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7382 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7383 PetscCheckSameComm(dm0, 1, dm1, 2); 7384 if (equal) PetscValidBoolPointer(equal, 3); 7385 if (message) PetscValidPointer(message, 4); 7386 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7387 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7388 { 7389 PetscInt n1; 7390 7391 PetscCall(DMGetNumLabels(dm0, &n)); 7392 PetscCall(DMGetNumLabels(dm1, &n1)); 7393 eq = (PetscBool)(n == n1); 7394 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7395 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7396 if (!eq) goto finish; 7397 } 7398 for (i = 0; i < n; i++) { 7399 DMLabel l0, l1; 7400 const char *name; 7401 char *msgInner; 7402 7403 /* Ignore label order */ 7404 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7405 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7406 PetscCall(DMGetLabel(dm1, name, &l1)); 7407 if (!l1) { 7408 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7409 eq = PETSC_FALSE; 7410 break; 7411 } 7412 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7413 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7414 PetscCall(PetscFree(msgInner)); 7415 if (!eq) break; 7416 } 7417 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7418 finish: 7419 /* If message output arg not set, print to stderr */ 7420 if (message) { 7421 *message = NULL; 7422 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7423 } else { 7424 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7425 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7426 } 7427 /* If same output arg not ser and labels are not equal, throw error */ 7428 if (equal) *equal = eq; 7429 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7430 PetscFunctionReturn(0); 7431 } 7432 7433 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7434 { 7435 PetscFunctionBegin; 7436 PetscValidPointer(label, 2); 7437 if (!*label) { 7438 PetscCall(DMCreateLabel(dm, name)); 7439 PetscCall(DMGetLabel(dm, name, label)); 7440 } 7441 PetscCall(DMLabelSetValue(*label, point, value)); 7442 PetscFunctionReturn(0); 7443 } 7444 7445 /* 7446 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7447 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7448 (label, id) pair in the DM. 7449 7450 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7451 each label. 7452 */ 7453 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7454 { 7455 DMUniversalLabel ul; 7456 PetscBool *active; 7457 PetscInt pStart, pEnd, p, Nl, l, m; 7458 7459 PetscFunctionBegin; 7460 PetscCall(PetscMalloc1(1, &ul)); 7461 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7462 PetscCall(DMGetNumLabels(dm, &Nl)); 7463 PetscCall(PetscCalloc1(Nl, &active)); 7464 ul->Nl = 0; 7465 for (l = 0; l < Nl; ++l) { 7466 PetscBool isdepth, iscelltype; 7467 const char *name; 7468 7469 PetscCall(DMGetLabelName(dm, l, &name)); 7470 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7471 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7472 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7473 if (active[l]) ++ul->Nl; 7474 } 7475 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7476 ul->Nv = 0; 7477 for (l = 0, m = 0; l < Nl; ++l) { 7478 DMLabel label; 7479 PetscInt nv; 7480 const char *name; 7481 7482 if (!active[l]) continue; 7483 PetscCall(DMGetLabelName(dm, l, &name)); 7484 PetscCall(DMGetLabelByNum(dm, l, &label)); 7485 PetscCall(DMLabelGetNumValues(label, &nv)); 7486 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7487 ul->indices[m] = l; 7488 ul->Nv += nv; 7489 ul->offsets[m + 1] = nv; 7490 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7491 ++m; 7492 } 7493 for (l = 1; l <= ul->Nl; ++l) { 7494 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7495 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7496 } 7497 for (l = 0; l < ul->Nl; ++l) { 7498 PetscInt b; 7499 7500 ul->masks[l] = 0; 7501 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7502 } 7503 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7504 for (l = 0, m = 0; l < Nl; ++l) { 7505 DMLabel label; 7506 IS valueIS; 7507 const PetscInt *varr; 7508 PetscInt nv, v; 7509 7510 if (!active[l]) continue; 7511 PetscCall(DMGetLabelByNum(dm, l, &label)); 7512 PetscCall(DMLabelGetNumValues(label, &nv)); 7513 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7514 PetscCall(ISGetIndices(valueIS, &varr)); 7515 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7516 PetscCall(ISRestoreIndices(valueIS, &varr)); 7517 PetscCall(ISDestroy(&valueIS)); 7518 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7519 ++m; 7520 } 7521 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7522 for (p = pStart; p < pEnd; ++p) { 7523 PetscInt uval = 0; 7524 PetscBool marked = PETSC_FALSE; 7525 7526 for (l = 0, m = 0; l < Nl; ++l) { 7527 DMLabel label; 7528 PetscInt val, defval, loc, nv; 7529 7530 if (!active[l]) continue; 7531 PetscCall(DMGetLabelByNum(dm, l, &label)); 7532 PetscCall(DMLabelGetValue(label, p, &val)); 7533 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7534 if (val == defval) { 7535 ++m; 7536 continue; 7537 } 7538 nv = ul->offsets[m + 1] - ul->offsets[m]; 7539 marked = PETSC_TRUE; 7540 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7541 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7542 uval += (loc + 1) << ul->bits[m]; 7543 ++m; 7544 } 7545 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7546 } 7547 PetscCall(PetscFree(active)); 7548 *universal = ul; 7549 PetscFunctionReturn(0); 7550 } 7551 7552 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7553 { 7554 PetscInt l; 7555 7556 PetscFunctionBegin; 7557 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7558 PetscCall(DMLabelDestroy(&(*universal)->label)); 7559 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7560 PetscCall(PetscFree((*universal)->values)); 7561 PetscCall(PetscFree(*universal)); 7562 *universal = NULL; 7563 PetscFunctionReturn(0); 7564 } 7565 7566 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7567 { 7568 PetscFunctionBegin; 7569 PetscValidPointer(ulabel, 2); 7570 *ulabel = ul->label; 7571 PetscFunctionReturn(0); 7572 } 7573 7574 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7575 { 7576 PetscInt Nl = ul->Nl, l; 7577 7578 PetscFunctionBegin; 7579 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7580 for (l = 0; l < Nl; ++l) { 7581 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7582 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7583 } 7584 if (preserveOrder) { 7585 for (l = 0; l < ul->Nl; ++l) { 7586 const char *name; 7587 PetscBool match; 7588 7589 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7590 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7591 PetscCheck(match, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %" PetscInt_FMT " name %s does not match new name %s", l, name, ul->names[l]); 7592 } 7593 } 7594 PetscFunctionReturn(0); 7595 } 7596 7597 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7598 { 7599 PetscInt l; 7600 7601 PetscFunctionBegin; 7602 for (l = 0; l < ul->Nl; ++l) { 7603 DMLabel label; 7604 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7605 7606 if (lval) { 7607 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7608 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7609 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7610 } 7611 } 7612 PetscFunctionReturn(0); 7613 } 7614 7615 /*@ 7616 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7617 7618 Not collective 7619 7620 Input Parameter: 7621 . dm - The `DM` object 7622 7623 Output Parameter: 7624 . cdm - The coarse `DM` 7625 7626 Level: intermediate 7627 7628 .seealso: `DMSetCoarseDM()`, `DMCoarsen()` 7629 @*/ 7630 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7631 { 7632 PetscFunctionBegin; 7633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7634 PetscValidPointer(cdm, 2); 7635 *cdm = dm->coarseMesh; 7636 PetscFunctionReturn(0); 7637 } 7638 7639 /*@ 7640 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7641 7642 Input Parameters: 7643 + dm - The `DM` object 7644 - cdm - The coarse `DM` 7645 7646 Level: intermediate 7647 7648 Note: 7649 Normally this is set automatically by `DMRefine()` 7650 7651 .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7652 @*/ 7653 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7654 { 7655 PetscFunctionBegin; 7656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7657 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7658 if (dm == cdm) cdm = NULL; 7659 PetscCall(PetscObjectReference((PetscObject)cdm)); 7660 PetscCall(DMDestroy(&dm->coarseMesh)); 7661 dm->coarseMesh = cdm; 7662 PetscFunctionReturn(0); 7663 } 7664 7665 /*@ 7666 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7667 7668 Input Parameter: 7669 . dm - The `DM` object 7670 7671 Output Parameter: 7672 . fdm - The fine `DM` 7673 7674 Level: intermediate 7675 7676 .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7677 @*/ 7678 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7679 { 7680 PetscFunctionBegin; 7681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7682 PetscValidPointer(fdm, 2); 7683 *fdm = dm->fineMesh; 7684 PetscFunctionReturn(0); 7685 } 7686 7687 /*@ 7688 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7689 7690 Input Parameters: 7691 + dm - The `DM` object 7692 - fdm - The fine `DM` 7693 7694 Level: developer 7695 7696 Note: 7697 Normally this is set automatically by `DMCoarsen()` 7698 7699 .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 7700 @*/ 7701 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 7702 { 7703 PetscFunctionBegin; 7704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7705 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 7706 if (dm == fdm) fdm = NULL; 7707 PetscCall(PetscObjectReference((PetscObject)fdm)); 7708 PetscCall(DMDestroy(&dm->fineMesh)); 7709 dm->fineMesh = fdm; 7710 PetscFunctionReturn(0); 7711 } 7712 7713 /*@C 7714 DMAddBoundary - Add a boundary condition to a model represented by a `DM` 7715 7716 Collective on dm 7717 7718 Input Parameters: 7719 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 7720 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 7721 . name - The BC name 7722 . label - The label defining constrained points 7723 . Nv - The number of `DMLabel` values for constrained points 7724 . values - An array of values for constrained points 7725 . field - The field to constrain 7726 . Nc - The number of constrained field components (0 will constrain all fields) 7727 . comps - An array of constrained component numbers 7728 . bcFunc - A pointwise function giving boundary values 7729 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 7730 - ctx - An optional user context for bcFunc 7731 7732 Output Parameter: 7733 . bd - (Optional) Boundary number 7734 7735 Options Database Keys: 7736 + -bc_<boundary name> <num> - Overrides the boundary ids 7737 - -bc_<boundary name>_comp <num> - Overrides the boundary components 7738 7739 Notes: 7740 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is: 7741 7742 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 7743 7744 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is: 7745 7746 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 7747 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 7748 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 7749 $ PetscReal time, const PetscReal x[], PetscScalar bcval[]) 7750 7751 + dim - the spatial dimension 7752 . Nf - the number of fields 7753 . uOff - the offset into u[] and u_t[] for each field 7754 . uOff_x - the offset into u_x[] for each field 7755 . u - each field evaluated at the current point 7756 . u_t - the time derivative of each field evaluated at the current point 7757 . u_x - the gradient of each field evaluated at the current point 7758 . aOff - the offset into a[] and a_t[] for each auxiliary field 7759 . aOff_x - the offset into a_x[] for each auxiliary field 7760 . a - each auxiliary field evaluated at the current point 7761 . a_t - the time derivative of each auxiliary field evaluated at the current point 7762 . a_x - the gradient of auxiliary each field evaluated at the current point 7763 . t - current time 7764 . x - coordinates of the current point 7765 . numConstants - number of constant parameters 7766 . constants - constant parameters 7767 - bcval - output values at the current point 7768 7769 Level: intermediate 7770 7771 .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()` 7772 @*/ 7773 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd) 7774 { 7775 PetscDS ds; 7776 7777 PetscFunctionBegin; 7778 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7779 PetscValidLogicalCollectiveEnum(dm, type, 2); 7780 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 7781 PetscValidLogicalCollectiveInt(dm, Nv, 5); 7782 PetscValidLogicalCollectiveInt(dm, field, 7); 7783 PetscValidLogicalCollectiveInt(dm, Nc, 8); 7784 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 7785 PetscCall(DMGetDS(dm, &ds)); 7786 /* Complete label */ 7787 if (label) { 7788 PetscObject obj; 7789 PetscClassId id; 7790 7791 PetscCall(DMGetField(dm, field, NULL, &obj)); 7792 PetscCall(PetscObjectGetClassId(obj, &id)); 7793 if (id == PETSCFE_CLASSID) { 7794 DM plex; 7795 7796 PetscCall(DMConvert(dm, DMPLEX, &plex)); 7797 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 7798 PetscCall(DMDestroy(&plex)); 7799 } 7800 } 7801 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 7802 PetscFunctionReturn(0); 7803 } 7804 7805 /* TODO Remove this since now the structures are the same */ 7806 static PetscErrorCode DMPopulateBoundary(DM dm) 7807 { 7808 PetscDS ds; 7809 DMBoundary *lastnext; 7810 DSBoundary dsbound; 7811 7812 PetscFunctionBegin; 7813 PetscCall(DMGetDS(dm, &ds)); 7814 dsbound = ds->boundary; 7815 if (dm->boundary) { 7816 DMBoundary next = dm->boundary; 7817 7818 /* quick check to see if the PetscDS has changed */ 7819 if (next->dsboundary == dsbound) PetscFunctionReturn(0); 7820 /* the PetscDS has changed: tear down and rebuild */ 7821 while (next) { 7822 DMBoundary b = next; 7823 7824 next = b->next; 7825 PetscCall(PetscFree(b)); 7826 } 7827 dm->boundary = NULL; 7828 } 7829 7830 lastnext = &(dm->boundary); 7831 while (dsbound) { 7832 DMBoundary dmbound; 7833 7834 PetscCall(PetscNew(&dmbound)); 7835 dmbound->dsboundary = dsbound; 7836 dmbound->label = dsbound->label; 7837 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 7838 *lastnext = dmbound; 7839 lastnext = &(dmbound->next); 7840 dsbound = dsbound->next; 7841 } 7842 PetscFunctionReturn(0); 7843 } 7844 7845 /* TODO: missing manual page */ 7846 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 7847 { 7848 DMBoundary b; 7849 7850 PetscFunctionBegin; 7851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7852 PetscValidBoolPointer(isBd, 3); 7853 *isBd = PETSC_FALSE; 7854 PetscCall(DMPopulateBoundary(dm)); 7855 b = dm->boundary; 7856 while (b && !(*isBd)) { 7857 DMLabel label = b->label; 7858 DSBoundary dsb = b->dsboundary; 7859 PetscInt i; 7860 7861 if (label) { 7862 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 7863 } 7864 b = b->next; 7865 } 7866 PetscFunctionReturn(0); 7867 } 7868 7869 /*@C 7870 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 7871 7872 Collective on dm 7873 7874 Input Parameters: 7875 + dm - The `DM` 7876 . time - The time 7877 . funcs - The coordinate functions to evaluate, one per field 7878 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 7879 - mode - The insertion mode for values 7880 7881 Output Parameter: 7882 . X - vector 7883 7884 Calling sequence of func: 7885 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 7886 7887 + dim - The spatial dimension 7888 . time - The time at which to sample 7889 . x - The coordinates 7890 . Nc - The number of components 7891 . u - The output field values 7892 - ctx - optional user-defined function context 7893 7894 Level: developer 7895 7896 Developer Notes: 7897 This API is specific to only particular usage of `DM` 7898 7899 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 7900 7901 .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 7902 @*/ 7903 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X) 7904 { 7905 Vec localX; 7906 7907 PetscFunctionBegin; 7908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7909 PetscCall(DMGetLocalVector(dm, &localX)); 7910 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 7911 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 7912 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 7913 PetscCall(DMRestoreLocalVector(dm, &localX)); 7914 PetscFunctionReturn(0); 7915 } 7916 7917 /*@C 7918 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 7919 7920 Not collective 7921 7922 Input Parameters: 7923 + dm - The `DM` 7924 . time - The time 7925 . funcs - The coordinate functions to evaluate, one per field 7926 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 7927 - mode - The insertion mode for values 7928 7929 Output Parameter: 7930 . localX - vector 7931 7932 Calling sequence of func: 7933 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 7934 7935 + dim - The spatial dimension 7936 . x - The coordinates 7937 . Nc - The number of components 7938 . u - The output field values 7939 - ctx - optional user-defined function context 7940 7941 Level: developer 7942 7943 Developer Notes: 7944 This API is specific to only particular usage of `DM` 7945 7946 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 7947 7948 .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 7949 @*/ 7950 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 7951 { 7952 PetscFunctionBegin; 7953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7954 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 7955 PetscCall((dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX)); 7956 PetscFunctionReturn(0); 7957 } 7958 7959 /*@C 7960 DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label. 7961 7962 Collective on dm 7963 7964 Input Parameters: 7965 + dm - The `DM` 7966 . time - The time 7967 . label - The `DMLabel` selecting the portion of the mesh for projection 7968 . funcs - The coordinate functions to evaluate, one per field 7969 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 7970 - mode - The insertion mode for values 7971 7972 Output Parameter: 7973 . X - vector 7974 7975 Calling sequence of func: 7976 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 7977 7978 + dim - The spatial dimension 7979 . x - The coordinates 7980 . Nc - The number of components 7981 . u - The output field values 7982 - ctx - optional user-defined function context 7983 7984 Level: developer 7985 7986 Developer Notes: 7987 This API is specific to only particular usage of `DM` 7988 7989 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 7990 7991 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 7992 @*/ 7993 PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X) 7994 { 7995 Vec localX; 7996 7997 PetscFunctionBegin; 7998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7999 PetscCall(DMGetLocalVector(dm, &localX)); 8000 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8001 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8002 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8003 PetscCall(DMRestoreLocalVector(dm, &localX)); 8004 PetscFunctionReturn(0); 8005 } 8006 8007 /*@C 8008 DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label. 8009 8010 Not collective 8011 8012 Input Parameters: 8013 + dm - The `DM` 8014 . time - The time 8015 . label - The `DMLabel` selecting the portion of the mesh for projection 8016 . funcs - The coordinate functions to evaluate, one per field 8017 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8018 - mode - The insertion mode for values 8019 8020 Output Parameter: 8021 . localX - vector 8022 8023 Calling sequence of func: 8024 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8025 8026 + dim - The spatial dimension 8027 . x - The coordinates 8028 . Nc - The number of components 8029 . u - The output field values 8030 - ctx - optional user-defined function context 8031 8032 Level: developer 8033 8034 Developer Notes: 8035 This API is specific to only particular usage of `DM` 8036 8037 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8038 8039 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8040 @*/ 8041 PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 8042 { 8043 PetscFunctionBegin; 8044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8045 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8046 PetscCall((dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8047 PetscFunctionReturn(0); 8048 } 8049 8050 /*@C 8051 DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector. 8052 8053 Not collective 8054 8055 Input Parameters: 8056 + dm - The `DM` 8057 . time - The time 8058 . localU - The input field vector 8059 . funcs - The functions to evaluate, one per field 8060 - mode - The insertion mode for values 8061 8062 Output Parameter: 8063 . localX - The output vector 8064 8065 Calling sequence of func: 8066 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8067 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8068 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8069 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 8070 8071 + dim - The spatial dimension 8072 . Nf - The number of input fields 8073 . NfAux - The number of input auxiliary fields 8074 . uOff - The offset of each field in u[] 8075 . uOff_x - The offset of each field in u_x[] 8076 . u - The field values at this point in space 8077 . u_t - The field time derivative at this point in space (or NULL) 8078 . u_x - The field derivatives at this point in space 8079 . aOff - The offset of each auxiliary field in u[] 8080 . aOff_x - The offset of each auxiliary field in u_x[] 8081 . a - The auxiliary field values at this point in space 8082 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8083 . a_x - The auxiliary field derivatives at this point in space 8084 . t - The current time 8085 . x - The coordinates of this point 8086 . numConstants - The number of constants 8087 . constants - The value of each constant 8088 - f - The value of the function at this point in space 8089 8090 Note: 8091 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs. 8092 The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or 8093 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8094 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8095 8096 Level: intermediate 8097 8098 Developer Notes: 8099 This API is specific to only particular usage of `DM` 8100 8101 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8102 8103 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8104 @*/ 8105 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX) 8106 { 8107 PetscFunctionBegin; 8108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8109 PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8110 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8111 PetscCall((dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX)); 8112 PetscFunctionReturn(0); 8113 } 8114 8115 /*@C 8116 DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label. 8117 8118 Not collective 8119 8120 Input Parameters: 8121 + dm - The `DM` 8122 . time - The time 8123 . label - The `DMLabel` marking the portion of the domain to output 8124 . numIds - The number of label ids to use 8125 . ids - The label ids to use for marking 8126 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8127 . comps - The components to set in the output, or NULL for all components 8128 . localU - The input field vector 8129 . funcs - The functions to evaluate, one per field 8130 - mode - The insertion mode for values 8131 8132 Output Parameter: 8133 . localX - The output vector 8134 8135 Calling sequence of func: 8136 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8137 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8138 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8139 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 8140 8141 + dim - The spatial dimension 8142 . Nf - The number of input fields 8143 . NfAux - The number of input auxiliary fields 8144 . uOff - The offset of each field in u[] 8145 . uOff_x - The offset of each field in u_x[] 8146 . u - The field values at this point in space 8147 . u_t - The field time derivative at this point in space (or NULL) 8148 . u_x - The field derivatives at this point in space 8149 . aOff - The offset of each auxiliary field in u[] 8150 . aOff_x - The offset of each auxiliary field in u_x[] 8151 . a - The auxiliary field values at this point in space 8152 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8153 . a_x - The auxiliary field derivatives at this point in space 8154 . t - The current time 8155 . x - The coordinates of this point 8156 . numConstants - The number of constants 8157 . constants - The value of each constant 8158 - f - The value of the function at this point in space 8159 8160 Note: 8161 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs. 8162 The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or 8163 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8164 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8165 8166 Level: intermediate 8167 8168 Developer Notes: 8169 This API is specific to only particular usage of `DM` 8170 8171 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8172 8173 .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8174 @*/ 8175 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX) 8176 { 8177 PetscFunctionBegin; 8178 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8179 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8180 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8181 PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8182 PetscFunctionReturn(0); 8183 } 8184 8185 /*@C 8186 DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label. 8187 8188 Not collective 8189 8190 Input Parameters: 8191 + dm - The `DM` 8192 . time - The time 8193 . label - The `DMLabel` marking the portion of the domain to output 8194 . numIds - The number of label ids to use 8195 . ids - The label ids to use for marking 8196 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8197 . comps - The components to set in the output, or NULL for all components 8198 . U - The input field vector 8199 . funcs - The functions to evaluate, one per field 8200 - mode - The insertion mode for values 8201 8202 Output Parameter: 8203 . X - The output vector 8204 8205 Calling sequence of func: 8206 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8207 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8208 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8209 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 8210 8211 + dim - The spatial dimension 8212 . Nf - The number of input fields 8213 . NfAux - The number of input auxiliary fields 8214 . uOff - The offset of each field in u[] 8215 . uOff_x - The offset of each field in u_x[] 8216 . u - The field values at this point in space 8217 . u_t - The field time derivative at this point in space (or NULL) 8218 . u_x - The field derivatives at this point in space 8219 . aOff - The offset of each auxiliary field in u[] 8220 . aOff_x - The offset of each auxiliary field in u_x[] 8221 . a - The auxiliary field values at this point in space 8222 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8223 . a_x - The auxiliary field derivatives at this point in space 8224 . t - The current time 8225 . x - The coordinates of this point 8226 . numConstants - The number of constants 8227 . constants - The value of each constant 8228 - f - The value of the function at this point in space 8229 8230 Note: 8231 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs. 8232 The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or 8233 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8234 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8235 8236 Level: intermediate 8237 8238 Developer Notes: 8239 This API is specific to only particular usage of `DM` 8240 8241 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8242 8243 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8244 @*/ 8245 PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec X) 8246 { 8247 DM dmIn; 8248 Vec localU, localX; 8249 8250 PetscFunctionBegin; 8251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8252 PetscCall(VecGetDM(U, &dmIn)); 8253 PetscCall(DMGetLocalVector(dmIn, &localU)); 8254 PetscCall(DMGetLocalVector(dm, &localX)); 8255 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8256 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8257 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8258 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8259 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8260 PetscCall(DMRestoreLocalVector(dm, &localX)); 8261 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8262 PetscFunctionReturn(0); 8263 } 8264 8265 /*@C 8266 DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label. 8267 8268 Not collective 8269 8270 Input Parameters: 8271 + dm - The `DM` 8272 . time - The time 8273 . label - The `DMLabel` marking the portion of the domain boundary to output 8274 . numIds - The number of label ids to use 8275 . ids - The label ids to use for marking 8276 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8277 . comps - The components to set in the output, or NULL for all components 8278 . localU - The input field vector 8279 . funcs - The functions to evaluate, one per field 8280 - mode - The insertion mode for values 8281 8282 Output Parameter: 8283 . localX - The output vector 8284 8285 Calling sequence of func: 8286 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8287 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8288 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8289 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 8290 8291 + dim - The spatial dimension 8292 . Nf - The number of input fields 8293 . NfAux - The number of input auxiliary fields 8294 . uOff - The offset of each field in u[] 8295 . uOff_x - The offset of each field in u_x[] 8296 . u - The field values at this point in space 8297 . u_t - The field time derivative at this point in space (or NULL) 8298 . u_x - The field derivatives at this point in space 8299 . aOff - The offset of each auxiliary field in u[] 8300 . aOff_x - The offset of each auxiliary field in u_x[] 8301 . a - The auxiliary field values at this point in space 8302 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8303 . a_x - The auxiliary field derivatives at this point in space 8304 . t - The current time 8305 . x - The coordinates of this point 8306 . n - The face normal 8307 . numConstants - The number of constants 8308 . constants - The value of each constant 8309 - f - The value of the function at this point in space 8310 8311 Note: 8312 There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs. 8313 The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or 8314 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8315 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8316 8317 Level: intermediate 8318 8319 Developer Notes: 8320 This API is specific to only particular usage of `DM` 8321 8322 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8323 8324 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8325 @*/ 8326 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX) 8327 { 8328 PetscFunctionBegin; 8329 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8330 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8331 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8332 PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8333 PetscFunctionReturn(0); 8334 } 8335 8336 /*@C 8337 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8338 8339 Collective on dm 8340 8341 Input Parameters: 8342 + dm - The `DM` 8343 . time - The time 8344 . funcs - The functions to evaluate for each field component 8345 . ctxs - Optional array of contexts to pass to each function, or NULL. 8346 - X - The coefficient vector u_h, a global vector 8347 8348 Output Parameter: 8349 . diff - The diff ||u - u_h||_2 8350 8351 Level: developer 8352 8353 Developer Notes: 8354 This API is specific to only particular usage of `DM` 8355 8356 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8357 8358 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8359 @*/ 8360 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8361 { 8362 PetscFunctionBegin; 8363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8364 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8365 PetscCall((dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff)); 8366 PetscFunctionReturn(0); 8367 } 8368 8369 /*@C 8370 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8371 8372 Collective on dm 8373 8374 Input Parameters: 8375 + dm - The `DM` 8376 , time - The time 8377 . funcs - The gradient functions to evaluate for each field component 8378 . ctxs - Optional array of contexts to pass to each function, or NULL. 8379 . X - The coefficient vector u_h, a global vector 8380 - n - The vector to project along 8381 8382 Output Parameter: 8383 . diff - The diff ||(grad u - grad u_h) . n||_2 8384 8385 Level: developer 8386 8387 Developer Notes: 8388 This API is specific to only particular usage of `DM` 8389 8390 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8391 8392 .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8393 @*/ 8394 PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff) 8395 { 8396 PetscFunctionBegin; 8397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8398 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8399 PetscCall((dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff)); 8400 PetscFunctionReturn(0); 8401 } 8402 8403 /*@C 8404 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8405 8406 Collective on dm 8407 8408 Input Parameters: 8409 + dm - The `DM` 8410 . time - The time 8411 . funcs - The functions to evaluate for each field component 8412 . ctxs - Optional array of contexts to pass to each function, or NULL. 8413 - X - The coefficient vector u_h, a global vector 8414 8415 Output Parameter: 8416 . diff - The array of differences, ||u^f - u^f_h||_2 8417 8418 Level: developer 8419 8420 Developer Notes: 8421 This API is specific to only particular usage of `DM` 8422 8423 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8424 8425 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8426 @*/ 8427 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8428 { 8429 PetscFunctionBegin; 8430 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8431 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8432 PetscCall((dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff)); 8433 PetscFunctionReturn(0); 8434 } 8435 8436 /*@C 8437 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8438 8439 Not Collective 8440 8441 Input Parameter: 8442 . dm - The `DM` 8443 8444 Output Parameters: 8445 + nranks - the number of neighbours 8446 - ranks - the neighbors ranks 8447 8448 Note: 8449 Do not free the array, it is freed when the `DM` is destroyed. 8450 8451 Level: beginner 8452 8453 .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8454 @*/ 8455 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8456 { 8457 PetscFunctionBegin; 8458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8459 PetscCall((dm->ops->getneighbors)(dm, nranks, ranks)); 8460 PetscFunctionReturn(0); 8461 } 8462 8463 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8464 8465 /* 8466 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8467 This has be a different function because it requires DM which is not defined in the Mat library 8468 */ 8469 PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8470 { 8471 PetscFunctionBegin; 8472 if (coloring->ctype == IS_COLORING_LOCAL) { 8473 Vec x1local; 8474 DM dm; 8475 PetscCall(MatGetDM(J, &dm)); 8476 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8477 PetscCall(DMGetLocalVector(dm, &x1local)); 8478 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8479 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8480 x1 = x1local; 8481 } 8482 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8483 if (coloring->ctype == IS_COLORING_LOCAL) { 8484 DM dm; 8485 PetscCall(MatGetDM(J, &dm)); 8486 PetscCall(DMRestoreLocalVector(dm, &x1)); 8487 } 8488 PetscFunctionReturn(0); 8489 } 8490 8491 /*@ 8492 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8493 8494 Input Parameter: 8495 . coloring - the `MatFDColoring` object 8496 8497 Developer Note: 8498 this routine exists because the PETSc `Mat` library does not know about the `DM` objects 8499 8500 Level: advanced 8501 8502 .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8503 @*/ 8504 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8505 { 8506 PetscFunctionBegin; 8507 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8508 PetscFunctionReturn(0); 8509 } 8510 8511 /*@ 8512 DMGetCompatibility - determine if two `DM`s are compatible 8513 8514 Collective 8515 8516 Input Parameters: 8517 + dm1 - the first `DM` 8518 - dm2 - the second `DM` 8519 8520 Output Parameters: 8521 + compatible - whether or not the two `DM`s are compatible 8522 - set - whether or not the compatible value was actually determined and set 8523 8524 Notes: 8525 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8526 of the same topology. This implies that the section (field data) on one 8527 "makes sense" with respect to the topology and parallel decomposition of the other. 8528 Loosely speaking, compatible `DM`s represent the same domain and parallel 8529 decomposition, but hold different data. 8530 8531 Typically, one would confirm compatibility if intending to simultaneously iterate 8532 over a pair of vectors obtained from different `DM`s. 8533 8534 For example, two `DMDA` objects are compatible if they have the same local 8535 and global sizes and the same stencil width. They can have different numbers 8536 of degrees of freedom per node. Thus, one could use the node numbering from 8537 either `DM` in bounds for a loop over vectors derived from either `DM`. 8538 8539 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8540 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8541 .vb 8542 ... 8543 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8544 if (set && compatible) { 8545 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8546 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8547 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8548 for (j=y; j<y+n; ++j) { 8549 for (i=x; i<x+m, ++i) { 8550 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8551 } 8552 } 8553 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8554 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8555 } else { 8556 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8557 } 8558 ... 8559 .ve 8560 8561 Checking compatibility might be expensive for a given implementation of `DM`, 8562 or might be impossible to unambiguously confirm or deny. For this reason, 8563 this function may decline to determine compatibility, and hence users should 8564 always check the "set" output parameter. 8565 8566 A `DM` is always compatible with itself. 8567 8568 In the current implementation, `DM`s which live on "unequal" communicators 8569 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8570 incompatible. 8571 8572 This function is labeled "Collective," as information about all subdomains 8573 is required on each rank. However, in `DM` implementations which store all this 8574 information locally, this function may be merely "Logically Collective". 8575 8576 Developer Note: 8577 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8578 iff B is compatible with A. Thus, this function checks the implementations 8579 of both dm and dmc (if they are of different types), attempting to determine 8580 compatibility. It is left to `DM` implementers to ensure that symmetry is 8581 preserved. The simplest way to do this is, when implementing type-specific 8582 logic for this function, is to check for existing logic in the implementation 8583 of other `DM` types and let *set = PETSC_FALSE if found. 8584 8585 Level: advanced 8586 8587 .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8588 @*/ 8589 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8590 { 8591 PetscMPIInt compareResult; 8592 DMType type, type2; 8593 PetscBool sameType; 8594 8595 PetscFunctionBegin; 8596 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8597 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8598 8599 /* Declare a DM compatible with itself */ 8600 if (dm1 == dm2) { 8601 *set = PETSC_TRUE; 8602 *compatible = PETSC_TRUE; 8603 PetscFunctionReturn(0); 8604 } 8605 8606 /* Declare a DM incompatible with a DM that lives on an "unequal" 8607 communicator. Note that this does not preclude compatibility with 8608 DMs living on "congruent" or "similar" communicators, but this must be 8609 determined by the implementation-specific logic */ 8610 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8611 if (compareResult == MPI_UNEQUAL) { 8612 *set = PETSC_TRUE; 8613 *compatible = PETSC_FALSE; 8614 PetscFunctionReturn(0); 8615 } 8616 8617 /* Pass to the implementation-specific routine, if one exists. */ 8618 if (dm1->ops->getcompatibility) { 8619 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8620 if (*set) PetscFunctionReturn(0); 8621 } 8622 8623 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8624 with an implementation of this function from dm2 */ 8625 PetscCall(DMGetType(dm1, &type)); 8626 PetscCall(DMGetType(dm2, &type2)); 8627 PetscCall(PetscStrcmp(type, type2, &sameType)); 8628 if (!sameType && dm2->ops->getcompatibility) { 8629 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8630 } else { 8631 *set = PETSC_FALSE; 8632 } 8633 PetscFunctionReturn(0); 8634 } 8635 8636 /*@C 8637 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8638 8639 Logically Collective on dm 8640 8641 Input Parameters: 8642 + DM - the `DM` 8643 . f - the monitor function 8644 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired) 8645 - monitordestroy - [optional] routine that frees monitor context (may be NULL) 8646 8647 Options Database Keys: 8648 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8649 does not cancel those set via the options database. 8650 8651 Note: 8652 Several different monitoring routines may be set by calling 8653 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 8654 order in which they were set. 8655 8656 Fortran Note: 8657 Only a single monitor function can be set for each `DM` object 8658 8659 Developer Note: 8660 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 8661 8662 Level: intermediate 8663 8664 .seealso: `DMMonitorCancel()`,`DMMonitorSetFromOptions()`, `DMMonitor()` 8665 @*/ 8666 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) 8667 { 8668 PetscInt m; 8669 8670 PetscFunctionBegin; 8671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8672 for (m = 0; m < dm->numbermonitors; ++m) { 8673 PetscBool identical; 8674 8675 PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 8676 if (identical) PetscFunctionReturn(0); 8677 } 8678 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 8679 dm->monitor[dm->numbermonitors] = f; 8680 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 8681 dm->monitorcontext[dm->numbermonitors++] = (void *)mctx; 8682 PetscFunctionReturn(0); 8683 } 8684 8685 /*@ 8686 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 8687 8688 Logically Collective on dm 8689 8690 Input Parameter: 8691 . dm - the DM 8692 8693 Options Database Key: 8694 . -dm_monitor_cancel - cancels all monitors that have been hardwired 8695 into a code by calls to `DMonitorSet()`, but does not cancel those 8696 set via the options database 8697 8698 Note: 8699 There is no way to clear one specific monitor from a `DM` object. 8700 8701 Level: intermediate 8702 8703 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8704 @*/ 8705 PetscErrorCode DMMonitorCancel(DM dm) 8706 { 8707 PetscInt m; 8708 8709 PetscFunctionBegin; 8710 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8711 for (m = 0; m < dm->numbermonitors; ++m) { 8712 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 8713 } 8714 dm->numbermonitors = 0; 8715 PetscFunctionReturn(0); 8716 } 8717 8718 /*@C 8719 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 8720 8721 Collective on dm 8722 8723 Input Parameters: 8724 + dm - `DM` object you wish to monitor 8725 . name - the monitor type one is seeking 8726 . help - message indicating what monitoring is done 8727 . manual - manual page for the monitor 8728 . monitor - the monitor function 8729 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `DM` or `PetscViewer` objects 8730 8731 Output Parameter: 8732 . flg - Flag set if the monitor was created 8733 8734 Level: developer 8735 8736 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 8737 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 8738 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`, 8739 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 8740 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 8741 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 8742 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 8743 @*/ 8744 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 8745 { 8746 PetscViewer viewer; 8747 PetscViewerFormat format; 8748 8749 PetscFunctionBegin; 8750 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8751 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 8752 if (*flg) { 8753 PetscViewerAndFormat *vf; 8754 8755 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 8756 PetscCall(PetscObjectDereference((PetscObject)viewer)); 8757 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 8758 PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy)); 8759 } 8760 PetscFunctionReturn(0); 8761 } 8762 8763 /*@ 8764 DMMonitor - runs the user provided monitor routines, if they exist 8765 8766 Collective on dm 8767 8768 Input Parameters: 8769 . dm - The `DM` 8770 8771 Level: developer 8772 8773 Question: 8774 Note should indicate when during the life of the `DM` the monitor is run. It appears to be related to the discretization process seems rather specialized 8775 since some `DM` have no concept of discretization 8776 8777 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()` 8778 @*/ 8779 PetscErrorCode DMMonitor(DM dm) 8780 { 8781 PetscInt m; 8782 8783 PetscFunctionBegin; 8784 if (!dm) PetscFunctionReturn(0); 8785 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8786 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 8787 PetscFunctionReturn(0); 8788 } 8789 8790 /*@ 8791 DMComputeError - Computes the error assuming the user has provided the exact solution functions 8792 8793 Collective on dm 8794 8795 Input Parameters: 8796 + dm - The `DM` 8797 - sol - The solution vector 8798 8799 Input/Output Parameter: 8800 . errors - An array of length Nf, the number of fields, or NULL for no output; on output 8801 contains the error in each field 8802 8803 Output Parameter: 8804 . errorVec - A vector to hold the cellwise error (may be NULL) 8805 8806 Note: 8807 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 8808 8809 Level: developer 8810 8811 .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 8812 @*/ 8813 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 8814 { 8815 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 8816 void **ctxs; 8817 PetscReal time; 8818 PetscInt Nf, f, Nds, s; 8819 8820 PetscFunctionBegin; 8821 PetscCall(DMGetNumFields(dm, &Nf)); 8822 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 8823 PetscCall(DMGetNumDS(dm, &Nds)); 8824 for (s = 0; s < Nds; ++s) { 8825 PetscDS ds; 8826 DMLabel label; 8827 IS fieldIS; 8828 const PetscInt *fields; 8829 PetscInt dsNf; 8830 8831 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 8832 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 8833 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 8834 for (f = 0; f < dsNf; ++f) { 8835 const PetscInt field = fields[f]; 8836 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 8837 } 8838 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 8839 } 8840 for (f = 0; f < Nf; ++f) PetscCheck(exactSol[f], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %" PetscInt_FMT, f); 8841 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 8842 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 8843 if (errorVec) { 8844 DM edm; 8845 DMPolytopeType ct; 8846 PetscBool simplex; 8847 PetscInt dim, cStart, Nf; 8848 8849 PetscCall(DMClone(dm, &edm)); 8850 PetscCall(DMGetDimension(edm, &dim)); 8851 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 8852 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8853 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8854 PetscCall(DMGetNumFields(dm, &Nf)); 8855 for (f = 0; f < Nf; ++f) { 8856 PetscFE fe, efe; 8857 PetscQuadrature q; 8858 const char *name; 8859 8860 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 8861 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 8862 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 8863 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 8864 PetscCall(PetscFEGetQuadrature(fe, &q)); 8865 PetscCall(PetscFESetQuadrature(efe, q)); 8866 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 8867 PetscCall(PetscFEDestroy(&efe)); 8868 } 8869 PetscCall(DMCreateDS(edm)); 8870 8871 PetscCall(DMCreateGlobalVector(edm, errorVec)); 8872 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 8873 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 8874 PetscCall(DMDestroy(&edm)); 8875 } 8876 PetscCall(PetscFree2(exactSol, ctxs)); 8877 PetscFunctionReturn(0); 8878 } 8879 8880 /*@ 8881 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 8882 8883 Not collective 8884 8885 Input Parameter: 8886 . dm - The `DM` 8887 8888 Output Parameter: 8889 . numAux - The number of auxiliary data vectors 8890 8891 Level: advanced 8892 8893 .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 8894 @*/ 8895 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 8896 { 8897 PetscFunctionBegin; 8898 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8899 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 8900 PetscFunctionReturn(0); 8901 } 8902 8903 /*@ 8904 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 8905 8906 Not collective 8907 8908 Input Parameters: 8909 + dm - The `DM` 8910 . label - The `DMLabel` 8911 . value - The label value indicating the region 8912 - part - The equation part, or 0 if unused 8913 8914 Output Parameter: 8915 . aux - The `Vec` holding auxiliary field data 8916 8917 Note: 8918 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 8919 8920 Level: advanced 8921 8922 .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 8923 @*/ 8924 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 8925 { 8926 PetscHashAuxKey key, wild = {NULL, 0, 0}; 8927 PetscBool has; 8928 8929 PetscFunctionBegin; 8930 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8931 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 8932 key.label = label; 8933 key.value = value; 8934 key.part = part; 8935 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 8936 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 8937 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 8938 PetscFunctionReturn(0); 8939 } 8940 8941 /*@ 8942 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 8943 8944 Not collective because auxilary vectors are not parallel 8945 8946 Input Parameters: 8947 + dm - The `DM` 8948 . label - The `DMLabel` 8949 . value - The label value indicating the region 8950 . part - The equation part, or 0 if unused 8951 - aux - The `Vec` holding auxiliary field data 8952 8953 Level: advanced 8954 8955 .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 8956 @*/ 8957 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 8958 { 8959 Vec old; 8960 PetscHashAuxKey key; 8961 8962 PetscFunctionBegin; 8963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8964 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 8965 key.label = label; 8966 key.value = value; 8967 key.part = part; 8968 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 8969 PetscCall(PetscObjectReference((PetscObject)aux)); 8970 PetscCall(PetscObjectDereference((PetscObject)old)); 8971 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 8972 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 8973 PetscFunctionReturn(0); 8974 } 8975 8976 /*@C 8977 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 8978 8979 Not collective 8980 8981 Input Parameter: 8982 . dm - The `DM` 8983 8984 Output Parameters: 8985 + labels - The `DMLabel`s for each `Vec` 8986 . values - The label values for each `Vec` 8987 - parts - The equation parts for each `Vec` 8988 8989 Note: 8990 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 8991 8992 Level: advanced 8993 8994 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()` 8995 @*/ 8996 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 8997 { 8998 PetscHashAuxKey *keys; 8999 PetscInt n, i, off = 0; 9000 9001 PetscFunctionBegin; 9002 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9003 PetscValidPointer(labels, 2); 9004 PetscValidIntPointer(values, 3); 9005 PetscValidIntPointer(parts, 4); 9006 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9007 PetscCall(PetscMalloc1(n, &keys)); 9008 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9009 for (i = 0; i < n; ++i) { 9010 labels[i] = keys[i].label; 9011 values[i] = keys[i].value; 9012 parts[i] = keys[i].part; 9013 } 9014 PetscCall(PetscFree(keys)); 9015 PetscFunctionReturn(0); 9016 } 9017 9018 /*@ 9019 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9020 9021 Not collective 9022 9023 Input Parameter: 9024 . dm - The `DM` 9025 9026 Output Parameter: 9027 . dmNew - The new `DM`, now with the same auxiliary data 9028 9029 Level: advanced 9030 9031 Note: 9032 This is a shallow copy of the auxiliary vectors 9033 9034 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9035 @*/ 9036 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9037 { 9038 PetscFunctionBegin; 9039 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9040 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9041 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9042 PetscFunctionReturn(0); 9043 } 9044 9045 /*@C 9046 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9047 9048 Not collective 9049 9050 Input Parameters: 9051 + ct - The `DMPolytopeType` 9052 . sourceCone - The source arrangement of faces 9053 - targetCone - The target arrangement of faces 9054 9055 Output Parameters: 9056 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9057 - found - Flag indicating that a suitable orientation was found 9058 9059 Level: advanced 9060 9061 Note: 9062 An arrangement is a face order combined with an orientation for each face 9063 9064 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2 9065 that labels each arrangement (face ordering plus orientation for each face). 9066 9067 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9068 9069 .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9070 @*/ 9071 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9072 { 9073 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9074 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2; 9075 PetscInt o, c; 9076 9077 PetscFunctionBegin; 9078 if (!nO) { 9079 *ornt = 0; 9080 *found = PETSC_TRUE; 9081 PetscFunctionReturn(0); 9082 } 9083 for (o = -nO; o < nO; ++o) { 9084 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 9085 9086 for (c = 0; c < cS; ++c) 9087 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9088 if (c == cS) { 9089 *ornt = o; 9090 break; 9091 } 9092 } 9093 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9094 PetscFunctionReturn(0); 9095 } 9096 9097 /*@C 9098 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9099 9100 Not collective 9101 9102 Input Parameters: 9103 + ct - The `DMPolytopeType` 9104 . sourceCone - The source arrangement of faces 9105 - targetCone - The target arrangement of faces 9106 9107 Output Parameters: 9108 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9109 9110 Level: advanced 9111 9112 Note: 9113 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9114 9115 Developer Note: 9116 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9117 9118 .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9119 @*/ 9120 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9121 { 9122 PetscBool found; 9123 9124 PetscFunctionBegin; 9125 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9126 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9127 PetscFunctionReturn(0); 9128 } 9129 9130 /*@C 9131 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9132 9133 Not collective 9134 9135 Input Parameters: 9136 + ct - The `DMPolytopeType` 9137 . sourceVert - The source arrangement of vertices 9138 - targetVert - The target arrangement of vertices 9139 9140 Output Parameters: 9141 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9142 - found - Flag indicating that a suitable orientation was found 9143 9144 Level: advanced 9145 9146 Note: 9147 An arrangement is a vertex order 9148 9149 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2 9150 that labels each arrangement (vertex ordering). 9151 9152 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9153 9154 .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()` 9155 @*/ 9156 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9157 { 9158 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9159 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2; 9160 PetscInt o, c; 9161 9162 PetscFunctionBegin; 9163 if (!nO) { 9164 *ornt = 0; 9165 *found = PETSC_TRUE; 9166 PetscFunctionReturn(0); 9167 } 9168 for (o = -nO; o < nO; ++o) { 9169 const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o); 9170 9171 for (c = 0; c < cS; ++c) 9172 if (sourceVert[arr[c]] != targetVert[c]) break; 9173 if (c == cS) { 9174 *ornt = o; 9175 break; 9176 } 9177 } 9178 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9179 PetscFunctionReturn(0); 9180 } 9181 9182 /*@C 9183 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9184 9185 Not collective 9186 9187 Input Parameters: 9188 + ct - The `DMPolytopeType` 9189 . sourceCone - The source arrangement of vertices 9190 - targetCone - The target arrangement of vertices 9191 9192 Output Parameters: 9193 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9194 9195 Level: advanced 9196 9197 Note: 9198 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9199 9200 Developer Note: 9201 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9202 9203 .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9204 @*/ 9205 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9206 { 9207 PetscBool found; 9208 9209 PetscFunctionBegin; 9210 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9211 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9212 PetscFunctionReturn(0); 9213 } 9214 9215 /*@C 9216 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9217 9218 Not collective 9219 9220 Input Parameters: 9221 + ct - The `DMPolytopeType` 9222 - point - Coordinates of the point 9223 9224 Output Parameters: 9225 . inside - Flag indicating whether the point is inside the reference cell of given type 9226 9227 Level: advanced 9228 9229 .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()` 9230 @*/ 9231 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9232 { 9233 PetscReal sum = 0.0; 9234 PetscInt d; 9235 9236 PetscFunctionBegin; 9237 *inside = PETSC_TRUE; 9238 switch (ct) { 9239 case DM_POLYTOPE_TRIANGLE: 9240 case DM_POLYTOPE_TETRAHEDRON: 9241 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9242 if (point[d] < -1.0) { 9243 *inside = PETSC_FALSE; 9244 break; 9245 } 9246 sum += point[d]; 9247 } 9248 if (sum > PETSC_SMALL) { 9249 *inside = PETSC_FALSE; 9250 break; 9251 } 9252 break; 9253 case DM_POLYTOPE_QUADRILATERAL: 9254 case DM_POLYTOPE_HEXAHEDRON: 9255 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9256 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9257 *inside = PETSC_FALSE; 9258 break; 9259 } 9260 break; 9261 default: 9262 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9263 } 9264 PetscFunctionReturn(0); 9265 } 9266