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