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