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