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