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