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