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