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