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) { 4140 conv = dm->ops->convert; 4141 } 4142 if (conv) goto foundconv; 4143 #endif 4144 4145 /* 5) Use a really basic converter. */ 4146 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype); 4147 4148 foundconv: 4149 PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0)); 4150 PetscCall((*conv)(dm, newtype, M)); 4151 /* Things that are independent of DM type: We should consult DMClone() here */ 4152 { 4153 const PetscReal *maxCell, *Lstart, *L; 4154 4155 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 4156 PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L)); 4157 (*M)->prealloc_only = dm->prealloc_only; 4158 PetscCall(PetscFree((*M)->vectype)); 4159 PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype)); 4160 PetscCall(PetscFree((*M)->mattype)); 4161 PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype)); 4162 } 4163 PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0)); 4164 } 4165 PetscCall(PetscObjectStateIncrease((PetscObject)*M)); 4166 PetscFunctionReturn(PETSC_SUCCESS); 4167 } 4168 4169 /*@C 4170 DMRegister - Adds a new `DM` type implementation 4171 4172 Not Collective, No Fortran Support 4173 4174 Input Parameters: 4175 + sname - The name of a new user-defined creation routine 4176 - function - The creation routine itself 4177 4178 Level: advanced 4179 4180 Note: 4181 `DMRegister()` may be called multiple times to add several user-defined `DM`s 4182 4183 Example Usage: 4184 .vb 4185 DMRegister("my_da", MyDMCreate); 4186 .ve 4187 4188 Then, your `DM` type can be chosen with the procedural interface via 4189 .vb 4190 DMCreate(MPI_Comm, DM *); 4191 DMSetType(DM,"my_da"); 4192 .ve 4193 or at runtime via the option 4194 .vb 4195 -da_type my_da 4196 .ve 4197 4198 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()` 4199 @*/ 4200 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM)) 4201 { 4202 PetscFunctionBegin; 4203 PetscCall(DMInitializePackage()); 4204 PetscCall(PetscFunctionListAdd(&DMList, sname, function)); 4205 PetscFunctionReturn(PETSC_SUCCESS); 4206 } 4207 4208 /*@ 4209 DMLoad - Loads a DM that has been stored in binary with `DMView()`. 4210 4211 Collective 4212 4213 Input Parameters: 4214 + newdm - the newly loaded `DM`, this needs to have been created with `DMCreate()` or 4215 some related function before a call to `DMLoad()`. 4216 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or 4217 `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()` 4218 4219 Level: intermediate 4220 4221 Notes: 4222 The type is determined by the data in the file, any type set into the DM before this call is ignored. 4223 4224 Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX` 4225 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 4226 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 4227 4228 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()` 4229 @*/ 4230 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer) 4231 { 4232 PetscBool isbinary, ishdf5; 4233 4234 PetscFunctionBegin; 4235 PetscValidHeaderSpecific(newdm, DM_CLASSID, 1); 4236 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 4237 PetscCall(PetscViewerCheckReadable(viewer)); 4238 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 4239 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 4240 PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0)); 4241 if (isbinary) { 4242 PetscInt classid; 4243 char type[256]; 4244 4245 PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT)); 4246 PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %" PetscInt_FMT, classid); 4247 PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR)); 4248 PetscCall(DMSetType(newdm, type)); 4249 PetscTryTypeMethod(newdm, load, viewer); 4250 } else if (ishdf5) { 4251 PetscTryTypeMethod(newdm, load, viewer); 4252 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()"); 4253 PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0)); 4254 PetscFunctionReturn(PETSC_SUCCESS); 4255 } 4256 4257 /* FEM Support */ 4258 4259 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[]) 4260 { 4261 PetscInt f; 4262 4263 PetscFunctionBegin; 4264 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name)); 4265 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %" PetscInt_FMT " |\n", x[f])); 4266 PetscFunctionReturn(PETSC_SUCCESS); 4267 } 4268 4269 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[]) 4270 { 4271 PetscInt f; 4272 4273 PetscFunctionBegin; 4274 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name)); 4275 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)PetscRealPart(x[f]))); 4276 PetscFunctionReturn(PETSC_SUCCESS); 4277 } 4278 4279 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[]) 4280 { 4281 PetscInt f; 4282 4283 PetscFunctionBegin; 4284 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name)); 4285 for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, " | %g |\n", (double)x[f])); 4286 PetscFunctionReturn(PETSC_SUCCESS); 4287 } 4288 4289 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[]) 4290 { 4291 PetscInt f, g; 4292 4293 PetscFunctionBegin; 4294 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name)); 4295 for (f = 0; f < rows; ++f) { 4296 PetscCall(PetscPrintf(PETSC_COMM_SELF, " |")); 4297 for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g]))); 4298 PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n")); 4299 } 4300 PetscFunctionReturn(PETSC_SUCCESS); 4301 } 4302 4303 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X) 4304 { 4305 PetscInt localSize, bs; 4306 PetscMPIInt size; 4307 Vec x, xglob; 4308 const PetscScalar *xarray; 4309 4310 PetscFunctionBegin; 4311 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 4312 PetscCall(VecDuplicate(X, &x)); 4313 PetscCall(VecCopy(X, x)); 4314 PetscCall(VecFilter(x, tol)); 4315 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name)); 4316 if (size > 1) { 4317 PetscCall(VecGetLocalSize(x, &localSize)); 4318 PetscCall(VecGetArrayRead(x, &xarray)); 4319 PetscCall(VecGetBlockSize(x, &bs)); 4320 PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob)); 4321 } else { 4322 xglob = x; 4323 } 4324 PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm)))); 4325 if (size > 1) { 4326 PetscCall(VecDestroy(&xglob)); 4327 PetscCall(VecRestoreArrayRead(x, &xarray)); 4328 } 4329 PetscCall(VecDestroy(&x)); 4330 PetscFunctionReturn(PETSC_SUCCESS); 4331 } 4332 4333 /*@ 4334 DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`. 4335 4336 Input Parameter: 4337 . dm - The `DM` 4338 4339 Output Parameter: 4340 . section - The `PetscSection` 4341 4342 Options Database Key: 4343 . -dm_petscsection_view - View the section created by the `DM` 4344 4345 Level: intermediate 4346 4347 Note: 4348 This gets a borrowed reference, so the user should not destroy this `PetscSection`. 4349 4350 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()` 4351 @*/ 4352 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section) 4353 { 4354 PetscFunctionBegin; 4355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4356 PetscAssertPointer(section, 2); 4357 if (!dm->localSection && dm->ops->createlocalsection) { 4358 PetscInt d; 4359 4360 if (dm->setfromoptionscalled) { 4361 PetscObject obj = (PetscObject)dm; 4362 PetscViewer viewer; 4363 PetscViewerFormat format; 4364 PetscBool flg; 4365 4366 PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg)); 4367 if (flg) PetscCall(PetscViewerPushFormat(viewer, format)); 4368 for (d = 0; d < dm->Nds; ++d) { 4369 PetscCall(PetscDSSetFromOptions(dm->probs[d].ds)); 4370 if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer)); 4371 } 4372 if (flg) { 4373 PetscCall(PetscViewerFlush(viewer)); 4374 PetscCall(PetscViewerPopFormat(viewer)); 4375 PetscCall(PetscViewerDestroy(&viewer)); 4376 } 4377 } 4378 PetscUseTypeMethod(dm, createlocalsection); 4379 if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view")); 4380 } 4381 *section = dm->localSection; 4382 PetscFunctionReturn(PETSC_SUCCESS); 4383 } 4384 4385 /*@ 4386 DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`. 4387 4388 Input Parameters: 4389 + dm - The `DM` 4390 - section - The `PetscSection` 4391 4392 Level: intermediate 4393 4394 Note: 4395 Any existing Section will be destroyed 4396 4397 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()` 4398 @*/ 4399 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section) 4400 { 4401 PetscInt numFields = 0; 4402 PetscInt f; 4403 4404 PetscFunctionBegin; 4405 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4406 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4407 PetscCall(PetscObjectReference((PetscObject)section)); 4408 PetscCall(PetscSectionDestroy(&dm->localSection)); 4409 dm->localSection = section; 4410 if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields)); 4411 if (numFields) { 4412 PetscCall(DMSetNumFields(dm, numFields)); 4413 for (f = 0; f < numFields; ++f) { 4414 PetscObject disc; 4415 const char *name; 4416 4417 PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name)); 4418 PetscCall(DMGetField(dm, f, NULL, &disc)); 4419 PetscCall(PetscObjectSetName(disc, name)); 4420 } 4421 } 4422 /* The global section and the SectionSF will be rebuilt 4423 in the next call to DMGetGlobalSection() and DMGetSectionSF(). */ 4424 PetscCall(PetscSectionDestroy(&dm->globalSection)); 4425 PetscCall(PetscSFDestroy(&dm->sectionSF)); 4426 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF)); 4427 4428 /* Clear scratch vectors */ 4429 PetscCall(DMClearGlobalVectors(dm)); 4430 PetscCall(DMClearLocalVectors(dm)); 4431 PetscCall(DMClearNamedGlobalVectors(dm)); 4432 PetscCall(DMClearNamedLocalVectors(dm)); 4433 PetscFunctionReturn(PETSC_SUCCESS); 4434 } 4435 4436 /*@C 4437 DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure. 4438 4439 Input Parameter: 4440 . dm - The `DM` 4441 4442 Output Parameters: 4443 + perm - A permutation of the mesh points in the chart 4444 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking 4445 4446 Level: developer 4447 4448 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()` 4449 @*/ 4450 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts) 4451 { 4452 PetscFunctionBegin; 4453 *perm = NULL; 4454 *blockStarts = NULL; 4455 PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts); 4456 PetscFunctionReturn(PETSC_SUCCESS); 4457 } 4458 4459 /*@ 4460 DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation. 4461 4462 not Collective 4463 4464 Input Parameter: 4465 . dm - The `DM` 4466 4467 Output Parameters: 4468 + 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. 4469 . 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. 4470 - bias - Vector containing bias to be added to constrained dofs 4471 4472 Level: advanced 4473 4474 Note: 4475 This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`. 4476 4477 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()` 4478 @*/ 4479 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias) 4480 { 4481 PetscFunctionBegin; 4482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4483 if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints); 4484 if (section) *section = dm->defaultConstraint.section; 4485 if (mat) *mat = dm->defaultConstraint.mat; 4486 if (bias) *bias = dm->defaultConstraint.bias; 4487 PetscFunctionReturn(PETSC_SUCCESS); 4488 } 4489 4490 /*@ 4491 DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation. 4492 4493 Collective 4494 4495 Input Parameters: 4496 + dm - The `DM` 4497 . 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). 4498 . 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). 4499 - 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). 4500 4501 Level: advanced 4502 4503 Notes: 4504 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()`. 4505 4506 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. 4507 4508 This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them. 4509 4510 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()` 4511 @*/ 4512 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias) 4513 { 4514 PetscMPIInt result; 4515 4516 PetscFunctionBegin; 4517 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4518 if (section) { 4519 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4520 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result)); 4521 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator"); 4522 } 4523 if (mat) { 4524 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3); 4525 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result)); 4526 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator"); 4527 } 4528 if (bias) { 4529 PetscValidHeaderSpecific(bias, VEC_CLASSID, 4); 4530 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result)); 4531 PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator"); 4532 } 4533 PetscCall(PetscObjectReference((PetscObject)section)); 4534 PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section)); 4535 dm->defaultConstraint.section = section; 4536 PetscCall(PetscObjectReference((PetscObject)mat)); 4537 PetscCall(MatDestroy(&dm->defaultConstraint.mat)); 4538 dm->defaultConstraint.mat = mat; 4539 PetscCall(PetscObjectReference((PetscObject)bias)); 4540 PetscCall(VecDestroy(&dm->defaultConstraint.bias)); 4541 dm->defaultConstraint.bias = bias; 4542 PetscFunctionReturn(PETSC_SUCCESS); 4543 } 4544 4545 #if defined(PETSC_USE_DEBUG) 4546 /* 4547 DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent. 4548 4549 Input Parameters: 4550 + dm - The `DM` 4551 . localSection - `PetscSection` describing the local data layout 4552 - globalSection - `PetscSection` describing the global data layout 4553 4554 Level: intermediate 4555 4556 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()` 4557 */ 4558 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection) 4559 { 4560 MPI_Comm comm; 4561 PetscLayout layout; 4562 const PetscInt *ranges; 4563 PetscInt pStart, pEnd, p, nroots; 4564 PetscMPIInt size, rank; 4565 PetscBool valid = PETSC_TRUE, gvalid; 4566 4567 PetscFunctionBegin; 4568 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 4569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4570 PetscCallMPI(MPI_Comm_size(comm, &size)); 4571 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 4572 PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd)); 4573 PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots)); 4574 PetscCall(PetscLayoutCreate(comm, &layout)); 4575 PetscCall(PetscLayoutSetBlockSize(layout, 1)); 4576 PetscCall(PetscLayoutSetLocalSize(layout, nroots)); 4577 PetscCall(PetscLayoutSetUp(layout)); 4578 PetscCall(PetscLayoutGetRanges(layout, &ranges)); 4579 for (p = pStart; p < pEnd; ++p) { 4580 PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d; 4581 4582 PetscCall(PetscSectionGetDof(localSection, p, &dof)); 4583 PetscCall(PetscSectionGetOffset(localSection, p, &off)); 4584 PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof)); 4585 PetscCall(PetscSectionGetDof(globalSection, p, &gdof)); 4586 PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof)); 4587 PetscCall(PetscSectionGetOffset(globalSection, p, &goff)); 4588 if (!gdof) continue; /* Censored point */ 4589 if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) { 4590 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof)); 4591 valid = PETSC_FALSE; 4592 } 4593 if (gcdof && (gcdof != cdof)) { 4594 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof)); 4595 valid = PETSC_FALSE; 4596 } 4597 if (gdof < 0) { 4598 gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof; 4599 for (d = 0; d < gsize; ++d) { 4600 PetscInt offset = -(goff + 1) + d, r; 4601 4602 PetscCall(PetscFindInt(offset, size + 1, ranges, &r)); 4603 if (r < 0) r = -(r + 2); 4604 if ((r < 0) || (r >= size)) { 4605 PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff)); 4606 valid = PETSC_FALSE; 4607 break; 4608 } 4609 } 4610 } 4611 } 4612 PetscCall(PetscLayoutDestroy(&layout)); 4613 PetscCall(PetscSynchronizedFlush(comm, NULL)); 4614 PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm)); 4615 if (!gvalid) { 4616 PetscCall(DMView(dm, NULL)); 4617 SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections"); 4618 } 4619 PetscFunctionReturn(PETSC_SUCCESS); 4620 } 4621 #endif 4622 4623 PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf) 4624 { 4625 PetscErrorCode (*f)(DM, PetscSF *); 4626 4627 PetscFunctionBegin; 4628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4629 PetscAssertPointer(sf, 2); 4630 PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f)); 4631 if (f) PetscCall(f(dm, sf)); 4632 else *sf = dm->sf; 4633 PetscFunctionReturn(PETSC_SUCCESS); 4634 } 4635 4636 /*@ 4637 DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`. 4638 4639 Collective 4640 4641 Input Parameter: 4642 . dm - The `DM` 4643 4644 Output Parameter: 4645 . section - The `PetscSection` 4646 4647 Level: intermediate 4648 4649 Note: 4650 This gets a borrowed reference, so the user should not destroy this `PetscSection`. 4651 4652 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()` 4653 @*/ 4654 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section) 4655 { 4656 PetscFunctionBegin; 4657 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4658 PetscAssertPointer(section, 2); 4659 if (!dm->globalSection) { 4660 PetscSection s; 4661 PetscSF sf; 4662 4663 PetscCall(DMGetLocalSection(dm, &s)); 4664 PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection"); 4665 PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection"); 4666 PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf)); 4667 PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection)); 4668 PetscCall(PetscLayoutDestroy(&dm->map)); 4669 PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map)); 4670 PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view")); 4671 } 4672 *section = dm->globalSection; 4673 PetscFunctionReturn(PETSC_SUCCESS); 4674 } 4675 4676 /*@ 4677 DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`. 4678 4679 Input Parameters: 4680 + dm - The `DM` 4681 - section - The PetscSection, or `NULL` 4682 4683 Level: intermediate 4684 4685 Note: 4686 Any existing `PetscSection` will be destroyed 4687 4688 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()` 4689 @*/ 4690 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section) 4691 { 4692 PetscFunctionBegin; 4693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4694 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4695 PetscCall(PetscObjectReference((PetscObject)section)); 4696 PetscCall(PetscSectionDestroy(&dm->globalSection)); 4697 dm->globalSection = section; 4698 #if defined(PETSC_USE_DEBUG) 4699 if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section)); 4700 #endif 4701 /* Clear global scratch vectors and sectionSF */ 4702 PetscCall(PetscSFDestroy(&dm->sectionSF)); 4703 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF)); 4704 PetscCall(DMClearGlobalVectors(dm)); 4705 PetscCall(DMClearNamedGlobalVectors(dm)); 4706 PetscFunctionReturn(PETSC_SUCCESS); 4707 } 4708 4709 /*@ 4710 DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set, 4711 it is created from the default `PetscSection` layouts in the `DM`. 4712 4713 Input Parameter: 4714 . dm - The `DM` 4715 4716 Output Parameter: 4717 . sf - The `PetscSF` 4718 4719 Level: intermediate 4720 4721 Note: 4722 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4723 4724 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4725 @*/ 4726 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf) 4727 { 4728 PetscInt nroots; 4729 4730 PetscFunctionBegin; 4731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4732 PetscAssertPointer(sf, 2); 4733 if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF)); 4734 PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL)); 4735 if (nroots < 0) { 4736 PetscSection section, gSection; 4737 4738 PetscCall(DMGetLocalSection(dm, §ion)); 4739 if (section) { 4740 PetscCall(DMGetGlobalSection(dm, &gSection)); 4741 PetscCall(DMCreateSectionSF(dm, section, gSection)); 4742 } else { 4743 *sf = NULL; 4744 PetscFunctionReturn(PETSC_SUCCESS); 4745 } 4746 } 4747 *sf = dm->sectionSF; 4748 PetscFunctionReturn(PETSC_SUCCESS); 4749 } 4750 4751 /*@ 4752 DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM` 4753 4754 Input Parameters: 4755 + dm - The `DM` 4756 - sf - The `PetscSF` 4757 4758 Level: intermediate 4759 4760 Note: 4761 Any previous `PetscSF` is destroyed 4762 4763 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()` 4764 @*/ 4765 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf) 4766 { 4767 PetscFunctionBegin; 4768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4769 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4770 PetscCall(PetscObjectReference((PetscObject)sf)); 4771 PetscCall(PetscSFDestroy(&dm->sectionSF)); 4772 dm->sectionSF = sf; 4773 PetscFunctionReturn(PETSC_SUCCESS); 4774 } 4775 4776 /*@ 4777 DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s 4778 describing the data layout. 4779 4780 Input Parameters: 4781 + dm - The `DM` 4782 . localSection - `PetscSection` describing the local data layout 4783 - globalSection - `PetscSection` describing the global data layout 4784 4785 Level: developer 4786 4787 Note: 4788 One usually uses `DMGetSectionSF()` to obtain the `PetscSF` 4789 4790 Developer Note: 4791 Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF` 4792 directly into the `DM`, perhaps this function should not take the local and global sections as 4793 input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing 4794 they create, this returns nothing 4795 4796 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 4797 @*/ 4798 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection) 4799 { 4800 PetscFunctionBegin; 4801 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4802 PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection)); 4803 PetscFunctionReturn(PETSC_SUCCESS); 4804 } 4805 4806 /*@ 4807 DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`. 4808 4809 Not collective but the resulting `PetscSF` is collective 4810 4811 Input Parameter: 4812 . dm - The `DM` 4813 4814 Output Parameter: 4815 . sf - The `PetscSF` 4816 4817 Level: intermediate 4818 4819 Note: 4820 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4821 4822 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4823 @*/ 4824 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf) 4825 { 4826 PetscFunctionBegin; 4827 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4828 PetscAssertPointer(sf, 2); 4829 *sf = dm->sf; 4830 PetscFunctionReturn(PETSC_SUCCESS); 4831 } 4832 4833 /*@ 4834 DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`. 4835 4836 Collective 4837 4838 Input Parameters: 4839 + dm - The `DM` 4840 - sf - The `PetscSF` 4841 4842 Level: intermediate 4843 4844 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4845 @*/ 4846 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf) 4847 { 4848 PetscFunctionBegin; 4849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4850 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4851 PetscCall(PetscObjectReference((PetscObject)sf)); 4852 PetscCall(PetscSFDestroy(&dm->sf)); 4853 dm->sf = sf; 4854 PetscFunctionReturn(PETSC_SUCCESS); 4855 } 4856 4857 /*@ 4858 DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering 4859 4860 Input Parameter: 4861 . dm - The `DM` 4862 4863 Output Parameter: 4864 . sf - The `PetscSF` 4865 4866 Level: intermediate 4867 4868 Note: 4869 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4870 4871 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4872 @*/ 4873 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf) 4874 { 4875 PetscFunctionBegin; 4876 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4877 PetscAssertPointer(sf, 2); 4878 *sf = dm->sfNatural; 4879 PetscFunctionReturn(PETSC_SUCCESS); 4880 } 4881 4882 /*@ 4883 DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering 4884 4885 Input Parameters: 4886 + dm - The DM 4887 - sf - The PetscSF 4888 4889 Level: intermediate 4890 4891 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4892 @*/ 4893 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf) 4894 { 4895 PetscFunctionBegin; 4896 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4897 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4898 PetscCall(PetscObjectReference((PetscObject)sf)); 4899 PetscCall(PetscSFDestroy(&dm->sfNatural)); 4900 dm->sfNatural = sf; 4901 PetscFunctionReturn(PETSC_SUCCESS); 4902 } 4903 4904 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc) 4905 { 4906 PetscClassId id; 4907 4908 PetscFunctionBegin; 4909 PetscCall(PetscObjectGetClassId(disc, &id)); 4910 if (id == PETSCFE_CLASSID) { 4911 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4912 } else if (id == PETSCFV_CLASSID) { 4913 PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE)); 4914 } else { 4915 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4916 } 4917 PetscFunctionReturn(PETSC_SUCCESS); 4918 } 4919 4920 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew) 4921 { 4922 RegionField *tmpr; 4923 PetscInt Nf = dm->Nf, f; 4924 4925 PetscFunctionBegin; 4926 if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS); 4927 PetscCall(PetscMalloc1(NfNew, &tmpr)); 4928 for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f]; 4929 for (f = Nf; f < NfNew; ++f) { 4930 tmpr[f].disc = NULL; 4931 tmpr[f].label = NULL; 4932 tmpr[f].avoidTensor = PETSC_FALSE; 4933 } 4934 PetscCall(PetscFree(dm->fields)); 4935 dm->Nf = NfNew; 4936 dm->fields = tmpr; 4937 PetscFunctionReturn(PETSC_SUCCESS); 4938 } 4939 4940 /*@ 4941 DMClearFields - Remove all fields from the `DM` 4942 4943 Logically Collective 4944 4945 Input Parameter: 4946 . dm - The `DM` 4947 4948 Level: intermediate 4949 4950 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()` 4951 @*/ 4952 PetscErrorCode DMClearFields(DM dm) 4953 { 4954 PetscInt f; 4955 4956 PetscFunctionBegin; 4957 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4958 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); // DMDA does not use fields field in DM 4959 for (f = 0; f < dm->Nf; ++f) { 4960 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 4961 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 4962 } 4963 PetscCall(PetscFree(dm->fields)); 4964 dm->fields = NULL; 4965 dm->Nf = 0; 4966 PetscFunctionReturn(PETSC_SUCCESS); 4967 } 4968 4969 /*@ 4970 DMGetNumFields - Get the number of fields in the `DM` 4971 4972 Not Collective 4973 4974 Input Parameter: 4975 . dm - The `DM` 4976 4977 Output Parameter: 4978 . numFields - The number of fields 4979 4980 Level: intermediate 4981 4982 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()` 4983 @*/ 4984 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields) 4985 { 4986 PetscFunctionBegin; 4987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4988 PetscAssertPointer(numFields, 2); 4989 *numFields = dm->Nf; 4990 PetscFunctionReturn(PETSC_SUCCESS); 4991 } 4992 4993 /*@ 4994 DMSetNumFields - Set the number of fields in the `DM` 4995 4996 Logically Collective 4997 4998 Input Parameters: 4999 + dm - The `DM` 5000 - numFields - The number of fields 5001 5002 Level: intermediate 5003 5004 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()` 5005 @*/ 5006 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields) 5007 { 5008 PetscInt Nf, f; 5009 5010 PetscFunctionBegin; 5011 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5012 PetscCall(DMGetNumFields(dm, &Nf)); 5013 for (f = Nf; f < numFields; ++f) { 5014 PetscContainer obj; 5015 5016 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj)); 5017 PetscCall(DMAddField(dm, NULL, (PetscObject)obj)); 5018 PetscCall(PetscContainerDestroy(&obj)); 5019 } 5020 PetscFunctionReturn(PETSC_SUCCESS); 5021 } 5022 5023 /*@ 5024 DMGetField - Return the `DMLabel` and discretization object for a given `DM` field 5025 5026 Not Collective 5027 5028 Input Parameters: 5029 + dm - The `DM` 5030 - f - The field number 5031 5032 Output Parameters: 5033 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed) 5034 - disc - The discretization object (pass in `NULL` if not needed) 5035 5036 Level: intermediate 5037 5038 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()` 5039 @*/ 5040 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc) 5041 { 5042 PetscFunctionBegin; 5043 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5044 PetscAssertPointer(disc, 4); 5045 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); 5046 if (!dm->fields) { 5047 if (label) *label = NULL; 5048 if (disc) *disc = NULL; 5049 } else { // some DM such as DMDA do not have dm->fields 5050 if (label) *label = dm->fields[f].label; 5051 if (disc) *disc = dm->fields[f].disc; 5052 } 5053 PetscFunctionReturn(PETSC_SUCCESS); 5054 } 5055 5056 /* Does not clear the DS */ 5057 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc) 5058 { 5059 PetscFunctionBegin; 5060 PetscCall(DMFieldEnlarge_Static(dm, f + 1)); 5061 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 5062 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 5063 dm->fields[f].label = label; 5064 dm->fields[f].disc = disc; 5065 PetscCall(PetscObjectReference((PetscObject)label)); 5066 PetscCall(PetscObjectReference(disc)); 5067 PetscFunctionReturn(PETSC_SUCCESS); 5068 } 5069 5070 /*@ 5071 DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles 5072 the field numbering. 5073 5074 Logically Collective 5075 5076 Input Parameters: 5077 + dm - The `DM` 5078 . f - The field number 5079 . label - The label indicating the support of the field, or `NULL` for the entire mesh 5080 - disc - The discretization object 5081 5082 Level: intermediate 5083 5084 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()` 5085 @*/ 5086 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc) 5087 { 5088 PetscFunctionBegin; 5089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5090 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5091 PetscValidHeader(disc, 4); 5092 PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f); 5093 PetscCall(DMSetField_Internal(dm, f, label, disc)); 5094 PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc)); 5095 PetscCall(DMClearDS(dm)); 5096 PetscFunctionReturn(PETSC_SUCCESS); 5097 } 5098 5099 /*@ 5100 DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities) 5101 and a discretization object that defines the function space associated with those points. 5102 5103 Logically Collective 5104 5105 Input Parameters: 5106 + dm - The `DM` 5107 . label - The label indicating the support of the field, or `NULL` for the entire mesh 5108 - disc - The discretization object 5109 5110 Level: intermediate 5111 5112 Notes: 5113 The label already exists or will be added to the `DM` with `DMSetLabel()`. 5114 5115 For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions 5116 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 5117 geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`. 5118 5119 Fortran Note: 5120 Use the argument `PetscObjectCast(disc)` as the second argument 5121 5122 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE` 5123 @*/ 5124 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc) 5125 { 5126 PetscInt Nf = dm->Nf; 5127 5128 PetscFunctionBegin; 5129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5130 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5131 PetscValidHeader(disc, 3); 5132 PetscCall(DMFieldEnlarge_Static(dm, Nf + 1)); 5133 dm->fields[Nf].label = label; 5134 dm->fields[Nf].disc = disc; 5135 PetscCall(PetscObjectReference((PetscObject)label)); 5136 PetscCall(PetscObjectReference(disc)); 5137 PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc)); 5138 PetscCall(DMClearDS(dm)); 5139 PetscFunctionReturn(PETSC_SUCCESS); 5140 } 5141 5142 /*@ 5143 DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells 5144 5145 Logically Collective 5146 5147 Input Parameters: 5148 + dm - The `DM` 5149 . f - The field index 5150 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells 5151 5152 Level: intermediate 5153 5154 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()` 5155 @*/ 5156 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor) 5157 { 5158 PetscFunctionBegin; 5159 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); 5160 dm->fields[f].avoidTensor = avoidTensor; 5161 PetscFunctionReturn(PETSC_SUCCESS); 5162 } 5163 5164 /*@ 5165 DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells 5166 5167 Not Collective 5168 5169 Input Parameters: 5170 + dm - The `DM` 5171 - f - The field index 5172 5173 Output Parameter: 5174 . avoidTensor - The flag to avoid defining the field on tensor cells 5175 5176 Level: intermediate 5177 5178 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()` 5179 @*/ 5180 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor) 5181 { 5182 PetscFunctionBegin; 5183 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); 5184 *avoidTensor = dm->fields[f].avoidTensor; 5185 PetscFunctionReturn(PETSC_SUCCESS); 5186 } 5187 5188 /*@ 5189 DMCopyFields - Copy the discretizations for the `DM` into another `DM` 5190 5191 Collective 5192 5193 Input Parameters: 5194 + dm - The `DM` 5195 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit 5196 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit 5197 5198 Output Parameter: 5199 . newdm - The `DM` 5200 5201 Level: advanced 5202 5203 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()` 5204 @*/ 5205 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm) 5206 { 5207 PetscInt Nf, f; 5208 5209 PetscFunctionBegin; 5210 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 5211 PetscCall(DMGetNumFields(dm, &Nf)); 5212 PetscCall(DMClearFields(newdm)); 5213 for (f = 0; f < Nf; ++f) { 5214 DMLabel label; 5215 PetscObject field; 5216 PetscClassId id; 5217 PetscBool useCone, useClosure; 5218 5219 PetscCall(DMGetField(dm, f, &label, &field)); 5220 PetscCall(PetscObjectGetClassId(field, &id)); 5221 if (id == PETSCFE_CLASSID) { 5222 PetscFE newfe; 5223 5224 PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe)); 5225 PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe)); 5226 PetscCall(PetscFEDestroy(&newfe)); 5227 } else { 5228 PetscCall(DMSetField(newdm, f, label, field)); 5229 } 5230 PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure)); 5231 PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure)); 5232 } 5233 // Create nullspace constructor slots 5234 if (dm->nullspaceConstructors) { 5235 PetscCall(PetscFree2(newdm->nullspaceConstructors, newdm->nearnullspaceConstructors)); 5236 PetscCall(PetscCalloc2(Nf, &newdm->nullspaceConstructors, Nf, &newdm->nearnullspaceConstructors)); 5237 } 5238 PetscFunctionReturn(PETSC_SUCCESS); 5239 } 5240 5241 /*@ 5242 DMGetAdjacency - Returns the flags for determining variable influence 5243 5244 Not Collective 5245 5246 Input Parameters: 5247 + dm - The `DM` object 5248 - f - The field number, or `PETSC_DEFAULT` for the default adjacency 5249 5250 Output Parameters: 5251 + useCone - Flag for variable influence starting with the cone operation 5252 - useClosure - Flag for variable influence using transitive closure 5253 5254 Level: developer 5255 5256 Notes: 5257 .vb 5258 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5259 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5260 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5261 .ve 5262 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5263 5264 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()` 5265 @*/ 5266 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure) 5267 { 5268 PetscFunctionBegin; 5269 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5270 if (useCone) PetscAssertPointer(useCone, 3); 5271 if (useClosure) PetscAssertPointer(useClosure, 4); 5272 if (f < 0) { 5273 if (useCone) *useCone = dm->adjacency[0]; 5274 if (useClosure) *useClosure = dm->adjacency[1]; 5275 } else { 5276 PetscInt Nf; 5277 5278 PetscCall(DMGetNumFields(dm, &Nf)); 5279 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5280 if (useCone) *useCone = dm->fields[f].adjacency[0]; 5281 if (useClosure) *useClosure = dm->fields[f].adjacency[1]; 5282 } 5283 PetscFunctionReturn(PETSC_SUCCESS); 5284 } 5285 5286 /*@ 5287 DMSetAdjacency - Set the flags for determining variable influence 5288 5289 Not Collective 5290 5291 Input Parameters: 5292 + dm - The `DM` object 5293 . f - The field number 5294 . useCone - Flag for variable influence starting with the cone operation 5295 - useClosure - Flag for variable influence using transitive closure 5296 5297 Level: developer 5298 5299 Notes: 5300 .vb 5301 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5302 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5303 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5304 .ve 5305 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5306 5307 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()` 5308 @*/ 5309 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure) 5310 { 5311 PetscFunctionBegin; 5312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5313 if (f < 0) { 5314 dm->adjacency[0] = useCone; 5315 dm->adjacency[1] = useClosure; 5316 } else { 5317 PetscInt Nf; 5318 5319 PetscCall(DMGetNumFields(dm, &Nf)); 5320 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5321 dm->fields[f].adjacency[0] = useCone; 5322 dm->fields[f].adjacency[1] = useClosure; 5323 } 5324 PetscFunctionReturn(PETSC_SUCCESS); 5325 } 5326 5327 /*@ 5328 DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined 5329 5330 Not collective 5331 5332 Input Parameter: 5333 . dm - The `DM` object 5334 5335 Output Parameters: 5336 + useCone - Flag for variable influence starting with the cone operation 5337 - useClosure - Flag for variable influence using transitive closure 5338 5339 Level: developer 5340 5341 Notes: 5342 .vb 5343 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5344 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5345 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5346 .ve 5347 5348 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5349 @*/ 5350 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure) 5351 { 5352 PetscInt Nf; 5353 5354 PetscFunctionBegin; 5355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5356 if (useCone) PetscAssertPointer(useCone, 2); 5357 if (useClosure) PetscAssertPointer(useClosure, 3); 5358 PetscCall(DMGetNumFields(dm, &Nf)); 5359 if (!Nf) { 5360 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5361 } else { 5362 PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure)); 5363 } 5364 PetscFunctionReturn(PETSC_SUCCESS); 5365 } 5366 5367 /*@ 5368 DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined 5369 5370 Not Collective 5371 5372 Input Parameters: 5373 + dm - The `DM` object 5374 . useCone - Flag for variable influence starting with the cone operation 5375 - useClosure - Flag for variable influence using transitive closure 5376 5377 Level: developer 5378 5379 Notes: 5380 .vb 5381 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5382 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5383 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5384 .ve 5385 5386 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5387 @*/ 5388 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure) 5389 { 5390 PetscInt Nf; 5391 5392 PetscFunctionBegin; 5393 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5394 PetscCall(DMGetNumFields(dm, &Nf)); 5395 if (!Nf) { 5396 PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5397 } else { 5398 PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure)); 5399 } 5400 PetscFunctionReturn(PETSC_SUCCESS); 5401 } 5402 5403 PetscErrorCode DMCompleteBCLabels_Internal(DM dm) 5404 { 5405 DM plex; 5406 DMLabel *labels, *glabels; 5407 const char **names; 5408 char *sendNames, *recvNames; 5409 PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m; 5410 size_t len; 5411 MPI_Comm comm; 5412 PetscMPIInt rank, size, p, *counts, *displs; 5413 5414 PetscFunctionBegin; 5415 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5416 PetscCallMPI(MPI_Comm_size(comm, &size)); 5417 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5418 PetscCall(DMGetNumDS(dm, &Nds)); 5419 for (s = 0; s < Nds; ++s) { 5420 PetscDS dsBC; 5421 PetscInt numBd; 5422 5423 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5424 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5425 maxLabels += numBd; 5426 } 5427 PetscCall(PetscCalloc1(maxLabels, &labels)); 5428 /* Get list of labels to be completed */ 5429 for (s = 0; s < Nds; ++s) { 5430 PetscDS dsBC; 5431 PetscInt numBd, bd; 5432 5433 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5434 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5435 for (bd = 0; bd < numBd; ++bd) { 5436 DMLabel label; 5437 PetscInt field; 5438 PetscObject obj; 5439 PetscClassId id; 5440 5441 PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 5442 PetscCall(DMGetField(dm, field, NULL, &obj)); 5443 PetscCall(PetscObjectGetClassId(obj, &id)); 5444 if (id != PETSCFE_CLASSID || !label) continue; 5445 for (l = 0; l < Nl; ++l) 5446 if (labels[l] == label) break; 5447 if (l == Nl) labels[Nl++] = label; 5448 } 5449 } 5450 /* Get label names */ 5451 PetscCall(PetscMalloc1(Nl, &names)); 5452 for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l])); 5453 for (l = 0; l < Nl; ++l) { 5454 PetscCall(PetscStrlen(names[l], &len)); 5455 maxLen = PetscMax(maxLen, (PetscInt)len + 2); 5456 } 5457 PetscCall(PetscFree(labels)); 5458 PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm)); 5459 PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames)); 5460 for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen)); 5461 PetscCall(PetscFree(names)); 5462 /* Put all names on all processes */ 5463 PetscCall(PetscCalloc2(size, &counts, size + 1, &displs)); 5464 PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm)); 5465 for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p]; 5466 gNl = displs[size]; 5467 for (p = 0; p < size; ++p) { 5468 counts[p] *= gmaxLen; 5469 displs[p] *= gmaxLen; 5470 } 5471 PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels)); 5472 PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm)); 5473 PetscCall(PetscFree2(counts, displs)); 5474 PetscCall(PetscFree(sendNames)); 5475 for (l = 0, gl = 0; l < gNl; ++l) { 5476 PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl])); 5477 PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank); 5478 for (m = 0; m < gl; ++m) 5479 if (glabels[m] == glabels[gl]) goto next_label; 5480 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5481 PetscCall(DMPlexLabelComplete(plex, glabels[gl])); 5482 PetscCall(DMDestroy(&plex)); 5483 ++gl; 5484 next_label: 5485 continue; 5486 } 5487 PetscCall(PetscFree2(recvNames, glabels)); 5488 PetscFunctionReturn(PETSC_SUCCESS); 5489 } 5490 5491 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew) 5492 { 5493 DMSpace *tmpd; 5494 PetscInt Nds = dm->Nds, s; 5495 5496 PetscFunctionBegin; 5497 if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS); 5498 PetscCall(PetscMalloc1(NdsNew, &tmpd)); 5499 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s]; 5500 for (s = Nds; s < NdsNew; ++s) { 5501 tmpd[s].ds = NULL; 5502 tmpd[s].label = NULL; 5503 tmpd[s].fields = NULL; 5504 } 5505 PetscCall(PetscFree(dm->probs)); 5506 dm->Nds = NdsNew; 5507 dm->probs = tmpd; 5508 PetscFunctionReturn(PETSC_SUCCESS); 5509 } 5510 5511 /*@ 5512 DMGetNumDS - Get the number of discrete systems in the `DM` 5513 5514 Not Collective 5515 5516 Input Parameter: 5517 . dm - The `DM` 5518 5519 Output Parameter: 5520 . Nds - The number of `PetscDS` objects 5521 5522 Level: intermediate 5523 5524 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()` 5525 @*/ 5526 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds) 5527 { 5528 PetscFunctionBegin; 5529 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5530 PetscAssertPointer(Nds, 2); 5531 *Nds = dm->Nds; 5532 PetscFunctionReturn(PETSC_SUCCESS); 5533 } 5534 5535 /*@ 5536 DMClearDS - Remove all discrete systems from the `DM` 5537 5538 Logically Collective 5539 5540 Input Parameter: 5541 . dm - The `DM` 5542 5543 Level: intermediate 5544 5545 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()` 5546 @*/ 5547 PetscErrorCode DMClearDS(DM dm) 5548 { 5549 PetscInt s; 5550 5551 PetscFunctionBegin; 5552 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5553 for (s = 0; s < dm->Nds; ++s) { 5554 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5555 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5556 PetscCall(DMLabelDestroy(&dm->probs[s].label)); 5557 PetscCall(ISDestroy(&dm->probs[s].fields)); 5558 } 5559 PetscCall(PetscFree(dm->probs)); 5560 dm->probs = NULL; 5561 dm->Nds = 0; 5562 PetscFunctionReturn(PETSC_SUCCESS); 5563 } 5564 5565 /*@ 5566 DMGetDS - Get the default `PetscDS` 5567 5568 Not Collective 5569 5570 Input Parameter: 5571 . dm - The `DM` 5572 5573 Output Parameter: 5574 . ds - The default `PetscDS` 5575 5576 Level: intermediate 5577 5578 Note: 5579 The `ds` is owned by the `dm` and should not be destroyed directly. 5580 5581 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()` 5582 @*/ 5583 PetscErrorCode DMGetDS(DM dm, PetscDS *ds) 5584 { 5585 PetscFunctionBeginHot; 5586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5587 PetscAssertPointer(ds, 2); 5588 PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()"); 5589 *ds = dm->probs[0].ds; 5590 PetscFunctionReturn(PETSC_SUCCESS); 5591 } 5592 5593 /*@ 5594 DMGetCellDS - Get the `PetscDS` defined on a given cell 5595 5596 Not Collective 5597 5598 Input Parameters: 5599 + dm - The `DM` 5600 - point - Cell for the `PetscDS` 5601 5602 Output Parameters: 5603 + ds - The `PetscDS` defined on the given cell 5604 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds 5605 5606 Level: developer 5607 5608 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()` 5609 @*/ 5610 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn) 5611 { 5612 PetscDS dsDef = NULL; 5613 PetscInt s; 5614 5615 PetscFunctionBeginHot; 5616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5617 if (ds) PetscAssertPointer(ds, 3); 5618 if (dsIn) PetscAssertPointer(dsIn, 4); 5619 PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point); 5620 if (ds) *ds = NULL; 5621 if (dsIn) *dsIn = NULL; 5622 for (s = 0; s < dm->Nds; ++s) { 5623 PetscInt val; 5624 5625 if (!dm->probs[s].label) { 5626 dsDef = dm->probs[s].ds; 5627 } else { 5628 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val)); 5629 if (val >= 0) { 5630 if (ds) *ds = dm->probs[s].ds; 5631 if (dsIn) *dsIn = dm->probs[s].dsIn; 5632 break; 5633 } 5634 } 5635 } 5636 if (ds && !*ds) *ds = dsDef; 5637 PetscFunctionReturn(PETSC_SUCCESS); 5638 } 5639 5640 /*@ 5641 DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel` 5642 5643 Not Collective 5644 5645 Input Parameters: 5646 + dm - The `DM` 5647 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5648 5649 Output Parameters: 5650 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5651 . ds - The `PetscDS` defined on the given region, or `NULL` 5652 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5653 5654 Level: advanced 5655 5656 Note: 5657 If a non-`NULL` label is given, but there is no `PetscDS` on that specific label, 5658 the `PetscDS` for the full domain (if present) is returned. Returns with 5659 fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain. 5660 5661 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5662 @*/ 5663 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5664 { 5665 PetscInt Nds = dm->Nds, s; 5666 5667 PetscFunctionBegin; 5668 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5669 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5670 if (fields) { 5671 PetscAssertPointer(fields, 3); 5672 *fields = NULL; 5673 } 5674 if (ds) { 5675 PetscAssertPointer(ds, 4); 5676 *ds = NULL; 5677 } 5678 if (dsIn) { 5679 PetscAssertPointer(dsIn, 5); 5680 *dsIn = NULL; 5681 } 5682 for (s = 0; s < Nds; ++s) { 5683 if (dm->probs[s].label == label || !dm->probs[s].label) { 5684 if (fields) *fields = dm->probs[s].fields; 5685 if (ds) *ds = dm->probs[s].ds; 5686 if (dsIn) *dsIn = dm->probs[s].dsIn; 5687 if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS); 5688 } 5689 } 5690 PetscFunctionReturn(PETSC_SUCCESS); 5691 } 5692 5693 /*@ 5694 DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel` 5695 5696 Collective 5697 5698 Input Parameters: 5699 + dm - The `DM` 5700 . label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5701 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields 5702 . ds - The `PetscDS` defined on the given region 5703 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5704 5705 Level: advanced 5706 5707 Note: 5708 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced, 5709 the fields argument is ignored. 5710 5711 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()` 5712 @*/ 5713 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5714 { 5715 PetscInt Nds = dm->Nds, s; 5716 5717 PetscFunctionBegin; 5718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5719 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5720 if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3); 5721 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4); 5722 if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5); 5723 for (s = 0; s < Nds; ++s) { 5724 if (dm->probs[s].label == label) { 5725 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5726 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5727 dm->probs[s].ds = ds; 5728 dm->probs[s].dsIn = dsIn; 5729 PetscFunctionReturn(PETSC_SUCCESS); 5730 } 5731 } 5732 PetscCall(DMDSEnlarge_Static(dm, Nds + 1)); 5733 PetscCall(PetscObjectReference((PetscObject)label)); 5734 PetscCall(PetscObjectReference((PetscObject)fields)); 5735 PetscCall(PetscObjectReference((PetscObject)ds)); 5736 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5737 if (!label) { 5738 /* Put the NULL label at the front, so it is returned as the default */ 5739 for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s]; 5740 Nds = 0; 5741 } 5742 dm->probs[Nds].label = label; 5743 dm->probs[Nds].fields = fields; 5744 dm->probs[Nds].ds = ds; 5745 dm->probs[Nds].dsIn = dsIn; 5746 PetscFunctionReturn(PETSC_SUCCESS); 5747 } 5748 5749 /*@ 5750 DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number 5751 5752 Not Collective 5753 5754 Input Parameters: 5755 + dm - The `DM` 5756 - num - The region number, in [0, Nds) 5757 5758 Output Parameters: 5759 + label - The region label, or `NULL` 5760 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5761 . ds - The `PetscDS` defined on the given region, or `NULL` 5762 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5763 5764 Level: advanced 5765 5766 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5767 @*/ 5768 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5769 { 5770 PetscInt Nds; 5771 5772 PetscFunctionBegin; 5773 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5774 PetscCall(DMGetNumDS(dm, &Nds)); 5775 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5776 if (label) { 5777 PetscAssertPointer(label, 3); 5778 *label = dm->probs[num].label; 5779 } 5780 if (fields) { 5781 PetscAssertPointer(fields, 4); 5782 *fields = dm->probs[num].fields; 5783 } 5784 if (ds) { 5785 PetscAssertPointer(ds, 5); 5786 *ds = dm->probs[num].ds; 5787 } 5788 if (dsIn) { 5789 PetscAssertPointer(dsIn, 6); 5790 *dsIn = dm->probs[num].dsIn; 5791 } 5792 PetscFunctionReturn(PETSC_SUCCESS); 5793 } 5794 5795 /*@ 5796 DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number 5797 5798 Not Collective 5799 5800 Input Parameters: 5801 + dm - The `DM` 5802 . num - The region number, in [0, Nds) 5803 . label - The region label, or `NULL` 5804 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting 5805 . ds - The `PetscDS` defined on the given region, or `NULL` to prevent setting 5806 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5807 5808 Level: advanced 5809 5810 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5811 @*/ 5812 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5813 { 5814 PetscInt Nds; 5815 5816 PetscFunctionBegin; 5817 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5818 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5819 PetscCall(DMGetNumDS(dm, &Nds)); 5820 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5821 PetscCall(PetscObjectReference((PetscObject)label)); 5822 PetscCall(DMLabelDestroy(&dm->probs[num].label)); 5823 dm->probs[num].label = label; 5824 if (fields) { 5825 PetscValidHeaderSpecific(fields, IS_CLASSID, 4); 5826 PetscCall(PetscObjectReference((PetscObject)fields)); 5827 PetscCall(ISDestroy(&dm->probs[num].fields)); 5828 dm->probs[num].fields = fields; 5829 } 5830 if (ds) { 5831 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5); 5832 PetscCall(PetscObjectReference((PetscObject)ds)); 5833 PetscCall(PetscDSDestroy(&dm->probs[num].ds)); 5834 dm->probs[num].ds = ds; 5835 } 5836 if (dsIn) { 5837 PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6); 5838 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5839 PetscCall(PetscDSDestroy(&dm->probs[num].dsIn)); 5840 dm->probs[num].dsIn = dsIn; 5841 } 5842 PetscFunctionReturn(PETSC_SUCCESS); 5843 } 5844 5845 /*@ 5846 DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found. 5847 5848 Not Collective 5849 5850 Input Parameters: 5851 + dm - The `DM` 5852 - ds - The `PetscDS` defined on the given region 5853 5854 Output Parameter: 5855 . num - The region number, in [0, Nds), or -1 if not found 5856 5857 Level: advanced 5858 5859 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5860 @*/ 5861 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num) 5862 { 5863 PetscInt Nds, n; 5864 5865 PetscFunctionBegin; 5866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5867 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2); 5868 PetscAssertPointer(num, 3); 5869 PetscCall(DMGetNumDS(dm, &Nds)); 5870 for (n = 0; n < Nds; ++n) 5871 if (ds == dm->probs[n].ds) break; 5872 if (n >= Nds) *num = -1; 5873 else *num = n; 5874 PetscFunctionReturn(PETSC_SUCCESS); 5875 } 5876 5877 /*@ 5878 DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh 5879 5880 Not Collective 5881 5882 Input Parameters: 5883 + dm - The `DM` 5884 . Nc - The number of components for the field 5885 . prefix - The options prefix for the output `PetscFE`, or `NULL` 5886 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree 5887 5888 Output Parameter: 5889 . fem - The `PetscFE` 5890 5891 Level: intermediate 5892 5893 Note: 5894 This is a convenience method that just calls `PetscFECreateByCell()` underneath. 5895 5896 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()` 5897 @*/ 5898 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem) 5899 { 5900 DMPolytopeType ct; 5901 PetscInt dim, cStart; 5902 5903 PetscFunctionBegin; 5904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5905 PetscValidLogicalCollectiveInt(dm, Nc, 2); 5906 if (prefix) PetscAssertPointer(prefix, 3); 5907 PetscValidLogicalCollectiveInt(dm, qorder, 4); 5908 PetscAssertPointer(fem, 5); 5909 PetscCall(DMGetDimension(dm, &dim)); 5910 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 5911 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 5912 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem)); 5913 PetscFunctionReturn(PETSC_SUCCESS); 5914 } 5915 5916 /*@ 5917 DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM` 5918 5919 Collective 5920 5921 Input Parameter: 5922 . dm - The `DM` 5923 5924 Options Database Key: 5925 . -dm_petscds_view - View all the `PetscDS` objects in this `DM` 5926 5927 Level: intermediate 5928 5929 Developer Note: 5930 The name of this function is wrong. Create functions always return the created object as one of the arguments. 5931 5932 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 5933 @*/ 5934 PetscErrorCode DMCreateDS(DM dm) 5935 { 5936 MPI_Comm comm; 5937 PetscDS dsDef; 5938 DMLabel *labelSet; 5939 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k; 5940 PetscBool doSetup = PETSC_TRUE, flg; 5941 5942 PetscFunctionBegin; 5943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5944 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); 5945 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5946 PetscCall(DMGetCoordinateDim(dm, &dE)); 5947 // Create nullspace constructor slots 5948 PetscCall(PetscFree2(dm->nullspaceConstructors, dm->nearnullspaceConstructors)); 5949 PetscCall(PetscCalloc2(Nf, &dm->nullspaceConstructors, Nf, &dm->nearnullspaceConstructors)); 5950 /* Determine how many regions we have */ 5951 PetscCall(PetscMalloc1(Nf, &labelSet)); 5952 Nl = 0; 5953 Ndef = 0; 5954 for (f = 0; f < Nf; ++f) { 5955 DMLabel label = dm->fields[f].label; 5956 PetscInt l; 5957 5958 #ifdef PETSC_HAVE_LIBCEED 5959 /* Move CEED context to discretizations */ 5960 { 5961 PetscClassId id; 5962 5963 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id)); 5964 if (id == PETSCFE_CLASSID) { 5965 Ceed ceed; 5966 5967 PetscCall(DMGetCeed(dm, &ceed)); 5968 PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed)); 5969 } 5970 } 5971 #endif 5972 if (!label) { 5973 ++Ndef; 5974 continue; 5975 } 5976 for (l = 0; l < Nl; ++l) 5977 if (label == labelSet[l]) break; 5978 if (l < Nl) continue; 5979 labelSet[Nl++] = label; 5980 } 5981 /* Create default DS if there are no labels to intersect with */ 5982 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5983 if (!dsDef && Ndef && !Nl) { 5984 IS fields; 5985 PetscInt *fld, nf; 5986 5987 for (f = 0, nf = 0; f < Nf; ++f) 5988 if (!dm->fields[f].label) ++nf; 5989 PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS"); 5990 PetscCall(PetscMalloc1(nf, &fld)); 5991 for (f = 0, nf = 0; f < Nf; ++f) 5992 if (!dm->fields[f].label) fld[nf++] = f; 5993 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5994 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5995 PetscCall(ISSetType(fields, ISGENERAL)); 5996 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5997 5998 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5999 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL)); 6000 PetscCall(PetscDSDestroy(&dsDef)); 6001 PetscCall(ISDestroy(&fields)); 6002 } 6003 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 6004 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 6005 /* Intersect labels with default fields */ 6006 if (Ndef && Nl) { 6007 DM plex; 6008 DMLabel cellLabel; 6009 IS fieldIS, allcellIS, defcellIS = NULL; 6010 PetscInt *fields; 6011 const PetscInt *cells; 6012 PetscInt depth, nf = 0, n, c; 6013 6014 PetscCall(DMConvert(dm, DMPLEX, &plex)); 6015 PetscCall(DMPlexGetDepth(plex, &depth)); 6016 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS)); 6017 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS)); 6018 /* TODO This looks like it only works for one label */ 6019 for (l = 0; l < Nl; ++l) { 6020 DMLabel label = labelSet[l]; 6021 IS pointIS; 6022 6023 PetscCall(ISDestroy(&defcellIS)); 6024 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 6025 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS)); 6026 PetscCall(ISDestroy(&pointIS)); 6027 } 6028 PetscCall(ISDestroy(&allcellIS)); 6029 6030 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel)); 6031 PetscCall(ISGetLocalSize(defcellIS, &n)); 6032 PetscCall(ISGetIndices(defcellIS, &cells)); 6033 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1)); 6034 PetscCall(ISRestoreIndices(defcellIS, &cells)); 6035 PetscCall(ISDestroy(&defcellIS)); 6036 PetscCall(DMPlexLabelComplete(plex, cellLabel)); 6037 6038 PetscCall(PetscMalloc1(Ndef, &fields)); 6039 for (f = 0; f < Nf; ++f) 6040 if (!dm->fields[f].label) fields[nf++] = f; 6041 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS)); 6042 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_")); 6043 PetscCall(ISSetType(fieldIS, ISGENERAL)); 6044 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER)); 6045 6046 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 6047 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL)); 6048 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 6049 PetscCall(DMLabelDestroy(&cellLabel)); 6050 PetscCall(PetscDSDestroy(&dsDef)); 6051 PetscCall(ISDestroy(&fieldIS)); 6052 PetscCall(DMDestroy(&plex)); 6053 } 6054 /* Create label DSes 6055 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS 6056 */ 6057 /* TODO Should check that labels are disjoint */ 6058 for (l = 0; l < Nl; ++l) { 6059 DMLabel label = labelSet[l]; 6060 PetscDS ds, dsIn = NULL; 6061 IS fields; 6062 PetscInt *fld, nf; 6063 6064 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 6065 for (f = 0, nf = 0; f < Nf; ++f) 6066 if (label == dm->fields[f].label || !dm->fields[f].label) ++nf; 6067 PetscCall(PetscMalloc1(nf, &fld)); 6068 for (f = 0, nf = 0; f < Nf; ++f) 6069 if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f; 6070 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 6071 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 6072 PetscCall(ISSetType(fields, ISGENERAL)); 6073 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 6074 PetscCall(PetscDSSetCoordinateDimension(ds, dE)); 6075 { 6076 DMPolytopeType ct; 6077 PetscInt lStart, lEnd; 6078 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive; 6079 6080 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd)); 6081 if (lStart >= 0) { 6082 PetscCall(DMPlexGetCellType(dm, lStart, &ct)); 6083 switch (ct) { 6084 case DM_POLYTOPE_POINT_PRISM_TENSOR: 6085 case DM_POLYTOPE_SEG_PRISM_TENSOR: 6086 case DM_POLYTOPE_TRI_PRISM_TENSOR: 6087 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 6088 isCohesiveLocal = PETSC_TRUE; 6089 break; 6090 default: 6091 break; 6092 } 6093 } 6094 PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm)); 6095 if (isCohesive) { 6096 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn)); 6097 PetscCall(PetscDSSetCoordinateDimension(dsIn, dE)); 6098 } 6099 for (f = 0, nf = 0; f < Nf; ++f) { 6100 if (label == dm->fields[f].label || !dm->fields[f].label) { 6101 if (label == dm->fields[f].label) { 6102 PetscCall(PetscDSSetDiscretization(ds, nf, NULL)); 6103 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive)); 6104 if (dsIn) { 6105 PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL)); 6106 PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive)); 6107 } 6108 } 6109 ++nf; 6110 } 6111 } 6112 } 6113 PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn)); 6114 PetscCall(ISDestroy(&fields)); 6115 PetscCall(PetscDSDestroy(&ds)); 6116 PetscCall(PetscDSDestroy(&dsIn)); 6117 } 6118 PetscCall(PetscFree(labelSet)); 6119 /* Set fields in DSes */ 6120 for (s = 0; s < dm->Nds; ++s) { 6121 PetscDS ds = dm->probs[s].ds; 6122 PetscDS dsIn = dm->probs[s].dsIn; 6123 IS fields = dm->probs[s].fields; 6124 const PetscInt *fld; 6125 PetscInt nf, dsnf; 6126 PetscBool isCohesive; 6127 6128 PetscCall(PetscDSGetNumFields(ds, &dsnf)); 6129 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 6130 PetscCall(ISGetLocalSize(fields, &nf)); 6131 PetscCall(ISGetIndices(fields, &fld)); 6132 for (f = 0; f < nf; ++f) { 6133 PetscObject disc = dm->fields[fld[f]].disc; 6134 PetscBool isCohesiveField; 6135 PetscClassId id; 6136 6137 /* Handle DS with no fields */ 6138 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 6139 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */ 6140 if (isCohesive) { 6141 if (!isCohesiveField) { 6142 PetscObject bdDisc; 6143 6144 PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc)); 6145 PetscCall(PetscDSSetDiscretization(ds, f, bdDisc)); 6146 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6147 } else { 6148 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6149 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6150 } 6151 } else { 6152 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6153 } 6154 /* We allow people to have placeholder fields and construct the Section by hand */ 6155 PetscCall(PetscObjectGetClassId(disc, &id)); 6156 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE; 6157 } 6158 PetscCall(ISRestoreIndices(fields, &fld)); 6159 } 6160 /* Allow k-jet tabulation */ 6161 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg)); 6162 if (flg) { 6163 for (s = 0; s < dm->Nds; ++s) { 6164 PetscDS ds = dm->probs[s].ds; 6165 PetscDS dsIn = dm->probs[s].dsIn; 6166 PetscInt Nf, f; 6167 6168 PetscCall(PetscDSGetNumFields(ds, &Nf)); 6169 for (f = 0; f < Nf; ++f) { 6170 PetscCall(PetscDSSetJetDegree(ds, f, k)); 6171 if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k)); 6172 } 6173 } 6174 } 6175 /* Setup DSes */ 6176 if (doSetup) { 6177 for (s = 0; s < dm->Nds; ++s) { 6178 if (dm->setfromoptionscalled) { 6179 PetscCall(PetscDSSetFromOptions(dm->probs[s].ds)); 6180 if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn)); 6181 } 6182 PetscCall(PetscDSSetUp(dm->probs[s].ds)); 6183 if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn)); 6184 } 6185 } 6186 PetscFunctionReturn(PETSC_SUCCESS); 6187 } 6188 6189 /*@ 6190 DMUseTensorOrder - Use a tensor product closure ordering for the default section 6191 6192 Input Parameters: 6193 + dm - The DM 6194 - tensor - Flag for tensor order 6195 6196 Level: developer 6197 6198 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()` 6199 @*/ 6200 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor) 6201 { 6202 PetscInt Nf; 6203 PetscBool reorder = PETSC_TRUE, isPlex; 6204 6205 PetscFunctionBegin; 6206 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 6207 PetscCall(DMGetNumFields(dm, &Nf)); 6208 for (PetscInt f = 0; f < Nf; ++f) { 6209 PetscObject obj; 6210 PetscClassId id; 6211 6212 PetscCall(DMGetField(dm, f, NULL, &obj)); 6213 PetscCall(PetscObjectGetClassId(obj, &id)); 6214 if (id == PETSCFE_CLASSID) { 6215 PetscSpace sp; 6216 PetscBool tensor; 6217 6218 PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp)); 6219 PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor)); 6220 reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE; 6221 } else reorder = PETSC_FALSE; 6222 } 6223 if (tensor) { 6224 if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 6225 } else { 6226 PetscSection s; 6227 6228 PetscCall(DMGetLocalSection(dm, &s)); 6229 if (s) PetscCall(PetscSectionResetClosurePermutation(s)); 6230 } 6231 PetscFunctionReturn(PETSC_SUCCESS); 6232 } 6233 6234 /*@ 6235 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information. 6236 6237 Collective 6238 6239 Input Parameters: 6240 + dm - The `DM` 6241 - time - The time 6242 6243 Output Parameters: 6244 + u - The vector will be filled with exact solution values, or `NULL` 6245 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL` 6246 6247 Level: developer 6248 6249 Note: 6250 The user must call `PetscDSSetExactSolution()` before using this routine 6251 6252 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()` 6253 @*/ 6254 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 6255 { 6256 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 6257 void **ectxs; 6258 Vec locu, locu_t; 6259 PetscInt Nf, Nds, s; 6260 6261 PetscFunctionBegin; 6262 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6263 if (u) { 6264 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 6265 PetscCall(DMGetLocalVector(dm, &locu)); 6266 PetscCall(VecSet(locu, 0.)); 6267 } 6268 if (u_t) { 6269 PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 6270 PetscCall(DMGetLocalVector(dm, &locu_t)); 6271 PetscCall(VecSet(locu_t, 0.)); 6272 } 6273 PetscCall(DMGetNumFields(dm, &Nf)); 6274 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 6275 PetscCall(DMGetNumDS(dm, &Nds)); 6276 for (s = 0; s < Nds; ++s) { 6277 PetscDS ds; 6278 DMLabel label; 6279 IS fieldIS; 6280 const PetscInt *fields, id = 1; 6281 PetscInt dsNf, f; 6282 6283 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 6284 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 6285 PetscCall(ISGetIndices(fieldIS, &fields)); 6286 PetscCall(PetscArrayzero(exacts, Nf)); 6287 PetscCall(PetscArrayzero(ectxs, Nf)); 6288 if (u) { 6289 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6290 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6291 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6292 } 6293 if (u_t) { 6294 PetscCall(PetscArrayzero(exacts, Nf)); 6295 PetscCall(PetscArrayzero(ectxs, Nf)); 6296 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6297 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6298 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6299 } 6300 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6301 } 6302 if (u) { 6303 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution")); 6304 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_")); 6305 } 6306 if (u_t) { 6307 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative")); 6308 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_")); 6309 } 6310 PetscCall(PetscFree2(exacts, ectxs)); 6311 if (u) { 6312 PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u)); 6313 PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u)); 6314 PetscCall(DMRestoreLocalVector(dm, &locu)); 6315 } 6316 if (u_t) { 6317 PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6318 PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6319 PetscCall(DMRestoreLocalVector(dm, &locu_t)); 6320 } 6321 PetscFunctionReturn(PETSC_SUCCESS); 6322 } 6323 6324 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn) 6325 { 6326 PetscDS dsNew, dsInNew = NULL; 6327 6328 PetscFunctionBegin; 6329 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew)); 6330 PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew)); 6331 if (dsIn) { 6332 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew)); 6333 PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew)); 6334 } 6335 PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew)); 6336 PetscCall(PetscDSDestroy(&dsNew)); 6337 PetscCall(PetscDSDestroy(&dsInNew)); 6338 PetscFunctionReturn(PETSC_SUCCESS); 6339 } 6340 6341 /*@ 6342 DMCopyDS - Copy the discrete systems for the `DM` into another `DM` 6343 6344 Collective 6345 6346 Input Parameters: 6347 + dm - The `DM` 6348 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit 6349 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit 6350 6351 Output Parameter: 6352 . newdm - The `DM` 6353 6354 Level: advanced 6355 6356 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 6357 @*/ 6358 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm) 6359 { 6360 PetscInt Nds, s; 6361 6362 PetscFunctionBegin; 6363 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 6364 PetscCall(DMGetNumDS(dm, &Nds)); 6365 PetscCall(DMClearDS(newdm)); 6366 for (s = 0; s < Nds; ++s) { 6367 DMLabel label; 6368 IS fields; 6369 PetscDS ds, dsIn, newds; 6370 PetscInt Nbd, bd; 6371 6372 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn)); 6373 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 6374 PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn)); 6375 /* Complete new labels in the new DS */ 6376 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL)); 6377 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 6378 for (bd = 0; bd < Nbd; ++bd) { 6379 PetscWeakForm wf; 6380 DMLabel label; 6381 PetscInt field; 6382 6383 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 6384 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 6385 } 6386 } 6387 PetscCall(DMCompleteBCLabels_Internal(newdm)); 6388 PetscFunctionReturn(PETSC_SUCCESS); 6389 } 6390 6391 /*@ 6392 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM` 6393 6394 Collective 6395 6396 Input Parameter: 6397 . dm - The `DM` 6398 6399 Output Parameter: 6400 . newdm - The `DM` 6401 6402 Level: advanced 6403 6404 Developer Note: 6405 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation 6406 6407 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()` 6408 @*/ 6409 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6410 { 6411 PetscFunctionBegin; 6412 PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm)); 6413 PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm)); 6414 PetscFunctionReturn(PETSC_SUCCESS); 6415 } 6416 6417 /*@ 6418 DMGetDimension - Return the topological dimension of the `DM` 6419 6420 Not Collective 6421 6422 Input Parameter: 6423 . dm - The `DM` 6424 6425 Output Parameter: 6426 . dim - The topological dimension 6427 6428 Level: beginner 6429 6430 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()` 6431 @*/ 6432 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6433 { 6434 PetscFunctionBegin; 6435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6436 PetscAssertPointer(dim, 2); 6437 *dim = dm->dim; 6438 PetscFunctionReturn(PETSC_SUCCESS); 6439 } 6440 6441 /*@ 6442 DMSetDimension - Set the topological dimension of the `DM` 6443 6444 Collective 6445 6446 Input Parameters: 6447 + dm - The `DM` 6448 - dim - The topological dimension 6449 6450 Level: beginner 6451 6452 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()` 6453 @*/ 6454 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6455 { 6456 PetscDS ds; 6457 PetscInt Nds, n; 6458 6459 PetscFunctionBegin; 6460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6461 PetscValidLogicalCollectiveInt(dm, dim, 2); 6462 dm->dim = dim; 6463 if (dm->dim >= 0) { 6464 PetscCall(DMGetNumDS(dm, &Nds)); 6465 for (n = 0; n < Nds; ++n) { 6466 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL)); 6467 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6468 } 6469 } 6470 PetscFunctionReturn(PETSC_SUCCESS); 6471 } 6472 6473 /*@ 6474 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6475 6476 Collective 6477 6478 Input Parameters: 6479 + dm - the `DM` 6480 - dim - the dimension 6481 6482 Output Parameters: 6483 + pStart - The first point of the given dimension 6484 - pEnd - The first point following points of the given dimension 6485 6486 Level: intermediate 6487 6488 Note: 6489 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6490 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6491 then the interval is empty. 6492 6493 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 6494 @*/ 6495 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6496 { 6497 PetscInt d; 6498 6499 PetscFunctionBegin; 6500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6501 PetscCall(DMGetDimension(dm, &d)); 6502 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6503 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd); 6504 PetscFunctionReturn(PETSC_SUCCESS); 6505 } 6506 6507 /*@ 6508 DMGetOutputDM - Retrieve the `DM` associated with the layout for output 6509 6510 Collective 6511 6512 Input Parameter: 6513 . dm - The original `DM` 6514 6515 Output Parameter: 6516 . odm - The `DM` which provides the layout for output 6517 6518 Level: intermediate 6519 6520 Note: 6521 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary 6522 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the 6523 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof. 6524 6525 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()` 6526 @*/ 6527 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 6528 { 6529 PetscSection section; 6530 IS perm; 6531 PetscBool hasConstraints, newDM, gnewDM; 6532 PetscInt num_face_sfs = 0; 6533 6534 PetscFunctionBegin; 6535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6536 PetscAssertPointer(odm, 2); 6537 PetscCall(DMGetLocalSection(dm, §ion)); 6538 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 6539 PetscCall(PetscSectionGetPermutation(section, &perm)); 6540 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL)); 6541 newDM = hasConstraints || perm || (num_face_sfs > 0) ? PETSC_TRUE : PETSC_FALSE; 6542 PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 6543 if (!gnewDM) { 6544 *odm = dm; 6545 PetscFunctionReturn(PETSC_SUCCESS); 6546 } 6547 if (!dm->dmBC) { 6548 PetscSection newSection, gsection; 6549 PetscSF sf, sfNatural; 6550 PetscBool usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE; 6551 6552 PetscCall(DMClone(dm, &dm->dmBC)); 6553 PetscCall(DMCopyDisc(dm, dm->dmBC)); 6554 PetscCall(PetscSectionClone(section, &newSection)); 6555 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 6556 PetscCall(PetscSectionDestroy(&newSection)); 6557 PetscCall(DMGetNaturalSF(dm, &sfNatural)); 6558 PetscCall(DMSetNaturalSF(dm->dmBC, sfNatural)); 6559 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 6560 PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection)); 6561 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 6562 PetscCall(PetscSectionDestroy(&gsection)); 6563 } 6564 *odm = dm->dmBC; 6565 PetscFunctionReturn(PETSC_SUCCESS); 6566 } 6567 6568 /*@ 6569 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 6570 6571 Input Parameter: 6572 . dm - The original `DM` 6573 6574 Output Parameters: 6575 + num - The output sequence number 6576 - val - The output sequence value 6577 6578 Level: intermediate 6579 6580 Note: 6581 This is intended for output that should appear in sequence, for instance 6582 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6583 6584 Developer Note: 6585 The `DM` serves as a convenient place to store the current iteration value. The iteration is not 6586 not directly related to the `DM`. 6587 6588 .seealso: [](ch_dmbase), `DM`, `VecView()` 6589 @*/ 6590 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 6591 { 6592 PetscFunctionBegin; 6593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6594 if (num) { 6595 PetscAssertPointer(num, 2); 6596 *num = dm->outputSequenceNum; 6597 } 6598 if (val) { 6599 PetscAssertPointer(val, 3); 6600 *val = dm->outputSequenceVal; 6601 } 6602 PetscFunctionReturn(PETSC_SUCCESS); 6603 } 6604 6605 /*@ 6606 DMSetOutputSequenceNumber - Set the sequence number/value for output 6607 6608 Input Parameters: 6609 + dm - The original `DM` 6610 . num - The output sequence number 6611 - val - The output sequence value 6612 6613 Level: intermediate 6614 6615 Note: 6616 This is intended for output that should appear in sequence, for instance 6617 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6618 6619 .seealso: [](ch_dmbase), `DM`, `VecView()` 6620 @*/ 6621 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 6622 { 6623 PetscFunctionBegin; 6624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6625 dm->outputSequenceNum = num; 6626 dm->outputSequenceVal = val; 6627 PetscFunctionReturn(PETSC_SUCCESS); 6628 } 6629 6630 /*@ 6631 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer` 6632 6633 Input Parameters: 6634 + dm - The original `DM` 6635 . viewer - The `PetscViewer` to get it from 6636 . name - The sequence name 6637 - num - The output sequence number 6638 6639 Output Parameter: 6640 . val - The output sequence value 6641 6642 Level: intermediate 6643 6644 Note: 6645 This is intended for output that should appear in sequence, for instance 6646 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6647 6648 Developer Note: 6649 It is unclear at the user API level why a `DM` is needed as input 6650 6651 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6652 @*/ 6653 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val) 6654 { 6655 PetscBool ishdf5; 6656 6657 PetscFunctionBegin; 6658 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6659 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6660 PetscAssertPointer(name, 3); 6661 PetscAssertPointer(val, 5); 6662 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6663 if (ishdf5) { 6664 #if defined(PETSC_HAVE_HDF5) 6665 PetscScalar value; 6666 6667 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 6668 *val = PetscRealPart(value); 6669 #endif 6670 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6671 PetscFunctionReturn(PETSC_SUCCESS); 6672 } 6673 6674 /*@ 6675 DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer` 6676 6677 Input Parameters: 6678 + dm - The original `DM` 6679 . viewer - The `PetscViewer` to get it from 6680 - name - The sequence name 6681 6682 Output Parameter: 6683 . len - The length of the output sequence 6684 6685 Level: intermediate 6686 6687 Note: 6688 This is intended for output that should appear in sequence, for instance 6689 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6690 6691 Developer Note: 6692 It is unclear at the user API level why a `DM` is needed as input 6693 6694 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6695 @*/ 6696 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len) 6697 { 6698 PetscBool ishdf5; 6699 6700 PetscFunctionBegin; 6701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6702 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6703 PetscAssertPointer(name, 3); 6704 PetscAssertPointer(len, 4); 6705 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6706 if (ishdf5) { 6707 #if defined(PETSC_HAVE_HDF5) 6708 PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer)); 6709 #endif 6710 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6711 PetscFunctionReturn(PETSC_SUCCESS); 6712 } 6713 6714 /*@ 6715 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6716 6717 Not Collective 6718 6719 Input Parameter: 6720 . dm - The `DM` 6721 6722 Output Parameter: 6723 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6724 6725 Level: beginner 6726 6727 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()` 6728 @*/ 6729 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6730 { 6731 PetscFunctionBegin; 6732 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6733 PetscAssertPointer(useNatural, 2); 6734 *useNatural = dm->useNatural; 6735 PetscFunctionReturn(PETSC_SUCCESS); 6736 } 6737 6738 /*@ 6739 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6740 6741 Collective 6742 6743 Input Parameters: 6744 + dm - The `DM` 6745 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6746 6747 Level: beginner 6748 6749 Note: 6750 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6751 6752 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6753 @*/ 6754 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6755 { 6756 PetscFunctionBegin; 6757 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6758 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6759 dm->useNatural = useNatural; 6760 PetscFunctionReturn(PETSC_SUCCESS); 6761 } 6762 6763 /*@ 6764 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6765 6766 Not Collective 6767 6768 Input Parameters: 6769 + dm - The `DM` object 6770 - name - The label name 6771 6772 Level: intermediate 6773 6774 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6775 @*/ 6776 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6777 { 6778 PetscBool flg; 6779 DMLabel label; 6780 6781 PetscFunctionBegin; 6782 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6783 PetscAssertPointer(name, 2); 6784 PetscCall(DMHasLabel(dm, name, &flg)); 6785 if (!flg) { 6786 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6787 PetscCall(DMAddLabel(dm, label)); 6788 PetscCall(DMLabelDestroy(&label)); 6789 } 6790 PetscFunctionReturn(PETSC_SUCCESS); 6791 } 6792 6793 /*@ 6794 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6795 6796 Not Collective 6797 6798 Input Parameters: 6799 + dm - The `DM` object 6800 . l - The index for the label 6801 - name - The label name 6802 6803 Level: intermediate 6804 6805 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6806 @*/ 6807 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6808 { 6809 DMLabelLink orig, prev = NULL; 6810 DMLabel label; 6811 PetscInt Nl, m; 6812 PetscBool flg, match; 6813 const char *lname; 6814 6815 PetscFunctionBegin; 6816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6817 PetscAssertPointer(name, 3); 6818 PetscCall(DMHasLabel(dm, name, &flg)); 6819 if (!flg) { 6820 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6821 PetscCall(DMAddLabel(dm, label)); 6822 PetscCall(DMLabelDestroy(&label)); 6823 } 6824 PetscCall(DMGetNumLabels(dm, &Nl)); 6825 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6826 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6827 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6828 PetscCall(PetscStrcmp(name, lname, &match)); 6829 if (match) break; 6830 } 6831 if (m == l) PetscFunctionReturn(PETSC_SUCCESS); 6832 if (!m) dm->labels = orig->next; 6833 else prev->next = orig->next; 6834 if (!l) { 6835 orig->next = dm->labels; 6836 dm->labels = orig; 6837 } else { 6838 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next); 6839 orig->next = prev->next; 6840 prev->next = orig; 6841 } 6842 PetscFunctionReturn(PETSC_SUCCESS); 6843 } 6844 6845 /*@ 6846 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6847 6848 Not Collective 6849 6850 Input Parameters: 6851 + dm - The `DM` object 6852 . name - The label name 6853 - point - The mesh point 6854 6855 Output Parameter: 6856 . value - The label value for this point, or -1 if the point is not in the label 6857 6858 Level: beginner 6859 6860 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6861 @*/ 6862 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6863 { 6864 DMLabel label; 6865 6866 PetscFunctionBegin; 6867 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6868 PetscAssertPointer(name, 2); 6869 PetscCall(DMGetLabel(dm, name, &label)); 6870 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6871 PetscCall(DMLabelGetValue(label, point, value)); 6872 PetscFunctionReturn(PETSC_SUCCESS); 6873 } 6874 6875 /*@ 6876 DMSetLabelValue - Add a point to a `DMLabel` with given value 6877 6878 Not Collective 6879 6880 Input Parameters: 6881 + dm - The `DM` object 6882 . name - The label name 6883 . point - The mesh point 6884 - value - The label value for this point 6885 6886 Output Parameter: 6887 6888 Level: beginner 6889 6890 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6891 @*/ 6892 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6893 { 6894 DMLabel label; 6895 6896 PetscFunctionBegin; 6897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6898 PetscAssertPointer(name, 2); 6899 PetscCall(DMGetLabel(dm, name, &label)); 6900 if (!label) { 6901 PetscCall(DMCreateLabel(dm, name)); 6902 PetscCall(DMGetLabel(dm, name, &label)); 6903 } 6904 PetscCall(DMLabelSetValue(label, point, value)); 6905 PetscFunctionReturn(PETSC_SUCCESS); 6906 } 6907 6908 /*@ 6909 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6910 6911 Not Collective 6912 6913 Input Parameters: 6914 + dm - The `DM` object 6915 . name - The label name 6916 . point - The mesh point 6917 - value - The label value for this point 6918 6919 Level: beginner 6920 6921 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6922 @*/ 6923 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6924 { 6925 DMLabel label; 6926 6927 PetscFunctionBegin; 6928 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6929 PetscAssertPointer(name, 2); 6930 PetscCall(DMGetLabel(dm, name, &label)); 6931 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6932 PetscCall(DMLabelClearValue(label, point, value)); 6933 PetscFunctionReturn(PETSC_SUCCESS); 6934 } 6935 6936 /*@ 6937 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6938 6939 Not Collective 6940 6941 Input Parameters: 6942 + dm - The `DM` object 6943 - name - The label name 6944 6945 Output Parameter: 6946 . size - The number of different integer ids, or 0 if the label does not exist 6947 6948 Level: beginner 6949 6950 Developer Note: 6951 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6952 6953 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6954 @*/ 6955 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6956 { 6957 DMLabel label; 6958 6959 PetscFunctionBegin; 6960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6961 PetscAssertPointer(name, 2); 6962 PetscAssertPointer(size, 3); 6963 PetscCall(DMGetLabel(dm, name, &label)); 6964 *size = 0; 6965 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6966 PetscCall(DMLabelGetNumValues(label, size)); 6967 PetscFunctionReturn(PETSC_SUCCESS); 6968 } 6969 6970 /*@ 6971 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6972 6973 Not Collective 6974 6975 Input Parameters: 6976 + dm - The `DM` object 6977 - name - The label name 6978 6979 Output Parameter: 6980 . ids - The integer ids, or `NULL` if the label does not exist 6981 6982 Level: beginner 6983 6984 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()` 6985 @*/ 6986 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6987 { 6988 DMLabel label; 6989 6990 PetscFunctionBegin; 6991 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6992 PetscAssertPointer(name, 2); 6993 PetscAssertPointer(ids, 3); 6994 PetscCall(DMGetLabel(dm, name, &label)); 6995 *ids = NULL; 6996 if (label) { 6997 PetscCall(DMLabelGetValueIS(label, ids)); 6998 } else { 6999 /* returning an empty IS */ 7000 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 7001 } 7002 PetscFunctionReturn(PETSC_SUCCESS); 7003 } 7004 7005 /*@ 7006 DMGetStratumSize - Get the number of points in a label stratum 7007 7008 Not Collective 7009 7010 Input Parameters: 7011 + dm - The `DM` object 7012 . name - The label name of the stratum 7013 - value - The stratum value 7014 7015 Output Parameter: 7016 . size - The number of points, also called the stratum size 7017 7018 Level: beginner 7019 7020 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 7021 @*/ 7022 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 7023 { 7024 DMLabel label; 7025 7026 PetscFunctionBegin; 7027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7028 PetscAssertPointer(name, 2); 7029 PetscAssertPointer(size, 4); 7030 PetscCall(DMGetLabel(dm, name, &label)); 7031 *size = 0; 7032 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7033 PetscCall(DMLabelGetStratumSize(label, value, size)); 7034 PetscFunctionReturn(PETSC_SUCCESS); 7035 } 7036 7037 /*@ 7038 DMGetStratumIS - Get the points in a label stratum 7039 7040 Not Collective 7041 7042 Input Parameters: 7043 + dm - The `DM` object 7044 . name - The label name 7045 - value - The stratum value 7046 7047 Output Parameter: 7048 . points - The stratum points, or `NULL` if the label does not exist or does not have that value 7049 7050 Level: beginner 7051 7052 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()` 7053 @*/ 7054 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 7055 { 7056 DMLabel label; 7057 7058 PetscFunctionBegin; 7059 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7060 PetscAssertPointer(name, 2); 7061 PetscAssertPointer(points, 4); 7062 PetscCall(DMGetLabel(dm, name, &label)); 7063 *points = NULL; 7064 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7065 PetscCall(DMLabelGetStratumIS(label, value, points)); 7066 PetscFunctionReturn(PETSC_SUCCESS); 7067 } 7068 7069 /*@ 7070 DMSetStratumIS - Set the points in a label stratum 7071 7072 Not Collective 7073 7074 Input Parameters: 7075 + dm - The `DM` object 7076 . name - The label name 7077 . value - The stratum value 7078 - points - The stratum points 7079 7080 Level: beginner 7081 7082 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 7083 @*/ 7084 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 7085 { 7086 DMLabel label; 7087 7088 PetscFunctionBegin; 7089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7090 PetscAssertPointer(name, 2); 7091 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 7092 PetscCall(DMGetLabel(dm, name, &label)); 7093 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7094 PetscCall(DMLabelSetStratumIS(label, value, points)); 7095 PetscFunctionReturn(PETSC_SUCCESS); 7096 } 7097 7098 /*@ 7099 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 7100 7101 Not Collective 7102 7103 Input Parameters: 7104 + dm - The `DM` object 7105 . name - The label name 7106 - value - The label value for this point 7107 7108 Output Parameter: 7109 7110 Level: beginner 7111 7112 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 7113 @*/ 7114 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 7115 { 7116 DMLabel label; 7117 7118 PetscFunctionBegin; 7119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7120 PetscAssertPointer(name, 2); 7121 PetscCall(DMGetLabel(dm, name, &label)); 7122 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7123 PetscCall(DMLabelClearStratum(label, value)); 7124 PetscFunctionReturn(PETSC_SUCCESS); 7125 } 7126 7127 /*@ 7128 DMGetNumLabels - Return the number of labels defined by on the `DM` 7129 7130 Not Collective 7131 7132 Input Parameter: 7133 . dm - The `DM` object 7134 7135 Output Parameter: 7136 . numLabels - the number of Labels 7137 7138 Level: intermediate 7139 7140 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7141 @*/ 7142 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 7143 { 7144 DMLabelLink next = dm->labels; 7145 PetscInt n = 0; 7146 7147 PetscFunctionBegin; 7148 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7149 PetscAssertPointer(numLabels, 2); 7150 while (next) { 7151 ++n; 7152 next = next->next; 7153 } 7154 *numLabels = n; 7155 PetscFunctionReturn(PETSC_SUCCESS); 7156 } 7157 7158 /*@ 7159 DMGetLabelName - Return the name of nth label 7160 7161 Not Collective 7162 7163 Input Parameters: 7164 + dm - The `DM` object 7165 - n - the label number 7166 7167 Output Parameter: 7168 . name - the label name 7169 7170 Level: intermediate 7171 7172 Developer Note: 7173 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 7174 7175 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7176 @*/ 7177 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[]) 7178 { 7179 DMLabelLink next = dm->labels; 7180 PetscInt l = 0; 7181 7182 PetscFunctionBegin; 7183 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7184 PetscAssertPointer(name, 3); 7185 while (next) { 7186 if (l == n) { 7187 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 7188 PetscFunctionReturn(PETSC_SUCCESS); 7189 } 7190 ++l; 7191 next = next->next; 7192 } 7193 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7194 } 7195 7196 /*@ 7197 DMHasLabel - Determine whether the `DM` has a label of a given name 7198 7199 Not Collective 7200 7201 Input Parameters: 7202 + dm - The `DM` object 7203 - name - The label name 7204 7205 Output Parameter: 7206 . hasLabel - `PETSC_TRUE` if the label is present 7207 7208 Level: intermediate 7209 7210 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7211 @*/ 7212 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7213 { 7214 DMLabelLink next = dm->labels; 7215 const char *lname; 7216 7217 PetscFunctionBegin; 7218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7219 PetscAssertPointer(name, 2); 7220 PetscAssertPointer(hasLabel, 3); 7221 *hasLabel = PETSC_FALSE; 7222 while (next) { 7223 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7224 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7225 if (*hasLabel) break; 7226 next = next->next; 7227 } 7228 PetscFunctionReturn(PETSC_SUCCESS); 7229 } 7230 7231 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7232 /*@ 7233 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM` 7234 7235 Not Collective 7236 7237 Input Parameters: 7238 + dm - The `DM` object 7239 - name - The label name 7240 7241 Output Parameter: 7242 . label - The `DMLabel`, or `NULL` if the label is absent 7243 7244 Default labels in a `DMPLEX`: 7245 + "depth" - Holds the depth (co-dimension) of each mesh point 7246 . "celltype" - Holds the topological type of each cell 7247 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7248 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7249 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7250 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7251 7252 Level: intermediate 7253 7254 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7255 @*/ 7256 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7257 { 7258 DMLabelLink next = dm->labels; 7259 PetscBool hasLabel; 7260 const char *lname; 7261 7262 PetscFunctionBegin; 7263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7264 PetscAssertPointer(name, 2); 7265 PetscAssertPointer(label, 3); 7266 *label = NULL; 7267 while (next) { 7268 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7269 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7270 if (hasLabel) { 7271 *label = next->label; 7272 break; 7273 } 7274 next = next->next; 7275 } 7276 PetscFunctionReturn(PETSC_SUCCESS); 7277 } 7278 7279 /*@ 7280 DMGetLabelByNum - Return the nth label on a `DM` 7281 7282 Not Collective 7283 7284 Input Parameters: 7285 + dm - The `DM` object 7286 - n - the label number 7287 7288 Output Parameter: 7289 . label - the label 7290 7291 Level: intermediate 7292 7293 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7294 @*/ 7295 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7296 { 7297 DMLabelLink next = dm->labels; 7298 PetscInt l = 0; 7299 7300 PetscFunctionBegin; 7301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7302 PetscAssertPointer(label, 3); 7303 while (next) { 7304 if (l == n) { 7305 *label = next->label; 7306 PetscFunctionReturn(PETSC_SUCCESS); 7307 } 7308 ++l; 7309 next = next->next; 7310 } 7311 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7312 } 7313 7314 /*@ 7315 DMAddLabel - Add the label to this `DM` 7316 7317 Not Collective 7318 7319 Input Parameters: 7320 + dm - The `DM` object 7321 - label - The `DMLabel` 7322 7323 Level: developer 7324 7325 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7326 @*/ 7327 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7328 { 7329 DMLabelLink l, *p, tmpLabel; 7330 PetscBool hasLabel; 7331 const char *lname; 7332 PetscBool flg; 7333 7334 PetscFunctionBegin; 7335 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7336 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7337 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7338 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7339 PetscCall(PetscCalloc1(1, &tmpLabel)); 7340 tmpLabel->label = label; 7341 tmpLabel->output = PETSC_TRUE; 7342 for (p = &dm->labels; (l = *p); p = &l->next) { } 7343 *p = tmpLabel; 7344 PetscCall(PetscObjectReference((PetscObject)label)); 7345 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7346 if (flg) dm->depthLabel = label; 7347 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7348 if (flg) dm->celltypeLabel = label; 7349 PetscFunctionReturn(PETSC_SUCCESS); 7350 } 7351 7352 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7353 /*@ 7354 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7355 7356 Not Collective 7357 7358 Input Parameters: 7359 + dm - The `DM` object 7360 - label - The `DMLabel`, having the same name, to substitute 7361 7362 Default labels in a `DMPLEX`: 7363 + "depth" - Holds the depth (co-dimension) of each mesh point 7364 . "celltype" - Holds the topological type of each cell 7365 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7366 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7367 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7368 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7369 7370 Level: intermediate 7371 7372 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7373 @*/ 7374 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7375 { 7376 DMLabelLink next = dm->labels; 7377 PetscBool hasLabel, flg; 7378 const char *name, *lname; 7379 7380 PetscFunctionBegin; 7381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7382 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7383 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7384 while (next) { 7385 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7386 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7387 if (hasLabel) { 7388 PetscCall(PetscObjectReference((PetscObject)label)); 7389 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7390 if (flg) dm->depthLabel = label; 7391 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7392 if (flg) dm->celltypeLabel = label; 7393 PetscCall(DMLabelDestroy(&next->label)); 7394 next->label = label; 7395 break; 7396 } 7397 next = next->next; 7398 } 7399 PetscFunctionReturn(PETSC_SUCCESS); 7400 } 7401 7402 /*@ 7403 DMRemoveLabel - Remove the label given by name from this `DM` 7404 7405 Not Collective 7406 7407 Input Parameters: 7408 + dm - The `DM` object 7409 - name - The label name 7410 7411 Output Parameter: 7412 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the 7413 caller is responsible for calling `DMLabelDestroy()`. 7414 7415 Level: developer 7416 7417 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7418 @*/ 7419 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7420 { 7421 DMLabelLink link, *pnext; 7422 PetscBool hasLabel; 7423 const char *lname; 7424 7425 PetscFunctionBegin; 7426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7427 PetscAssertPointer(name, 2); 7428 if (label) { 7429 PetscAssertPointer(label, 3); 7430 *label = NULL; 7431 } 7432 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7433 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7434 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7435 if (hasLabel) { 7436 *pnext = link->next; /* Remove from list */ 7437 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7438 if (hasLabel) dm->depthLabel = NULL; 7439 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7440 if (hasLabel) dm->celltypeLabel = NULL; 7441 if (label) *label = link->label; 7442 else PetscCall(DMLabelDestroy(&link->label)); 7443 PetscCall(PetscFree(link)); 7444 break; 7445 } 7446 } 7447 PetscFunctionReturn(PETSC_SUCCESS); 7448 } 7449 7450 /*@ 7451 DMRemoveLabelBySelf - Remove the label from this `DM` 7452 7453 Not Collective 7454 7455 Input Parameters: 7456 + dm - The `DM` object 7457 . label - The `DMLabel` to be removed from the `DM` 7458 - failNotFound - Should it fail if the label is not found in the `DM`? 7459 7460 Level: developer 7461 7462 Note: 7463 Only exactly the same instance is removed if found, name match is ignored. 7464 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7465 *label nullified. 7466 7467 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7468 @*/ 7469 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7470 { 7471 DMLabelLink link, *pnext; 7472 PetscBool hasLabel = PETSC_FALSE; 7473 7474 PetscFunctionBegin; 7475 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7476 PetscAssertPointer(label, 2); 7477 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS); 7478 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7479 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7480 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7481 if (*label == link->label) { 7482 hasLabel = PETSC_TRUE; 7483 *pnext = link->next; /* Remove from list */ 7484 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7485 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7486 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7487 PetscCall(DMLabelDestroy(&link->label)); 7488 PetscCall(PetscFree(link)); 7489 break; 7490 } 7491 } 7492 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7493 PetscFunctionReturn(PETSC_SUCCESS); 7494 } 7495 7496 /*@ 7497 DMGetLabelOutput - Get the output flag for a given label 7498 7499 Not Collective 7500 7501 Input Parameters: 7502 + dm - The `DM` object 7503 - name - The label name 7504 7505 Output Parameter: 7506 . output - The flag for output 7507 7508 Level: developer 7509 7510 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7511 @*/ 7512 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7513 { 7514 DMLabelLink next = dm->labels; 7515 const char *lname; 7516 7517 PetscFunctionBegin; 7518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7519 PetscAssertPointer(name, 2); 7520 PetscAssertPointer(output, 3); 7521 while (next) { 7522 PetscBool flg; 7523 7524 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7525 PetscCall(PetscStrcmp(name, lname, &flg)); 7526 if (flg) { 7527 *output = next->output; 7528 PetscFunctionReturn(PETSC_SUCCESS); 7529 } 7530 next = next->next; 7531 } 7532 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7533 } 7534 7535 /*@ 7536 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7537 7538 Not Collective 7539 7540 Input Parameters: 7541 + dm - The `DM` object 7542 . name - The label name 7543 - output - `PETSC_TRUE` to save the label to the viewer 7544 7545 Level: developer 7546 7547 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7548 @*/ 7549 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7550 { 7551 DMLabelLink next = dm->labels; 7552 const char *lname; 7553 7554 PetscFunctionBegin; 7555 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7556 PetscAssertPointer(name, 2); 7557 while (next) { 7558 PetscBool flg; 7559 7560 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7561 PetscCall(PetscStrcmp(name, lname, &flg)); 7562 if (flg) { 7563 next->output = output; 7564 PetscFunctionReturn(PETSC_SUCCESS); 7565 } 7566 next = next->next; 7567 } 7568 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7569 } 7570 7571 /*@ 7572 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7573 7574 Collective 7575 7576 Input Parameters: 7577 + dmA - The `DM` object with initial labels 7578 . dmB - The `DM` object to which labels are copied 7579 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7580 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7581 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7582 7583 Level: intermediate 7584 7585 Note: 7586 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7587 7588 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7589 @*/ 7590 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7591 { 7592 DMLabel label, labelNew, labelOld; 7593 const char *name; 7594 PetscBool flg; 7595 DMLabelLink link; 7596 7597 PetscFunctionBegin; 7598 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7599 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7600 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7601 PetscValidLogicalCollectiveBool(dmA, all, 4); 7602 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7603 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 7604 for (link = dmA->labels; link; link = link->next) { 7605 label = link->label; 7606 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7607 if (!all) { 7608 PetscCall(PetscStrcmp(name, "depth", &flg)); 7609 if (flg) continue; 7610 PetscCall(PetscStrcmp(name, "dim", &flg)); 7611 if (flg) continue; 7612 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7613 if (flg) continue; 7614 } 7615 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7616 if (labelOld) { 7617 switch (emode) { 7618 case DM_COPY_LABELS_KEEP: 7619 continue; 7620 case DM_COPY_LABELS_REPLACE: 7621 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7622 break; 7623 case DM_COPY_LABELS_FAIL: 7624 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7625 default: 7626 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7627 } 7628 } 7629 if (mode == PETSC_COPY_VALUES) { 7630 PetscCall(DMLabelDuplicate(label, &labelNew)); 7631 } else { 7632 labelNew = label; 7633 } 7634 PetscCall(DMAddLabel(dmB, labelNew)); 7635 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7636 } 7637 PetscFunctionReturn(PETSC_SUCCESS); 7638 } 7639 7640 /*@C 7641 DMCompareLabels - Compare labels between two `DM` objects 7642 7643 Collective; No Fortran Support 7644 7645 Input Parameters: 7646 + dm0 - First `DM` object 7647 - dm1 - Second `DM` object 7648 7649 Output Parameters: 7650 + equal - (Optional) Flag whether labels of `dm0` and `dm1` are the same 7651 - message - (Optional) Message describing the difference, or `NULL` if there is no difference 7652 7653 Level: intermediate 7654 7655 Notes: 7656 The output flag equal will be the same on all processes. 7657 7658 If equal is passed as `NULL` and difference is found, an error is thrown on all processes. 7659 7660 Make sure to pass equal is `NULL` on all processes or none of them. 7661 7662 The output message is set independently on each rank. 7663 7664 message must be freed with `PetscFree()` 7665 7666 If message is passed as `NULL` and a difference is found, the difference description is printed to `stderr` in synchronized manner. 7667 7668 Make sure to pass message as `NULL` on all processes or no processes. 7669 7670 Labels are matched by name. If the number of labels and their names are equal, 7671 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7672 7673 Developer Note: 7674 Cannot automatically generate the Fortran stub because `message` must be freed with `PetscFree()` 7675 7676 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7677 @*/ 7678 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char *message[]) PeNS 7679 { 7680 PetscInt n, i; 7681 char msg[PETSC_MAX_PATH_LEN] = ""; 7682 PetscBool eq; 7683 MPI_Comm comm; 7684 PetscMPIInt rank; 7685 7686 PetscFunctionBegin; 7687 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7688 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7689 PetscCheckSameComm(dm0, 1, dm1, 2); 7690 if (equal) PetscAssertPointer(equal, 3); 7691 if (message) PetscAssertPointer(message, 4); 7692 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7693 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7694 { 7695 PetscInt n1; 7696 7697 PetscCall(DMGetNumLabels(dm0, &n)); 7698 PetscCall(DMGetNumLabels(dm1, &n1)); 7699 eq = (PetscBool)(n == n1); 7700 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7701 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7702 if (!eq) goto finish; 7703 } 7704 for (i = 0; i < n; i++) { 7705 DMLabel l0, l1; 7706 const char *name; 7707 char *msgInner; 7708 7709 /* Ignore label order */ 7710 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7711 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7712 PetscCall(DMGetLabel(dm1, name, &l1)); 7713 if (!l1) { 7714 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7715 eq = PETSC_FALSE; 7716 break; 7717 } 7718 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7719 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7720 PetscCall(PetscFree(msgInner)); 7721 if (!eq) break; 7722 } 7723 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7724 finish: 7725 /* If message output arg not set, print to stderr */ 7726 if (message) { 7727 *message = NULL; 7728 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7729 } else { 7730 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7731 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7732 } 7733 /* If same output arg not ser and labels are not equal, throw error */ 7734 if (equal) *equal = eq; 7735 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7736 PetscFunctionReturn(PETSC_SUCCESS); 7737 } 7738 7739 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7740 { 7741 PetscFunctionBegin; 7742 PetscAssertPointer(label, 2); 7743 if (!*label) { 7744 PetscCall(DMCreateLabel(dm, name)); 7745 PetscCall(DMGetLabel(dm, name, label)); 7746 } 7747 PetscCall(DMLabelSetValue(*label, point, value)); 7748 PetscFunctionReturn(PETSC_SUCCESS); 7749 } 7750 7751 /* 7752 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7753 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7754 (label, id) pair in the DM. 7755 7756 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7757 each label. 7758 */ 7759 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7760 { 7761 DMUniversalLabel ul; 7762 PetscBool *active; 7763 PetscInt pStart, pEnd, p, Nl, l, m; 7764 7765 PetscFunctionBegin; 7766 PetscCall(PetscMalloc1(1, &ul)); 7767 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7768 PetscCall(DMGetNumLabels(dm, &Nl)); 7769 PetscCall(PetscCalloc1(Nl, &active)); 7770 ul->Nl = 0; 7771 for (l = 0; l < Nl; ++l) { 7772 PetscBool isdepth, iscelltype; 7773 const char *name; 7774 7775 PetscCall(DMGetLabelName(dm, l, &name)); 7776 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7777 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7778 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7779 if (active[l]) ++ul->Nl; 7780 } 7781 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7782 ul->Nv = 0; 7783 for (l = 0, m = 0; l < Nl; ++l) { 7784 DMLabel label; 7785 PetscInt nv; 7786 const char *name; 7787 7788 if (!active[l]) continue; 7789 PetscCall(DMGetLabelName(dm, l, &name)); 7790 PetscCall(DMGetLabelByNum(dm, l, &label)); 7791 PetscCall(DMLabelGetNumValues(label, &nv)); 7792 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7793 ul->indices[m] = l; 7794 ul->Nv += nv; 7795 ul->offsets[m + 1] = nv; 7796 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7797 ++m; 7798 } 7799 for (l = 1; l <= ul->Nl; ++l) { 7800 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7801 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7802 } 7803 for (l = 0; l < ul->Nl; ++l) { 7804 PetscInt b; 7805 7806 ul->masks[l] = 0; 7807 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7808 } 7809 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7810 for (l = 0, m = 0; l < Nl; ++l) { 7811 DMLabel label; 7812 IS valueIS; 7813 const PetscInt *varr; 7814 PetscInt nv, v; 7815 7816 if (!active[l]) continue; 7817 PetscCall(DMGetLabelByNum(dm, l, &label)); 7818 PetscCall(DMLabelGetNumValues(label, &nv)); 7819 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7820 PetscCall(ISGetIndices(valueIS, &varr)); 7821 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7822 PetscCall(ISRestoreIndices(valueIS, &varr)); 7823 PetscCall(ISDestroy(&valueIS)); 7824 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7825 ++m; 7826 } 7827 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7828 for (p = pStart; p < pEnd; ++p) { 7829 PetscInt uval = 0; 7830 PetscBool marked = PETSC_FALSE; 7831 7832 for (l = 0, m = 0; l < Nl; ++l) { 7833 DMLabel label; 7834 PetscInt val, defval, loc, nv; 7835 7836 if (!active[l]) continue; 7837 PetscCall(DMGetLabelByNum(dm, l, &label)); 7838 PetscCall(DMLabelGetValue(label, p, &val)); 7839 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7840 if (val == defval) { 7841 ++m; 7842 continue; 7843 } 7844 nv = ul->offsets[m + 1] - ul->offsets[m]; 7845 marked = PETSC_TRUE; 7846 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7847 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7848 uval += (loc + 1) << ul->bits[m]; 7849 ++m; 7850 } 7851 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7852 } 7853 PetscCall(PetscFree(active)); 7854 *universal = ul; 7855 PetscFunctionReturn(PETSC_SUCCESS); 7856 } 7857 7858 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7859 { 7860 PetscInt l; 7861 7862 PetscFunctionBegin; 7863 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7864 PetscCall(DMLabelDestroy(&(*universal)->label)); 7865 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7866 PetscCall(PetscFree((*universal)->values)); 7867 PetscCall(PetscFree(*universal)); 7868 *universal = NULL; 7869 PetscFunctionReturn(PETSC_SUCCESS); 7870 } 7871 7872 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7873 { 7874 PetscFunctionBegin; 7875 PetscAssertPointer(ulabel, 2); 7876 *ulabel = ul->label; 7877 PetscFunctionReturn(PETSC_SUCCESS); 7878 } 7879 7880 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7881 { 7882 PetscInt Nl = ul->Nl, l; 7883 7884 PetscFunctionBegin; 7885 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7886 for (l = 0; l < Nl; ++l) { 7887 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7888 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7889 } 7890 if (preserveOrder) { 7891 for (l = 0; l < ul->Nl; ++l) { 7892 const char *name; 7893 PetscBool match; 7894 7895 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7896 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7897 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]); 7898 } 7899 } 7900 PetscFunctionReturn(PETSC_SUCCESS); 7901 } 7902 7903 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7904 { 7905 PetscInt l; 7906 7907 PetscFunctionBegin; 7908 for (l = 0; l < ul->Nl; ++l) { 7909 DMLabel label; 7910 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7911 7912 if (lval) { 7913 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7914 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7915 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7916 } 7917 } 7918 PetscFunctionReturn(PETSC_SUCCESS); 7919 } 7920 7921 /*@ 7922 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7923 7924 Not Collective 7925 7926 Input Parameter: 7927 . dm - The `DM` object 7928 7929 Output Parameter: 7930 . cdm - The coarse `DM` 7931 7932 Level: intermediate 7933 7934 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7935 @*/ 7936 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7937 { 7938 PetscFunctionBegin; 7939 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7940 PetscAssertPointer(cdm, 2); 7941 *cdm = dm->coarseMesh; 7942 PetscFunctionReturn(PETSC_SUCCESS); 7943 } 7944 7945 /*@ 7946 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7947 7948 Input Parameters: 7949 + dm - The `DM` object 7950 - cdm - The coarse `DM` 7951 7952 Level: intermediate 7953 7954 Note: 7955 Normally this is set automatically by `DMRefine()` 7956 7957 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7958 @*/ 7959 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7960 { 7961 PetscFunctionBegin; 7962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7963 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7964 if (dm == cdm) cdm = NULL; 7965 PetscCall(PetscObjectReference((PetscObject)cdm)); 7966 PetscCall(DMDestroy(&dm->coarseMesh)); 7967 dm->coarseMesh = cdm; 7968 PetscFunctionReturn(PETSC_SUCCESS); 7969 } 7970 7971 /*@ 7972 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7973 7974 Input Parameter: 7975 . dm - The `DM` object 7976 7977 Output Parameter: 7978 . fdm - The fine `DM` 7979 7980 Level: intermediate 7981 7982 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7983 @*/ 7984 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7985 { 7986 PetscFunctionBegin; 7987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7988 PetscAssertPointer(fdm, 2); 7989 *fdm = dm->fineMesh; 7990 PetscFunctionReturn(PETSC_SUCCESS); 7991 } 7992 7993 /*@ 7994 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7995 7996 Input Parameters: 7997 + dm - The `DM` object 7998 - fdm - The fine `DM` 7999 8000 Level: developer 8001 8002 Note: 8003 Normally this is set automatically by `DMCoarsen()` 8004 8005 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 8006 @*/ 8007 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 8008 { 8009 PetscFunctionBegin; 8010 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8011 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 8012 if (dm == fdm) fdm = NULL; 8013 PetscCall(PetscObjectReference((PetscObject)fdm)); 8014 PetscCall(DMDestroy(&dm->fineMesh)); 8015 dm->fineMesh = fdm; 8016 PetscFunctionReturn(PETSC_SUCCESS); 8017 } 8018 8019 /*@C 8020 DMAddBoundary - Add a boundary condition, for a single field, to a model represented by a `DM` 8021 8022 Collective 8023 8024 Input Parameters: 8025 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 8026 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 8027 . name - The BC name 8028 . label - The label defining constrained points 8029 . Nv - The number of `DMLabel` values for constrained points 8030 . values - An array of values for constrained points 8031 . field - The field to constrain 8032 . Nc - The number of constrained field components (0 will constrain all components) 8033 . comps - An array of constrained component numbers 8034 . bcFunc - A pointwise function giving boundary values 8035 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 8036 - ctx - An optional user context for bcFunc 8037 8038 Output Parameter: 8039 . bd - (Optional) Boundary number 8040 8041 Options Database Keys: 8042 + -bc_<boundary name> <num> - Overrides the boundary ids 8043 - -bc_<boundary name>_comp <num> - Overrides the boundary components 8044 8045 Level: intermediate 8046 8047 Notes: 8048 If the `DM` is of type `DMPLEX` and the field is of type `PetscFE`, then this function completes the label using `DMPlexLabelComplete()`. 8049 8050 Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 8051 .vb 8052 void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 8053 .ve 8054 8055 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 8056 8057 .vb 8058 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8059 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8060 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8061 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 8062 .ve 8063 + dim - the spatial dimension 8064 . Nf - the number of fields 8065 . uOff - the offset into u[] and u_t[] for each field 8066 . uOff_x - the offset into u_x[] for each field 8067 . u - each field evaluated at the current point 8068 . u_t - the time derivative of each field evaluated at the current point 8069 . u_x - the gradient of each field evaluated at the current point 8070 . aOff - the offset into a[] and a_t[] for each auxiliary field 8071 . aOff_x - the offset into a_x[] for each auxiliary field 8072 . a - each auxiliary field evaluated at the current point 8073 . a_t - the time derivative of each auxiliary field evaluated at the current point 8074 . a_x - the gradient of auxiliary each field evaluated at the current point 8075 . t - current time 8076 . x - coordinates of the current point 8077 . numConstants - number of constant parameters 8078 . constants - constant parameters 8079 - bcval - output values at the current point 8080 8081 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 8082 @*/ 8083 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) 8084 { 8085 PetscDS ds; 8086 8087 PetscFunctionBegin; 8088 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8089 PetscValidLogicalCollectiveEnum(dm, type, 2); 8090 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 8091 PetscValidLogicalCollectiveInt(dm, Nv, 5); 8092 PetscValidLogicalCollectiveInt(dm, field, 7); 8093 PetscValidLogicalCollectiveInt(dm, Nc, 8); 8094 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 8095 PetscCall(DMGetDS(dm, &ds)); 8096 /* Complete label */ 8097 if (label) { 8098 PetscObject obj; 8099 PetscClassId id; 8100 8101 PetscCall(DMGetField(dm, field, NULL, &obj)); 8102 PetscCall(PetscObjectGetClassId(obj, &id)); 8103 if (id == PETSCFE_CLASSID) { 8104 DM plex; 8105 8106 PetscCall(DMConvert(dm, DMPLEX, &plex)); 8107 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 8108 PetscCall(DMDestroy(&plex)); 8109 } 8110 } 8111 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 8112 PetscFunctionReturn(PETSC_SUCCESS); 8113 } 8114 8115 /* TODO Remove this since now the structures are the same */ 8116 static PetscErrorCode DMPopulateBoundary(DM dm) 8117 { 8118 PetscDS ds; 8119 DMBoundary *lastnext; 8120 DSBoundary dsbound; 8121 8122 PetscFunctionBegin; 8123 PetscCall(DMGetDS(dm, &ds)); 8124 dsbound = ds->boundary; 8125 if (dm->boundary) { 8126 DMBoundary next = dm->boundary; 8127 8128 /* quick check to see if the PetscDS has changed */ 8129 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 8130 /* the PetscDS has changed: tear down and rebuild */ 8131 while (next) { 8132 DMBoundary b = next; 8133 8134 next = b->next; 8135 PetscCall(PetscFree(b)); 8136 } 8137 dm->boundary = NULL; 8138 } 8139 8140 lastnext = &dm->boundary; 8141 while (dsbound) { 8142 DMBoundary dmbound; 8143 8144 PetscCall(PetscNew(&dmbound)); 8145 dmbound->dsboundary = dsbound; 8146 dmbound->label = dsbound->label; 8147 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8148 *lastnext = dmbound; 8149 lastnext = &dmbound->next; 8150 dsbound = dsbound->next; 8151 } 8152 PetscFunctionReturn(PETSC_SUCCESS); 8153 } 8154 8155 /* TODO: missing manual page */ 8156 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8157 { 8158 DMBoundary b; 8159 8160 PetscFunctionBegin; 8161 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8162 PetscAssertPointer(isBd, 3); 8163 *isBd = PETSC_FALSE; 8164 PetscCall(DMPopulateBoundary(dm)); 8165 b = dm->boundary; 8166 while (b && !*isBd) { 8167 DMLabel label = b->label; 8168 DSBoundary dsb = b->dsboundary; 8169 PetscInt i; 8170 8171 if (label) { 8172 for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8173 } 8174 b = b->next; 8175 } 8176 PetscFunctionReturn(PETSC_SUCCESS); 8177 } 8178 8179 /*@ 8180 DMHasBound - Determine whether a bound condition was specified 8181 8182 Logically collective 8183 8184 Input Parameter: 8185 . dm - The `DM`, with a `PetscDS` that matches the problem being constrained 8186 8187 Output Parameter: 8188 . hasBound - Flag indicating if a bound condition was specified 8189 8190 Level: intermediate 8191 8192 .seealso: [](ch_dmbase), `DM`, `DSAddBoundary()`, `PetscDSAddBoundary()` 8193 @*/ 8194 PetscErrorCode DMHasBound(DM dm, PetscBool *hasBound) 8195 { 8196 PetscDS ds; 8197 PetscInt Nf, numBd; 8198 8199 PetscFunctionBegin; 8200 *hasBound = PETSC_FALSE; 8201 PetscCall(DMGetDS(dm, &ds)); 8202 PetscCall(PetscDSGetNumFields(ds, &Nf)); 8203 for (PetscInt f = 0; f < Nf; ++f) { 8204 PetscSimplePointFn *lfunc, *ufunc; 8205 8206 PetscCall(PetscDSGetLowerBound(ds, f, &lfunc, NULL)); 8207 PetscCall(PetscDSGetUpperBound(ds, f, &ufunc, NULL)); 8208 if (lfunc || ufunc) *hasBound = PETSC_TRUE; 8209 } 8210 8211 PetscCall(PetscDSGetNumBoundary(ds, &numBd)); 8212 PetscCall(PetscDSUpdateBoundaryLabels(ds, dm)); 8213 for (PetscInt b = 0; b < numBd; ++b) { 8214 PetscWeakForm wf; 8215 DMBoundaryConditionType type; 8216 const char *name; 8217 DMLabel label; 8218 PetscInt numids; 8219 const PetscInt *ids; 8220 PetscInt field, Nc; 8221 const PetscInt *comps; 8222 void (*bvfunc)(void); 8223 void *ctx; 8224 8225 PetscCall(PetscDSGetBoundary(ds, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 8226 if (type == DM_BC_LOWER_BOUND || type == DM_BC_UPPER_BOUND) *hasBound = PETSC_TRUE; 8227 } 8228 PetscFunctionReturn(PETSC_SUCCESS); 8229 } 8230 8231 /*@C 8232 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 8233 8234 Collective 8235 8236 Input Parameters: 8237 + dm - The `DM` 8238 . time - The time 8239 . funcs - The coordinate functions to evaluate, one per field 8240 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8241 - mode - The insertion mode for values 8242 8243 Output Parameter: 8244 . X - vector 8245 8246 Calling sequence of `funcs`: 8247 + dim - The spatial dimension 8248 . time - The time at which to sample 8249 . x - The coordinates 8250 . Nc - The number of components 8251 . u - The output field values 8252 - ctx - optional user-defined function context 8253 8254 Level: developer 8255 8256 Developer Notes: 8257 This API is specific to only particular usage of `DM` 8258 8259 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8260 8261 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8262 @*/ 8263 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) 8264 { 8265 Vec localX; 8266 8267 PetscFunctionBegin; 8268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8269 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8270 PetscCall(DMGetLocalVector(dm, &localX)); 8271 PetscCall(VecSet(localX, 0.)); 8272 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8273 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8274 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8275 PetscCall(DMRestoreLocalVector(dm, &localX)); 8276 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8277 PetscFunctionReturn(PETSC_SUCCESS); 8278 } 8279 8280 /*@C 8281 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8282 8283 Not Collective 8284 8285 Input Parameters: 8286 + dm - The `DM` 8287 . time - The time 8288 . funcs - The coordinate functions to evaluate, one per field 8289 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8290 - mode - The insertion mode for values 8291 8292 Output Parameter: 8293 . localX - vector 8294 8295 Calling sequence of `funcs`: 8296 + dim - The spatial dimension 8297 . time - The current timestep 8298 . x - The coordinates 8299 . Nc - The number of components 8300 . u - The output field values 8301 - ctx - optional user-defined function context 8302 8303 Level: developer 8304 8305 Developer Notes: 8306 This API is specific to only particular usage of `DM` 8307 8308 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8309 8310 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8311 @*/ 8312 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) 8313 { 8314 PetscFunctionBegin; 8315 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8316 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8317 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX); 8318 PetscFunctionReturn(PETSC_SUCCESS); 8319 } 8320 8321 /*@C 8322 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. 8323 8324 Collective 8325 8326 Input Parameters: 8327 + dm - The `DM` 8328 . time - The time 8329 . numIds - The number of ids 8330 . ids - The ids 8331 . Nc - The number of components 8332 . comps - The components 8333 . label - The `DMLabel` selecting the portion of the mesh for projection 8334 . funcs - The coordinate functions to evaluate, one per field 8335 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8336 - mode - The insertion mode for values 8337 8338 Output Parameter: 8339 . X - vector 8340 8341 Calling sequence of `funcs`: 8342 + dim - The spatial dimension 8343 . time - The current timestep 8344 . x - The coordinates 8345 . Nc - The number of components 8346 . u - The output field values 8347 - ctx - optional user-defined function context 8348 8349 Level: developer 8350 8351 Developer Notes: 8352 This API is specific to only particular usage of `DM` 8353 8354 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8355 8356 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8357 @*/ 8358 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) 8359 { 8360 Vec localX; 8361 8362 PetscFunctionBegin; 8363 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8364 PetscCall(DMGetLocalVector(dm, &localX)); 8365 PetscCall(VecSet(localX, 0.)); 8366 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8367 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8368 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8369 PetscCall(DMRestoreLocalVector(dm, &localX)); 8370 PetscFunctionReturn(PETSC_SUCCESS); 8371 } 8372 8373 /*@C 8374 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. 8375 8376 Not Collective 8377 8378 Input Parameters: 8379 + dm - The `DM` 8380 . time - The time 8381 . label - The `DMLabel` selecting the portion of the mesh for projection 8382 . numIds - The number of ids 8383 . ids - The ids 8384 . Nc - The number of components 8385 . comps - The components 8386 . funcs - The coordinate functions to evaluate, one per field 8387 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8388 - mode - The insertion mode for values 8389 8390 Output Parameter: 8391 . localX - vector 8392 8393 Calling sequence of `funcs`: 8394 + dim - The spatial dimension 8395 . time - The current time 8396 . x - The coordinates 8397 . Nc - The number of components 8398 . u - The output field values 8399 - ctx - optional user-defined function context 8400 8401 Level: developer 8402 8403 Developer Notes: 8404 This API is specific to only particular usage of `DM` 8405 8406 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8407 8408 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8409 @*/ 8410 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) 8411 { 8412 PetscFunctionBegin; 8413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8414 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8415 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX); 8416 PetscFunctionReturn(PETSC_SUCCESS); 8417 } 8418 8419 /*@C 8420 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. 8421 8422 Not Collective 8423 8424 Input Parameters: 8425 + dm - The `DM` 8426 . time - The time 8427 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8428 . funcs - The functions to evaluate, one per field 8429 - mode - The insertion mode for values 8430 8431 Output Parameter: 8432 . localX - The output vector 8433 8434 Calling sequence of `funcs`: 8435 + dim - The spatial dimension 8436 . Nf - The number of input fields 8437 . NfAux - The number of input auxiliary fields 8438 . uOff - The offset of each field in u[] 8439 . uOff_x - The offset of each field in u_x[] 8440 . u - The field values at this point in space 8441 . u_t - The field time derivative at this point in space (or NULL) 8442 . u_x - The field derivatives at this point in space 8443 . aOff - The offset of each auxiliary field in u[] 8444 . aOff_x - The offset of each auxiliary field in u_x[] 8445 . a - The auxiliary field values at this point in space 8446 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8447 . a_x - The auxiliary field derivatives at this point in space 8448 . t - The current time 8449 . x - The coordinates of this point 8450 . numConstants - The number of constants 8451 . constants - The value of each constant 8452 - f - The value of the function at this point in space 8453 8454 Level: intermediate 8455 8456 Note: 8457 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. 8458 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 8459 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8460 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8461 8462 Developer Notes: 8463 This API is specific to only particular usage of `DM` 8464 8465 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8466 8467 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8468 `DMProjectFunction()`, `DMComputeL2Diff()` 8469 @*/ 8470 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) 8471 { 8472 PetscFunctionBegin; 8473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8474 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8475 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8476 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX); 8477 PetscFunctionReturn(PETSC_SUCCESS); 8478 } 8479 8480 /*@C 8481 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. 8482 8483 Not Collective 8484 8485 Input Parameters: 8486 + dm - The `DM` 8487 . time - The time 8488 . label - The `DMLabel` marking the portion of the domain to output 8489 . numIds - The number of label ids to use 8490 . ids - The label ids to use for marking 8491 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8492 . comps - The components to set in the output, or `NULL` for all components 8493 . localU - The input field vector 8494 . funcs - The functions to evaluate, one per field 8495 - mode - The insertion mode for values 8496 8497 Output Parameter: 8498 . localX - The output vector 8499 8500 Calling sequence of `funcs`: 8501 + dim - The spatial dimension 8502 . Nf - The number of input fields 8503 . NfAux - The number of input auxiliary fields 8504 . uOff - The offset of each field in u[] 8505 . uOff_x - The offset of each field in u_x[] 8506 . u - The field values at this point in space 8507 . u_t - The field time derivative at this point in space (or NULL) 8508 . u_x - The field derivatives at this point in space 8509 . aOff - The offset of each auxiliary field in u[] 8510 . aOff_x - The offset of each auxiliary field in u_x[] 8511 . a - The auxiliary field values at this point in space 8512 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8513 . a_x - The auxiliary field derivatives at this point in space 8514 . t - The current time 8515 . x - The coordinates of this point 8516 . numConstants - The number of constants 8517 . constants - The value of each constant 8518 - f - The value of the function at this point in space 8519 8520 Level: intermediate 8521 8522 Note: 8523 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. 8524 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 8525 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8526 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8527 8528 Developer Notes: 8529 This API is specific to only particular usage of `DM` 8530 8531 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8532 8533 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8534 @*/ 8535 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) 8536 { 8537 PetscFunctionBegin; 8538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8539 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8540 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8541 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8542 PetscFunctionReturn(PETSC_SUCCESS); 8543 } 8544 8545 /*@C 8546 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. 8547 8548 Not Collective 8549 8550 Input Parameters: 8551 + dm - The `DM` 8552 . time - The time 8553 . label - The `DMLabel` marking the portion of the domain to output 8554 . numIds - The number of label ids to use 8555 . ids - The label ids to use for marking 8556 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8557 . comps - The components to set in the output, or `NULL` for all components 8558 . U - The input field vector 8559 . funcs - The functions to evaluate, one per field 8560 - mode - The insertion mode for values 8561 8562 Output Parameter: 8563 . X - The output vector 8564 8565 Calling sequence of `funcs`: 8566 + dim - The spatial dimension 8567 . Nf - The number of input fields 8568 . NfAux - The number of input auxiliary fields 8569 . uOff - The offset of each field in u[] 8570 . uOff_x - The offset of each field in u_x[] 8571 . u - The field values at this point in space 8572 . u_t - The field time derivative at this point in space (or NULL) 8573 . u_x - The field derivatives at this point in space 8574 . aOff - The offset of each auxiliary field in u[] 8575 . aOff_x - The offset of each auxiliary field in u_x[] 8576 . a - The auxiliary field values at this point in space 8577 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8578 . a_x - The auxiliary field derivatives at this point in space 8579 . t - The current time 8580 . x - The coordinates of this point 8581 . numConstants - The number of constants 8582 . constants - The value of each constant 8583 - f - The value of the function at this point in space 8584 8585 Level: intermediate 8586 8587 Note: 8588 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. 8589 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 8590 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8591 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8592 8593 Developer Notes: 8594 This API is specific to only particular usage of `DM` 8595 8596 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8597 8598 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8599 @*/ 8600 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) 8601 { 8602 DM dmIn; 8603 Vec localU, localX; 8604 8605 PetscFunctionBegin; 8606 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8607 PetscCall(VecGetDM(U, &dmIn)); 8608 PetscCall(DMGetLocalVector(dmIn, &localU)); 8609 PetscCall(DMGetLocalVector(dm, &localX)); 8610 PetscCall(VecSet(localX, 0.)); 8611 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8612 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8613 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8614 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8615 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8616 PetscCall(DMRestoreLocalVector(dm, &localX)); 8617 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8618 PetscFunctionReturn(PETSC_SUCCESS); 8619 } 8620 8621 /*@C 8622 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. 8623 8624 Not Collective 8625 8626 Input Parameters: 8627 + dm - The `DM` 8628 . time - The time 8629 . label - The `DMLabel` marking the portion of the domain boundary to output 8630 . numIds - The number of label ids to use 8631 . ids - The label ids to use for marking 8632 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8633 . comps - The components to set in the output, or `NULL` for all components 8634 . localU - The input field vector 8635 . funcs - The functions to evaluate, one per field 8636 - mode - The insertion mode for values 8637 8638 Output Parameter: 8639 . localX - The output vector 8640 8641 Calling sequence of `funcs`: 8642 + dim - The spatial dimension 8643 . Nf - The number of input fields 8644 . NfAux - The number of input auxiliary fields 8645 . uOff - The offset of each field in u[] 8646 . uOff_x - The offset of each field in u_x[] 8647 . u - The field values at this point in space 8648 . u_t - The field time derivative at this point in space (or NULL) 8649 . u_x - The field derivatives at this point in space 8650 . aOff - The offset of each auxiliary field in u[] 8651 . aOff_x - The offset of each auxiliary field in u_x[] 8652 . a - The auxiliary field values at this point in space 8653 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8654 . a_x - The auxiliary field derivatives at this point in space 8655 . t - The current time 8656 . x - The coordinates of this point 8657 . n - The face normal 8658 . numConstants - The number of constants 8659 . constants - The value of each constant 8660 - f - The value of the function at this point in space 8661 8662 Level: intermediate 8663 8664 Note: 8665 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. 8666 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 8667 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8668 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8669 8670 Developer Notes: 8671 This API is specific to only particular usage of `DM` 8672 8673 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8674 8675 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8676 @*/ 8677 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) 8678 { 8679 PetscFunctionBegin; 8680 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8681 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8682 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8683 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8684 PetscFunctionReturn(PETSC_SUCCESS); 8685 } 8686 8687 /*@C 8688 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8689 8690 Collective 8691 8692 Input Parameters: 8693 + dm - The `DM` 8694 . time - The time 8695 . funcs - The functions to evaluate for each field component 8696 . ctxs - Optional array of contexts to pass to each function, or NULL. 8697 - X - The coefficient vector u_h, a global vector 8698 8699 Output Parameter: 8700 . diff - The diff ||u - u_h||_2 8701 8702 Level: developer 8703 8704 Developer Notes: 8705 This API is specific to only particular usage of `DM` 8706 8707 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8708 8709 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8710 @*/ 8711 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8712 { 8713 PetscFunctionBegin; 8714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8715 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8716 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff); 8717 PetscFunctionReturn(PETSC_SUCCESS); 8718 } 8719 8720 /*@C 8721 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8722 8723 Collective 8724 8725 Input Parameters: 8726 + dm - The `DM` 8727 . time - The time 8728 . funcs - The gradient functions to evaluate for each field component 8729 . ctxs - Optional array of contexts to pass to each function, or NULL. 8730 . X - The coefficient vector u_h, a global vector 8731 - n - The vector to project along 8732 8733 Output Parameter: 8734 . diff - The diff ||(grad u - grad u_h) . n||_2 8735 8736 Level: developer 8737 8738 Developer Notes: 8739 This API is specific to only particular usage of `DM` 8740 8741 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8742 8743 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8744 @*/ 8745 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) 8746 { 8747 PetscFunctionBegin; 8748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8749 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8750 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff); 8751 PetscFunctionReturn(PETSC_SUCCESS); 8752 } 8753 8754 /*@C 8755 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8756 8757 Collective 8758 8759 Input Parameters: 8760 + dm - The `DM` 8761 . time - The time 8762 . funcs - The functions to evaluate for each field component 8763 . ctxs - Optional array of contexts to pass to each function, or NULL. 8764 - X - The coefficient vector u_h, a global vector 8765 8766 Output Parameter: 8767 . diff - The array of differences, ||u^f - u^f_h||_2 8768 8769 Level: developer 8770 8771 Developer Notes: 8772 This API is specific to only particular usage of `DM` 8773 8774 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8775 8776 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8777 @*/ 8778 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8779 { 8780 PetscFunctionBegin; 8781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8782 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8783 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff); 8784 PetscFunctionReturn(PETSC_SUCCESS); 8785 } 8786 8787 /*@C 8788 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8789 8790 Not Collective 8791 8792 Input Parameter: 8793 . dm - The `DM` 8794 8795 Output Parameters: 8796 + nranks - the number of neighbours 8797 - ranks - the neighbors ranks 8798 8799 Level: beginner 8800 8801 Note: 8802 Do not free the array, it is freed when the `DM` is destroyed. 8803 8804 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8805 @*/ 8806 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8807 { 8808 PetscFunctionBegin; 8809 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8810 PetscUseTypeMethod(dm, getneighbors, nranks, ranks); 8811 PetscFunctionReturn(PETSC_SUCCESS); 8812 } 8813 8814 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8815 8816 /* 8817 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8818 This must be a different function because it requires DM which is not defined in the Mat library 8819 */ 8820 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8821 { 8822 PetscFunctionBegin; 8823 if (coloring->ctype == IS_COLORING_LOCAL) { 8824 Vec x1local; 8825 DM dm; 8826 PetscCall(MatGetDM(J, &dm)); 8827 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8828 PetscCall(DMGetLocalVector(dm, &x1local)); 8829 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8830 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8831 x1 = x1local; 8832 } 8833 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8834 if (coloring->ctype == IS_COLORING_LOCAL) { 8835 DM dm; 8836 PetscCall(MatGetDM(J, &dm)); 8837 PetscCall(DMRestoreLocalVector(dm, &x1)); 8838 } 8839 PetscFunctionReturn(PETSC_SUCCESS); 8840 } 8841 8842 /*@ 8843 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8844 8845 Input Parameters: 8846 + coloring - The matrix to get the `DM` from 8847 - fdcoloring - the `MatFDColoring` object 8848 8849 Level: advanced 8850 8851 Developer Note: 8852 This routine exists because the PETSc `Mat` library does not know about the `DM` objects 8853 8854 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8855 @*/ 8856 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8857 { 8858 PetscFunctionBegin; 8859 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8860 PetscFunctionReturn(PETSC_SUCCESS); 8861 } 8862 8863 /*@ 8864 DMGetCompatibility - determine if two `DM`s are compatible 8865 8866 Collective 8867 8868 Input Parameters: 8869 + dm1 - the first `DM` 8870 - dm2 - the second `DM` 8871 8872 Output Parameters: 8873 + compatible - whether or not the two `DM`s are compatible 8874 - set - whether or not the compatible value was actually determined and set 8875 8876 Level: advanced 8877 8878 Notes: 8879 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8880 of the same topology. This implies that the section (field data) on one 8881 "makes sense" with respect to the topology and parallel decomposition of the other. 8882 Loosely speaking, compatible `DM`s represent the same domain and parallel 8883 decomposition, but hold different data. 8884 8885 Typically, one would confirm compatibility if intending to simultaneously iterate 8886 over a pair of vectors obtained from different `DM`s. 8887 8888 For example, two `DMDA` objects are compatible if they have the same local 8889 and global sizes and the same stencil width. They can have different numbers 8890 of degrees of freedom per node. Thus, one could use the node numbering from 8891 either `DM` in bounds for a loop over vectors derived from either `DM`. 8892 8893 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8894 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8895 .vb 8896 ... 8897 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8898 if (set && compatible) { 8899 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8900 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8901 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8902 for (j=y; j<y+n; ++j) { 8903 for (i=x; i<x+m, ++i) { 8904 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8905 } 8906 } 8907 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8908 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8909 } else { 8910 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8911 } 8912 ... 8913 .ve 8914 8915 Checking compatibility might be expensive for a given implementation of `DM`, 8916 or might be impossible to unambiguously confirm or deny. For this reason, 8917 this function may decline to determine compatibility, and hence users should 8918 always check the "set" output parameter. 8919 8920 A `DM` is always compatible with itself. 8921 8922 In the current implementation, `DM`s which live on "unequal" communicators 8923 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8924 incompatible. 8925 8926 This function is labeled "Collective," as information about all subdomains 8927 is required on each rank. However, in `DM` implementations which store all this 8928 information locally, this function may be merely "Logically Collective". 8929 8930 Developer Note: 8931 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8932 iff B is compatible with A. Thus, this function checks the implementations 8933 of both dm and dmc (if they are of different types), attempting to determine 8934 compatibility. It is left to `DM` implementers to ensure that symmetry is 8935 preserved. The simplest way to do this is, when implementing type-specific 8936 logic for this function, is to check for existing logic in the implementation 8937 of other `DM` types and let *set = PETSC_FALSE if found. 8938 8939 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8940 @*/ 8941 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8942 { 8943 PetscMPIInt compareResult; 8944 DMType type, type2; 8945 PetscBool sameType; 8946 8947 PetscFunctionBegin; 8948 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8949 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8950 8951 /* Declare a DM compatible with itself */ 8952 if (dm1 == dm2) { 8953 *set = PETSC_TRUE; 8954 *compatible = PETSC_TRUE; 8955 PetscFunctionReturn(PETSC_SUCCESS); 8956 } 8957 8958 /* Declare a DM incompatible with a DM that lives on an "unequal" 8959 communicator. Note that this does not preclude compatibility with 8960 DMs living on "congruent" or "similar" communicators, but this must be 8961 determined by the implementation-specific logic */ 8962 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8963 if (compareResult == MPI_UNEQUAL) { 8964 *set = PETSC_TRUE; 8965 *compatible = PETSC_FALSE; 8966 PetscFunctionReturn(PETSC_SUCCESS); 8967 } 8968 8969 /* Pass to the implementation-specific routine, if one exists. */ 8970 if (dm1->ops->getcompatibility) { 8971 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8972 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8973 } 8974 8975 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8976 with an implementation of this function from dm2 */ 8977 PetscCall(DMGetType(dm1, &type)); 8978 PetscCall(DMGetType(dm2, &type2)); 8979 PetscCall(PetscStrcmp(type, type2, &sameType)); 8980 if (!sameType && dm2->ops->getcompatibility) { 8981 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8982 } else { 8983 *set = PETSC_FALSE; 8984 } 8985 PetscFunctionReturn(PETSC_SUCCESS); 8986 } 8987 8988 /*@C 8989 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8990 8991 Logically Collective 8992 8993 Input Parameters: 8994 + dm - the `DM` 8995 . f - the monitor function 8996 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8997 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence 8998 8999 Options Database Key: 9000 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 9001 does not cancel those set via the options database. 9002 9003 Level: intermediate 9004 9005 Note: 9006 Several different monitoring routines may be set by calling 9007 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 9008 order in which they were set. 9009 9010 Fortran Note: 9011 Only a single monitor function can be set for each `DM` object 9012 9013 Developer Note: 9014 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 9015 9016 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn` 9017 @*/ 9018 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy) 9019 { 9020 PetscInt m; 9021 9022 PetscFunctionBegin; 9023 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9024 for (m = 0; m < dm->numbermonitors; ++m) { 9025 PetscBool identical; 9026 9027 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 9028 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 9029 } 9030 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 9031 dm->monitor[dm->numbermonitors] = f; 9032 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 9033 dm->monitorcontext[dm->numbermonitors++] = mctx; 9034 PetscFunctionReturn(PETSC_SUCCESS); 9035 } 9036 9037 /*@ 9038 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 9039 9040 Logically Collective 9041 9042 Input Parameter: 9043 . dm - the DM 9044 9045 Options Database Key: 9046 . -dm_monitor_cancel - cancels all monitors that have been hardwired 9047 into a code by calls to `DMonitorSet()`, but does not cancel those 9048 set via the options database 9049 9050 Level: intermediate 9051 9052 Note: 9053 There is no way to clear one specific monitor from a `DM` object. 9054 9055 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 9056 @*/ 9057 PetscErrorCode DMMonitorCancel(DM dm) 9058 { 9059 PetscInt m; 9060 9061 PetscFunctionBegin; 9062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9063 for (m = 0; m < dm->numbermonitors; ++m) { 9064 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 9065 } 9066 dm->numbermonitors = 0; 9067 PetscFunctionReturn(PETSC_SUCCESS); 9068 } 9069 9070 /*@C 9071 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 9072 9073 Collective 9074 9075 Input Parameters: 9076 + dm - `DM` object you wish to monitor 9077 . name - the monitor type one is seeking 9078 . help - message indicating what monitoring is done 9079 . manual - manual page for the monitor 9080 . monitor - the monitor function, this must use a `PetscViewerFormat` as its context 9081 - 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 9082 9083 Output Parameter: 9084 . flg - Flag set if the monitor was created 9085 9086 Level: developer 9087 9088 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 9089 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 9090 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 9091 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 9092 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 9093 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 9094 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 9095 @*/ 9096 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 9097 { 9098 PetscViewer viewer; 9099 PetscViewerFormat format; 9100 9101 PetscFunctionBegin; 9102 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9103 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 9104 if (*flg) { 9105 PetscViewerAndFormat *vf; 9106 9107 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 9108 PetscCall(PetscViewerDestroy(&viewer)); 9109 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 9110 PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy)); 9111 } 9112 PetscFunctionReturn(PETSC_SUCCESS); 9113 } 9114 9115 /*@ 9116 DMMonitor - runs the user provided monitor routines, if they exist 9117 9118 Collective 9119 9120 Input Parameter: 9121 . dm - The `DM` 9122 9123 Level: developer 9124 9125 Developer Note: 9126 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 9127 related to the discretization process seems rather specialized since some `DM` have no 9128 concept of discretization. 9129 9130 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 9131 @*/ 9132 PetscErrorCode DMMonitor(DM dm) 9133 { 9134 PetscInt m; 9135 9136 PetscFunctionBegin; 9137 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 9138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9139 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 9140 PetscFunctionReturn(PETSC_SUCCESS); 9141 } 9142 9143 /*@ 9144 DMComputeError - Computes the error assuming the user has provided the exact solution functions 9145 9146 Collective 9147 9148 Input Parameters: 9149 + dm - The `DM` 9150 - sol - The solution vector 9151 9152 Input/Output Parameter: 9153 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 9154 contains the error in each field 9155 9156 Output Parameter: 9157 . errorVec - A vector to hold the cellwise error (may be `NULL`) 9158 9159 Level: developer 9160 9161 Note: 9162 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 9163 9164 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 9165 @*/ 9166 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 9167 { 9168 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 9169 void **ctxs; 9170 PetscReal time; 9171 PetscInt Nf, f, Nds, s; 9172 9173 PetscFunctionBegin; 9174 PetscCall(DMGetNumFields(dm, &Nf)); 9175 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 9176 PetscCall(DMGetNumDS(dm, &Nds)); 9177 for (s = 0; s < Nds; ++s) { 9178 PetscDS ds; 9179 DMLabel label; 9180 IS fieldIS; 9181 const PetscInt *fields; 9182 PetscInt dsNf; 9183 9184 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 9185 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9186 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9187 for (f = 0; f < dsNf; ++f) { 9188 const PetscInt field = fields[f]; 9189 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9190 } 9191 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9192 } 9193 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); 9194 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9195 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9196 if (errorVec) { 9197 DM edm; 9198 DMPolytopeType ct; 9199 PetscBool simplex; 9200 PetscInt dim, cStart, Nf; 9201 9202 PetscCall(DMClone(dm, &edm)); 9203 PetscCall(DMGetDimension(edm, &dim)); 9204 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9205 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9206 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9207 PetscCall(DMGetNumFields(dm, &Nf)); 9208 for (f = 0; f < Nf; ++f) { 9209 PetscFE fe, efe; 9210 PetscQuadrature q; 9211 const char *name; 9212 9213 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 9214 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9215 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 9216 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 9217 PetscCall(PetscFEGetQuadrature(fe, &q)); 9218 PetscCall(PetscFESetQuadrature(efe, q)); 9219 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 9220 PetscCall(PetscFEDestroy(&efe)); 9221 } 9222 PetscCall(DMCreateDS(edm)); 9223 9224 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9225 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 9226 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9227 PetscCall(DMDestroy(&edm)); 9228 } 9229 PetscCall(PetscFree2(exactSol, ctxs)); 9230 PetscFunctionReturn(PETSC_SUCCESS); 9231 } 9232 9233 /*@ 9234 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 9235 9236 Not Collective 9237 9238 Input Parameter: 9239 . dm - The `DM` 9240 9241 Output Parameter: 9242 . numAux - The number of auxiliary data vectors 9243 9244 Level: advanced 9245 9246 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 9247 @*/ 9248 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9249 { 9250 PetscFunctionBegin; 9251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9252 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9253 PetscFunctionReturn(PETSC_SUCCESS); 9254 } 9255 9256 /*@ 9257 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9258 9259 Not Collective 9260 9261 Input Parameters: 9262 + dm - The `DM` 9263 . label - The `DMLabel` 9264 . value - The label value indicating the region 9265 - part - The equation part, or 0 if unused 9266 9267 Output Parameter: 9268 . aux - The `Vec` holding auxiliary field data 9269 9270 Level: advanced 9271 9272 Note: 9273 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9274 9275 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9276 @*/ 9277 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9278 { 9279 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9280 PetscBool has; 9281 9282 PetscFunctionBegin; 9283 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9284 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9285 key.label = label; 9286 key.value = value; 9287 key.part = part; 9288 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9289 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9290 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9291 PetscFunctionReturn(PETSC_SUCCESS); 9292 } 9293 9294 /*@ 9295 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9296 9297 Not Collective because auxiliary vectors are not parallel 9298 9299 Input Parameters: 9300 + dm - The `DM` 9301 . label - The `DMLabel` 9302 . value - The label value indicating the region 9303 . part - The equation part, or 0 if unused 9304 - aux - The `Vec` holding auxiliary field data 9305 9306 Level: advanced 9307 9308 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9309 @*/ 9310 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9311 { 9312 Vec old; 9313 PetscHashAuxKey key; 9314 9315 PetscFunctionBegin; 9316 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9317 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9318 key.label = label; 9319 key.value = value; 9320 key.part = part; 9321 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9322 PetscCall(PetscObjectReference((PetscObject)aux)); 9323 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9324 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9325 PetscCall(VecDestroy(&old)); 9326 PetscFunctionReturn(PETSC_SUCCESS); 9327 } 9328 9329 /*@ 9330 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9331 9332 Not Collective 9333 9334 Input Parameter: 9335 . dm - The `DM` 9336 9337 Output Parameters: 9338 + labels - The `DMLabel`s for each `Vec` 9339 . values - The label values for each `Vec` 9340 - parts - The equation parts for each `Vec` 9341 9342 Level: advanced 9343 9344 Note: 9345 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9346 9347 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9348 @*/ 9349 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9350 { 9351 PetscHashAuxKey *keys; 9352 PetscInt n, i, off = 0; 9353 9354 PetscFunctionBegin; 9355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9356 PetscAssertPointer(labels, 2); 9357 PetscAssertPointer(values, 3); 9358 PetscAssertPointer(parts, 4); 9359 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9360 PetscCall(PetscMalloc1(n, &keys)); 9361 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9362 for (i = 0; i < n; ++i) { 9363 labels[i] = keys[i].label; 9364 values[i] = keys[i].value; 9365 parts[i] = keys[i].part; 9366 } 9367 PetscCall(PetscFree(keys)); 9368 PetscFunctionReturn(PETSC_SUCCESS); 9369 } 9370 9371 /*@ 9372 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9373 9374 Not Collective 9375 9376 Input Parameter: 9377 . dm - The `DM` 9378 9379 Output Parameter: 9380 . dmNew - The new `DM`, now with the same auxiliary data 9381 9382 Level: advanced 9383 9384 Note: 9385 This is a shallow copy of the auxiliary vectors 9386 9387 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9388 @*/ 9389 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9390 { 9391 PetscFunctionBegin; 9392 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9393 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2); 9394 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS); 9395 PetscCall(DMClearAuxiliaryVec(dmNew)); 9396 9397 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9398 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9399 { 9400 Vec *auxData; 9401 PetscInt n, i, off = 0; 9402 9403 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n)); 9404 PetscCall(PetscMalloc1(n, &auxData)); 9405 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData)); 9406 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i])); 9407 PetscCall(PetscFree(auxData)); 9408 } 9409 PetscFunctionReturn(PETSC_SUCCESS); 9410 } 9411 9412 /*@ 9413 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one 9414 9415 Not Collective 9416 9417 Input Parameter: 9418 . dm - The `DM` 9419 9420 Level: advanced 9421 9422 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9423 @*/ 9424 PetscErrorCode DMClearAuxiliaryVec(DM dm) 9425 { 9426 Vec *auxData; 9427 PetscInt n, i, off = 0; 9428 9429 PetscFunctionBegin; 9430 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n)); 9431 PetscCall(PetscMalloc1(n, &auxData)); 9432 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData)); 9433 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 9434 PetscCall(PetscFree(auxData)); 9435 PetscCall(PetscHMapAuxDestroy(&dm->auxData)); 9436 PetscCall(PetscHMapAuxCreate(&dm->auxData)); 9437 PetscFunctionReturn(PETSC_SUCCESS); 9438 } 9439 9440 /*@ 9441 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9442 9443 Not Collective 9444 9445 Input Parameters: 9446 + ct - The `DMPolytopeType` 9447 . sourceCone - The source arrangement of faces 9448 - targetCone - The target arrangement of faces 9449 9450 Output Parameters: 9451 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9452 - found - Flag indicating that a suitable orientation was found 9453 9454 Level: advanced 9455 9456 Note: 9457 An arrangement is a face order combined with an orientation for each face 9458 9459 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9460 that labels each arrangement (face ordering plus orientation for each face). 9461 9462 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9463 9464 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9465 @*/ 9466 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9467 { 9468 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9469 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9470 PetscInt o, c; 9471 9472 PetscFunctionBegin; 9473 if (!nO) { 9474 *ornt = 0; 9475 *found = PETSC_TRUE; 9476 PetscFunctionReturn(PETSC_SUCCESS); 9477 } 9478 for (o = -nO; o < nO; ++o) { 9479 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 9480 9481 for (c = 0; c < cS; ++c) 9482 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9483 if (c == cS) { 9484 *ornt = o; 9485 break; 9486 } 9487 } 9488 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9489 PetscFunctionReturn(PETSC_SUCCESS); 9490 } 9491 9492 /*@ 9493 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9494 9495 Not Collective 9496 9497 Input Parameters: 9498 + ct - The `DMPolytopeType` 9499 . sourceCone - The source arrangement of faces 9500 - targetCone - The target arrangement of faces 9501 9502 Output Parameter: 9503 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9504 9505 Level: advanced 9506 9507 Note: 9508 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9509 9510 Developer Note: 9511 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9512 9513 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9514 @*/ 9515 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9516 { 9517 PetscBool found; 9518 9519 PetscFunctionBegin; 9520 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9521 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9522 PetscFunctionReturn(PETSC_SUCCESS); 9523 } 9524 9525 /*@ 9526 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9527 9528 Not Collective 9529 9530 Input Parameters: 9531 + ct - The `DMPolytopeType` 9532 . sourceVert - The source arrangement of vertices 9533 - targetVert - The target arrangement of vertices 9534 9535 Output Parameters: 9536 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9537 - found - Flag indicating that a suitable orientation was found 9538 9539 Level: advanced 9540 9541 Notes: 9542 An arrangement is a vertex order 9543 9544 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9545 that labels each arrangement (vertex ordering). 9546 9547 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9548 9549 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()` 9550 @*/ 9551 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9552 { 9553 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9554 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9555 PetscInt o, c; 9556 9557 PetscFunctionBegin; 9558 if (!nO) { 9559 *ornt = 0; 9560 *found = PETSC_TRUE; 9561 PetscFunctionReturn(PETSC_SUCCESS); 9562 } 9563 for (o = -nO; o < nO; ++o) { 9564 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o); 9565 9566 for (c = 0; c < cS; ++c) 9567 if (sourceVert[arr[c]] != targetVert[c]) break; 9568 if (c == cS) { 9569 *ornt = o; 9570 break; 9571 } 9572 } 9573 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9574 PetscFunctionReturn(PETSC_SUCCESS); 9575 } 9576 9577 /*@ 9578 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9579 9580 Not Collective 9581 9582 Input Parameters: 9583 + ct - The `DMPolytopeType` 9584 . sourceCone - The source arrangement of vertices 9585 - targetCone - The target arrangement of vertices 9586 9587 Output Parameter: 9588 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9589 9590 Level: advanced 9591 9592 Note: 9593 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9594 9595 Developer Note: 9596 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9597 9598 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9599 @*/ 9600 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9601 { 9602 PetscBool found; 9603 9604 PetscFunctionBegin; 9605 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9606 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9607 PetscFunctionReturn(PETSC_SUCCESS); 9608 } 9609 9610 /*@ 9611 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9612 9613 Not Collective 9614 9615 Input Parameters: 9616 + ct - The `DMPolytopeType` 9617 - point - Coordinates of the point 9618 9619 Output Parameter: 9620 . inside - Flag indicating whether the point is inside the reference cell of given type 9621 9622 Level: advanced 9623 9624 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9625 @*/ 9626 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9627 { 9628 PetscReal sum = 0.0; 9629 PetscInt d; 9630 9631 PetscFunctionBegin; 9632 *inside = PETSC_TRUE; 9633 switch (ct) { 9634 case DM_POLYTOPE_TRIANGLE: 9635 case DM_POLYTOPE_TETRAHEDRON: 9636 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9637 if (point[d] < -1.0) { 9638 *inside = PETSC_FALSE; 9639 break; 9640 } 9641 sum += point[d]; 9642 } 9643 if (sum > PETSC_SMALL) { 9644 *inside = PETSC_FALSE; 9645 break; 9646 } 9647 break; 9648 case DM_POLYTOPE_QUADRILATERAL: 9649 case DM_POLYTOPE_HEXAHEDRON: 9650 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9651 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9652 *inside = PETSC_FALSE; 9653 break; 9654 } 9655 break; 9656 default: 9657 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9658 } 9659 PetscFunctionReturn(PETSC_SUCCESS); 9660 } 9661 9662 /*@ 9663 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default 9664 9665 Logically collective 9666 9667 Input Parameters: 9668 + dm - The DM 9669 - reorder - Flag for reordering 9670 9671 Level: intermediate 9672 9673 .seealso: `DMReorderSectionGetDefault()` 9674 @*/ 9675 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder) 9676 { 9677 PetscFunctionBegin; 9678 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9679 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); 9680 PetscFunctionReturn(PETSC_SUCCESS); 9681 } 9682 9683 /*@ 9684 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default 9685 9686 Not collective 9687 9688 Input Parameter: 9689 . dm - The DM 9690 9691 Output Parameter: 9692 . reorder - Flag for reordering 9693 9694 Level: intermediate 9695 9696 .seealso: `DMReorderSetDefault()` 9697 @*/ 9698 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder) 9699 { 9700 PetscFunctionBegin; 9701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9702 PetscAssertPointer(reorder, 2); 9703 *reorder = DM_REORDER_DEFAULT_NOTSET; 9704 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); 9705 PetscFunctionReturn(PETSC_SUCCESS); 9706 } 9707 9708 /*@ 9709 DMReorderSectionSetType - Set the type of local section reordering 9710 9711 Logically collective 9712 9713 Input Parameters: 9714 + dm - The DM 9715 - reorder - The reordering method 9716 9717 Level: intermediate 9718 9719 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()` 9720 @*/ 9721 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder) 9722 { 9723 PetscFunctionBegin; 9724 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9725 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder)); 9726 PetscFunctionReturn(PETSC_SUCCESS); 9727 } 9728 9729 /*@ 9730 DMReorderSectionGetType - Get the reordering type for the local section 9731 9732 Not collective 9733 9734 Input Parameter: 9735 . dm - The DM 9736 9737 Output Parameter: 9738 . reorder - The reordering method 9739 9740 Level: intermediate 9741 9742 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()` 9743 @*/ 9744 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder) 9745 { 9746 PetscFunctionBegin; 9747 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9748 PetscAssertPointer(reorder, 2); 9749 *reorder = NULL; 9750 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder)); 9751 PetscFunctionReturn(PETSC_SUCCESS); 9752 } 9753