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