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_filename <str> - File containing a mesh 838 . -dm_plex_boundary_filename <str> - File containing a mesh boundary 839 . -dm_plex_name <str> - Name of the mesh in the file 840 . -dm_plex_shape <shape> - The domain shape, such as `BOX`, `SPHERE`, etc. 841 . -dm_plex_cell <ct> - Cell shape 842 . -dm_plex_reference_cell_domain <bool> - Use a reference cell domain 843 . -dm_plex_dim <dim> - Set the topological dimension 844 . -dm_plex_simplex <bool> - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements 845 . -dm_plex_interpolate <bool> - `PETSC_TRUE` turns on topological interpolation (creating edges and faces) 846 . -dm_plex_scale <sc> - Scale factor for mesh coordinates 847 . -dm_coord_remap <bool> - Map coordinates using a function 848 . -dm_coord_map <mapname> - Select a builtin coordinate map 849 . -dm_coord_map_params <p0,p1,p2,...> - Set coordinate mapping parameters 850 . -dm_plex_box_faces <m,n,p> - Number of faces along each dimension 851 . -dm_plex_box_lower <x,y,z> - Specify lower-left-bottom coordinates for the box 852 . -dm_plex_box_upper <x,y,z> - Specify upper-right-top coordinates for the box 853 . -dm_plex_box_bd <bx,by,bz> - Specify the `DMBoundaryType` for each direction 854 . -dm_plex_sphere_radius <r> - The sphere radius 855 . -dm_plex_ball_radius <r> - Radius of the ball 856 . -dm_plex_cylinder_bd <bz> - Boundary type in the z direction 857 . -dm_plex_cylinder_num_wedges <n> - Number of wedges around the cylinder 858 . -dm_plex_reorder <order> - Reorder the mesh using the specified algorithm 859 . -dm_refine_pre <n> - The number of refinements before distribution 860 . -dm_refine_uniform_pre <bool> - Flag for uniform refinement before distribution 861 . -dm_refine_volume_limit_pre <v> - The maximum cell volume after refinement before distribution 862 . -dm_refine <n> - The number of refinements after distribution 863 . -dm_extrude <l> - Activate extrusion and specify the number of layers to extrude 864 . -dm_plex_transform_extrude_thickness <t> - The total thickness of extruded layers 865 . -dm_plex_transform_extrude_use_tensor <bool> - Use tensor cells when extruding 866 . -dm_plex_transform_extrude_symmetric <bool> - Extrude layers symmetrically about the surface 867 . -dm_plex_transform_extrude_normal <n0,...,nd> - Specify the extrusion direction 868 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer 869 . -dm_plex_create_fv_ghost_cells - Flag to create finite volume ghost cells on the boundary 870 . -dm_plex_fv_ghost_cells_label <name> - Label name for ghost cells boundary 871 . -dm_distribute <bool> - Flag to redistribute a mesh among processes 872 . -dm_distribute_overlap <n> - The size of the overlap halo 873 . -dm_plex_adj_cone <bool> - Set adjacency direction 874 . -dm_plex_adj_closure <bool> - Set adjacency size 875 . -dm_plex_use_ceed <bool> - Use LibCEED as the FEM backend 876 . -dm_plex_check_symmetry - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()` 877 . -dm_plex_check_skeleton - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()` 878 . -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()` 879 . -dm_plex_check_geometry - Check that cells have positive volume - `DMPlexCheckGeometry()` 880 . -dm_plex_check_pointsf - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()` 881 . -dm_plex_check_interface_cones - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()` 882 - -dm_plex_check_all - Perform all the checks above 883 884 Level: intermediate 885 886 Note: 887 For some `DMType` such as `DMDA` this cannot be called after `DMSetUp()` has been called. 888 889 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, 890 `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`, 891 `DMSetOptionsPrefix()`, `DMType`, `DMPLEX`, `DMDA`, `DMSetUp()` 892 @*/ 893 PetscErrorCode DMSetFromOptions(DM dm) 894 { 895 char typeName[256]; 896 PetscBool flg; 897 898 PetscFunctionBegin; 899 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 900 dm->setfromoptionscalled = PETSC_TRUE; 901 if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf)); 902 if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF)); 903 if (dm->coordinates[0].dm) PetscCall(DMSetFromOptions(dm->coordinates[0].dm)); 904 PetscObjectOptionsBegin((PetscObject)dm); 905 PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL)); 906 PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg)); 907 if (flg) PetscCall(DMSetVecType(dm, typeName)); 908 PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg)); 909 if (flg) PetscCall(DMSetMatType(dm, typeName)); 910 PetscCall(PetscOptionsEnum("-dm_blocking_type", "Topological point or field node blocking", "DMSetBlockingType", DMBlockingTypes, (PetscEnum)dm->blocking_type, (PetscEnum *)&dm->blocking_type, NULL)); 911 PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL)); 912 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)); 913 PetscCall(PetscOptionsBool("-dm_ignore_perm_output", "Ignore the local section permutation on output", "DMGetOutputDM", dm->ignorePermOutput, &dm->ignorePermOutput, NULL)); 914 PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject); 915 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 916 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject)); 917 PetscOptionsEnd(); 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 /*@ 922 DMViewFromOptions - View a `DM` in a particular way based on a request in the options database 923 924 Collective 925 926 Input Parameters: 927 + dm - the `DM` object 928 . obj - optional object that provides the prefix for the options database (if `NULL` then the prefix in obj is used) 929 - name - option string that is used to activate viewing 930 931 Level: intermediate 932 933 Note: 934 See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed 935 936 .seealso: [](ch_dmbase), `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()` 937 @*/ 938 PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[]) 939 { 940 PetscFunctionBegin; 941 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 942 PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name)); 943 PetscFunctionReturn(PETSC_SUCCESS); 944 } 945 946 /*@ 947 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 948 save the `DM` in a binary file to be loaded later or create a visualization of the `DM` 949 950 Collective 951 952 Input Parameters: 953 + dm - the `DM` object to view 954 - v - the viewer 955 956 Level: beginner 957 958 Notes: 959 960 `PetscViewer` = `PETSCVIEWERHDF5` i.e. HDF5 format can be used with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` to save multiple `DMPLEX` 961 meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()` 962 before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object. 963 964 `PetscViewer` = `PETSCVIEWEREXODUSII` i.e. ExodusII format assumes that element blocks (mapped to "Cell sets" labels) 965 consists of sequentially numbered cells. 966 967 If `dm` has been distributed, only the part of the `DM` on MPI rank 0 (including "ghost" cells and vertices) will be written. 968 969 Only TRI, TET, QUAD, and HEX cells are supported. 970 971 `DMPLEX` only represents geometry while most post-processing software expect that a mesh also provides information on the discretization space. This function assumes that the file represents Lagrange finite elements of order 1 or 2. 972 The order of the mesh shall be set using `PetscViewerExodusIISetOrder()` 973 974 Variable names can be set and queried using `PetscViewerExodusII[Set/Get][Nodal/Zonal]VariableNames[s]`. 975 976 .seealso: [](ch_dmbase), `DM`, `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat()`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()` 977 @*/ 978 PetscErrorCode DMView(DM dm, PetscViewer v) 979 { 980 PetscBool isbinary; 981 PetscMPIInt size; 982 PetscViewerFormat format; 983 984 PetscFunctionBegin; 985 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 986 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v)); 987 PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2); 988 /* Ideally, we would like to have this test on. 989 However, it currently breaks socket viz via GLVis. 990 During DMView(parallel_mesh,glvis_viewer), each 991 process opens a sequential ASCII socket to visualize 992 the local mesh, and PetscObjectView(dm,local_socket) 993 is internally called inside VecView_GLVis, incurring 994 in an error here */ 995 /* PetscCheckSameComm(dm,1,v,2); */ 996 PetscCall(PetscViewerCheckWritable(v)); 997 998 PetscCall(PetscViewerGetFormat(v, &format)); 999 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 1000 if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS); 1001 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v)); 1002 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary)); 1003 if (isbinary) { 1004 PetscInt classid = DM_FILE_CLASSID; 1005 char type[256]; 1006 1007 PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT)); 1008 PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, sizeof(type))); 1009 PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR)); 1010 } 1011 PetscTryTypeMethod(dm, view, v); 1012 PetscFunctionReturn(PETSC_SUCCESS); 1013 } 1014 1015 /*@ 1016 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, 1017 that is it has no ghost locations. 1018 1019 Collective 1020 1021 Input Parameter: 1022 . dm - the `DM` object 1023 1024 Output Parameter: 1025 . vec - the global vector 1026 1027 Level: beginner 1028 1029 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, 1030 `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()` 1031 @*/ 1032 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec) 1033 { 1034 PetscFunctionBegin; 1035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1036 PetscAssertPointer(vec, 2); 1037 PetscUseTypeMethod(dm, createglobalvector, vec); 1038 if (PetscDefined(USE_DEBUG)) { 1039 DM vdm; 1040 1041 PetscCall(VecGetDM(*vec, &vdm)); 1042 PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name); 1043 } 1044 PetscFunctionReturn(PETSC_SUCCESS); 1045 } 1046 1047 /*@ 1048 DMCreateLocalVector - Creates a local vector from a `DM` object. 1049 1050 Not Collective 1051 1052 Input Parameter: 1053 . dm - the `DM` object 1054 1055 Output Parameter: 1056 . vec - the local vector 1057 1058 Level: beginner 1059 1060 Note: 1061 A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations. 1062 1063 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()` 1064 `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()` 1065 @*/ 1066 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec) 1067 { 1068 PetscFunctionBegin; 1069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1070 PetscAssertPointer(vec, 2); 1071 PetscUseTypeMethod(dm, createlocalvector, vec); 1072 if (PetscDefined(USE_DEBUG)) { 1073 DM vdm; 1074 1075 PetscCall(VecGetDM(*vec, &vdm)); 1076 PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name); 1077 } 1078 PetscFunctionReturn(PETSC_SUCCESS); 1079 } 1080 1081 /*@ 1082 DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`. 1083 1084 Collective 1085 1086 Input Parameter: 1087 . dm - the `DM` that provides the mapping 1088 1089 Output Parameter: 1090 . ltog - the mapping 1091 1092 Level: advanced 1093 1094 Notes: 1095 The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()` 1096 1097 Vectors obtained with `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do 1098 need to use this function with those objects. 1099 1100 This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`. 1101 1102 .seealso: [](ch_dmbase), `DM`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`, 1103 `DMCreateMatrix()` 1104 @*/ 1105 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog) 1106 { 1107 PetscInt bs = -1, bsLocal[2], bsMinMax[2]; 1108 1109 PetscFunctionBegin; 1110 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1111 PetscAssertPointer(ltog, 2); 1112 if (!dm->ltogmap) { 1113 PetscSection section, sectionGlobal; 1114 1115 PetscCall(DMGetLocalSection(dm, §ion)); 1116 if (section) { 1117 const PetscInt *cdofs; 1118 PetscInt *ltog; 1119 PetscInt pStart, pEnd, n, p, k, l; 1120 1121 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 1122 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 1123 PetscCall(PetscSectionGetStorageSize(section, &n)); 1124 PetscCall(PetscMalloc1(n, <og)); /* We want the local+overlap size */ 1125 for (p = pStart, l = 0; p < pEnd; ++p) { 1126 PetscInt bdof, cdof, dof, off, c, cind; 1127 1128 /* Should probably use constrained dofs */ 1129 PetscCall(PetscSectionGetDof(section, p, &dof)); 1130 PetscCall(PetscSectionGetConstraintDof(section, p, &cdof)); 1131 PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs)); 1132 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off)); 1133 /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */ 1134 bdof = cdof && (dof - cdof) ? 1 : dof; 1135 if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof); 1136 1137 for (c = 0, cind = 0; c < dof; ++c, ++l) { 1138 if (cind < cdof && c == cdofs[cind]) { 1139 ltog[l] = off < 0 ? off - c : -(off + c + 1); 1140 cind++; 1141 } else { 1142 ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind; 1143 } 1144 } 1145 } 1146 /* Must have same blocksize on all procs (some might have no points) */ 1147 bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs; 1148 bsLocal[1] = bs; 1149 PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax)); 1150 if (bsMinMax[0] != bsMinMax[1]) { 1151 bs = 1; 1152 } else { 1153 bs = bsMinMax[0]; 1154 } 1155 bs = bs < 0 ? 1 : bs; 1156 /* Must reduce indices by blocksize */ 1157 if (bs > 1) { 1158 for (l = 0, k = 0; l < n; l += bs, ++k) { 1159 // Integer division of negative values truncates toward zero(!), not toward negative infinity 1160 ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1); 1161 } 1162 n /= bs; 1163 } 1164 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap)); 1165 } else PetscUseTypeMethod(dm, getlocaltoglobalmapping); 1166 } 1167 *ltog = dm->ltogmap; 1168 PetscFunctionReturn(PETSC_SUCCESS); 1169 } 1170 1171 /*@ 1172 DMGetBlockSize - Gets the inherent block size associated with a `DM` 1173 1174 Not Collective 1175 1176 Input Parameter: 1177 . dm - the `DM` with block structure 1178 1179 Output Parameter: 1180 . bs - the block size, 1 implies no exploitable block structure 1181 1182 Level: intermediate 1183 1184 Notes: 1185 This might be the number of degrees of freedom at each grid point for a structured grid. 1186 1187 Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but 1188 rather different locations in the vectors may have a different block size. 1189 1190 .seealso: [](ch_dmbase), `DM`, `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()` 1191 @*/ 1192 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs) 1193 { 1194 PetscFunctionBegin; 1195 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1196 PetscAssertPointer(bs, 2); 1197 PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet"); 1198 *bs = dm->bs; 1199 PetscFunctionReturn(PETSC_SUCCESS); 1200 } 1201 1202 /*@ 1203 DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by 1204 `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`. 1205 1206 Collective 1207 1208 Input Parameters: 1209 + dmc - the `DM` object 1210 - dmf - the second, finer `DM` object 1211 1212 Output Parameters: 1213 + mat - the interpolation 1214 - vec - the scaling (optional, pass `NULL` if not needed), see `DMCreateInterpolationScale()` 1215 1216 Level: developer 1217 1218 Notes: 1219 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by 1220 DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation. 1221 1222 For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate 1223 vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic. 1224 1225 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()` 1226 @*/ 1227 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec) 1228 { 1229 PetscFunctionBegin; 1230 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1231 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1232 PetscAssertPointer(mat, 3); 1233 PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0)); 1234 PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec); 1235 PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0)); 1236 PetscFunctionReturn(PETSC_SUCCESS); 1237 } 1238 1239 /*@ 1240 DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is 1241 the transpose of the interpolation between the `DM`. 1242 1243 Input Parameters: 1244 + dac - `DM` that defines a coarse mesh 1245 . daf - `DM` that defines a fine mesh 1246 - mat - the restriction (or interpolation operator) from fine to coarse 1247 1248 Output Parameter: 1249 . scale - the scaled vector 1250 1251 Level: advanced 1252 1253 Note: 1254 xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual) 1255 restriction. In other words xcoarse is the coarse representation of xfine. 1256 1257 Developer Note: 1258 If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()` 1259 on the restriction/interpolation operator to set the bindingpropagates flag to true. 1260 1261 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()` 1262 @*/ 1263 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale) 1264 { 1265 Vec fine; 1266 PetscScalar one = 1.0; 1267 #if defined(PETSC_HAVE_CUDA) 1268 PetscBool bindingpropagates, isbound; 1269 #endif 1270 1271 PetscFunctionBegin; 1272 PetscCall(DMCreateGlobalVector(daf, &fine)); 1273 PetscCall(DMCreateGlobalVector(dac, scale)); 1274 PetscCall(VecSet(fine, one)); 1275 #if defined(PETSC_HAVE_CUDA) 1276 /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well. 1277 * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL, 1278 * we'll need to do it for that case, too.*/ 1279 PetscCall(VecGetBindingPropagates(fine, &bindingpropagates)); 1280 if (bindingpropagates) { 1281 PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE)); 1282 PetscCall(VecBoundToCPU(fine, &isbound)); 1283 PetscCall(MatBindToCPU(mat, isbound)); 1284 } 1285 #endif 1286 PetscCall(MatRestrict(mat, fine, *scale)); 1287 PetscCall(VecDestroy(&fine)); 1288 PetscCall(VecReciprocal(*scale)); 1289 PetscFunctionReturn(PETSC_SUCCESS); 1290 } 1291 1292 /*@ 1293 DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by 1294 `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`. 1295 1296 Collective 1297 1298 Input Parameters: 1299 + dmc - the `DM` object 1300 - dmf - the second, finer `DM` object 1301 1302 Output Parameter: 1303 . mat - the restriction 1304 1305 Level: developer 1306 1307 Note: 1308 This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that 1309 matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object. 1310 1311 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()` 1312 @*/ 1313 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat) 1314 { 1315 PetscFunctionBegin; 1316 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1317 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1318 PetscAssertPointer(mat, 3); 1319 PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0)); 1320 PetscUseTypeMethod(dmc, createrestriction, dmf, mat); 1321 PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0)); 1322 PetscFunctionReturn(PETSC_SUCCESS); 1323 } 1324 1325 /*@ 1326 DMCreateInjection - Gets injection matrix between two `DM` objects. 1327 1328 Collective 1329 1330 Input Parameters: 1331 + dac - the `DM` object 1332 - daf - the second, finer `DM` object 1333 1334 Output Parameter: 1335 . mat - the injection 1336 1337 Level: developer 1338 1339 Notes: 1340 This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the 1341 fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting 1342 the values on the coarse grid points. This compares to the operator obtained by 1343 `DMCreateRestriction()` or the transpose of the operator obtained by 1344 `DMCreateInterpolation()` that uses a "local weighted average" of the values around the 1345 coarse grid point as the coarse grid value. 1346 1347 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by 1348 `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection. 1349 1350 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`, 1351 `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()` 1352 @*/ 1353 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat) 1354 { 1355 PetscFunctionBegin; 1356 PetscValidHeaderSpecific(dac, DM_CLASSID, 1); 1357 PetscValidHeaderSpecific(daf, DM_CLASSID, 2); 1358 PetscAssertPointer(mat, 3); 1359 PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0)); 1360 PetscUseTypeMethod(dac, createinjection, daf, mat); 1361 PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0)); 1362 PetscFunctionReturn(PETSC_SUCCESS); 1363 } 1364 1365 /*@ 1366 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 1367 a Galerkin finite element model on the `DM` 1368 1369 Collective 1370 1371 Input Parameters: 1372 + dmc - the target `DM` object 1373 - dmf - the source `DM` object, can be `NULL` 1374 1375 Output Parameter: 1376 . mat - the mass matrix 1377 1378 Level: developer 1379 1380 Notes: 1381 For `DMPLEX` the finite element model for the `DM` must have been already provided. 1382 1383 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()` 1384 1385 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()` 1386 @*/ 1387 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat) 1388 { 1389 PetscFunctionBegin; 1390 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1391 if (!dmf) dmf = dmc; 1392 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1393 PetscAssertPointer(mat, 3); 1394 PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, dmc, dmf, 0, 0)); 1395 PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat); 1396 PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, dmc, dmf, 0, 0)); 1397 PetscFunctionReturn(PETSC_SUCCESS); 1398 } 1399 1400 /*@ 1401 DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM` 1402 1403 Collective 1404 1405 Input Parameter: 1406 . dm - the `DM` object 1407 1408 Output Parameters: 1409 + llm - the local lumped mass matrix, which is a diagonal matrix, represented as a vector 1410 - lm - the global lumped mass matrix, which is a diagonal matrix, represented as a vector 1411 1412 Level: developer 1413 1414 Note: 1415 See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix. 1416 1417 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()` 1418 @*/ 1419 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *llm, Vec *lm) 1420 { 1421 PetscFunctionBegin; 1422 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1423 if (llm) PetscAssertPointer(llm, 2); 1424 if (lm) PetscAssertPointer(lm, 3); 1425 if (llm || lm) PetscUseTypeMethod(dm, createmassmatrixlumped, llm, lm); 1426 PetscFunctionReturn(PETSC_SUCCESS); 1427 } 1428 1429 /*@ 1430 DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization 1431 of a PDE on the `DM`. 1432 1433 Collective 1434 1435 Input Parameters: 1436 + dm - the `DM` object 1437 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL` 1438 1439 Output Parameter: 1440 . coloring - the coloring 1441 1442 Level: developer 1443 1444 Notes: 1445 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 1446 matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors). 1447 1448 This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()` 1449 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, 1450 otherwise an error will be generated. 1451 1452 .seealso: [](ch_dmbase), `DM`, `ISColoring`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()` 1453 @*/ 1454 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring) 1455 { 1456 PetscFunctionBegin; 1457 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1458 PetscAssertPointer(coloring, 3); 1459 PetscUseTypeMethod(dm, getcoloring, ctype, coloring); 1460 PetscFunctionReturn(PETSC_SUCCESS); 1461 } 1462 1463 /*@ 1464 DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator. 1465 1466 Collective 1467 1468 Input Parameter: 1469 . dm - the `DM` object 1470 1471 Output Parameter: 1472 . mat - the empty Jacobian 1473 1474 Options Database Key: 1475 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros 1476 1477 Level: beginner 1478 1479 Notes: 1480 This properly preallocates the number of nonzeros in the sparse matrix so you 1481 do not need to do it yourself. 1482 1483 By default it also sets the nonzero structure and puts in the zero entries. To prevent setting 1484 the nonzero pattern call `DMSetMatrixPreallocateOnly()` 1485 1486 For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used 1487 internally by PETSc. 1488 1489 For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because 1490 `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute 1491 1492 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()` 1493 @*/ 1494 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat) 1495 { 1496 PetscFunctionBegin; 1497 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1498 PetscAssertPointer(mat, 2); 1499 PetscCall(MatInitializePackage()); 1500 PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0)); 1501 PetscUseTypeMethod(dm, creatematrix, mat); 1502 if (PetscDefined(USE_DEBUG)) { 1503 DM mdm; 1504 1505 PetscCall(MatGetDM(*mat, &mdm)); 1506 PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name); 1507 } 1508 /* Handle nullspace and near nullspace */ 1509 if (dm->Nf) { 1510 MatNullSpace nullSpace; 1511 PetscInt Nf, f; 1512 1513 PetscCall(DMGetNumFields(dm, &Nf)); 1514 for (f = 0; f < Nf; ++f) { 1515 if (dm->nullspaceConstructors[f]) { 1516 PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace)); 1517 PetscCall(MatSetNullSpace(*mat, nullSpace)); 1518 PetscCall(MatNullSpaceDestroy(&nullSpace)); 1519 break; 1520 } 1521 } 1522 for (f = 0; f < Nf; ++f) { 1523 if (dm->nearnullspaceConstructors[f]) { 1524 PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace)); 1525 PetscCall(MatSetNearNullSpace(*mat, nullSpace)); 1526 PetscCall(MatNullSpaceDestroy(&nullSpace)); 1527 } 1528 } 1529 } 1530 PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0)); 1531 PetscFunctionReturn(PETSC_SUCCESS); 1532 } 1533 1534 /*@ 1535 DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and 1536 `ISLocalToGlobalMapping` will be properly set, but the data structures to store values in the 1537 matrices will not be preallocated. 1538 1539 Logically Collective 1540 1541 Input Parameters: 1542 + dm - the `DM` 1543 - skip - `PETSC_TRUE` to skip preallocation 1544 1545 Level: developer 1546 1547 Note: 1548 This is most useful to reduce initialization costs when `MatSetPreallocationCOO()` and 1549 `MatSetValuesCOO()` will be used. 1550 1551 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()` 1552 @*/ 1553 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip) 1554 { 1555 PetscFunctionBegin; 1556 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1557 dm->prealloc_skip = skip; 1558 PetscFunctionReturn(PETSC_SUCCESS); 1559 } 1560 1561 /*@ 1562 DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly 1563 preallocated but the nonzero structure and zero values will not be set. 1564 1565 Logically Collective 1566 1567 Input Parameters: 1568 + dm - the `DM` 1569 - only - `PETSC_TRUE` if only want preallocation 1570 1571 Options Database Key: 1572 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros 1573 1574 Level: developer 1575 1576 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()` 1577 @*/ 1578 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only) 1579 { 1580 PetscFunctionBegin; 1581 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1582 dm->prealloc_only = only; 1583 PetscFunctionReturn(PETSC_SUCCESS); 1584 } 1585 1586 /*@ 1587 DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix structure will be created 1588 but the array for numerical values will not be allocated. 1589 1590 Logically Collective 1591 1592 Input Parameters: 1593 + dm - the `DM` 1594 - only - `PETSC_TRUE` if you only want matrix structure 1595 1596 Level: developer 1597 1598 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()` 1599 @*/ 1600 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only) 1601 { 1602 PetscFunctionBegin; 1603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1604 dm->structure_only = only; 1605 PetscFunctionReturn(PETSC_SUCCESS); 1606 } 1607 1608 /*@ 1609 DMSetBlockingType - set the blocking granularity to be used for variable block size `DMCreateMatrix()` is called 1610 1611 Logically Collective 1612 1613 Input Parameters: 1614 + dm - the `DM` 1615 - btype - block by topological point or field node 1616 1617 Options Database Key: 1618 . -dm_blocking_type [topological_point, field_node] - use topological point blocking or field node blocking 1619 1620 Level: advanced 1621 1622 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()` 1623 @*/ 1624 PetscErrorCode DMSetBlockingType(DM dm, DMBlockingType btype) 1625 { 1626 PetscFunctionBegin; 1627 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1628 dm->blocking_type = btype; 1629 PetscFunctionReturn(PETSC_SUCCESS); 1630 } 1631 1632 /*@ 1633 DMGetBlockingType - get the blocking granularity to be used for variable block size `DMCreateMatrix()` is called 1634 1635 Not Collective 1636 1637 Input Parameter: 1638 . dm - the `DM` 1639 1640 Output Parameter: 1641 . btype - block by topological point or field node 1642 1643 Level: advanced 1644 1645 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()` 1646 @*/ 1647 PetscErrorCode DMGetBlockingType(DM dm, DMBlockingType *btype) 1648 { 1649 PetscFunctionBegin; 1650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1651 PetscAssertPointer(btype, 2); 1652 *btype = dm->blocking_type; 1653 PetscFunctionReturn(PETSC_SUCCESS); 1654 } 1655 1656 /*@C 1657 DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()` 1658 1659 Not Collective 1660 1661 Input Parameters: 1662 + dm - the `DM` object 1663 . count - The minimum size 1664 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, or `MPIU_INT`) 1665 1666 Output Parameter: 1667 . mem - the work array 1668 1669 Level: developer 1670 1671 Notes: 1672 A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()` 1673 1674 The array may contain nonzero values 1675 1676 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()` 1677 @*/ 1678 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem) 1679 { 1680 DMWorkLink link; 1681 PetscMPIInt dsize; 1682 1683 PetscFunctionBegin; 1684 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1685 PetscAssertPointer(mem, 4); 1686 if (!count) { 1687 *(void **)mem = NULL; 1688 PetscFunctionReturn(PETSC_SUCCESS); 1689 } 1690 if (dm->workin) { 1691 link = dm->workin; 1692 dm->workin = dm->workin->next; 1693 } else { 1694 PetscCall(PetscNew(&link)); 1695 } 1696 /* Avoid MPI_Type_size for most used datatypes 1697 Get size directly */ 1698 if (dtype == MPIU_INT) dsize = sizeof(PetscInt); 1699 else if (dtype == MPIU_REAL) dsize = sizeof(PetscReal); 1700 #if defined(PETSC_USE_64BIT_INDICES) 1701 else if (dtype == MPI_INT) dsize = sizeof(int); 1702 #endif 1703 #if defined(PETSC_USE_COMPLEX) 1704 else if (dtype == MPIU_SCALAR) dsize = sizeof(PetscScalar); 1705 #endif 1706 else PetscCallMPI(MPI_Type_size(dtype, &dsize)); 1707 1708 if (((size_t)dsize * count) > link->bytes) { 1709 PetscCall(PetscFree(link->mem)); 1710 PetscCall(PetscMalloc(dsize * count, &link->mem)); 1711 link->bytes = dsize * count; 1712 } 1713 link->next = dm->workout; 1714 dm->workout = link; 1715 #if defined(__MEMCHECK_H) && (defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) || defined(PLAT_amd64_darwin)) 1716 VALGRIND_MAKE_MEM_NOACCESS((char *)link->mem + (size_t)dsize * count, link->bytes - (size_t)dsize * count); 1717 VALGRIND_MAKE_MEM_UNDEFINED(link->mem, (size_t)dsize * count); 1718 #endif 1719 *(void **)mem = link->mem; 1720 PetscFunctionReturn(PETSC_SUCCESS); 1721 } 1722 1723 /*@C 1724 DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()` 1725 1726 Not Collective 1727 1728 Input Parameters: 1729 + dm - the `DM` object 1730 . count - The minimum size 1731 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, `MPIU_INT` 1732 1733 Output Parameter: 1734 . mem - the work array 1735 1736 Level: developer 1737 1738 Developer Note: 1739 count and dtype are ignored, they are only needed for `DMGetWorkArray()` 1740 1741 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()` 1742 @*/ 1743 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem) 1744 { 1745 DMWorkLink *p, link; 1746 1747 PetscFunctionBegin; 1748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1749 PetscAssertPointer(mem, 4); 1750 (void)count; 1751 (void)dtype; 1752 if (!*(void **)mem) PetscFunctionReturn(PETSC_SUCCESS); 1753 for (p = &dm->workout; (link = *p); p = &link->next) { 1754 if (link->mem == *(void **)mem) { 1755 *p = link->next; 1756 link->next = dm->workin; 1757 dm->workin = link; 1758 *(void **)mem = NULL; 1759 PetscFunctionReturn(PETSC_SUCCESS); 1760 } 1761 } 1762 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out"); 1763 } 1764 1765 /*@C 1766 DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces 1767 are joined or split, such as in `DMCreateSubDM()` 1768 1769 Logically Collective; No Fortran Support 1770 1771 Input Parameters: 1772 + dm - The `DM` 1773 . field - The field number for the nullspace 1774 - nullsp - A callback to create the nullspace 1775 1776 Calling sequence of `nullsp`: 1777 + dm - The present `DM` 1778 . origField - The field number given above, in the original `DM` 1779 . field - The field number in dm 1780 - nullSpace - The nullspace for the given field 1781 1782 Level: intermediate 1783 1784 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 1785 @*/ 1786 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)) 1787 { 1788 PetscFunctionBegin; 1789 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1790 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1791 dm->nullspaceConstructors[field] = nullsp; 1792 PetscFunctionReturn(PETSC_SUCCESS); 1793 } 1794 1795 /*@C 1796 DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()` 1797 1798 Not Collective; No Fortran Support 1799 1800 Input Parameters: 1801 + dm - The `DM` 1802 - field - The field number for the nullspace 1803 1804 Output Parameter: 1805 . nullsp - A callback to create the nullspace 1806 1807 Calling sequence of `nullsp`: 1808 + dm - The present DM 1809 . origField - The field number given above, in the original DM 1810 . field - The field number in dm 1811 - nullSpace - The nullspace for the given field 1812 1813 Level: intermediate 1814 1815 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 1816 @*/ 1817 PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)) 1818 { 1819 PetscFunctionBegin; 1820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1821 PetscAssertPointer(nullsp, 3); 1822 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1823 *nullsp = dm->nullspaceConstructors[field]; 1824 PetscFunctionReturn(PETSC_SUCCESS); 1825 } 1826 1827 /*@C 1828 DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()` 1829 1830 Logically Collective; No Fortran Support 1831 1832 Input Parameters: 1833 + dm - The `DM` 1834 . field - The field number for the nullspace 1835 - nullsp - A callback to create the near-nullspace 1836 1837 Calling sequence of `nullsp`: 1838 + dm - The present `DM` 1839 . origField - The field number given above, in the original `DM` 1840 . field - The field number in dm 1841 - nullSpace - The nullspace for the given field 1842 1843 Level: intermediate 1844 1845 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`, 1846 `MatNullSpace` 1847 @*/ 1848 PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)) 1849 { 1850 PetscFunctionBegin; 1851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1852 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1853 dm->nearnullspaceConstructors[field] = nullsp; 1854 PetscFunctionReturn(PETSC_SUCCESS); 1855 } 1856 1857 /*@C 1858 DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()` 1859 1860 Not Collective; No Fortran Support 1861 1862 Input Parameters: 1863 + dm - The `DM` 1864 - field - The field number for the nullspace 1865 1866 Output Parameter: 1867 . nullsp - A callback to create the near-nullspace 1868 1869 Calling sequence of `nullsp`: 1870 + dm - The present `DM` 1871 . origField - The field number given above, in the original `DM` 1872 . field - The field number in dm 1873 - nullSpace - The nullspace for the given field 1874 1875 Level: intermediate 1876 1877 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, 1878 `MatNullSpace`, `DMCreateSuperDM()` 1879 @*/ 1880 PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace)) 1881 { 1882 PetscFunctionBegin; 1883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1884 PetscAssertPointer(nullsp, 3); 1885 PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field); 1886 *nullsp = dm->nearnullspaceConstructors[field]; 1887 PetscFunctionReturn(PETSC_SUCCESS); 1888 } 1889 1890 /*@C 1891 DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()` 1892 1893 Not Collective; No Fortran Support 1894 1895 Input Parameter: 1896 . dm - the `DM` object 1897 1898 Output Parameters: 1899 + numFields - The number of fields (or `NULL` if not requested) 1900 . fieldNames - The number of each field (or `NULL` if not requested) 1901 - fields - The global indices for each field (or `NULL` if not requested) 1902 1903 Level: intermediate 1904 1905 Note: 1906 The user is responsible for freeing all requested arrays. In particular, every entry of `fieldNames` should be freed with 1907 `PetscFree()`, every entry of `fields` should be destroyed with `ISDestroy()`, and both arrays should be freed with 1908 `PetscFree()`. 1909 1910 Developer Note: 1911 It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should 1912 likely be removed. 1913 1914 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, 1915 `DMCreateFieldDecomposition()` 1916 @*/ 1917 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields) 1918 { 1919 PetscSection section, sectionGlobal; 1920 1921 PetscFunctionBegin; 1922 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1923 if (numFields) { 1924 PetscAssertPointer(numFields, 2); 1925 *numFields = 0; 1926 } 1927 if (fieldNames) { 1928 PetscAssertPointer(fieldNames, 3); 1929 *fieldNames = NULL; 1930 } 1931 if (fields) { 1932 PetscAssertPointer(fields, 4); 1933 *fields = NULL; 1934 } 1935 PetscCall(DMGetLocalSection(dm, §ion)); 1936 if (section) { 1937 PetscInt *fieldSizes, *fieldNc, **fieldIndices; 1938 PetscInt nF, f, pStart, pEnd, p; 1939 1940 PetscCall(DMGetGlobalSection(dm, §ionGlobal)); 1941 PetscCall(PetscSectionGetNumFields(section, &nF)); 1942 PetscCall(PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices)); 1943 PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd)); 1944 for (f = 0; f < nF; ++f) { 1945 fieldSizes[f] = 0; 1946 PetscCall(PetscSectionGetFieldComponents(section, f, &fieldNc[f])); 1947 } 1948 for (p = pStart; p < pEnd; ++p) { 1949 PetscInt gdof; 1950 1951 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 1952 if (gdof > 0) { 1953 for (f = 0; f < nF; ++f) { 1954 PetscInt fdof, fcdof, fpdof; 1955 1956 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 1957 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 1958 fpdof = fdof - fcdof; 1959 if (fpdof && fpdof != fieldNc[f]) { 1960 /* Layout does not admit a pointwise block size */ 1961 fieldNc[f] = 1; 1962 } 1963 fieldSizes[f] += fpdof; 1964 } 1965 } 1966 } 1967 for (f = 0; f < nF; ++f) { 1968 PetscCall(PetscMalloc1(fieldSizes[f], &fieldIndices[f])); 1969 fieldSizes[f] = 0; 1970 } 1971 for (p = pStart; p < pEnd; ++p) { 1972 PetscInt gdof, goff; 1973 1974 PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof)); 1975 if (gdof > 0) { 1976 PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff)); 1977 for (f = 0; f < nF; ++f) { 1978 PetscInt fdof, fcdof, fc; 1979 1980 PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof)); 1981 PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 1982 for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++; 1983 } 1984 } 1985 } 1986 if (numFields) *numFields = nF; 1987 if (fieldNames) { 1988 PetscCall(PetscMalloc1(nF, fieldNames)); 1989 for (f = 0; f < nF; ++f) { 1990 const char *fieldName; 1991 1992 PetscCall(PetscSectionGetFieldName(section, f, &fieldName)); 1993 PetscCall(PetscStrallocpy(fieldName, (char **)&(*fieldNames)[f])); 1994 } 1995 } 1996 if (fields) { 1997 PetscCall(PetscMalloc1(nF, fields)); 1998 for (f = 0; f < nF; ++f) { 1999 PetscInt bs, in[2], out[2]; 2000 2001 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f])); 2002 in[0] = -fieldNc[f]; 2003 in[1] = fieldNc[f]; 2004 PetscCallMPI(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 2005 bs = (-out[0] == out[1]) ? out[1] : 1; 2006 PetscCall(ISSetBlockSize((*fields)[f], bs)); 2007 } 2008 } 2009 PetscCall(PetscFree3(fieldSizes, fieldNc, fieldIndices)); 2010 } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields); 2011 PetscFunctionReturn(PETSC_SUCCESS); 2012 } 2013 2014 /*@C 2015 DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems 2016 corresponding to different fields. 2017 2018 Not Collective; No Fortran Support 2019 2020 Input Parameter: 2021 . dm - the `DM` object 2022 2023 Output Parameters: 2024 + len - The number of fields (or `NULL` if not requested) 2025 . namelist - The name for each field (or `NULL` if not requested) 2026 . islist - The global indices for each field (or `NULL` if not requested) 2027 - dmlist - The `DM`s for each field subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined) 2028 2029 Level: intermediate 2030 2031 Notes: 2032 Each `IS` contains the global indices of the dofs of the corresponding field, defined by 2033 `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem. 2034 2035 The same as `DMCreateFieldIS()` but also returns a `DM` for each field. 2036 2037 The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with 2038 `PetscFree()`, every entry of `islist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`, 2039 and all of the arrays should be freed with `PetscFree()`. 2040 2041 Developer Notes: 2042 It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing. 2043 2044 Unlike `DMRefine()`, `DMCoarsen()`, and `DMCreateDomainDecomposition()` this provides no mechanism to provide hooks that are called after the 2045 decomposition is computed. 2046 2047 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()` 2048 @*/ 2049 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist) 2050 { 2051 PetscFunctionBegin; 2052 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2053 if (len) { 2054 PetscAssertPointer(len, 2); 2055 *len = 0; 2056 } 2057 if (namelist) { 2058 PetscAssertPointer(namelist, 3); 2059 *namelist = NULL; 2060 } 2061 if (islist) { 2062 PetscAssertPointer(islist, 4); 2063 *islist = NULL; 2064 } 2065 if (dmlist) { 2066 PetscAssertPointer(dmlist, 5); 2067 *dmlist = NULL; 2068 } 2069 /* 2070 Is it a good idea to apply the following check across all impls? 2071 Perhaps some impls can have a well-defined decomposition before DMSetUp? 2072 This, however, follows the general principle that accessors are not well-behaved until the object is set up. 2073 */ 2074 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp"); 2075 if (!dm->ops->createfielddecomposition) { 2076 PetscSection section; 2077 PetscInt numFields, f; 2078 2079 PetscCall(DMGetLocalSection(dm, §ion)); 2080 if (section) PetscCall(PetscSectionGetNumFields(section, &numFields)); 2081 if (section && numFields && dm->ops->createsubdm) { 2082 if (len) *len = numFields; 2083 if (namelist) PetscCall(PetscMalloc1(numFields, namelist)); 2084 if (islist) PetscCall(PetscMalloc1(numFields, islist)); 2085 if (dmlist) PetscCall(PetscMalloc1(numFields, dmlist)); 2086 for (f = 0; f < numFields; ++f) { 2087 const char *fieldName; 2088 2089 PetscCall(DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL)); 2090 if (namelist) { 2091 PetscCall(PetscSectionGetFieldName(section, f, &fieldName)); 2092 PetscCall(PetscStrallocpy(fieldName, (char **)&(*namelist)[f])); 2093 } 2094 } 2095 } else { 2096 PetscCall(DMCreateFieldIS(dm, len, namelist, islist)); 2097 /* By default there are no DMs associated with subproblems. */ 2098 if (dmlist) *dmlist = NULL; 2099 } 2100 } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist); 2101 PetscFunctionReturn(PETSC_SUCCESS); 2102 } 2103 2104 /*@ 2105 DMCreateSubDM - Returns an `IS` and `DM` encapsulating a subproblem defined by the fields passed in. 2106 The fields are defined by `DMCreateFieldIS()`. 2107 2108 Not collective 2109 2110 Input Parameters: 2111 + dm - The `DM` object 2112 . numFields - The number of fields to select 2113 - fields - The field numbers of the selected fields 2114 2115 Output Parameters: 2116 + is - The global indices for all the degrees of freedom in the new sub `DM`, use `NULL` if not needed 2117 - subdm - The `DM` for the subproblem, use `NULL` if not needed 2118 2119 Level: intermediate 2120 2121 Note: 2122 You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed 2123 2124 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()` 2125 @*/ 2126 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm) 2127 { 2128 PetscFunctionBegin; 2129 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2130 PetscAssertPointer(fields, 3); 2131 if (is) PetscAssertPointer(is, 4); 2132 if (subdm) PetscAssertPointer(subdm, 5); 2133 PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm); 2134 PetscFunctionReturn(PETSC_SUCCESS); 2135 } 2136 2137 /*@C 2138 DMCreateSuperDM - Returns an arrays of `IS` and `DM` encapsulating a superproblem defined by multiple `DM`s passed in. 2139 2140 Not collective 2141 2142 Input Parameters: 2143 + dms - The `DM` objects 2144 - n - The number of `DM`s 2145 2146 Output Parameters: 2147 + is - The global indices for each of subproblem within the super `DM`, or NULL 2148 - superdm - The `DM` for the superproblem 2149 2150 Level: intermediate 2151 2152 Note: 2153 You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed 2154 2155 .seealso: [](ch_dmbase), `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`, `DMCreateDomainDecomposition()` 2156 @*/ 2157 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS *is[], DM *superdm) 2158 { 2159 PetscInt i; 2160 2161 PetscFunctionBegin; 2162 PetscAssertPointer(dms, 1); 2163 for (i = 0; i < n; ++i) PetscValidHeaderSpecific(dms[i], DM_CLASSID, 1); 2164 if (is) PetscAssertPointer(is, 3); 2165 PetscAssertPointer(superdm, 4); 2166 PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %" PetscInt_FMT, n); 2167 if (n) { 2168 DM dm = dms[0]; 2169 PetscCheck(dm->ops->createsuperdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No method createsuperdm for DM of type %s", ((PetscObject)dm)->type_name); 2170 PetscCall((*dm->ops->createsuperdm)(dms, n, is, superdm)); 2171 } 2172 PetscFunctionReturn(PETSC_SUCCESS); 2173 } 2174 2175 /*@C 2176 DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a 2177 problem into subproblems corresponding to restrictions to pairs of nested subdomains. 2178 2179 Not Collective 2180 2181 Input Parameter: 2182 . dm - the `DM` object 2183 2184 Output Parameters: 2185 + n - The number of subproblems in the domain decomposition (or `NULL` if not requested) 2186 . namelist - The name for each subdomain (or `NULL` if not requested) 2187 . innerislist - The global indices for each inner subdomain (or `NULL`, if not requested) 2188 . outerislist - The global indices for each outer subdomain (or `NULL`, if not requested) 2189 - dmlist - The `DM`s for each subdomain subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined) 2190 2191 Level: intermediate 2192 2193 Notes: 2194 Each `IS` contains the global indices of the dofs of the corresponding subdomains with in the 2195 dofs of the original `DM`. The inner subdomains conceptually define a nonoverlapping 2196 covering, while outer subdomains can overlap. 2197 2198 The optional list of `DM`s define a `DM` for each subproblem. 2199 2200 The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with 2201 `PetscFree()`, every entry of `innerislist` and `outerislist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`, 2202 and all of the arrays should be freed with `PetscFree()`. 2203 2204 Developer Notes: 2205 The `dmlist` is for the inner subdomains or the outer subdomains or all subdomains? 2206 2207 The names are inconsistent, the hooks use `DMSubDomainHook` which is nothing like `DMCreateDomainDecomposition()` while `DMRefineHook` is used for `DMRefine()`. 2208 2209 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`, 2210 `DMSubDomainHookAdd()`, `DMSubDomainHookRemove()`,`DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()` 2211 @*/ 2212 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist) 2213 { 2214 DMSubDomainHookLink link; 2215 PetscInt i, l; 2216 2217 PetscFunctionBegin; 2218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2219 if (n) { 2220 PetscAssertPointer(n, 2); 2221 *n = 0; 2222 } 2223 if (namelist) { 2224 PetscAssertPointer(namelist, 3); 2225 *namelist = NULL; 2226 } 2227 if (innerislist) { 2228 PetscAssertPointer(innerislist, 4); 2229 *innerislist = NULL; 2230 } 2231 if (outerislist) { 2232 PetscAssertPointer(outerislist, 5); 2233 *outerislist = NULL; 2234 } 2235 if (dmlist) { 2236 PetscAssertPointer(dmlist, 6); 2237 *dmlist = NULL; 2238 } 2239 /* 2240 Is it a good idea to apply the following check across all impls? 2241 Perhaps some impls can have a well-defined decomposition before DMSetUp? 2242 This, however, follows the general principle that accessors are not well-behaved until the object is set up. 2243 */ 2244 PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp"); 2245 if (dm->ops->createdomaindecomposition) { 2246 PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist); 2247 /* copy subdomain hooks and context over to the subdomain DMs */ 2248 if (dmlist && *dmlist) { 2249 for (i = 0; i < l; i++) { 2250 for (link = dm->subdomainhook; link; link = link->next) { 2251 if (link->ddhook) PetscCall((*link->ddhook)(dm, (*dmlist)[i], link->ctx)); 2252 } 2253 if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx; 2254 } 2255 } 2256 if (n) *n = l; 2257 } 2258 PetscFunctionReturn(PETSC_SUCCESS); 2259 } 2260 2261 /*@C 2262 DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector for subdomains created with 2263 `DMCreateDomainDecomposition()` 2264 2265 Not Collective 2266 2267 Input Parameters: 2268 + dm - the `DM` object 2269 . n - the number of subdomains 2270 - subdms - the local subdomains 2271 2272 Output Parameters: 2273 + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain 2274 . oscat - scatter from global vector to overlapping global vector entries on subdomain 2275 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts) 2276 2277 Level: developer 2278 2279 Note: 2280 This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution 2281 of general nonlinear problems with overlapping subdomain methods. While merely having index sets that enable subsets 2282 of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of 2283 solution and residual data. 2284 2285 Developer Note: 2286 Can the subdms input be anything or are they exactly the `DM` obtained from 2287 `DMCreateDomainDecomposition()`? 2288 2289 .seealso: [](ch_dmbase), `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()` 2290 @*/ 2291 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter *iscat[], VecScatter *oscat[], VecScatter *gscat[]) 2292 { 2293 PetscFunctionBegin; 2294 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2295 PetscAssertPointer(subdms, 3); 2296 PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat); 2297 PetscFunctionReturn(PETSC_SUCCESS); 2298 } 2299 2300 /*@ 2301 DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh 2302 2303 Collective 2304 2305 Input Parameters: 2306 + dm - the `DM` object 2307 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`) 2308 2309 Output Parameter: 2310 . dmf - the refined `DM`, or `NULL` 2311 2312 Options Database Key: 2313 . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex 2314 2315 Level: developer 2316 2317 Note: 2318 If no refinement was done, the return value is `NULL` 2319 2320 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`, 2321 `DMRefineHookAdd()`, `DMRefineHookRemove()` 2322 @*/ 2323 PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf) 2324 { 2325 DMRefineHookLink link; 2326 2327 PetscFunctionBegin; 2328 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2329 PetscCall(PetscLogEventBegin(DM_Refine, dm, 0, 0, 0)); 2330 PetscUseTypeMethod(dm, refine, comm, dmf); 2331 if (*dmf) { 2332 (*dmf)->ops->creatematrix = dm->ops->creatematrix; 2333 2334 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf)); 2335 2336 (*dmf)->ctx = dm->ctx; 2337 (*dmf)->leveldown = dm->leveldown; 2338 (*dmf)->levelup = dm->levelup + 1; 2339 2340 PetscCall(DMSetMatType(*dmf, dm->mattype)); 2341 for (link = dm->refinehook; link; link = link->next) { 2342 if (link->refinehook) PetscCall((*link->refinehook)(dm, *dmf, link->ctx)); 2343 } 2344 } 2345 PetscCall(PetscLogEventEnd(DM_Refine, dm, 0, 0, 0)); 2346 PetscFunctionReturn(PETSC_SUCCESS); 2347 } 2348 2349 /*@C 2350 DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid 2351 2352 Logically Collective; No Fortran Support 2353 2354 Input Parameters: 2355 + coarse - `DM` on which to run a hook when interpolating to a finer level 2356 . refinehook - function to run when setting up the finer level 2357 . interphook - function to run to update data on finer levels (once per `SNESSolve()`) 2358 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 2359 2360 Calling sequence of `refinehook`: 2361 + coarse - coarse level `DM` 2362 . fine - fine level `DM` to interpolate problem to 2363 - ctx - optional user-defined function context 2364 2365 Calling sequence of `interphook`: 2366 + coarse - coarse level `DM` 2367 . interp - matrix interpolating a coarse-level solution to the finer grid 2368 . fine - fine level `DM` to update 2369 - ctx - optional user-defined function context 2370 2371 Level: advanced 2372 2373 Notes: 2374 This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be 2375 passed to fine grids while grid sequencing. 2376 2377 The actual interpolation is done when `DMInterpolate()` is called. 2378 2379 If this function is called multiple times, the hooks will be run in the order they are added. 2380 2381 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2382 @*/ 2383 PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM coarse, DM fine, void *ctx), PetscErrorCode (*interphook)(DM coarse, Mat interp, DM fine, void *ctx), void *ctx) 2384 { 2385 DMRefineHookLink link, *p; 2386 2387 PetscFunctionBegin; 2388 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1); 2389 for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */ 2390 if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS); 2391 } 2392 PetscCall(PetscNew(&link)); 2393 link->refinehook = refinehook; 2394 link->interphook = interphook; 2395 link->ctx = ctx; 2396 link->next = NULL; 2397 *p = link; 2398 PetscFunctionReturn(PETSC_SUCCESS); 2399 } 2400 2401 /*@C 2402 DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating 2403 a nonlinear problem to a finer grid 2404 2405 Logically Collective; No Fortran Support 2406 2407 Input Parameters: 2408 + coarse - the `DM` on which to run a hook when restricting to a coarser level 2409 . refinehook - function to run when setting up a finer level 2410 . interphook - function to run to update data on finer levels 2411 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 2412 2413 Level: advanced 2414 2415 Note: 2416 This function does nothing if the hook is not in the list. 2417 2418 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2419 @*/ 2420 PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx) 2421 { 2422 DMRefineHookLink link, *p; 2423 2424 PetscFunctionBegin; 2425 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1); 2426 for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */ 2427 if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) { 2428 link = *p; 2429 *p = link->next; 2430 PetscCall(PetscFree(link)); 2431 break; 2432 } 2433 } 2434 PetscFunctionReturn(PETSC_SUCCESS); 2435 } 2436 2437 /*@ 2438 DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()` 2439 2440 Collective if any hooks are 2441 2442 Input Parameters: 2443 + coarse - coarser `DM` to use as a base 2444 . interp - interpolation matrix, apply using `MatInterpolate()` 2445 - fine - finer `DM` to update 2446 2447 Level: developer 2448 2449 Developer Note: 2450 This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an 2451 an API with consistent terminology. 2452 2453 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `MatInterpolate()` 2454 @*/ 2455 PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine) 2456 { 2457 DMRefineHookLink link; 2458 2459 PetscFunctionBegin; 2460 for (link = fine->refinehook; link; link = link->next) { 2461 if (link->interphook) PetscCall((*link->interphook)(coarse, interp, fine, link->ctx)); 2462 } 2463 PetscFunctionReturn(PETSC_SUCCESS); 2464 } 2465 2466 /*@ 2467 DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh. 2468 2469 Collective 2470 2471 Input Parameters: 2472 + coarse - coarse `DM` 2473 . fine - fine `DM` 2474 . interp - (optional) the matrix computed by `DMCreateInterpolation()`. Implementations may not need this, but if it 2475 is available it can avoid some recomputation. If it is provided, `MatInterpolate()` will be used if 2476 the coarse `DM` does not have a specialized implementation. 2477 - coarseSol - solution on the coarse mesh 2478 2479 Output Parameter: 2480 . fineSol - the interpolation of coarseSol to the fine mesh 2481 2482 Level: developer 2483 2484 Note: 2485 This function exists because the interpolation of a solution vector between meshes is not always a linear 2486 map. For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed 2487 out of the solution vector. Or if interpolation is inherently a nonlinear operation, such as a method using 2488 slope-limiting reconstruction. 2489 2490 Developer Note: 2491 This doesn't just interpolate "solutions" so its API name is questionable. 2492 2493 .seealso: [](ch_dmbase), `DM`, `DMInterpolate()`, `DMCreateInterpolation()` 2494 @*/ 2495 PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol) 2496 { 2497 PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL; 2498 2499 PetscFunctionBegin; 2500 PetscValidHeaderSpecific(coarse, DM_CLASSID, 1); 2501 if (interp) PetscValidHeaderSpecific(interp, MAT_CLASSID, 3); 2502 PetscValidHeaderSpecific(coarseSol, VEC_CLASSID, 4); 2503 PetscValidHeaderSpecific(fineSol, VEC_CLASSID, 5); 2504 2505 PetscCall(PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol)); 2506 if (interpsol) { 2507 PetscCall((*interpsol)(coarse, fine, interp, coarseSol, fineSol)); 2508 } else if (interp) { 2509 PetscCall(MatInterpolate(interp, coarseSol, fineSol)); 2510 } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name); 2511 PetscFunctionReturn(PETSC_SUCCESS); 2512 } 2513 2514 /*@ 2515 DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`. 2516 2517 Not Collective 2518 2519 Input Parameter: 2520 . dm - the `DM` object 2521 2522 Output Parameter: 2523 . level - number of refinements 2524 2525 Level: developer 2526 2527 Note: 2528 This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver. 2529 2530 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 2531 @*/ 2532 PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level) 2533 { 2534 PetscFunctionBegin; 2535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2536 *level = dm->levelup; 2537 PetscFunctionReturn(PETSC_SUCCESS); 2538 } 2539 2540 /*@ 2541 DMSetRefineLevel - Sets the number of refinements that have generated this `DM`. 2542 2543 Not Collective 2544 2545 Input Parameters: 2546 + dm - the `DM` object 2547 - level - number of refinements 2548 2549 Level: advanced 2550 2551 Notes: 2552 This value is used by `PCMG` to determine how many multigrid levels to use 2553 2554 The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine. 2555 2556 .seealso: [](ch_dmbase), `DM`, `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 2557 @*/ 2558 PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level) 2559 { 2560 PetscFunctionBegin; 2561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2562 dm->levelup = level; 2563 PetscFunctionReturn(PETSC_SUCCESS); 2564 } 2565 2566 /*@ 2567 DMExtrude - Extrude a `DM` object from a surface 2568 2569 Collective 2570 2571 Input Parameters: 2572 + dm - the `DM` object 2573 - layers - the number of extruded cell layers 2574 2575 Output Parameter: 2576 . dme - the extruded `DM`, or `NULL` 2577 2578 Level: developer 2579 2580 Note: 2581 If no extrusion was done, the return value is `NULL` 2582 2583 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()` 2584 @*/ 2585 PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme) 2586 { 2587 PetscFunctionBegin; 2588 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2589 PetscUseTypeMethod(dm, extrude, layers, dme); 2590 if (*dme) { 2591 (*dme)->ops->creatematrix = dm->ops->creatematrix; 2592 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme)); 2593 (*dme)->ctx = dm->ctx; 2594 PetscCall(DMSetMatType(*dme, dm->mattype)); 2595 } 2596 PetscFunctionReturn(PETSC_SUCCESS); 2597 } 2598 2599 PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm) 2600 { 2601 PetscFunctionBegin; 2602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2603 PetscAssertPointer(tdm, 2); 2604 *tdm = dm->transformDM; 2605 PetscFunctionReturn(PETSC_SUCCESS); 2606 } 2607 2608 PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv) 2609 { 2610 PetscFunctionBegin; 2611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2612 PetscAssertPointer(tv, 2); 2613 *tv = dm->transform; 2614 PetscFunctionReturn(PETSC_SUCCESS); 2615 } 2616 2617 /*@ 2618 DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors 2619 2620 Input Parameter: 2621 . dm - The `DM` 2622 2623 Output Parameter: 2624 . flg - `PETSC_TRUE` if a basis transformation should be done 2625 2626 Level: developer 2627 2628 .seealso: [](ch_dmbase), `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()` 2629 @*/ 2630 PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg) 2631 { 2632 Vec tv; 2633 2634 PetscFunctionBegin; 2635 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2636 PetscAssertPointer(flg, 2); 2637 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 2638 *flg = tv ? PETSC_TRUE : PETSC_FALSE; 2639 PetscFunctionReturn(PETSC_SUCCESS); 2640 } 2641 2642 PetscErrorCode DMConstructBasisTransform_Internal(DM dm) 2643 { 2644 PetscSection s, ts; 2645 PetscScalar *ta; 2646 PetscInt cdim, pStart, pEnd, p, Nf, f, Nc, dof; 2647 2648 PetscFunctionBegin; 2649 PetscCall(DMGetCoordinateDim(dm, &cdim)); 2650 PetscCall(DMGetLocalSection(dm, &s)); 2651 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2652 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2653 PetscCall(DMClone(dm, &dm->transformDM)); 2654 PetscCall(DMGetLocalSection(dm->transformDM, &ts)); 2655 PetscCall(PetscSectionSetNumFields(ts, Nf)); 2656 PetscCall(PetscSectionSetChart(ts, pStart, pEnd)); 2657 for (f = 0; f < Nf; ++f) { 2658 PetscCall(PetscSectionGetFieldComponents(s, f, &Nc)); 2659 /* We could start to label fields by their transformation properties */ 2660 if (Nc != cdim) continue; 2661 for (p = pStart; p < pEnd; ++p) { 2662 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 2663 if (!dof) continue; 2664 PetscCall(PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim))); 2665 PetscCall(PetscSectionAddDof(ts, p, PetscSqr(cdim))); 2666 } 2667 } 2668 PetscCall(PetscSectionSetUp(ts)); 2669 PetscCall(DMCreateLocalVector(dm->transformDM, &dm->transform)); 2670 PetscCall(VecGetArray(dm->transform, &ta)); 2671 for (p = pStart; p < pEnd; ++p) { 2672 for (f = 0; f < Nf; ++f) { 2673 PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 2674 if (dof) { 2675 PetscReal x[3] = {0.0, 0.0, 0.0}; 2676 PetscScalar *tva; 2677 const PetscScalar *A; 2678 2679 /* TODO Get quadrature point for this dual basis vector for coordinate */ 2680 PetscCall((*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx)); 2681 PetscCall(DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva)); 2682 PetscCall(PetscArraycpy(tva, A, PetscSqr(cdim))); 2683 } 2684 } 2685 } 2686 PetscCall(VecRestoreArray(dm->transform, &ta)); 2687 PetscFunctionReturn(PETSC_SUCCESS); 2688 } 2689 2690 PetscErrorCode DMCopyTransform(DM dm, DM newdm) 2691 { 2692 PetscFunctionBegin; 2693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2694 PetscValidHeaderSpecific(newdm, DM_CLASSID, 2); 2695 newdm->transformCtx = dm->transformCtx; 2696 newdm->transformSetUp = dm->transformSetUp; 2697 newdm->transformDestroy = NULL; 2698 newdm->transformGetMatrix = dm->transformGetMatrix; 2699 if (newdm->transformSetUp) PetscCall(DMConstructBasisTransform_Internal(newdm)); 2700 PetscFunctionReturn(PETSC_SUCCESS); 2701 } 2702 2703 /*@C 2704 DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called 2705 2706 Logically Collective 2707 2708 Input Parameters: 2709 + dm - the `DM` 2710 . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()` 2711 . endhook - function to run after `DMGlobalToLocalEnd()` has completed 2712 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 2713 2714 Calling sequence of `beginhook`: 2715 + dm - global `DM` 2716 . g - global vector 2717 . mode - mode 2718 . l - local vector 2719 - ctx - optional user-defined function context 2720 2721 Calling sequence of `endhook`: 2722 + dm - global `DM` 2723 . g - global vector 2724 . mode - mode 2725 . l - local vector 2726 - ctx - optional user-defined function context 2727 2728 Level: advanced 2729 2730 Note: 2731 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. 2732 2733 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2734 @*/ 2735 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) 2736 { 2737 DMGlobalToLocalHookLink link, *p; 2738 2739 PetscFunctionBegin; 2740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2741 for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */ 2742 PetscCall(PetscNew(&link)); 2743 link->beginhook = beginhook; 2744 link->endhook = endhook; 2745 link->ctx = ctx; 2746 link->next = NULL; 2747 *p = link; 2748 PetscFunctionReturn(PETSC_SUCCESS); 2749 } 2750 2751 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx) 2752 { 2753 Mat cMat; 2754 Vec cVec, cBias; 2755 PetscSection section, cSec; 2756 PetscInt pStart, pEnd, p, dof; 2757 2758 PetscFunctionBegin; 2759 (void)g; 2760 (void)ctx; 2761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2762 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias)); 2763 if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) { 2764 PetscInt nRows; 2765 2766 PetscCall(MatGetSize(cMat, &nRows, NULL)); 2767 if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS); 2768 PetscCall(DMGetLocalSection(dm, §ion)); 2769 PetscCall(MatCreateVecs(cMat, NULL, &cVec)); 2770 PetscCall(MatMult(cMat, l, cVec)); 2771 if (cBias) PetscCall(VecAXPY(cVec, 1., cBias)); 2772 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 2773 for (p = pStart; p < pEnd; p++) { 2774 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 2775 if (dof) { 2776 PetscScalar *vals; 2777 PetscCall(VecGetValuesSection(cVec, cSec, p, &vals)); 2778 PetscCall(VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES)); 2779 } 2780 } 2781 PetscCall(VecDestroy(&cVec)); 2782 } 2783 PetscFunctionReturn(PETSC_SUCCESS); 2784 } 2785 2786 /*@ 2787 DMGlobalToLocal - update local vectors from global vector 2788 2789 Neighbor-wise Collective 2790 2791 Input Parameters: 2792 + dm - the `DM` object 2793 . g - the global vector 2794 . mode - `INSERT_VALUES` or `ADD_VALUES` 2795 - l - the local vector 2796 2797 Level: beginner 2798 2799 Notes: 2800 The communication involved in this update can be overlapped with computation by instead using 2801 `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`. 2802 2803 `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process. 2804 2805 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, 2806 `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, 2807 `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()` 2808 @*/ 2809 PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l) 2810 { 2811 PetscFunctionBegin; 2812 PetscCall(DMGlobalToLocalBegin(dm, g, mode, l)); 2813 PetscCall(DMGlobalToLocalEnd(dm, g, mode, l)); 2814 PetscFunctionReturn(PETSC_SUCCESS); 2815 } 2816 2817 /*@ 2818 DMGlobalToLocalBegin - Begins updating local vectors from global vector 2819 2820 Neighbor-wise Collective 2821 2822 Input Parameters: 2823 + dm - the `DM` object 2824 . g - the global vector 2825 . mode - `INSERT_VALUES` or `ADD_VALUES` 2826 - l - the local vector 2827 2828 Level: intermediate 2829 2830 Notes: 2831 The operation is completed with `DMGlobalToLocalEnd()` 2832 2833 One can perform local computations between the `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()` to overlap communication and computation 2834 2835 `DMGlobalToLocal()` is a short form of `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()` 2836 2837 `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process. 2838 2839 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()` 2840 @*/ 2841 PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l) 2842 { 2843 PetscSF sf; 2844 DMGlobalToLocalHookLink link; 2845 2846 PetscFunctionBegin; 2847 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2848 for (link = dm->gtolhook; link; link = link->next) { 2849 if (link->beginhook) PetscCall((*link->beginhook)(dm, g, mode, l, link->ctx)); 2850 } 2851 PetscCall(DMGetSectionSF(dm, &sf)); 2852 if (sf) { 2853 const PetscScalar *gArray; 2854 PetscScalar *lArray; 2855 PetscMemType lmtype, gmtype; 2856 2857 PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode); 2858 PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype)); 2859 PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype)); 2860 PetscCall(PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE)); 2861 PetscCall(VecRestoreArrayAndMemType(l, &lArray)); 2862 PetscCall(VecRestoreArrayReadAndMemType(g, &gArray)); 2863 } else { 2864 PetscUseTypeMethod(dm, globaltolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l); 2865 } 2866 PetscFunctionReturn(PETSC_SUCCESS); 2867 } 2868 2869 /*@ 2870 DMGlobalToLocalEnd - Ends updating local vectors from global vector 2871 2872 Neighbor-wise Collective 2873 2874 Input Parameters: 2875 + dm - the `DM` object 2876 . g - the global vector 2877 . mode - `INSERT_VALUES` or `ADD_VALUES` 2878 - l - the local vector 2879 2880 Level: intermediate 2881 2882 Note: 2883 See `DMGlobalToLocalBegin()` for details. 2884 2885 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()` 2886 @*/ 2887 PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l) 2888 { 2889 PetscSF sf; 2890 const PetscScalar *gArray; 2891 PetscScalar *lArray; 2892 PetscBool transform; 2893 DMGlobalToLocalHookLink link; 2894 PetscMemType lmtype, gmtype; 2895 2896 PetscFunctionBegin; 2897 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2898 PetscCall(DMGetSectionSF(dm, &sf)); 2899 PetscCall(DMHasBasisTransform(dm, &transform)); 2900 if (sf) { 2901 PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode); 2902 2903 PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype)); 2904 PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype)); 2905 PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE)); 2906 PetscCall(VecRestoreArrayAndMemType(l, &lArray)); 2907 PetscCall(VecRestoreArrayReadAndMemType(g, &gArray)); 2908 if (transform) PetscCall(DMPlexGlobalToLocalBasis(dm, l)); 2909 } else { 2910 PetscUseTypeMethod(dm, globaltolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l); 2911 } 2912 PetscCall(DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL)); 2913 for (link = dm->gtolhook; link; link = link->next) { 2914 if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx)); 2915 } 2916 PetscFunctionReturn(PETSC_SUCCESS); 2917 } 2918 2919 /*@C 2920 DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called 2921 2922 Logically Collective 2923 2924 Input Parameters: 2925 + dm - the `DM` 2926 . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()` 2927 . endhook - function to run after `DMLocalToGlobalEnd()` has completed 2928 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 2929 2930 Calling sequence of `beginhook`: 2931 + global - global `DM` 2932 . l - local vector 2933 . mode - mode 2934 . g - global vector 2935 - ctx - optional user-defined function context 2936 2937 Calling sequence of `endhook`: 2938 + global - global `DM` 2939 . l - local vector 2940 . mode - mode 2941 . g - global vector 2942 - ctx - optional user-defined function context 2943 2944 Level: advanced 2945 2946 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 2947 @*/ 2948 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) 2949 { 2950 DMLocalToGlobalHookLink link, *p; 2951 2952 PetscFunctionBegin; 2953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2954 for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */ 2955 PetscCall(PetscNew(&link)); 2956 link->beginhook = beginhook; 2957 link->endhook = endhook; 2958 link->ctx = ctx; 2959 link->next = NULL; 2960 *p = link; 2961 PetscFunctionReturn(PETSC_SUCCESS); 2962 } 2963 2964 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx) 2965 { 2966 PetscFunctionBegin; 2967 (void)g; 2968 (void)ctx; 2969 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2970 if (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES) { 2971 Mat cMat; 2972 Vec cVec; 2973 PetscInt nRows; 2974 PetscSection section, cSec; 2975 PetscInt pStart, pEnd, p, dof; 2976 2977 PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL)); 2978 if (!cMat) PetscFunctionReturn(PETSC_SUCCESS); 2979 2980 PetscCall(MatGetSize(cMat, &nRows, NULL)); 2981 if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS); 2982 PetscCall(DMGetLocalSection(dm, §ion)); 2983 PetscCall(MatCreateVecs(cMat, NULL, &cVec)); 2984 PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd)); 2985 for (p = pStart; p < pEnd; p++) { 2986 PetscCall(PetscSectionGetDof(cSec, p, &dof)); 2987 if (dof) { 2988 PetscInt d; 2989 PetscScalar *vals; 2990 PetscCall(VecGetValuesSection(l, section, p, &vals)); 2991 PetscCall(VecSetValuesSection(cVec, cSec, p, vals, mode)); 2992 /* for this to be the true transpose, we have to zero the values that 2993 * we just extracted */ 2994 for (d = 0; d < dof; d++) vals[d] = 0.; 2995 } 2996 } 2997 PetscCall(MatMultTransposeAdd(cMat, cVec, l, l)); 2998 PetscCall(VecDestroy(&cVec)); 2999 } 3000 PetscFunctionReturn(PETSC_SUCCESS); 3001 } 3002 /*@ 3003 DMLocalToGlobal - updates global vectors from local vectors 3004 3005 Neighbor-wise Collective 3006 3007 Input Parameters: 3008 + dm - the `DM` object 3009 . l - the local vector 3010 . 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. 3011 - g - the global vector 3012 3013 Level: beginner 3014 3015 Notes: 3016 The communication involved in this update can be overlapped with computation by using 3017 `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`. 3018 3019 In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation. 3020 3021 `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one. 3022 3023 Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process 3024 3025 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()` 3026 @*/ 3027 PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g) 3028 { 3029 PetscFunctionBegin; 3030 PetscCall(DMLocalToGlobalBegin(dm, l, mode, g)); 3031 PetscCall(DMLocalToGlobalEnd(dm, l, mode, g)); 3032 PetscFunctionReturn(PETSC_SUCCESS); 3033 } 3034 3035 /*@ 3036 DMLocalToGlobalBegin - begins updating global vectors from local vectors 3037 3038 Neighbor-wise Collective 3039 3040 Input Parameters: 3041 + dm - the `DM` object 3042 . l - the local vector 3043 . 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. 3044 - g - the global vector 3045 3046 Level: intermediate 3047 3048 Notes: 3049 In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation. 3050 3051 `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one. 3052 3053 Use `DMLocalToGlobalEnd()` to complete the communication process. 3054 3055 `DMLocalToGlobal()` is a short form of `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()` 3056 3057 `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process. 3058 3059 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()` 3060 @*/ 3061 PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g) 3062 { 3063 PetscSF sf; 3064 PetscSection s, gs; 3065 DMLocalToGlobalHookLink link; 3066 Vec tmpl; 3067 const PetscScalar *lArray; 3068 PetscScalar *gArray; 3069 PetscBool isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE; 3070 PetscMemType lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST; 3071 3072 PetscFunctionBegin; 3073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3074 for (link = dm->ltoghook; link; link = link->next) { 3075 if (link->beginhook) PetscCall((*link->beginhook)(dm, l, mode, g, link->ctx)); 3076 } 3077 PetscCall(DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL)); 3078 PetscCall(DMGetSectionSF(dm, &sf)); 3079 PetscCall(DMGetLocalSection(dm, &s)); 3080 switch (mode) { 3081 case INSERT_VALUES: 3082 case INSERT_ALL_VALUES: 3083 case INSERT_BC_VALUES: 3084 isInsert = PETSC_TRUE; 3085 break; 3086 case ADD_VALUES: 3087 case ADD_ALL_VALUES: 3088 case ADD_BC_VALUES: 3089 isInsert = PETSC_FALSE; 3090 break; 3091 default: 3092 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode); 3093 } 3094 if ((sf && !isInsert) || (s && isInsert)) { 3095 PetscCall(DMHasBasisTransform(dm, &transform)); 3096 if (transform) { 3097 PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3098 PetscCall(VecCopy(l, tmpl)); 3099 PetscCall(DMPlexLocalToGlobalBasis(dm, tmpl)); 3100 PetscCall(VecGetArrayRead(tmpl, &lArray)); 3101 } else if (isInsert) { 3102 PetscCall(VecGetArrayRead(l, &lArray)); 3103 } else { 3104 PetscCall(VecGetArrayReadAndMemType(l, &lArray, &lmtype)); 3105 l_inplace = PETSC_TRUE; 3106 } 3107 if (s && isInsert) { 3108 PetscCall(VecGetArray(g, &gArray)); 3109 } else { 3110 PetscCall(VecGetArrayAndMemType(g, &gArray, &gmtype)); 3111 g_inplace = PETSC_TRUE; 3112 } 3113 if (sf && !isInsert) { 3114 PetscCall(PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM)); 3115 } else if (s && isInsert) { 3116 PetscInt gStart, pStart, pEnd, p; 3117 3118 PetscCall(DMGetGlobalSection(dm, &gs)); 3119 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 3120 PetscCall(VecGetOwnershipRange(g, &gStart, NULL)); 3121 for (p = pStart; p < pEnd; ++p) { 3122 PetscInt dof, gdof, cdof, gcdof, off, goff, d, e; 3123 3124 PetscCall(PetscSectionGetDof(s, p, &dof)); 3125 PetscCall(PetscSectionGetDof(gs, p, &gdof)); 3126 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 3127 PetscCall(PetscSectionGetConstraintDof(gs, p, &gcdof)); 3128 PetscCall(PetscSectionGetOffset(s, p, &off)); 3129 PetscCall(PetscSectionGetOffset(gs, p, &goff)); 3130 /* Ignore off-process data and points with no global data */ 3131 if (!gdof || goff < 0) continue; 3132 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); 3133 /* If no constraints are enforced in the global vector */ 3134 if (!gcdof) { 3135 for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d]; 3136 /* If constraints are enforced in the global vector */ 3137 } else if (cdof == gcdof) { 3138 const PetscInt *cdofs; 3139 PetscInt cind = 0; 3140 3141 PetscCall(PetscSectionGetConstraintIndices(s, p, &cdofs)); 3142 for (d = 0, e = 0; d < dof; ++d) { 3143 if ((cind < cdof) && (d == cdofs[cind])) { 3144 ++cind; 3145 continue; 3146 } 3147 gArray[goff - gStart + e++] = lArray[off + d]; 3148 } 3149 } 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); 3150 } 3151 } 3152 if (g_inplace) { 3153 PetscCall(VecRestoreArrayAndMemType(g, &gArray)); 3154 } else { 3155 PetscCall(VecRestoreArray(g, &gArray)); 3156 } 3157 if (transform) { 3158 PetscCall(VecRestoreArrayRead(tmpl, &lArray)); 3159 PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3160 } else if (l_inplace) { 3161 PetscCall(VecRestoreArrayReadAndMemType(l, &lArray)); 3162 } else { 3163 PetscCall(VecRestoreArrayRead(l, &lArray)); 3164 } 3165 } else { 3166 PetscUseTypeMethod(dm, localtoglobalbegin, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g); 3167 } 3168 PetscFunctionReturn(PETSC_SUCCESS); 3169 } 3170 3171 /*@ 3172 DMLocalToGlobalEnd - updates global vectors from local vectors 3173 3174 Neighbor-wise Collective 3175 3176 Input Parameters: 3177 + dm - the `DM` object 3178 . l - the local vector 3179 . mode - `INSERT_VALUES` or `ADD_VALUES` 3180 - g - the global vector 3181 3182 Level: intermediate 3183 3184 Note: 3185 See `DMLocalToGlobalBegin()` for full details 3186 3187 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()` 3188 @*/ 3189 PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g) 3190 { 3191 PetscSF sf; 3192 PetscSection s; 3193 DMLocalToGlobalHookLink link; 3194 PetscBool isInsert, transform; 3195 3196 PetscFunctionBegin; 3197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3198 PetscCall(DMGetSectionSF(dm, &sf)); 3199 PetscCall(DMGetLocalSection(dm, &s)); 3200 switch (mode) { 3201 case INSERT_VALUES: 3202 case INSERT_ALL_VALUES: 3203 isInsert = PETSC_TRUE; 3204 break; 3205 case ADD_VALUES: 3206 case ADD_ALL_VALUES: 3207 isInsert = PETSC_FALSE; 3208 break; 3209 default: 3210 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode); 3211 } 3212 if (sf && !isInsert) { 3213 const PetscScalar *lArray; 3214 PetscScalar *gArray; 3215 Vec tmpl; 3216 3217 PetscCall(DMHasBasisTransform(dm, &transform)); 3218 if (transform) { 3219 PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3220 PetscCall(VecGetArrayRead(tmpl, &lArray)); 3221 } else { 3222 PetscCall(VecGetArrayReadAndMemType(l, &lArray, NULL)); 3223 } 3224 PetscCall(VecGetArrayAndMemType(g, &gArray, NULL)); 3225 PetscCall(PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM)); 3226 if (transform) { 3227 PetscCall(VecRestoreArrayRead(tmpl, &lArray)); 3228 PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl)); 3229 } else { 3230 PetscCall(VecRestoreArrayReadAndMemType(l, &lArray)); 3231 } 3232 PetscCall(VecRestoreArrayAndMemType(g, &gArray)); 3233 } else if (s && isInsert) { 3234 } else { 3235 PetscUseTypeMethod(dm, localtoglobalend, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g); 3236 } 3237 for (link = dm->ltoghook; link; link = link->next) { 3238 if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx)); 3239 } 3240 PetscFunctionReturn(PETSC_SUCCESS); 3241 } 3242 3243 /*@ 3244 DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include 3245 ghost points that contain irrelevant values) to another local vector where the ghost points 3246 in the second are set correctly from values on other MPI ranks. 3247 3248 Neighbor-wise Collective 3249 3250 Input Parameters: 3251 + dm - the `DM` object 3252 . g - the original local vector 3253 - mode - one of `INSERT_VALUES` or `ADD_VALUES` 3254 3255 Output Parameter: 3256 . l - the local vector with correct ghost values 3257 3258 Level: intermediate 3259 3260 Note: 3261 Must be followed by `DMLocalToLocalEnd()`. 3262 3263 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()` 3264 @*/ 3265 PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l) 3266 { 3267 PetscFunctionBegin; 3268 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3269 PetscValidHeaderSpecific(g, VEC_CLASSID, 2); 3270 PetscValidHeaderSpecific(l, VEC_CLASSID, 4); 3271 PetscUseTypeMethod(dm, localtolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l); 3272 PetscFunctionReturn(PETSC_SUCCESS); 3273 } 3274 3275 /*@ 3276 DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost 3277 points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`. 3278 3279 Neighbor-wise Collective 3280 3281 Input Parameters: 3282 + dm - the `DM` object 3283 . g - the original local vector 3284 - mode - one of `INSERT_VALUES` or `ADD_VALUES` 3285 3286 Output Parameter: 3287 . l - the local vector with correct ghost values 3288 3289 Level: intermediate 3290 3291 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()` 3292 @*/ 3293 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l) 3294 { 3295 PetscFunctionBegin; 3296 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3297 PetscValidHeaderSpecific(g, VEC_CLASSID, 2); 3298 PetscValidHeaderSpecific(l, VEC_CLASSID, 4); 3299 PetscUseTypeMethod(dm, localtolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l); 3300 PetscFunctionReturn(PETSC_SUCCESS); 3301 } 3302 3303 /*@ 3304 DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh 3305 3306 Collective 3307 3308 Input Parameters: 3309 + dm - the `DM` object 3310 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`) 3311 3312 Output Parameter: 3313 . dmc - the coarsened `DM` 3314 3315 Level: developer 3316 3317 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`, 3318 `DMCoarsenHookAdd()`, `DMCoarsenHookRemove()` 3319 @*/ 3320 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc) 3321 { 3322 DMCoarsenHookLink link; 3323 3324 PetscFunctionBegin; 3325 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3326 PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0)); 3327 PetscUseTypeMethod(dm, coarsen, comm, dmc); 3328 if (*dmc) { 3329 (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */ 3330 PetscCall(DMSetCoarseDM(dm, *dmc)); 3331 (*dmc)->ops->creatematrix = dm->ops->creatematrix; 3332 PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc)); 3333 (*dmc)->ctx = dm->ctx; 3334 (*dmc)->levelup = dm->levelup; 3335 (*dmc)->leveldown = dm->leveldown + 1; 3336 PetscCall(DMSetMatType(*dmc, dm->mattype)); 3337 for (link = dm->coarsenhook; link; link = link->next) { 3338 if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx)); 3339 } 3340 } 3341 PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0)); 3342 PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced"); 3343 PetscFunctionReturn(PETSC_SUCCESS); 3344 } 3345 3346 /*@C 3347 DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid 3348 3349 Logically Collective; No Fortran Support 3350 3351 Input Parameters: 3352 + fine - `DM` on which to run a hook when restricting to a coarser level 3353 . coarsenhook - function to run when setting up a coarser level 3354 . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`) 3355 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 3356 3357 Calling sequence of `coarsenhook`: 3358 + fine - fine level `DM` 3359 . coarse - coarse level `DM` to restrict problem to 3360 - ctx - optional user-defined function context 3361 3362 Calling sequence of `restricthook`: 3363 + fine - fine level `DM` 3364 . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation 3365 . rscale - scaling vector for restriction 3366 . inject - matrix restricting by injection 3367 . coarse - coarse level DM to update 3368 - ctx - optional user-defined function context 3369 3370 Level: advanced 3371 3372 Notes: 3373 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`. 3374 3375 If this function is called multiple times, the hooks will be run in the order they are added. 3376 3377 In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to 3378 extract the finest level information from its context (instead of from the `SNES`). 3379 3380 The hooks are automatically called by `DMRestrict()` 3381 3382 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 3383 @*/ 3384 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) 3385 { 3386 DMCoarsenHookLink link, *p; 3387 3388 PetscFunctionBegin; 3389 PetscValidHeaderSpecific(fine, DM_CLASSID, 1); 3390 for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */ 3391 if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS); 3392 } 3393 PetscCall(PetscNew(&link)); 3394 link->coarsenhook = coarsenhook; 3395 link->restricthook = restricthook; 3396 link->ctx = ctx; 3397 link->next = NULL; 3398 *p = link; 3399 PetscFunctionReturn(PETSC_SUCCESS); 3400 } 3401 3402 /*@C 3403 DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()` 3404 3405 Logically Collective; No Fortran Support 3406 3407 Input Parameters: 3408 + fine - `DM` on which to run a hook when restricting to a coarser level 3409 . coarsenhook - function to run when setting up a coarser level 3410 . restricthook - function to run to update data on coarser levels 3411 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 3412 3413 Level: advanced 3414 3415 Notes: 3416 This function does nothing if the `coarsenhook` is not in the list. 3417 3418 See `DMCoarsenHookAdd()` for the calling sequence of `coarsenhook` and `restricthook` 3419 3420 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()` 3421 @*/ 3422 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx) 3423 { 3424 DMCoarsenHookLink link, *p; 3425 3426 PetscFunctionBegin; 3427 PetscValidHeaderSpecific(fine, DM_CLASSID, 1); 3428 for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */ 3429 if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) { 3430 link = *p; 3431 *p = link->next; 3432 PetscCall(PetscFree(link)); 3433 break; 3434 } 3435 } 3436 PetscFunctionReturn(PETSC_SUCCESS); 3437 } 3438 3439 /*@ 3440 DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()` 3441 3442 Collective if any hooks are 3443 3444 Input Parameters: 3445 + fine - finer `DM` from which the data is obtained 3446 . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation 3447 . rscale - scaling vector for restriction 3448 . inject - injection matrix, also use `MatRestrict()` 3449 - coarse - coarser `DM` to update 3450 3451 Level: developer 3452 3453 Developer Note: 3454 Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better 3455 3456 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()` 3457 @*/ 3458 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse) 3459 { 3460 DMCoarsenHookLink link; 3461 3462 PetscFunctionBegin; 3463 for (link = fine->coarsenhook; link; link = link->next) { 3464 if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx)); 3465 } 3466 PetscFunctionReturn(PETSC_SUCCESS); 3467 } 3468 3469 /*@C 3470 DMSubDomainHookAdd - adds a callback to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()` 3471 3472 Logically Collective; No Fortran Support 3473 3474 Input Parameters: 3475 + global - global `DM` 3476 . ddhook - function to run to pass data to the decomposition `DM` upon its creation 3477 . restricthook - function to run to update data on block solve (at the beginning of the block solve) 3478 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 3479 3480 Calling sequence of `ddhook`: 3481 + global - global `DM` 3482 . block - subdomain `DM` 3483 - ctx - optional user-defined function context 3484 3485 Calling sequence of `restricthook`: 3486 + global - global `DM` 3487 . out - scatter to the outer (with ghost and overlap points) sub vector 3488 . in - scatter to sub vector values only owned locally 3489 . block - subdomain `DM` 3490 - ctx - optional user-defined function context 3491 3492 Level: advanced 3493 3494 Notes: 3495 This function can be used if auxiliary data needs to be set up on subdomain `DM`s. 3496 3497 If this function is called multiple times, the hooks will be run in the order they are added. 3498 3499 In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to 3500 extract the global information from its context (instead of from the `SNES`). 3501 3502 Developer Note: 3503 It is unclear what "block solve" means within the definition of `restricthook` 3504 3505 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`, `DMCreateDomainDecomposition()` 3506 @*/ 3507 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) 3508 { 3509 DMSubDomainHookLink link, *p; 3510 3511 PetscFunctionBegin; 3512 PetscValidHeaderSpecific(global, DM_CLASSID, 1); 3513 for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */ 3514 if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 PetscCall(PetscNew(&link)); 3517 link->restricthook = restricthook; 3518 link->ddhook = ddhook; 3519 link->ctx = ctx; 3520 link->next = NULL; 3521 *p = link; 3522 PetscFunctionReturn(PETSC_SUCCESS); 3523 } 3524 3525 /*@C 3526 DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()` 3527 3528 Logically Collective; No Fortran Support 3529 3530 Input Parameters: 3531 + global - global `DM` 3532 . ddhook - function to run to pass data to the decomposition `DM` upon its creation 3533 . restricthook - function to run to update data on block solve (at the beginning of the block solve) 3534 - ctx - [optional] user-defined context for provide data for the hooks (may be `NULL`) 3535 3536 Level: advanced 3537 3538 Note: 3539 See `DMSubDomainHookAdd()` for the calling sequences of `ddhook` and `restricthook` 3540 3541 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`, 3542 `DMCreateDomainDecomposition()` 3543 @*/ 3544 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx) 3545 { 3546 DMSubDomainHookLink link, *p; 3547 3548 PetscFunctionBegin; 3549 PetscValidHeaderSpecific(global, DM_CLASSID, 1); 3550 for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */ 3551 if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) { 3552 link = *p; 3553 *p = link->next; 3554 PetscCall(PetscFree(link)); 3555 break; 3556 } 3557 } 3558 PetscFunctionReturn(PETSC_SUCCESS); 3559 } 3560 3561 /*@ 3562 DMSubDomainRestrict - restricts user-defined problem data to a subdomain `DM` by running hooks registered by `DMSubDomainHookAdd()` 3563 3564 Collective if any hooks are 3565 3566 Input Parameters: 3567 + global - The global `DM` to use as a base 3568 . oscatter - The scatter from domain global vector filling subdomain global vector with overlap 3569 . gscatter - The scatter from domain global vector filling subdomain local vector with ghosts 3570 - subdm - The subdomain `DM` to update 3571 3572 Level: developer 3573 3574 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMCreateDomainDecomposition()` 3575 @*/ 3576 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm) 3577 { 3578 DMSubDomainHookLink link; 3579 3580 PetscFunctionBegin; 3581 for (link = global->subdomainhook; link; link = link->next) { 3582 if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx)); 3583 } 3584 PetscFunctionReturn(PETSC_SUCCESS); 3585 } 3586 3587 /*@ 3588 DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`. 3589 3590 Not Collective 3591 3592 Input Parameter: 3593 . dm - the `DM` object 3594 3595 Output Parameter: 3596 . level - number of coarsenings 3597 3598 Level: developer 3599 3600 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3601 @*/ 3602 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level) 3603 { 3604 PetscFunctionBegin; 3605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3606 PetscAssertPointer(level, 2); 3607 *level = dm->leveldown; 3608 PetscFunctionReturn(PETSC_SUCCESS); 3609 } 3610 3611 /*@ 3612 DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`. 3613 3614 Collective 3615 3616 Input Parameters: 3617 + dm - the `DM` object 3618 - level - number of coarsenings 3619 3620 Level: developer 3621 3622 Note: 3623 This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()` 3624 3625 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3626 @*/ 3627 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level) 3628 { 3629 PetscFunctionBegin; 3630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3631 dm->leveldown = level; 3632 PetscFunctionReturn(PETSC_SUCCESS); 3633 } 3634 3635 /*@ 3636 DMRefineHierarchy - Refines a `DM` object, all levels at once 3637 3638 Collective 3639 3640 Input Parameters: 3641 + dm - the `DM` object 3642 - nlevels - the number of levels of refinement 3643 3644 Output Parameter: 3645 . dmf - the refined `DM` hierarchy 3646 3647 Level: developer 3648 3649 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3650 @*/ 3651 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[]) 3652 { 3653 PetscFunctionBegin; 3654 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3655 PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative"); 3656 if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS); 3657 PetscAssertPointer(dmf, 3); 3658 if (dm->ops->refine && !dm->ops->refinehierarchy) { 3659 PetscInt i; 3660 3661 PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0])); 3662 for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i])); 3663 } else PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf); 3664 PetscFunctionReturn(PETSC_SUCCESS); 3665 } 3666 3667 /*@ 3668 DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once 3669 3670 Collective 3671 3672 Input Parameters: 3673 + dm - the `DM` object 3674 - nlevels - the number of levels of coarsening 3675 3676 Output Parameter: 3677 . dmc - the coarsened `DM` hierarchy 3678 3679 Level: developer 3680 3681 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()` 3682 @*/ 3683 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[]) 3684 { 3685 PetscFunctionBegin; 3686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3687 PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative"); 3688 if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS); 3689 PetscAssertPointer(dmc, 3); 3690 if (dm->ops->coarsen && !dm->ops->coarsenhierarchy) { 3691 PetscInt i; 3692 3693 PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0])); 3694 for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i])); 3695 } else PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc); 3696 PetscFunctionReturn(PETSC_SUCCESS); 3697 } 3698 3699 /*@C 3700 DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed 3701 3702 Logically Collective if the function is collective 3703 3704 Input Parameters: 3705 + dm - the `DM` object 3706 - destroy - the destroy function, see `PetscCtxDestroyFn` for the calling sequence 3707 3708 Level: intermediate 3709 3710 .seealso: [](ch_dmbase), `DM`, `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, 3711 `DMGetApplicationContext()`, `PetscCtxDestroyFn` 3712 @*/ 3713 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscCtxDestroyFn *destroy) 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`), see `PetscCtxDestroyFn` for the calling sequence 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()`, `PetscCtxDestroyFn` 8918 @*/ 8919 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy) 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, this must use a `PetscViewerFormat` as its context 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, (PetscCtxDestroyFn *)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