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