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, MPIU_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, MPIU_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, MPIU_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 if (ishdf5) { 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 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6669 PetscFunctionReturn(PETSC_SUCCESS); 6670 } 6671 6672 /*@ 6673 DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer` 6674 6675 Input Parameters: 6676 + dm - The original `DM` 6677 . viewer - The `PetscViewer` to get it from 6678 - name - The sequence name 6679 6680 Output Parameter: 6681 . len - The length of the output sequence 6682 6683 Level: intermediate 6684 6685 Note: 6686 This is intended for output that should appear in sequence, for instance 6687 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6688 6689 Developer Note: 6690 It is unclear at the user API level why a `DM` is needed as input 6691 6692 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6693 @*/ 6694 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len) 6695 { 6696 PetscBool ishdf5; 6697 6698 PetscFunctionBegin; 6699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6700 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6701 PetscAssertPointer(name, 3); 6702 PetscAssertPointer(len, 4); 6703 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6704 if (ishdf5) { 6705 #if defined(PETSC_HAVE_HDF5) 6706 PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer)); 6707 #endif 6708 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6709 PetscFunctionReturn(PETSC_SUCCESS); 6710 } 6711 6712 /*@ 6713 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6714 6715 Not Collective 6716 6717 Input Parameter: 6718 . dm - The `DM` 6719 6720 Output Parameter: 6721 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6722 6723 Level: beginner 6724 6725 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()` 6726 @*/ 6727 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6728 { 6729 PetscFunctionBegin; 6730 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6731 PetscAssertPointer(useNatural, 2); 6732 *useNatural = dm->useNatural; 6733 PetscFunctionReturn(PETSC_SUCCESS); 6734 } 6735 6736 /*@ 6737 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6738 6739 Collective 6740 6741 Input Parameters: 6742 + dm - The `DM` 6743 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6744 6745 Level: beginner 6746 6747 Note: 6748 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6749 6750 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6751 @*/ 6752 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6753 { 6754 PetscFunctionBegin; 6755 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6756 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6757 dm->useNatural = useNatural; 6758 PetscFunctionReturn(PETSC_SUCCESS); 6759 } 6760 6761 /*@ 6762 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6763 6764 Not Collective 6765 6766 Input Parameters: 6767 + dm - The `DM` object 6768 - name - The label name 6769 6770 Level: intermediate 6771 6772 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6773 @*/ 6774 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6775 { 6776 PetscBool flg; 6777 DMLabel label; 6778 6779 PetscFunctionBegin; 6780 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6781 PetscAssertPointer(name, 2); 6782 PetscCall(DMHasLabel(dm, name, &flg)); 6783 if (!flg) { 6784 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6785 PetscCall(DMAddLabel(dm, label)); 6786 PetscCall(DMLabelDestroy(&label)); 6787 } 6788 PetscFunctionReturn(PETSC_SUCCESS); 6789 } 6790 6791 /*@ 6792 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6793 6794 Not Collective 6795 6796 Input Parameters: 6797 + dm - The `DM` object 6798 . l - The index for the label 6799 - name - The label name 6800 6801 Level: intermediate 6802 6803 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6804 @*/ 6805 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6806 { 6807 DMLabelLink orig, prev = NULL; 6808 DMLabel label; 6809 PetscInt Nl, m; 6810 PetscBool flg, match; 6811 const char *lname; 6812 6813 PetscFunctionBegin; 6814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6815 PetscAssertPointer(name, 3); 6816 PetscCall(DMHasLabel(dm, name, &flg)); 6817 if (!flg) { 6818 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6819 PetscCall(DMAddLabel(dm, label)); 6820 PetscCall(DMLabelDestroy(&label)); 6821 } 6822 PetscCall(DMGetNumLabels(dm, &Nl)); 6823 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6824 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6825 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6826 PetscCall(PetscStrcmp(name, lname, &match)); 6827 if (match) break; 6828 } 6829 if (m == l) PetscFunctionReturn(PETSC_SUCCESS); 6830 if (!m) dm->labels = orig->next; 6831 else prev->next = orig->next; 6832 if (!l) { 6833 orig->next = dm->labels; 6834 dm->labels = orig; 6835 } else { 6836 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next); 6837 orig->next = prev->next; 6838 prev->next = orig; 6839 } 6840 PetscFunctionReturn(PETSC_SUCCESS); 6841 } 6842 6843 /*@ 6844 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6845 6846 Not Collective 6847 6848 Input Parameters: 6849 + dm - The `DM` object 6850 . name - The label name 6851 - point - The mesh point 6852 6853 Output Parameter: 6854 . value - The label value for this point, or -1 if the point is not in the label 6855 6856 Level: beginner 6857 6858 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6859 @*/ 6860 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6861 { 6862 DMLabel label; 6863 6864 PetscFunctionBegin; 6865 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6866 PetscAssertPointer(name, 2); 6867 PetscCall(DMGetLabel(dm, name, &label)); 6868 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6869 PetscCall(DMLabelGetValue(label, point, value)); 6870 PetscFunctionReturn(PETSC_SUCCESS); 6871 } 6872 6873 /*@ 6874 DMSetLabelValue - Add a point to a `DMLabel` with given value 6875 6876 Not Collective 6877 6878 Input Parameters: 6879 + dm - The `DM` object 6880 . name - The label name 6881 . point - The mesh point 6882 - value - The label value for this point 6883 6884 Output Parameter: 6885 6886 Level: beginner 6887 6888 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6889 @*/ 6890 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6891 { 6892 DMLabel label; 6893 6894 PetscFunctionBegin; 6895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6896 PetscAssertPointer(name, 2); 6897 PetscCall(DMGetLabel(dm, name, &label)); 6898 if (!label) { 6899 PetscCall(DMCreateLabel(dm, name)); 6900 PetscCall(DMGetLabel(dm, name, &label)); 6901 } 6902 PetscCall(DMLabelSetValue(label, point, value)); 6903 PetscFunctionReturn(PETSC_SUCCESS); 6904 } 6905 6906 /*@ 6907 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6908 6909 Not Collective 6910 6911 Input Parameters: 6912 + dm - The `DM` object 6913 . name - The label name 6914 . point - The mesh point 6915 - value - The label value for this point 6916 6917 Level: beginner 6918 6919 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6920 @*/ 6921 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6922 { 6923 DMLabel label; 6924 6925 PetscFunctionBegin; 6926 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6927 PetscAssertPointer(name, 2); 6928 PetscCall(DMGetLabel(dm, name, &label)); 6929 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6930 PetscCall(DMLabelClearValue(label, point, value)); 6931 PetscFunctionReturn(PETSC_SUCCESS); 6932 } 6933 6934 /*@ 6935 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6936 6937 Not Collective 6938 6939 Input Parameters: 6940 + dm - The `DM` object 6941 - name - The label name 6942 6943 Output Parameter: 6944 . size - The number of different integer ids, or 0 if the label does not exist 6945 6946 Level: beginner 6947 6948 Developer Note: 6949 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6950 6951 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6952 @*/ 6953 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6954 { 6955 DMLabel label; 6956 6957 PetscFunctionBegin; 6958 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6959 PetscAssertPointer(name, 2); 6960 PetscAssertPointer(size, 3); 6961 PetscCall(DMGetLabel(dm, name, &label)); 6962 *size = 0; 6963 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6964 PetscCall(DMLabelGetNumValues(label, size)); 6965 PetscFunctionReturn(PETSC_SUCCESS); 6966 } 6967 6968 /*@ 6969 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6970 6971 Not Collective 6972 6973 Input Parameters: 6974 + dm - The `DM` object 6975 - name - The label name 6976 6977 Output Parameter: 6978 . ids - The integer ids, or `NULL` if the label does not exist 6979 6980 Level: beginner 6981 6982 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()` 6983 @*/ 6984 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6985 { 6986 DMLabel label; 6987 6988 PetscFunctionBegin; 6989 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6990 PetscAssertPointer(name, 2); 6991 PetscAssertPointer(ids, 3); 6992 PetscCall(DMGetLabel(dm, name, &label)); 6993 *ids = NULL; 6994 if (label) { 6995 PetscCall(DMLabelGetValueIS(label, ids)); 6996 } else { 6997 /* returning an empty IS */ 6998 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 6999 } 7000 PetscFunctionReturn(PETSC_SUCCESS); 7001 } 7002 7003 /*@ 7004 DMGetStratumSize - Get the number of points in a label stratum 7005 7006 Not Collective 7007 7008 Input Parameters: 7009 + dm - The `DM` object 7010 . name - The label name of the stratum 7011 - value - The stratum value 7012 7013 Output Parameter: 7014 . size - The number of points, also called the stratum size 7015 7016 Level: beginner 7017 7018 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 7019 @*/ 7020 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 7021 { 7022 DMLabel label; 7023 7024 PetscFunctionBegin; 7025 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7026 PetscAssertPointer(name, 2); 7027 PetscAssertPointer(size, 4); 7028 PetscCall(DMGetLabel(dm, name, &label)); 7029 *size = 0; 7030 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7031 PetscCall(DMLabelGetStratumSize(label, value, size)); 7032 PetscFunctionReturn(PETSC_SUCCESS); 7033 } 7034 7035 /*@ 7036 DMGetStratumIS - Get the points in a label stratum 7037 7038 Not Collective 7039 7040 Input Parameters: 7041 + dm - The `DM` object 7042 . name - The label name 7043 - value - The stratum value 7044 7045 Output Parameter: 7046 . points - The stratum points, or `NULL` if the label does not exist or does not have that value 7047 7048 Level: beginner 7049 7050 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()` 7051 @*/ 7052 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 7053 { 7054 DMLabel label; 7055 7056 PetscFunctionBegin; 7057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7058 PetscAssertPointer(name, 2); 7059 PetscAssertPointer(points, 4); 7060 PetscCall(DMGetLabel(dm, name, &label)); 7061 *points = NULL; 7062 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7063 PetscCall(DMLabelGetStratumIS(label, value, points)); 7064 PetscFunctionReturn(PETSC_SUCCESS); 7065 } 7066 7067 /*@ 7068 DMSetStratumIS - Set the points in a label stratum 7069 7070 Not Collective 7071 7072 Input Parameters: 7073 + dm - The `DM` object 7074 . name - The label name 7075 . value - The stratum value 7076 - points - The stratum points 7077 7078 Level: beginner 7079 7080 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 7081 @*/ 7082 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 7083 { 7084 DMLabel label; 7085 7086 PetscFunctionBegin; 7087 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7088 PetscAssertPointer(name, 2); 7089 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 7090 PetscCall(DMGetLabel(dm, name, &label)); 7091 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7092 PetscCall(DMLabelSetStratumIS(label, value, points)); 7093 PetscFunctionReturn(PETSC_SUCCESS); 7094 } 7095 7096 /*@ 7097 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 7098 7099 Not Collective 7100 7101 Input Parameters: 7102 + dm - The `DM` object 7103 . name - The label name 7104 - value - The label value for this point 7105 7106 Output Parameter: 7107 7108 Level: beginner 7109 7110 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 7111 @*/ 7112 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 7113 { 7114 DMLabel label; 7115 7116 PetscFunctionBegin; 7117 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7118 PetscAssertPointer(name, 2); 7119 PetscCall(DMGetLabel(dm, name, &label)); 7120 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7121 PetscCall(DMLabelClearStratum(label, value)); 7122 PetscFunctionReturn(PETSC_SUCCESS); 7123 } 7124 7125 /*@ 7126 DMGetNumLabels - Return the number of labels defined by on the `DM` 7127 7128 Not Collective 7129 7130 Input Parameter: 7131 . dm - The `DM` object 7132 7133 Output Parameter: 7134 . numLabels - the number of Labels 7135 7136 Level: intermediate 7137 7138 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7139 @*/ 7140 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 7141 { 7142 DMLabelLink next = dm->labels; 7143 PetscInt n = 0; 7144 7145 PetscFunctionBegin; 7146 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7147 PetscAssertPointer(numLabels, 2); 7148 while (next) { 7149 ++n; 7150 next = next->next; 7151 } 7152 *numLabels = n; 7153 PetscFunctionReturn(PETSC_SUCCESS); 7154 } 7155 7156 /*@ 7157 DMGetLabelName - Return the name of nth label 7158 7159 Not Collective 7160 7161 Input Parameters: 7162 + dm - The `DM` object 7163 - n - the label number 7164 7165 Output Parameter: 7166 . name - the label name 7167 7168 Level: intermediate 7169 7170 Developer Note: 7171 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 7172 7173 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7174 @*/ 7175 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[]) 7176 { 7177 DMLabelLink next = dm->labels; 7178 PetscInt l = 0; 7179 7180 PetscFunctionBegin; 7181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7182 PetscAssertPointer(name, 3); 7183 while (next) { 7184 if (l == n) { 7185 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 7186 PetscFunctionReturn(PETSC_SUCCESS); 7187 } 7188 ++l; 7189 next = next->next; 7190 } 7191 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7192 } 7193 7194 /*@ 7195 DMHasLabel - Determine whether the `DM` has a label of a given name 7196 7197 Not Collective 7198 7199 Input Parameters: 7200 + dm - The `DM` object 7201 - name - The label name 7202 7203 Output Parameter: 7204 . hasLabel - `PETSC_TRUE` if the label is present 7205 7206 Level: intermediate 7207 7208 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7209 @*/ 7210 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7211 { 7212 DMLabelLink next = dm->labels; 7213 const char *lname; 7214 7215 PetscFunctionBegin; 7216 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7217 PetscAssertPointer(name, 2); 7218 PetscAssertPointer(hasLabel, 3); 7219 *hasLabel = PETSC_FALSE; 7220 while (next) { 7221 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7222 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7223 if (*hasLabel) break; 7224 next = next->next; 7225 } 7226 PetscFunctionReturn(PETSC_SUCCESS); 7227 } 7228 7229 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7230 /*@ 7231 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM` 7232 7233 Not Collective 7234 7235 Input Parameters: 7236 + dm - The `DM` object 7237 - name - The label name 7238 7239 Output Parameter: 7240 . label - The `DMLabel`, or `NULL` if the label is absent 7241 7242 Default labels in a `DMPLEX`: 7243 + "depth" - Holds the depth (co-dimension) of each mesh point 7244 . "celltype" - Holds the topological type of each cell 7245 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7246 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7247 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7248 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7249 7250 Level: intermediate 7251 7252 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7253 @*/ 7254 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7255 { 7256 DMLabelLink next = dm->labels; 7257 PetscBool hasLabel; 7258 const char *lname; 7259 7260 PetscFunctionBegin; 7261 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7262 PetscAssertPointer(name, 2); 7263 PetscAssertPointer(label, 3); 7264 *label = NULL; 7265 while (next) { 7266 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7267 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7268 if (hasLabel) { 7269 *label = next->label; 7270 break; 7271 } 7272 next = next->next; 7273 } 7274 PetscFunctionReturn(PETSC_SUCCESS); 7275 } 7276 7277 /*@ 7278 DMGetLabelByNum - Return the nth label on a `DM` 7279 7280 Not Collective 7281 7282 Input Parameters: 7283 + dm - The `DM` object 7284 - n - the label number 7285 7286 Output Parameter: 7287 . label - the label 7288 7289 Level: intermediate 7290 7291 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7292 @*/ 7293 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7294 { 7295 DMLabelLink next = dm->labels; 7296 PetscInt l = 0; 7297 7298 PetscFunctionBegin; 7299 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7300 PetscAssertPointer(label, 3); 7301 while (next) { 7302 if (l == n) { 7303 *label = next->label; 7304 PetscFunctionReturn(PETSC_SUCCESS); 7305 } 7306 ++l; 7307 next = next->next; 7308 } 7309 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7310 } 7311 7312 /*@ 7313 DMAddLabel - Add the label to this `DM` 7314 7315 Not Collective 7316 7317 Input Parameters: 7318 + dm - The `DM` object 7319 - label - The `DMLabel` 7320 7321 Level: developer 7322 7323 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7324 @*/ 7325 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7326 { 7327 DMLabelLink l, *p, tmpLabel; 7328 PetscBool hasLabel; 7329 const char *lname; 7330 PetscBool flg; 7331 7332 PetscFunctionBegin; 7333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7334 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7335 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7336 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7337 PetscCall(PetscCalloc1(1, &tmpLabel)); 7338 tmpLabel->label = label; 7339 tmpLabel->output = PETSC_TRUE; 7340 for (p = &dm->labels; (l = *p); p = &l->next) { } 7341 *p = tmpLabel; 7342 PetscCall(PetscObjectReference((PetscObject)label)); 7343 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7344 if (flg) dm->depthLabel = label; 7345 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7346 if (flg) dm->celltypeLabel = label; 7347 PetscFunctionReturn(PETSC_SUCCESS); 7348 } 7349 7350 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7351 /*@ 7352 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7353 7354 Not Collective 7355 7356 Input Parameters: 7357 + dm - The `DM` object 7358 - label - The `DMLabel`, having the same name, to substitute 7359 7360 Default labels in a `DMPLEX`: 7361 + "depth" - Holds the depth (co-dimension) of each mesh point 7362 . "celltype" - Holds the topological type of each cell 7363 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7364 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7365 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7366 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7367 7368 Level: intermediate 7369 7370 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7371 @*/ 7372 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7373 { 7374 DMLabelLink next = dm->labels; 7375 PetscBool hasLabel, flg; 7376 const char *name, *lname; 7377 7378 PetscFunctionBegin; 7379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7380 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7381 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7382 while (next) { 7383 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7384 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7385 if (hasLabel) { 7386 PetscCall(PetscObjectReference((PetscObject)label)); 7387 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7388 if (flg) dm->depthLabel = label; 7389 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7390 if (flg) dm->celltypeLabel = label; 7391 PetscCall(DMLabelDestroy(&next->label)); 7392 next->label = label; 7393 break; 7394 } 7395 next = next->next; 7396 } 7397 PetscFunctionReturn(PETSC_SUCCESS); 7398 } 7399 7400 /*@ 7401 DMRemoveLabel - Remove the label given by name from this `DM` 7402 7403 Not Collective 7404 7405 Input Parameters: 7406 + dm - The `DM` object 7407 - name - The label name 7408 7409 Output Parameter: 7410 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the 7411 caller is responsible for calling `DMLabelDestroy()`. 7412 7413 Level: developer 7414 7415 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7416 @*/ 7417 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7418 { 7419 DMLabelLink link, *pnext; 7420 PetscBool hasLabel; 7421 const char *lname; 7422 7423 PetscFunctionBegin; 7424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7425 PetscAssertPointer(name, 2); 7426 if (label) { 7427 PetscAssertPointer(label, 3); 7428 *label = NULL; 7429 } 7430 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7431 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7432 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7433 if (hasLabel) { 7434 *pnext = link->next; /* Remove from list */ 7435 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7436 if (hasLabel) dm->depthLabel = NULL; 7437 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7438 if (hasLabel) dm->celltypeLabel = NULL; 7439 if (label) *label = link->label; 7440 else PetscCall(DMLabelDestroy(&link->label)); 7441 PetscCall(PetscFree(link)); 7442 break; 7443 } 7444 } 7445 PetscFunctionReturn(PETSC_SUCCESS); 7446 } 7447 7448 /*@ 7449 DMRemoveLabelBySelf - Remove the label from this `DM` 7450 7451 Not Collective 7452 7453 Input Parameters: 7454 + dm - The `DM` object 7455 . label - The `DMLabel` to be removed from the `DM` 7456 - failNotFound - Should it fail if the label is not found in the `DM`? 7457 7458 Level: developer 7459 7460 Note: 7461 Only exactly the same instance is removed if found, name match is ignored. 7462 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7463 *label nullified. 7464 7465 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7466 @*/ 7467 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7468 { 7469 DMLabelLink link, *pnext; 7470 PetscBool hasLabel = PETSC_FALSE; 7471 7472 PetscFunctionBegin; 7473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7474 PetscAssertPointer(label, 2); 7475 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS); 7476 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7477 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7478 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7479 if (*label == link->label) { 7480 hasLabel = PETSC_TRUE; 7481 *pnext = link->next; /* Remove from list */ 7482 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7483 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7484 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7485 PetscCall(DMLabelDestroy(&link->label)); 7486 PetscCall(PetscFree(link)); 7487 break; 7488 } 7489 } 7490 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7491 PetscFunctionReturn(PETSC_SUCCESS); 7492 } 7493 7494 /*@ 7495 DMGetLabelOutput - Get the output flag for a given label 7496 7497 Not Collective 7498 7499 Input Parameters: 7500 + dm - The `DM` object 7501 - name - The label name 7502 7503 Output Parameter: 7504 . output - The flag for output 7505 7506 Level: developer 7507 7508 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7509 @*/ 7510 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7511 { 7512 DMLabelLink next = dm->labels; 7513 const char *lname; 7514 7515 PetscFunctionBegin; 7516 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7517 PetscAssertPointer(name, 2); 7518 PetscAssertPointer(output, 3); 7519 while (next) { 7520 PetscBool flg; 7521 7522 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7523 PetscCall(PetscStrcmp(name, lname, &flg)); 7524 if (flg) { 7525 *output = next->output; 7526 PetscFunctionReturn(PETSC_SUCCESS); 7527 } 7528 next = next->next; 7529 } 7530 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7531 } 7532 7533 /*@ 7534 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7535 7536 Not Collective 7537 7538 Input Parameters: 7539 + dm - The `DM` object 7540 . name - The label name 7541 - output - `PETSC_TRUE` to save the label to the viewer 7542 7543 Level: developer 7544 7545 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7546 @*/ 7547 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7548 { 7549 DMLabelLink next = dm->labels; 7550 const char *lname; 7551 7552 PetscFunctionBegin; 7553 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7554 PetscAssertPointer(name, 2); 7555 while (next) { 7556 PetscBool flg; 7557 7558 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7559 PetscCall(PetscStrcmp(name, lname, &flg)); 7560 if (flg) { 7561 next->output = output; 7562 PetscFunctionReturn(PETSC_SUCCESS); 7563 } 7564 next = next->next; 7565 } 7566 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7567 } 7568 7569 /*@ 7570 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7571 7572 Collective 7573 7574 Input Parameters: 7575 + dmA - The `DM` object with initial labels 7576 . dmB - The `DM` object to which labels are copied 7577 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7578 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7579 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7580 7581 Level: intermediate 7582 7583 Note: 7584 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7585 7586 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7587 @*/ 7588 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7589 { 7590 DMLabel label, labelNew, labelOld; 7591 const char *name; 7592 PetscBool flg; 7593 DMLabelLink link; 7594 7595 PetscFunctionBegin; 7596 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7597 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7598 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7599 PetscValidLogicalCollectiveBool(dmA, all, 4); 7600 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7601 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 7602 for (link = dmA->labels; link; link = link->next) { 7603 label = link->label; 7604 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7605 if (!all) { 7606 PetscCall(PetscStrcmp(name, "depth", &flg)); 7607 if (flg) continue; 7608 PetscCall(PetscStrcmp(name, "dim", &flg)); 7609 if (flg) continue; 7610 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7611 if (flg) continue; 7612 } 7613 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7614 if (labelOld) { 7615 switch (emode) { 7616 case DM_COPY_LABELS_KEEP: 7617 continue; 7618 case DM_COPY_LABELS_REPLACE: 7619 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7620 break; 7621 case DM_COPY_LABELS_FAIL: 7622 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7623 default: 7624 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7625 } 7626 } 7627 if (mode == PETSC_COPY_VALUES) { 7628 PetscCall(DMLabelDuplicate(label, &labelNew)); 7629 } else { 7630 labelNew = label; 7631 } 7632 PetscCall(DMAddLabel(dmB, labelNew)); 7633 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7634 } 7635 PetscFunctionReturn(PETSC_SUCCESS); 7636 } 7637 7638 /*@C 7639 DMCompareLabels - Compare labels between two `DM` objects 7640 7641 Collective; No Fortran Support 7642 7643 Input Parameters: 7644 + dm0 - First `DM` object 7645 - dm1 - Second `DM` object 7646 7647 Output Parameters: 7648 + equal - (Optional) Flag whether labels of `dm0` and `dm1` are the same 7649 - message - (Optional) Message describing the difference, or `NULL` if there is no difference 7650 7651 Level: intermediate 7652 7653 Notes: 7654 The output flag equal will be the same on all processes. 7655 7656 If equal is passed as `NULL` and difference is found, an error is thrown on all processes. 7657 7658 Make sure to pass equal is `NULL` on all processes or none of them. 7659 7660 The output message is set independently on each rank. 7661 7662 message must be freed with `PetscFree()` 7663 7664 If message is passed as `NULL` and a difference is found, the difference description is printed to `stderr` in synchronized manner. 7665 7666 Make sure to pass message as `NULL` on all processes or no processes. 7667 7668 Labels are matched by name. If the number of labels and their names are equal, 7669 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7670 7671 Developer Note: 7672 Cannot automatically generate the Fortran stub because `message` must be freed with `PetscFree()` 7673 7674 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7675 @*/ 7676 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char *message[]) PeNS 7677 { 7678 PetscInt n, i; 7679 char msg[PETSC_MAX_PATH_LEN] = ""; 7680 PetscBool eq; 7681 MPI_Comm comm; 7682 PetscMPIInt rank; 7683 7684 PetscFunctionBegin; 7685 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7686 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7687 PetscCheckSameComm(dm0, 1, dm1, 2); 7688 if (equal) PetscAssertPointer(equal, 3); 7689 if (message) PetscAssertPointer(message, 4); 7690 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7691 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7692 { 7693 PetscInt n1; 7694 7695 PetscCall(DMGetNumLabels(dm0, &n)); 7696 PetscCall(DMGetNumLabels(dm1, &n1)); 7697 eq = (PetscBool)(n == n1); 7698 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7699 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7700 if (!eq) goto finish; 7701 } 7702 for (i = 0; i < n; i++) { 7703 DMLabel l0, l1; 7704 const char *name; 7705 char *msgInner; 7706 7707 /* Ignore label order */ 7708 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7709 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7710 PetscCall(DMGetLabel(dm1, name, &l1)); 7711 if (!l1) { 7712 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7713 eq = PETSC_FALSE; 7714 break; 7715 } 7716 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7717 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7718 PetscCall(PetscFree(msgInner)); 7719 if (!eq) break; 7720 } 7721 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7722 finish: 7723 /* If message output arg not set, print to stderr */ 7724 if (message) { 7725 *message = NULL; 7726 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7727 } else { 7728 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7729 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7730 } 7731 /* If same output arg not ser and labels are not equal, throw error */ 7732 if (equal) *equal = eq; 7733 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7734 PetscFunctionReturn(PETSC_SUCCESS); 7735 } 7736 7737 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7738 { 7739 PetscFunctionBegin; 7740 PetscAssertPointer(label, 2); 7741 if (!*label) { 7742 PetscCall(DMCreateLabel(dm, name)); 7743 PetscCall(DMGetLabel(dm, name, label)); 7744 } 7745 PetscCall(DMLabelSetValue(*label, point, value)); 7746 PetscFunctionReturn(PETSC_SUCCESS); 7747 } 7748 7749 /* 7750 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7751 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7752 (label, id) pair in the DM. 7753 7754 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7755 each label. 7756 */ 7757 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7758 { 7759 DMUniversalLabel ul; 7760 PetscBool *active; 7761 PetscInt pStart, pEnd, p, Nl, l, m; 7762 7763 PetscFunctionBegin; 7764 PetscCall(PetscMalloc1(1, &ul)); 7765 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7766 PetscCall(DMGetNumLabels(dm, &Nl)); 7767 PetscCall(PetscCalloc1(Nl, &active)); 7768 ul->Nl = 0; 7769 for (l = 0; l < Nl; ++l) { 7770 PetscBool isdepth, iscelltype; 7771 const char *name; 7772 7773 PetscCall(DMGetLabelName(dm, l, &name)); 7774 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7775 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7776 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7777 if (active[l]) ++ul->Nl; 7778 } 7779 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7780 ul->Nv = 0; 7781 for (l = 0, m = 0; l < Nl; ++l) { 7782 DMLabel label; 7783 PetscInt nv; 7784 const char *name; 7785 7786 if (!active[l]) continue; 7787 PetscCall(DMGetLabelName(dm, l, &name)); 7788 PetscCall(DMGetLabelByNum(dm, l, &label)); 7789 PetscCall(DMLabelGetNumValues(label, &nv)); 7790 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7791 ul->indices[m] = l; 7792 ul->Nv += nv; 7793 ul->offsets[m + 1] = nv; 7794 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7795 ++m; 7796 } 7797 for (l = 1; l <= ul->Nl; ++l) { 7798 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7799 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7800 } 7801 for (l = 0; l < ul->Nl; ++l) { 7802 PetscInt b; 7803 7804 ul->masks[l] = 0; 7805 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7806 } 7807 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7808 for (l = 0, m = 0; l < Nl; ++l) { 7809 DMLabel label; 7810 IS valueIS; 7811 const PetscInt *varr; 7812 PetscInt nv, v; 7813 7814 if (!active[l]) continue; 7815 PetscCall(DMGetLabelByNum(dm, l, &label)); 7816 PetscCall(DMLabelGetNumValues(label, &nv)); 7817 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7818 PetscCall(ISGetIndices(valueIS, &varr)); 7819 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7820 PetscCall(ISRestoreIndices(valueIS, &varr)); 7821 PetscCall(ISDestroy(&valueIS)); 7822 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7823 ++m; 7824 } 7825 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7826 for (p = pStart; p < pEnd; ++p) { 7827 PetscInt uval = 0; 7828 PetscBool marked = PETSC_FALSE; 7829 7830 for (l = 0, m = 0; l < Nl; ++l) { 7831 DMLabel label; 7832 PetscInt val, defval, loc, nv; 7833 7834 if (!active[l]) continue; 7835 PetscCall(DMGetLabelByNum(dm, l, &label)); 7836 PetscCall(DMLabelGetValue(label, p, &val)); 7837 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7838 if (val == defval) { 7839 ++m; 7840 continue; 7841 } 7842 nv = ul->offsets[m + 1] - ul->offsets[m]; 7843 marked = PETSC_TRUE; 7844 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7845 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7846 uval += (loc + 1) << ul->bits[m]; 7847 ++m; 7848 } 7849 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7850 } 7851 PetscCall(PetscFree(active)); 7852 *universal = ul; 7853 PetscFunctionReturn(PETSC_SUCCESS); 7854 } 7855 7856 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7857 { 7858 PetscInt l; 7859 7860 PetscFunctionBegin; 7861 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7862 PetscCall(DMLabelDestroy(&(*universal)->label)); 7863 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7864 PetscCall(PetscFree((*universal)->values)); 7865 PetscCall(PetscFree(*universal)); 7866 *universal = NULL; 7867 PetscFunctionReturn(PETSC_SUCCESS); 7868 } 7869 7870 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7871 { 7872 PetscFunctionBegin; 7873 PetscAssertPointer(ulabel, 2); 7874 *ulabel = ul->label; 7875 PetscFunctionReturn(PETSC_SUCCESS); 7876 } 7877 7878 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7879 { 7880 PetscInt Nl = ul->Nl, l; 7881 7882 PetscFunctionBegin; 7883 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7884 for (l = 0; l < Nl; ++l) { 7885 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7886 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7887 } 7888 if (preserveOrder) { 7889 for (l = 0; l < ul->Nl; ++l) { 7890 const char *name; 7891 PetscBool match; 7892 7893 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7894 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7895 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]); 7896 } 7897 } 7898 PetscFunctionReturn(PETSC_SUCCESS); 7899 } 7900 7901 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7902 { 7903 PetscInt l; 7904 7905 PetscFunctionBegin; 7906 for (l = 0; l < ul->Nl; ++l) { 7907 DMLabel label; 7908 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7909 7910 if (lval) { 7911 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7912 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7913 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7914 } 7915 } 7916 PetscFunctionReturn(PETSC_SUCCESS); 7917 } 7918 7919 /*@ 7920 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7921 7922 Not Collective 7923 7924 Input Parameter: 7925 . dm - The `DM` object 7926 7927 Output Parameter: 7928 . cdm - The coarse `DM` 7929 7930 Level: intermediate 7931 7932 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7933 @*/ 7934 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7935 { 7936 PetscFunctionBegin; 7937 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7938 PetscAssertPointer(cdm, 2); 7939 *cdm = dm->coarseMesh; 7940 PetscFunctionReturn(PETSC_SUCCESS); 7941 } 7942 7943 /*@ 7944 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7945 7946 Input Parameters: 7947 + dm - The `DM` object 7948 - cdm - The coarse `DM` 7949 7950 Level: intermediate 7951 7952 Note: 7953 Normally this is set automatically by `DMRefine()` 7954 7955 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7956 @*/ 7957 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7958 { 7959 PetscFunctionBegin; 7960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7961 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7962 if (dm == cdm) cdm = NULL; 7963 PetscCall(PetscObjectReference((PetscObject)cdm)); 7964 PetscCall(DMDestroy(&dm->coarseMesh)); 7965 dm->coarseMesh = cdm; 7966 PetscFunctionReturn(PETSC_SUCCESS); 7967 } 7968 7969 /*@ 7970 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7971 7972 Input Parameter: 7973 . dm - The `DM` object 7974 7975 Output Parameter: 7976 . fdm - The fine `DM` 7977 7978 Level: intermediate 7979 7980 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7981 @*/ 7982 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7983 { 7984 PetscFunctionBegin; 7985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7986 PetscAssertPointer(fdm, 2); 7987 *fdm = dm->fineMesh; 7988 PetscFunctionReturn(PETSC_SUCCESS); 7989 } 7990 7991 /*@ 7992 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7993 7994 Input Parameters: 7995 + dm - The `DM` object 7996 - fdm - The fine `DM` 7997 7998 Level: developer 7999 8000 Note: 8001 Normally this is set automatically by `DMCoarsen()` 8002 8003 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 8004 @*/ 8005 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 8006 { 8007 PetscFunctionBegin; 8008 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8009 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 8010 if (dm == fdm) fdm = NULL; 8011 PetscCall(PetscObjectReference((PetscObject)fdm)); 8012 PetscCall(DMDestroy(&dm->fineMesh)); 8013 dm->fineMesh = fdm; 8014 PetscFunctionReturn(PETSC_SUCCESS); 8015 } 8016 8017 /*@C 8018 DMAddBoundary - Add a boundary condition, for a single field, to a model represented by a `DM` 8019 8020 Collective 8021 8022 Input Parameters: 8023 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 8024 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 8025 . name - The BC name 8026 . label - The label defining constrained points 8027 . Nv - The number of `DMLabel` values for constrained points 8028 . values - An array of values for constrained points 8029 . field - The field to constrain 8030 . Nc - The number of constrained field components (0 will constrain all components) 8031 . comps - An array of constrained component numbers 8032 . bcFunc - A pointwise function giving boundary values 8033 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 8034 - ctx - An optional user context for bcFunc 8035 8036 Output Parameter: 8037 . bd - (Optional) Boundary number 8038 8039 Options Database Keys: 8040 + -bc_<boundary name> <num> - Overrides the boundary ids 8041 - -bc_<boundary name>_comp <num> - Overrides the boundary components 8042 8043 Level: intermediate 8044 8045 Notes: 8046 If the `DM` is of type `DMPLEX` and the field is of type `PetscFE`, then this function completes the label using `DMPlexLabelComplete()`. 8047 8048 Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 8049 .vb 8050 void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 8051 .ve 8052 8053 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 8054 8055 .vb 8056 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8057 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8058 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8059 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 8060 .ve 8061 + dim - the spatial dimension 8062 . Nf - the number of fields 8063 . uOff - the offset into u[] and u_t[] for each field 8064 . uOff_x - the offset into u_x[] for each field 8065 . u - each field evaluated at the current point 8066 . u_t - the time derivative of each field evaluated at the current point 8067 . u_x - the gradient of each field evaluated at the current point 8068 . aOff - the offset into a[] and a_t[] for each auxiliary field 8069 . aOff_x - the offset into a_x[] for each auxiliary field 8070 . a - each auxiliary field evaluated at the current point 8071 . a_t - the time derivative of each auxiliary field evaluated at the current point 8072 . a_x - the gradient of auxiliary each field evaluated at the current point 8073 . t - current time 8074 . x - coordinates of the current point 8075 . numConstants - number of constant parameters 8076 . constants - constant parameters 8077 - bcval - output values at the current point 8078 8079 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 8080 @*/ 8081 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd) 8082 { 8083 PetscDS ds; 8084 8085 PetscFunctionBegin; 8086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8087 PetscValidLogicalCollectiveEnum(dm, type, 2); 8088 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 8089 PetscValidLogicalCollectiveInt(dm, Nv, 5); 8090 PetscValidLogicalCollectiveInt(dm, field, 7); 8091 PetscValidLogicalCollectiveInt(dm, Nc, 8); 8092 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 8093 PetscCall(DMGetDS(dm, &ds)); 8094 /* Complete label */ 8095 if (label) { 8096 PetscObject obj; 8097 PetscClassId id; 8098 8099 PetscCall(DMGetField(dm, field, NULL, &obj)); 8100 PetscCall(PetscObjectGetClassId(obj, &id)); 8101 if (id == PETSCFE_CLASSID) { 8102 DM plex; 8103 8104 PetscCall(DMConvert(dm, DMPLEX, &plex)); 8105 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 8106 PetscCall(DMDestroy(&plex)); 8107 } 8108 } 8109 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 8110 PetscFunctionReturn(PETSC_SUCCESS); 8111 } 8112 8113 /* TODO Remove this since now the structures are the same */ 8114 static PetscErrorCode DMPopulateBoundary(DM dm) 8115 { 8116 PetscDS ds; 8117 DMBoundary *lastnext; 8118 DSBoundary dsbound; 8119 8120 PetscFunctionBegin; 8121 PetscCall(DMGetDS(dm, &ds)); 8122 dsbound = ds->boundary; 8123 if (dm->boundary) { 8124 DMBoundary next = dm->boundary; 8125 8126 /* quick check to see if the PetscDS has changed */ 8127 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 8128 /* the PetscDS has changed: tear down and rebuild */ 8129 while (next) { 8130 DMBoundary b = next; 8131 8132 next = b->next; 8133 PetscCall(PetscFree(b)); 8134 } 8135 dm->boundary = NULL; 8136 } 8137 8138 lastnext = &dm->boundary; 8139 while (dsbound) { 8140 DMBoundary dmbound; 8141 8142 PetscCall(PetscNew(&dmbound)); 8143 dmbound->dsboundary = dsbound; 8144 dmbound->label = dsbound->label; 8145 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8146 *lastnext = dmbound; 8147 lastnext = &dmbound->next; 8148 dsbound = dsbound->next; 8149 } 8150 PetscFunctionReturn(PETSC_SUCCESS); 8151 } 8152 8153 /* TODO: missing manual page */ 8154 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8155 { 8156 DMBoundary b; 8157 8158 PetscFunctionBegin; 8159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8160 PetscAssertPointer(isBd, 3); 8161 *isBd = PETSC_FALSE; 8162 PetscCall(DMPopulateBoundary(dm)); 8163 b = dm->boundary; 8164 while (b && !*isBd) { 8165 DMLabel label = b->label; 8166 DSBoundary dsb = b->dsboundary; 8167 PetscInt i; 8168 8169 if (label) { 8170 for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8171 } 8172 b = b->next; 8173 } 8174 PetscFunctionReturn(PETSC_SUCCESS); 8175 } 8176 8177 /*@ 8178 DMHasBound - Determine whether a bound condition was specified 8179 8180 Logically collective 8181 8182 Input Parameter: 8183 . dm - The `DM`, with a `PetscDS` that matches the problem being constrained 8184 8185 Output Parameter: 8186 . hasBound - Flag indicating if a bound condition was specified 8187 8188 Level: intermediate 8189 8190 .seealso: [](ch_dmbase), `DM`, `DSAddBoundary()`, `PetscDSAddBoundary()` 8191 @*/ 8192 PetscErrorCode DMHasBound(DM dm, PetscBool *hasBound) 8193 { 8194 PetscDS ds; 8195 PetscInt Nf, numBd; 8196 8197 PetscFunctionBegin; 8198 *hasBound = PETSC_FALSE; 8199 PetscCall(DMGetDS(dm, &ds)); 8200 PetscCall(PetscDSGetNumFields(ds, &Nf)); 8201 for (PetscInt f = 0; f < Nf; ++f) { 8202 PetscSimplePointFn *lfunc, *ufunc; 8203 8204 PetscCall(PetscDSGetLowerBound(ds, f, &lfunc, NULL)); 8205 PetscCall(PetscDSGetUpperBound(ds, f, &ufunc, NULL)); 8206 if (lfunc || ufunc) *hasBound = PETSC_TRUE; 8207 } 8208 8209 PetscCall(PetscDSGetNumBoundary(ds, &numBd)); 8210 PetscCall(PetscDSUpdateBoundaryLabels(ds, dm)); 8211 for (PetscInt b = 0; b < numBd; ++b) { 8212 PetscWeakForm wf; 8213 DMBoundaryConditionType type; 8214 const char *name; 8215 DMLabel label; 8216 PetscInt numids; 8217 const PetscInt *ids; 8218 PetscInt field, Nc; 8219 const PetscInt *comps; 8220 void (*bvfunc)(void); 8221 void *ctx; 8222 8223 PetscCall(PetscDSGetBoundary(ds, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 8224 if (type == DM_BC_LOWER_BOUND || type == DM_BC_UPPER_BOUND) *hasBound = PETSC_TRUE; 8225 } 8226 PetscFunctionReturn(PETSC_SUCCESS); 8227 } 8228 8229 /*@C 8230 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 8231 8232 Collective 8233 8234 Input Parameters: 8235 + dm - The `DM` 8236 . time - The time 8237 . funcs - The coordinate functions to evaluate, one per field 8238 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8239 - mode - The insertion mode for values 8240 8241 Output Parameter: 8242 . X - vector 8243 8244 Calling sequence of `funcs`: 8245 + dim - The spatial dimension 8246 . time - The time at which to sample 8247 . x - The coordinates 8248 . Nc - The number of components 8249 . u - The output field values 8250 - ctx - optional user-defined function context 8251 8252 Level: developer 8253 8254 Developer Notes: 8255 This API is specific to only particular usage of `DM` 8256 8257 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8258 8259 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8260 @*/ 8261 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) 8262 { 8263 Vec localX; 8264 8265 PetscFunctionBegin; 8266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8267 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8268 PetscCall(DMGetLocalVector(dm, &localX)); 8269 PetscCall(VecSet(localX, 0.)); 8270 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8271 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8272 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8273 PetscCall(DMRestoreLocalVector(dm, &localX)); 8274 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8275 PetscFunctionReturn(PETSC_SUCCESS); 8276 } 8277 8278 /*@C 8279 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8280 8281 Not Collective 8282 8283 Input Parameters: 8284 + dm - The `DM` 8285 . time - The time 8286 . funcs - The coordinate functions to evaluate, one per field 8287 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8288 - mode - The insertion mode for values 8289 8290 Output Parameter: 8291 . localX - vector 8292 8293 Calling sequence of `funcs`: 8294 + dim - The spatial dimension 8295 . time - The current timestep 8296 . x - The coordinates 8297 . Nc - The number of components 8298 . u - The output field values 8299 - ctx - optional user-defined function context 8300 8301 Level: developer 8302 8303 Developer Notes: 8304 This API is specific to only particular usage of `DM` 8305 8306 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8307 8308 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8309 @*/ 8310 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) 8311 { 8312 PetscFunctionBegin; 8313 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8314 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8315 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX); 8316 PetscFunctionReturn(PETSC_SUCCESS); 8317 } 8318 8319 /*@C 8320 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. 8321 8322 Collective 8323 8324 Input Parameters: 8325 + dm - The `DM` 8326 . time - The time 8327 . numIds - The number of ids 8328 . ids - The ids 8329 . Nc - The number of components 8330 . comps - The components 8331 . label - The `DMLabel` selecting the portion of the mesh for projection 8332 . funcs - The coordinate functions to evaluate, one per field 8333 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8334 - mode - The insertion mode for values 8335 8336 Output Parameter: 8337 . X - vector 8338 8339 Calling sequence of `funcs`: 8340 + dim - The spatial dimension 8341 . time - The current timestep 8342 . x - The coordinates 8343 . Nc - The number of components 8344 . u - The output field values 8345 - ctx - optional user-defined function context 8346 8347 Level: developer 8348 8349 Developer Notes: 8350 This API is specific to only particular usage of `DM` 8351 8352 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8353 8354 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8355 @*/ 8356 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) 8357 { 8358 Vec localX; 8359 8360 PetscFunctionBegin; 8361 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8362 PetscCall(DMGetLocalVector(dm, &localX)); 8363 PetscCall(VecSet(localX, 0.)); 8364 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8365 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8366 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8367 PetscCall(DMRestoreLocalVector(dm, &localX)); 8368 PetscFunctionReturn(PETSC_SUCCESS); 8369 } 8370 8371 /*@C 8372 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. 8373 8374 Not Collective 8375 8376 Input Parameters: 8377 + dm - The `DM` 8378 . time - The time 8379 . label - The `DMLabel` selecting the portion of the mesh for projection 8380 . numIds - The number of ids 8381 . ids - The ids 8382 . Nc - The number of components 8383 . comps - The components 8384 . funcs - The coordinate functions to evaluate, one per field 8385 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8386 - mode - The insertion mode for values 8387 8388 Output Parameter: 8389 . localX - vector 8390 8391 Calling sequence of `funcs`: 8392 + dim - The spatial dimension 8393 . time - The current time 8394 . x - The coordinates 8395 . Nc - The number of components 8396 . u - The output field values 8397 - ctx - optional user-defined function context 8398 8399 Level: developer 8400 8401 Developer Notes: 8402 This API is specific to only particular usage of `DM` 8403 8404 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8405 8406 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8407 @*/ 8408 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) 8409 { 8410 PetscFunctionBegin; 8411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8412 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8413 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX); 8414 PetscFunctionReturn(PETSC_SUCCESS); 8415 } 8416 8417 /*@C 8418 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. 8419 8420 Not Collective 8421 8422 Input Parameters: 8423 + dm - The `DM` 8424 . time - The time 8425 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8426 . funcs - The functions to evaluate, one per field 8427 - mode - The insertion mode for values 8428 8429 Output Parameter: 8430 . localX - The output vector 8431 8432 Calling sequence of `funcs`: 8433 + dim - The spatial dimension 8434 . Nf - The number of input fields 8435 . NfAux - The number of input auxiliary fields 8436 . uOff - The offset of each field in u[] 8437 . uOff_x - The offset of each field in u_x[] 8438 . u - The field values at this point in space 8439 . u_t - The field time derivative at this point in space (or NULL) 8440 . u_x - The field derivatives at this point in space 8441 . aOff - The offset of each auxiliary field in u[] 8442 . aOff_x - The offset of each auxiliary field in u_x[] 8443 . a - The auxiliary field values at this point in space 8444 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8445 . a_x - The auxiliary field derivatives at this point in space 8446 . t - The current time 8447 . x - The coordinates of this point 8448 . numConstants - The number of constants 8449 . constants - The value of each constant 8450 - f - The value of the function at this point in space 8451 8452 Level: intermediate 8453 8454 Note: 8455 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. 8456 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 8457 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8458 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8459 8460 Developer Notes: 8461 This API is specific to only particular usage of `DM` 8462 8463 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8464 8465 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8466 `DMProjectFunction()`, `DMComputeL2Diff()` 8467 @*/ 8468 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) 8469 { 8470 PetscFunctionBegin; 8471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8472 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8473 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8474 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX); 8475 PetscFunctionReturn(PETSC_SUCCESS); 8476 } 8477 8478 /*@C 8479 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. 8480 8481 Not Collective 8482 8483 Input Parameters: 8484 + dm - The `DM` 8485 . time - The time 8486 . label - The `DMLabel` marking the portion of the domain to output 8487 . numIds - The number of label ids to use 8488 . ids - The label ids to use for marking 8489 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8490 . comps - The components to set in the output, or `NULL` for all components 8491 . localU - The input field vector 8492 . funcs - The functions to evaluate, one per field 8493 - mode - The insertion mode for values 8494 8495 Output Parameter: 8496 . localX - The output vector 8497 8498 Calling sequence of `funcs`: 8499 + dim - The spatial dimension 8500 . Nf - The number of input fields 8501 . NfAux - The number of input auxiliary fields 8502 . uOff - The offset of each field in u[] 8503 . uOff_x - The offset of each field in u_x[] 8504 . u - The field values at this point in space 8505 . u_t - The field time derivative at this point in space (or NULL) 8506 . u_x - The field derivatives at this point in space 8507 . aOff - The offset of each auxiliary field in u[] 8508 . aOff_x - The offset of each auxiliary field in u_x[] 8509 . a - The auxiliary field values at this point in space 8510 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8511 . a_x - The auxiliary field derivatives at this point in space 8512 . t - The current time 8513 . x - The coordinates of this point 8514 . numConstants - The number of constants 8515 . constants - The value of each constant 8516 - f - The value of the function at this point in space 8517 8518 Level: intermediate 8519 8520 Note: 8521 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. 8522 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 8523 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8524 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8525 8526 Developer Notes: 8527 This API is specific to only particular usage of `DM` 8528 8529 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8530 8531 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8532 @*/ 8533 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) 8534 { 8535 PetscFunctionBegin; 8536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8537 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8538 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8539 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8540 PetscFunctionReturn(PETSC_SUCCESS); 8541 } 8542 8543 /*@C 8544 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. 8545 8546 Not Collective 8547 8548 Input Parameters: 8549 + dm - The `DM` 8550 . time - The time 8551 . label - The `DMLabel` marking the portion of the domain to output 8552 . numIds - The number of label ids to use 8553 . ids - The label ids to use for marking 8554 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8555 . comps - The components to set in the output, or `NULL` for all components 8556 . U - The input field vector 8557 . funcs - The functions to evaluate, one per field 8558 - mode - The insertion mode for values 8559 8560 Output Parameter: 8561 . X - The output vector 8562 8563 Calling sequence of `funcs`: 8564 + dim - The spatial dimension 8565 . Nf - The number of input fields 8566 . NfAux - The number of input auxiliary fields 8567 . uOff - The offset of each field in u[] 8568 . uOff_x - The offset of each field in u_x[] 8569 . u - The field values at this point in space 8570 . u_t - The field time derivative at this point in space (or NULL) 8571 . u_x - The field derivatives at this point in space 8572 . aOff - The offset of each auxiliary field in u[] 8573 . aOff_x - The offset of each auxiliary field in u_x[] 8574 . a - The auxiliary field values at this point in space 8575 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8576 . a_x - The auxiliary field derivatives at this point in space 8577 . t - The current time 8578 . x - The coordinates of this point 8579 . numConstants - The number of constants 8580 . constants - The value of each constant 8581 - f - The value of the function at this point in space 8582 8583 Level: intermediate 8584 8585 Note: 8586 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. 8587 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 8588 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8589 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8590 8591 Developer Notes: 8592 This API is specific to only particular usage of `DM` 8593 8594 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8595 8596 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8597 @*/ 8598 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) 8599 { 8600 DM dmIn; 8601 Vec localU, localX; 8602 8603 PetscFunctionBegin; 8604 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8605 PetscCall(VecGetDM(U, &dmIn)); 8606 PetscCall(DMGetLocalVector(dmIn, &localU)); 8607 PetscCall(DMGetLocalVector(dm, &localX)); 8608 PetscCall(VecSet(localX, 0.)); 8609 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8610 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8611 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8612 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8613 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8614 PetscCall(DMRestoreLocalVector(dm, &localX)); 8615 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8616 PetscFunctionReturn(PETSC_SUCCESS); 8617 } 8618 8619 /*@C 8620 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. 8621 8622 Not Collective 8623 8624 Input Parameters: 8625 + dm - The `DM` 8626 . time - The time 8627 . label - The `DMLabel` marking the portion of the domain boundary to output 8628 . numIds - The number of label ids to use 8629 . ids - The label ids to use for marking 8630 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8631 . comps - The components to set in the output, or `NULL` for all components 8632 . localU - The input field vector 8633 . funcs - The functions to evaluate, one per field 8634 - mode - The insertion mode for values 8635 8636 Output Parameter: 8637 . localX - The output vector 8638 8639 Calling sequence of `funcs`: 8640 + dim - The spatial dimension 8641 . Nf - The number of input fields 8642 . NfAux - The number of input auxiliary fields 8643 . uOff - The offset of each field in u[] 8644 . uOff_x - The offset of each field in u_x[] 8645 . u - The field values at this point in space 8646 . u_t - The field time derivative at this point in space (or NULL) 8647 . u_x - The field derivatives at this point in space 8648 . aOff - The offset of each auxiliary field in u[] 8649 . aOff_x - The offset of each auxiliary field in u_x[] 8650 . a - The auxiliary field values at this point in space 8651 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8652 . a_x - The auxiliary field derivatives at this point in space 8653 . t - The current time 8654 . x - The coordinates of this point 8655 . n - The face normal 8656 . numConstants - The number of constants 8657 . constants - The value of each constant 8658 - f - The value of the function at this point in space 8659 8660 Level: intermediate 8661 8662 Note: 8663 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. 8664 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 8665 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8666 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8667 8668 Developer Notes: 8669 This API is specific to only particular usage of `DM` 8670 8671 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8672 8673 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8674 @*/ 8675 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) 8676 { 8677 PetscFunctionBegin; 8678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8679 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8680 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8681 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8682 PetscFunctionReturn(PETSC_SUCCESS); 8683 } 8684 8685 /*@C 8686 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8687 8688 Collective 8689 8690 Input Parameters: 8691 + dm - The `DM` 8692 . time - The time 8693 . funcs - The functions to evaluate for each field component 8694 . ctxs - Optional array of contexts to pass to each function, or NULL. 8695 - X - The coefficient vector u_h, a global vector 8696 8697 Output Parameter: 8698 . diff - The diff ||u - u_h||_2 8699 8700 Level: developer 8701 8702 Developer Notes: 8703 This API is specific to only particular usage of `DM` 8704 8705 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8706 8707 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8708 @*/ 8709 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8710 { 8711 PetscFunctionBegin; 8712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8713 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8714 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff); 8715 PetscFunctionReturn(PETSC_SUCCESS); 8716 } 8717 8718 /*@C 8719 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8720 8721 Collective 8722 8723 Input Parameters: 8724 + dm - The `DM` 8725 . time - The time 8726 . funcs - The gradient functions to evaluate for each field component 8727 . ctxs - Optional array of contexts to pass to each function, or NULL. 8728 . X - The coefficient vector u_h, a global vector 8729 - n - The vector to project along 8730 8731 Output Parameter: 8732 . diff - The diff ||(grad u - grad u_h) . n||_2 8733 8734 Level: developer 8735 8736 Developer Notes: 8737 This API is specific to only particular usage of `DM` 8738 8739 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8740 8741 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8742 @*/ 8743 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) 8744 { 8745 PetscFunctionBegin; 8746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8747 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8748 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff); 8749 PetscFunctionReturn(PETSC_SUCCESS); 8750 } 8751 8752 /*@C 8753 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8754 8755 Collective 8756 8757 Input Parameters: 8758 + dm - The `DM` 8759 . time - The time 8760 . funcs - The functions to evaluate for each field component 8761 . ctxs - Optional array of contexts to pass to each function, or NULL. 8762 - X - The coefficient vector u_h, a global vector 8763 8764 Output Parameter: 8765 . diff - The array of differences, ||u^f - u^f_h||_2 8766 8767 Level: developer 8768 8769 Developer Notes: 8770 This API is specific to only particular usage of `DM` 8771 8772 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8773 8774 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8775 @*/ 8776 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8777 { 8778 PetscFunctionBegin; 8779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8780 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8781 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff); 8782 PetscFunctionReturn(PETSC_SUCCESS); 8783 } 8784 8785 /*@C 8786 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8787 8788 Not Collective 8789 8790 Input Parameter: 8791 . dm - The `DM` 8792 8793 Output Parameters: 8794 + nranks - the number of neighbours 8795 - ranks - the neighbors ranks 8796 8797 Level: beginner 8798 8799 Note: 8800 Do not free the array, it is freed when the `DM` is destroyed. 8801 8802 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8803 @*/ 8804 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8805 { 8806 PetscFunctionBegin; 8807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8808 PetscUseTypeMethod(dm, getneighbors, nranks, ranks); 8809 PetscFunctionReturn(PETSC_SUCCESS); 8810 } 8811 8812 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8813 8814 /* 8815 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8816 This must be a different function because it requires DM which is not defined in the Mat library 8817 */ 8818 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8819 { 8820 PetscFunctionBegin; 8821 if (coloring->ctype == IS_COLORING_LOCAL) { 8822 Vec x1local; 8823 DM dm; 8824 PetscCall(MatGetDM(J, &dm)); 8825 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8826 PetscCall(DMGetLocalVector(dm, &x1local)); 8827 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8828 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8829 x1 = x1local; 8830 } 8831 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8832 if (coloring->ctype == IS_COLORING_LOCAL) { 8833 DM dm; 8834 PetscCall(MatGetDM(J, &dm)); 8835 PetscCall(DMRestoreLocalVector(dm, &x1)); 8836 } 8837 PetscFunctionReturn(PETSC_SUCCESS); 8838 } 8839 8840 /*@ 8841 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8842 8843 Input Parameters: 8844 + coloring - The matrix to get the `DM` from 8845 - fdcoloring - the `MatFDColoring` object 8846 8847 Level: advanced 8848 8849 Developer Note: 8850 This routine exists because the PETSc `Mat` library does not know about the `DM` objects 8851 8852 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8853 @*/ 8854 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8855 { 8856 PetscFunctionBegin; 8857 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8858 PetscFunctionReturn(PETSC_SUCCESS); 8859 } 8860 8861 /*@ 8862 DMGetCompatibility - determine if two `DM`s are compatible 8863 8864 Collective 8865 8866 Input Parameters: 8867 + dm1 - the first `DM` 8868 - dm2 - the second `DM` 8869 8870 Output Parameters: 8871 + compatible - whether or not the two `DM`s are compatible 8872 - set - whether or not the compatible value was actually determined and set 8873 8874 Level: advanced 8875 8876 Notes: 8877 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8878 of the same topology. This implies that the section (field data) on one 8879 "makes sense" with respect to the topology and parallel decomposition of the other. 8880 Loosely speaking, compatible `DM`s represent the same domain and parallel 8881 decomposition, but hold different data. 8882 8883 Typically, one would confirm compatibility if intending to simultaneously iterate 8884 over a pair of vectors obtained from different `DM`s. 8885 8886 For example, two `DMDA` objects are compatible if they have the same local 8887 and global sizes and the same stencil width. They can have different numbers 8888 of degrees of freedom per node. Thus, one could use the node numbering from 8889 either `DM` in bounds for a loop over vectors derived from either `DM`. 8890 8891 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8892 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8893 .vb 8894 ... 8895 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8896 if (set && compatible) { 8897 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8898 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8899 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8900 for (j=y; j<y+n; ++j) { 8901 for (i=x; i<x+m, ++i) { 8902 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8903 } 8904 } 8905 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8906 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8907 } else { 8908 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8909 } 8910 ... 8911 .ve 8912 8913 Checking compatibility might be expensive for a given implementation of `DM`, 8914 or might be impossible to unambiguously confirm or deny. For this reason, 8915 this function may decline to determine compatibility, and hence users should 8916 always check the "set" output parameter. 8917 8918 A `DM` is always compatible with itself. 8919 8920 In the current implementation, `DM`s which live on "unequal" communicators 8921 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8922 incompatible. 8923 8924 This function is labeled "Collective," as information about all subdomains 8925 is required on each rank. However, in `DM` implementations which store all this 8926 information locally, this function may be merely "Logically Collective". 8927 8928 Developer Note: 8929 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8930 iff B is compatible with A. Thus, this function checks the implementations 8931 of both dm and dmc (if they are of different types), attempting to determine 8932 compatibility. It is left to `DM` implementers to ensure that symmetry is 8933 preserved. The simplest way to do this is, when implementing type-specific 8934 logic for this function, is to check for existing logic in the implementation 8935 of other `DM` types and let *set = PETSC_FALSE if found. 8936 8937 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8938 @*/ 8939 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8940 { 8941 PetscMPIInt compareResult; 8942 DMType type, type2; 8943 PetscBool sameType; 8944 8945 PetscFunctionBegin; 8946 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8947 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8948 8949 /* Declare a DM compatible with itself */ 8950 if (dm1 == dm2) { 8951 *set = PETSC_TRUE; 8952 *compatible = PETSC_TRUE; 8953 PetscFunctionReturn(PETSC_SUCCESS); 8954 } 8955 8956 /* Declare a DM incompatible with a DM that lives on an "unequal" 8957 communicator. Note that this does not preclude compatibility with 8958 DMs living on "congruent" or "similar" communicators, but this must be 8959 determined by the implementation-specific logic */ 8960 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8961 if (compareResult == MPI_UNEQUAL) { 8962 *set = PETSC_TRUE; 8963 *compatible = PETSC_FALSE; 8964 PetscFunctionReturn(PETSC_SUCCESS); 8965 } 8966 8967 /* Pass to the implementation-specific routine, if one exists. */ 8968 if (dm1->ops->getcompatibility) { 8969 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8970 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8971 } 8972 8973 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8974 with an implementation of this function from dm2 */ 8975 PetscCall(DMGetType(dm1, &type)); 8976 PetscCall(DMGetType(dm2, &type2)); 8977 PetscCall(PetscStrcmp(type, type2, &sameType)); 8978 if (!sameType && dm2->ops->getcompatibility) { 8979 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8980 } else { 8981 *set = PETSC_FALSE; 8982 } 8983 PetscFunctionReturn(PETSC_SUCCESS); 8984 } 8985 8986 /*@C 8987 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8988 8989 Logically Collective 8990 8991 Input Parameters: 8992 + dm - the `DM` 8993 . f - the monitor function 8994 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8995 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence 8996 8997 Options Database Key: 8998 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8999 does not cancel those set via the options database. 9000 9001 Level: intermediate 9002 9003 Note: 9004 Several different monitoring routines may be set by calling 9005 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 9006 order in which they were set. 9007 9008 Fortran Note: 9009 Only a single monitor function can be set for each `DM` object 9010 9011 Developer Note: 9012 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 9013 9014 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn` 9015 @*/ 9016 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy) 9017 { 9018 PetscInt m; 9019 9020 PetscFunctionBegin; 9021 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9022 for (m = 0; m < dm->numbermonitors; ++m) { 9023 PetscBool identical; 9024 9025 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 9026 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 9027 } 9028 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 9029 dm->monitor[dm->numbermonitors] = f; 9030 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 9031 dm->monitorcontext[dm->numbermonitors++] = mctx; 9032 PetscFunctionReturn(PETSC_SUCCESS); 9033 } 9034 9035 /*@ 9036 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 9037 9038 Logically Collective 9039 9040 Input Parameter: 9041 . dm - the DM 9042 9043 Options Database Key: 9044 . -dm_monitor_cancel - cancels all monitors that have been hardwired 9045 into a code by calls to `DMonitorSet()`, but does not cancel those 9046 set via the options database 9047 9048 Level: intermediate 9049 9050 Note: 9051 There is no way to clear one specific monitor from a `DM` object. 9052 9053 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 9054 @*/ 9055 PetscErrorCode DMMonitorCancel(DM dm) 9056 { 9057 PetscInt m; 9058 9059 PetscFunctionBegin; 9060 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9061 for (m = 0; m < dm->numbermonitors; ++m) { 9062 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 9063 } 9064 dm->numbermonitors = 0; 9065 PetscFunctionReturn(PETSC_SUCCESS); 9066 } 9067 9068 /*@C 9069 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 9070 9071 Collective 9072 9073 Input Parameters: 9074 + dm - `DM` object you wish to monitor 9075 . name - the monitor type one is seeking 9076 . help - message indicating what monitoring is done 9077 . manual - manual page for the monitor 9078 . monitor - the monitor function, this must use a `PetscViewerFormat` as its context 9079 - 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 9080 9081 Output Parameter: 9082 . flg - Flag set if the monitor was created 9083 9084 Level: developer 9085 9086 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 9087 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 9088 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 9089 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 9090 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 9091 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 9092 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 9093 @*/ 9094 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 9095 { 9096 PetscViewer viewer; 9097 PetscViewerFormat format; 9098 9099 PetscFunctionBegin; 9100 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9101 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 9102 if (*flg) { 9103 PetscViewerAndFormat *vf; 9104 9105 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 9106 PetscCall(PetscViewerDestroy(&viewer)); 9107 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 9108 PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy)); 9109 } 9110 PetscFunctionReturn(PETSC_SUCCESS); 9111 } 9112 9113 /*@ 9114 DMMonitor - runs the user provided monitor routines, if they exist 9115 9116 Collective 9117 9118 Input Parameter: 9119 . dm - The `DM` 9120 9121 Level: developer 9122 9123 Developer Note: 9124 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 9125 related to the discretization process seems rather specialized since some `DM` have no 9126 concept of discretization. 9127 9128 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 9129 @*/ 9130 PetscErrorCode DMMonitor(DM dm) 9131 { 9132 PetscInt m; 9133 9134 PetscFunctionBegin; 9135 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 9136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9137 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 9138 PetscFunctionReturn(PETSC_SUCCESS); 9139 } 9140 9141 /*@ 9142 DMComputeError - Computes the error assuming the user has provided the exact solution functions 9143 9144 Collective 9145 9146 Input Parameters: 9147 + dm - The `DM` 9148 - sol - The solution vector 9149 9150 Input/Output Parameter: 9151 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 9152 contains the error in each field 9153 9154 Output Parameter: 9155 . errorVec - A vector to hold the cellwise error (may be `NULL`) 9156 9157 Level: developer 9158 9159 Note: 9160 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 9161 9162 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 9163 @*/ 9164 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 9165 { 9166 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 9167 void **ctxs; 9168 PetscReal time; 9169 PetscInt Nf, f, Nds, s; 9170 9171 PetscFunctionBegin; 9172 PetscCall(DMGetNumFields(dm, &Nf)); 9173 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 9174 PetscCall(DMGetNumDS(dm, &Nds)); 9175 for (s = 0; s < Nds; ++s) { 9176 PetscDS ds; 9177 DMLabel label; 9178 IS fieldIS; 9179 const PetscInt *fields; 9180 PetscInt dsNf; 9181 9182 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 9183 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9184 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9185 for (f = 0; f < dsNf; ++f) { 9186 const PetscInt field = fields[f]; 9187 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9188 } 9189 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9190 } 9191 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); 9192 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9193 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9194 if (errorVec) { 9195 DM edm; 9196 DMPolytopeType ct; 9197 PetscBool simplex; 9198 PetscInt dim, cStart, Nf; 9199 9200 PetscCall(DMClone(dm, &edm)); 9201 PetscCall(DMGetDimension(edm, &dim)); 9202 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9203 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9204 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9205 PetscCall(DMGetNumFields(dm, &Nf)); 9206 for (f = 0; f < Nf; ++f) { 9207 PetscFE fe, efe; 9208 PetscQuadrature q; 9209 const char *name; 9210 9211 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 9212 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9213 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 9214 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 9215 PetscCall(PetscFEGetQuadrature(fe, &q)); 9216 PetscCall(PetscFESetQuadrature(efe, q)); 9217 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 9218 PetscCall(PetscFEDestroy(&efe)); 9219 } 9220 PetscCall(DMCreateDS(edm)); 9221 9222 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9223 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 9224 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9225 PetscCall(DMDestroy(&edm)); 9226 } 9227 PetscCall(PetscFree2(exactSol, ctxs)); 9228 PetscFunctionReturn(PETSC_SUCCESS); 9229 } 9230 9231 /*@ 9232 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 9233 9234 Not Collective 9235 9236 Input Parameter: 9237 . dm - The `DM` 9238 9239 Output Parameter: 9240 . numAux - The number of auxiliary data vectors 9241 9242 Level: advanced 9243 9244 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 9245 @*/ 9246 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9247 { 9248 PetscFunctionBegin; 9249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9250 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9251 PetscFunctionReturn(PETSC_SUCCESS); 9252 } 9253 9254 /*@ 9255 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9256 9257 Not Collective 9258 9259 Input Parameters: 9260 + dm - The `DM` 9261 . label - The `DMLabel` 9262 . value - The label value indicating the region 9263 - part - The equation part, or 0 if unused 9264 9265 Output Parameter: 9266 . aux - The `Vec` holding auxiliary field data 9267 9268 Level: advanced 9269 9270 Note: 9271 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9272 9273 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9274 @*/ 9275 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9276 { 9277 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9278 PetscBool has; 9279 9280 PetscFunctionBegin; 9281 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9282 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9283 key.label = label; 9284 key.value = value; 9285 key.part = part; 9286 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9287 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9288 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9289 PetscFunctionReturn(PETSC_SUCCESS); 9290 } 9291 9292 /*@ 9293 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9294 9295 Not Collective because auxiliary vectors are not parallel 9296 9297 Input Parameters: 9298 + dm - The `DM` 9299 . label - The `DMLabel` 9300 . value - The label value indicating the region 9301 . part - The equation part, or 0 if unused 9302 - aux - The `Vec` holding auxiliary field data 9303 9304 Level: advanced 9305 9306 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9307 @*/ 9308 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9309 { 9310 Vec old; 9311 PetscHashAuxKey key; 9312 9313 PetscFunctionBegin; 9314 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9315 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9316 key.label = label; 9317 key.value = value; 9318 key.part = part; 9319 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9320 PetscCall(PetscObjectReference((PetscObject)aux)); 9321 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9322 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9323 PetscCall(VecDestroy(&old)); 9324 PetscFunctionReturn(PETSC_SUCCESS); 9325 } 9326 9327 /*@ 9328 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9329 9330 Not Collective 9331 9332 Input Parameter: 9333 . dm - The `DM` 9334 9335 Output Parameters: 9336 + labels - The `DMLabel`s for each `Vec` 9337 . values - The label values for each `Vec` 9338 - parts - The equation parts for each `Vec` 9339 9340 Level: advanced 9341 9342 Note: 9343 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9344 9345 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9346 @*/ 9347 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9348 { 9349 PetscHashAuxKey *keys; 9350 PetscInt n, i, off = 0; 9351 9352 PetscFunctionBegin; 9353 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9354 PetscAssertPointer(labels, 2); 9355 PetscAssertPointer(values, 3); 9356 PetscAssertPointer(parts, 4); 9357 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9358 PetscCall(PetscMalloc1(n, &keys)); 9359 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9360 for (i = 0; i < n; ++i) { 9361 labels[i] = keys[i].label; 9362 values[i] = keys[i].value; 9363 parts[i] = keys[i].part; 9364 } 9365 PetscCall(PetscFree(keys)); 9366 PetscFunctionReturn(PETSC_SUCCESS); 9367 } 9368 9369 /*@ 9370 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9371 9372 Not Collective 9373 9374 Input Parameter: 9375 . dm - The `DM` 9376 9377 Output Parameter: 9378 . dmNew - The new `DM`, now with the same auxiliary data 9379 9380 Level: advanced 9381 9382 Note: 9383 This is a shallow copy of the auxiliary vectors 9384 9385 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9386 @*/ 9387 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9388 { 9389 PetscFunctionBegin; 9390 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9391 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2); 9392 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS); 9393 PetscCall(DMClearAuxiliaryVec(dmNew)); 9394 9395 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9396 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9397 { 9398 Vec *auxData; 9399 PetscInt n, i, off = 0; 9400 9401 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n)); 9402 PetscCall(PetscMalloc1(n, &auxData)); 9403 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData)); 9404 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i])); 9405 PetscCall(PetscFree(auxData)); 9406 } 9407 PetscFunctionReturn(PETSC_SUCCESS); 9408 } 9409 9410 /*@ 9411 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one 9412 9413 Not Collective 9414 9415 Input Parameter: 9416 . dm - The `DM` 9417 9418 Level: advanced 9419 9420 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9421 @*/ 9422 PetscErrorCode DMClearAuxiliaryVec(DM dm) 9423 { 9424 Vec *auxData; 9425 PetscInt n, i, off = 0; 9426 9427 PetscFunctionBegin; 9428 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n)); 9429 PetscCall(PetscMalloc1(n, &auxData)); 9430 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData)); 9431 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 9432 PetscCall(PetscFree(auxData)); 9433 PetscCall(PetscHMapAuxDestroy(&dm->auxData)); 9434 PetscCall(PetscHMapAuxCreate(&dm->auxData)); 9435 PetscFunctionReturn(PETSC_SUCCESS); 9436 } 9437 9438 /*@ 9439 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9440 9441 Not Collective 9442 9443 Input Parameters: 9444 + ct - The `DMPolytopeType` 9445 . sourceCone - The source arrangement of faces 9446 - targetCone - The target arrangement of faces 9447 9448 Output Parameters: 9449 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9450 - found - Flag indicating that a suitable orientation was found 9451 9452 Level: advanced 9453 9454 Note: 9455 An arrangement is a face order combined with an orientation for each face 9456 9457 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9458 that labels each arrangement (face ordering plus orientation for each face). 9459 9460 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9461 9462 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9463 @*/ 9464 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9465 { 9466 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9467 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9468 PetscInt o, c; 9469 9470 PetscFunctionBegin; 9471 if (!nO) { 9472 *ornt = 0; 9473 *found = PETSC_TRUE; 9474 PetscFunctionReturn(PETSC_SUCCESS); 9475 } 9476 for (o = -nO; o < nO; ++o) { 9477 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 9478 9479 for (c = 0; c < cS; ++c) 9480 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9481 if (c == cS) { 9482 *ornt = o; 9483 break; 9484 } 9485 } 9486 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9487 PetscFunctionReturn(PETSC_SUCCESS); 9488 } 9489 9490 /*@ 9491 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9492 9493 Not Collective 9494 9495 Input Parameters: 9496 + ct - The `DMPolytopeType` 9497 . sourceCone - The source arrangement of faces 9498 - targetCone - The target arrangement of faces 9499 9500 Output Parameter: 9501 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9502 9503 Level: advanced 9504 9505 Note: 9506 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9507 9508 Developer Note: 9509 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9510 9511 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9512 @*/ 9513 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9514 { 9515 PetscBool found; 9516 9517 PetscFunctionBegin; 9518 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9519 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9520 PetscFunctionReturn(PETSC_SUCCESS); 9521 } 9522 9523 /*@ 9524 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9525 9526 Not Collective 9527 9528 Input Parameters: 9529 + ct - The `DMPolytopeType` 9530 . sourceVert - The source arrangement of vertices 9531 - targetVert - The target arrangement of vertices 9532 9533 Output Parameters: 9534 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9535 - found - Flag indicating that a suitable orientation was found 9536 9537 Level: advanced 9538 9539 Notes: 9540 An arrangement is a vertex order 9541 9542 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9543 that labels each arrangement (vertex ordering). 9544 9545 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9546 9547 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()` 9548 @*/ 9549 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9550 { 9551 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9552 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9553 PetscInt o, c; 9554 9555 PetscFunctionBegin; 9556 if (!nO) { 9557 *ornt = 0; 9558 *found = PETSC_TRUE; 9559 PetscFunctionReturn(PETSC_SUCCESS); 9560 } 9561 for (o = -nO; o < nO; ++o) { 9562 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o); 9563 9564 for (c = 0; c < cS; ++c) 9565 if (sourceVert[arr[c]] != targetVert[c]) break; 9566 if (c == cS) { 9567 *ornt = o; 9568 break; 9569 } 9570 } 9571 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9572 PetscFunctionReturn(PETSC_SUCCESS); 9573 } 9574 9575 /*@ 9576 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9577 9578 Not Collective 9579 9580 Input Parameters: 9581 + ct - The `DMPolytopeType` 9582 . sourceCone - The source arrangement of vertices 9583 - targetCone - The target arrangement of vertices 9584 9585 Output Parameter: 9586 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9587 9588 Level: advanced 9589 9590 Note: 9591 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9592 9593 Developer Note: 9594 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9595 9596 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9597 @*/ 9598 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9599 { 9600 PetscBool found; 9601 9602 PetscFunctionBegin; 9603 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9604 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9605 PetscFunctionReturn(PETSC_SUCCESS); 9606 } 9607 9608 /*@ 9609 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9610 9611 Not Collective 9612 9613 Input Parameters: 9614 + ct - The `DMPolytopeType` 9615 - point - Coordinates of the point 9616 9617 Output Parameter: 9618 . inside - Flag indicating whether the point is inside the reference cell of given type 9619 9620 Level: advanced 9621 9622 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9623 @*/ 9624 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9625 { 9626 PetscReal sum = 0.0; 9627 PetscInt d; 9628 9629 PetscFunctionBegin; 9630 *inside = PETSC_TRUE; 9631 switch (ct) { 9632 case DM_POLYTOPE_TRIANGLE: 9633 case DM_POLYTOPE_TETRAHEDRON: 9634 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9635 if (point[d] < -1.0) { 9636 *inside = PETSC_FALSE; 9637 break; 9638 } 9639 sum += point[d]; 9640 } 9641 if (sum > PETSC_SMALL) { 9642 *inside = PETSC_FALSE; 9643 break; 9644 } 9645 break; 9646 case DM_POLYTOPE_QUADRILATERAL: 9647 case DM_POLYTOPE_HEXAHEDRON: 9648 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9649 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9650 *inside = PETSC_FALSE; 9651 break; 9652 } 9653 break; 9654 default: 9655 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9656 } 9657 PetscFunctionReturn(PETSC_SUCCESS); 9658 } 9659 9660 /*@ 9661 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default 9662 9663 Logically collective 9664 9665 Input Parameters: 9666 + dm - The DM 9667 - reorder - Flag for reordering 9668 9669 Level: intermediate 9670 9671 .seealso: `DMReorderSectionGetDefault()` 9672 @*/ 9673 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder) 9674 { 9675 PetscFunctionBegin; 9676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9677 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); 9678 PetscFunctionReturn(PETSC_SUCCESS); 9679 } 9680 9681 /*@ 9682 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default 9683 9684 Not collective 9685 9686 Input Parameter: 9687 . dm - The DM 9688 9689 Output Parameter: 9690 . reorder - Flag for reordering 9691 9692 Level: intermediate 9693 9694 .seealso: `DMReorderSetDefault()` 9695 @*/ 9696 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder) 9697 { 9698 PetscFunctionBegin; 9699 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9700 PetscAssertPointer(reorder, 2); 9701 *reorder = DM_REORDER_DEFAULT_NOTSET; 9702 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); 9703 PetscFunctionReturn(PETSC_SUCCESS); 9704 } 9705 9706 /*@ 9707 DMReorderSectionSetType - Set the type of local section reordering 9708 9709 Logically collective 9710 9711 Input Parameters: 9712 + dm - The DM 9713 - reorder - The reordering method 9714 9715 Level: intermediate 9716 9717 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()` 9718 @*/ 9719 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder) 9720 { 9721 PetscFunctionBegin; 9722 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9723 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder)); 9724 PetscFunctionReturn(PETSC_SUCCESS); 9725 } 9726 9727 /*@ 9728 DMReorderSectionGetType - Get the reordering type for the local section 9729 9730 Not collective 9731 9732 Input Parameter: 9733 . dm - The DM 9734 9735 Output Parameter: 9736 . reorder - The reordering method 9737 9738 Level: intermediate 9739 9740 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()` 9741 @*/ 9742 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder) 9743 { 9744 PetscFunctionBegin; 9745 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9746 PetscAssertPointer(reorder, 2); 9747 *reorder = NULL; 9748 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder)); 9749 PetscFunctionReturn(PETSC_SUCCESS); 9750 } 9751