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