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