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