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