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