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