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