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