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