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