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