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