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