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