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