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 Parameter: 5166 . dm - The `DM` 5167 5168 Output Parameter: 5169 . newdm - The `DM` 5170 5171 Level: advanced 5172 5173 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()` 5174 @*/ 5175 PetscErrorCode DMCopyFields(DM dm, DM newdm) 5176 { 5177 PetscInt Nf, f; 5178 5179 PetscFunctionBegin; 5180 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 5181 PetscCall(DMGetNumFields(dm, &Nf)); 5182 PetscCall(DMClearFields(newdm)); 5183 for (f = 0; f < Nf; ++f) { 5184 DMLabel label; 5185 PetscObject field; 5186 PetscBool useCone, useClosure; 5187 5188 PetscCall(DMGetField(dm, f, &label, &field)); 5189 PetscCall(DMSetField(newdm, f, label, field)); 5190 PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure)); 5191 PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure)); 5192 } 5193 PetscFunctionReturn(PETSC_SUCCESS); 5194 } 5195 5196 /*@ 5197 DMGetAdjacency - Returns the flags for determining variable influence 5198 5199 Not Collective 5200 5201 Input Parameters: 5202 + dm - The `DM` object 5203 - f - The field number, or `PETSC_DEFAULT` for the default adjacency 5204 5205 Output Parameters: 5206 + useCone - Flag for variable influence starting with the cone operation 5207 - useClosure - Flag for variable influence using transitive closure 5208 5209 Level: developer 5210 5211 Notes: 5212 .vb 5213 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5214 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5215 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5216 .ve 5217 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5218 5219 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()` 5220 @*/ 5221 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure) 5222 { 5223 PetscFunctionBegin; 5224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5225 if (useCone) PetscAssertPointer(useCone, 3); 5226 if (useClosure) PetscAssertPointer(useClosure, 4); 5227 if (f < 0) { 5228 if (useCone) *useCone = dm->adjacency[0]; 5229 if (useClosure) *useClosure = dm->adjacency[1]; 5230 } else { 5231 PetscInt Nf; 5232 5233 PetscCall(DMGetNumFields(dm, &Nf)); 5234 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5235 if (useCone) *useCone = dm->fields[f].adjacency[0]; 5236 if (useClosure) *useClosure = dm->fields[f].adjacency[1]; 5237 } 5238 PetscFunctionReturn(PETSC_SUCCESS); 5239 } 5240 5241 /*@ 5242 DMSetAdjacency - Set the flags for determining variable influence 5243 5244 Not Collective 5245 5246 Input Parameters: 5247 + dm - The `DM` object 5248 . f - The field number 5249 . useCone - Flag for variable influence starting with the cone operation 5250 - useClosure - Flag for variable influence using transitive closure 5251 5252 Level: developer 5253 5254 Notes: 5255 .vb 5256 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5257 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5258 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5259 .ve 5260 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5261 5262 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()` 5263 @*/ 5264 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure) 5265 { 5266 PetscFunctionBegin; 5267 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5268 if (f < 0) { 5269 dm->adjacency[0] = useCone; 5270 dm->adjacency[1] = useClosure; 5271 } else { 5272 PetscInt Nf; 5273 5274 PetscCall(DMGetNumFields(dm, &Nf)); 5275 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5276 dm->fields[f].adjacency[0] = useCone; 5277 dm->fields[f].adjacency[1] = useClosure; 5278 } 5279 PetscFunctionReturn(PETSC_SUCCESS); 5280 } 5281 5282 /*@ 5283 DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined 5284 5285 Not collective 5286 5287 Input Parameter: 5288 . dm - The `DM` object 5289 5290 Output Parameters: 5291 + useCone - Flag for variable influence starting with the cone operation 5292 - useClosure - Flag for variable influence using transitive closure 5293 5294 Level: developer 5295 5296 Notes: 5297 .vb 5298 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5299 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5300 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5301 .ve 5302 5303 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5304 @*/ 5305 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure) 5306 { 5307 PetscInt Nf; 5308 5309 PetscFunctionBegin; 5310 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5311 if (useCone) PetscAssertPointer(useCone, 2); 5312 if (useClosure) PetscAssertPointer(useClosure, 3); 5313 PetscCall(DMGetNumFields(dm, &Nf)); 5314 if (!Nf) { 5315 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5316 } else { 5317 PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure)); 5318 } 5319 PetscFunctionReturn(PETSC_SUCCESS); 5320 } 5321 5322 /*@ 5323 DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined 5324 5325 Not Collective 5326 5327 Input Parameters: 5328 + dm - The `DM` object 5329 . useCone - Flag for variable influence starting with the cone operation 5330 - useClosure - Flag for variable influence using transitive closure 5331 5332 Level: developer 5333 5334 Notes: 5335 .vb 5336 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5337 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5338 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5339 .ve 5340 5341 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5342 @*/ 5343 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure) 5344 { 5345 PetscInt Nf; 5346 5347 PetscFunctionBegin; 5348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5349 PetscCall(DMGetNumFields(dm, &Nf)); 5350 if (!Nf) { 5351 PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5352 } else { 5353 PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure)); 5354 } 5355 PetscFunctionReturn(PETSC_SUCCESS); 5356 } 5357 5358 PetscErrorCode DMCompleteBCLabels_Internal(DM dm) 5359 { 5360 DM plex; 5361 DMLabel *labels, *glabels; 5362 const char **names; 5363 char *sendNames, *recvNames; 5364 PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m; 5365 size_t len; 5366 MPI_Comm comm; 5367 PetscMPIInt rank, size, p, *counts, *displs; 5368 5369 PetscFunctionBegin; 5370 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5371 PetscCallMPI(MPI_Comm_size(comm, &size)); 5372 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5373 PetscCall(DMGetNumDS(dm, &Nds)); 5374 for (s = 0; s < Nds; ++s) { 5375 PetscDS dsBC; 5376 PetscInt numBd; 5377 5378 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5379 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5380 maxLabels += numBd; 5381 } 5382 PetscCall(PetscCalloc1(maxLabels, &labels)); 5383 /* Get list of labels to be completed */ 5384 for (s = 0; s < Nds; ++s) { 5385 PetscDS dsBC; 5386 PetscInt numBd, bd; 5387 5388 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5389 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5390 for (bd = 0; bd < numBd; ++bd) { 5391 DMLabel label; 5392 PetscInt field; 5393 PetscObject obj; 5394 PetscClassId id; 5395 5396 PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 5397 PetscCall(DMGetField(dm, field, NULL, &obj)); 5398 PetscCall(PetscObjectGetClassId(obj, &id)); 5399 if (!(id == PETSCFE_CLASSID) || !label) continue; 5400 for (l = 0; l < Nl; ++l) 5401 if (labels[l] == label) break; 5402 if (l == Nl) labels[Nl++] = label; 5403 } 5404 } 5405 /* Get label names */ 5406 PetscCall(PetscMalloc1(Nl, &names)); 5407 for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l])); 5408 for (l = 0; l < Nl; ++l) { 5409 PetscCall(PetscStrlen(names[l], &len)); 5410 maxLen = PetscMax(maxLen, (PetscInt)len + 2); 5411 } 5412 PetscCall(PetscFree(labels)); 5413 PetscCall(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm)); 5414 PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames)); 5415 for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen)); 5416 PetscCall(PetscFree(names)); 5417 /* Put all names on all processes */ 5418 PetscCall(PetscCalloc2(size, &counts, size + 1, &displs)); 5419 PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm)); 5420 for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p]; 5421 gNl = displs[size]; 5422 for (p = 0; p < size; ++p) { 5423 counts[p] *= gmaxLen; 5424 displs[p] *= gmaxLen; 5425 } 5426 PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels)); 5427 PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm)); 5428 PetscCall(PetscFree2(counts, displs)); 5429 PetscCall(PetscFree(sendNames)); 5430 for (l = 0, gl = 0; l < gNl; ++l) { 5431 PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl])); 5432 PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank); 5433 for (m = 0; m < gl; ++m) 5434 if (glabels[m] == glabels[gl]) continue; 5435 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5436 PetscCall(DMPlexLabelComplete(plex, glabels[gl])); 5437 PetscCall(DMDestroy(&plex)); 5438 ++gl; 5439 } 5440 PetscCall(PetscFree2(recvNames, glabels)); 5441 PetscFunctionReturn(PETSC_SUCCESS); 5442 } 5443 5444 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew) 5445 { 5446 DMSpace *tmpd; 5447 PetscInt Nds = dm->Nds, s; 5448 5449 PetscFunctionBegin; 5450 if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS); 5451 PetscCall(PetscMalloc1(NdsNew, &tmpd)); 5452 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s]; 5453 for (s = Nds; s < NdsNew; ++s) { 5454 tmpd[s].ds = NULL; 5455 tmpd[s].label = NULL; 5456 tmpd[s].fields = NULL; 5457 } 5458 PetscCall(PetscFree(dm->probs)); 5459 dm->Nds = NdsNew; 5460 dm->probs = tmpd; 5461 PetscFunctionReturn(PETSC_SUCCESS); 5462 } 5463 5464 /*@ 5465 DMGetNumDS - Get the number of discrete systems in the `DM` 5466 5467 Not Collective 5468 5469 Input Parameter: 5470 . dm - The `DM` 5471 5472 Output Parameter: 5473 . Nds - The number of `PetscDS` objects 5474 5475 Level: intermediate 5476 5477 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()` 5478 @*/ 5479 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds) 5480 { 5481 PetscFunctionBegin; 5482 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5483 PetscAssertPointer(Nds, 2); 5484 *Nds = dm->Nds; 5485 PetscFunctionReturn(PETSC_SUCCESS); 5486 } 5487 5488 /*@ 5489 DMClearDS - Remove all discrete systems from the `DM` 5490 5491 Logically Collective 5492 5493 Input Parameter: 5494 . dm - The `DM` 5495 5496 Level: intermediate 5497 5498 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()` 5499 @*/ 5500 PetscErrorCode DMClearDS(DM dm) 5501 { 5502 PetscInt s; 5503 5504 PetscFunctionBegin; 5505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5506 for (s = 0; s < dm->Nds; ++s) { 5507 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5508 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5509 PetscCall(DMLabelDestroy(&dm->probs[s].label)); 5510 PetscCall(ISDestroy(&dm->probs[s].fields)); 5511 } 5512 PetscCall(PetscFree(dm->probs)); 5513 dm->probs = NULL; 5514 dm->Nds = 0; 5515 PetscFunctionReturn(PETSC_SUCCESS); 5516 } 5517 5518 /*@ 5519 DMGetDS - Get the default `PetscDS` 5520 5521 Not Collective 5522 5523 Input Parameter: 5524 . dm - The `DM` 5525 5526 Output Parameter: 5527 . ds - The default `PetscDS` 5528 5529 Level: intermediate 5530 5531 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()` 5532 @*/ 5533 PetscErrorCode DMGetDS(DM dm, PetscDS *ds) 5534 { 5535 PetscFunctionBeginHot; 5536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5537 PetscAssertPointer(ds, 2); 5538 PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()"); 5539 *ds = dm->probs[0].ds; 5540 PetscFunctionReturn(PETSC_SUCCESS); 5541 } 5542 5543 /*@ 5544 DMGetCellDS - Get the `PetscDS` defined on a given cell 5545 5546 Not Collective 5547 5548 Input Parameters: 5549 + dm - The `DM` 5550 - point - Cell for the `PetscDS` 5551 5552 Output Parameters: 5553 + ds - The `PetscDS` defined on the given cell 5554 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds 5555 5556 Level: developer 5557 5558 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()` 5559 @*/ 5560 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn) 5561 { 5562 PetscDS dsDef = NULL; 5563 PetscInt s; 5564 5565 PetscFunctionBeginHot; 5566 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5567 if (ds) PetscAssertPointer(ds, 3); 5568 if (dsIn) PetscAssertPointer(dsIn, 4); 5569 PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point); 5570 if (ds) *ds = NULL; 5571 if (dsIn) *dsIn = NULL; 5572 for (s = 0; s < dm->Nds; ++s) { 5573 PetscInt val; 5574 5575 if (!dm->probs[s].label) { 5576 dsDef = dm->probs[s].ds; 5577 } else { 5578 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val)); 5579 if (val >= 0) { 5580 if (ds) *ds = dm->probs[s].ds; 5581 if (dsIn) *dsIn = dm->probs[s].dsIn; 5582 break; 5583 } 5584 } 5585 } 5586 if (ds && !*ds) *ds = dsDef; 5587 PetscFunctionReturn(PETSC_SUCCESS); 5588 } 5589 5590 /*@ 5591 DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel` 5592 5593 Not Collective 5594 5595 Input Parameters: 5596 + dm - The `DM` 5597 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5598 5599 Output Parameters: 5600 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5601 . ds - The `PetscDS` defined on the given region, or `NULL` 5602 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5603 5604 Level: advanced 5605 5606 Note: 5607 If a non-`NULL` label is given, but there is no `PetscDS` on that specific label, 5608 the `PetscDS` for the full domain (if present) is returned. Returns with 5609 fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain. 5610 5611 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5612 @*/ 5613 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5614 { 5615 PetscInt Nds = dm->Nds, s; 5616 5617 PetscFunctionBegin; 5618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5619 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5620 if (fields) { 5621 PetscAssertPointer(fields, 3); 5622 *fields = NULL; 5623 } 5624 if (ds) { 5625 PetscAssertPointer(ds, 4); 5626 *ds = NULL; 5627 } 5628 if (dsIn) { 5629 PetscAssertPointer(dsIn, 5); 5630 *dsIn = NULL; 5631 } 5632 for (s = 0; s < Nds; ++s) { 5633 if (dm->probs[s].label == label || !dm->probs[s].label) { 5634 if (fields) *fields = dm->probs[s].fields; 5635 if (ds) *ds = dm->probs[s].ds; 5636 if (dsIn) *dsIn = dm->probs[s].dsIn; 5637 if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS); 5638 } 5639 } 5640 PetscFunctionReturn(PETSC_SUCCESS); 5641 } 5642 5643 /*@ 5644 DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel` 5645 5646 Collective 5647 5648 Input Parameters: 5649 + dm - The `DM` 5650 . label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5651 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields 5652 . ds - The `PetscDS` defined on the given region 5653 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5654 5655 Level: advanced 5656 5657 Note: 5658 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced, 5659 the fields argument is ignored. 5660 5661 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()` 5662 @*/ 5663 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5664 { 5665 PetscInt Nds = dm->Nds, s; 5666 5667 PetscFunctionBegin; 5668 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5669 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5670 if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3); 5671 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4); 5672 if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5); 5673 for (s = 0; s < Nds; ++s) { 5674 if (dm->probs[s].label == label) { 5675 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5676 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5677 dm->probs[s].ds = ds; 5678 dm->probs[s].dsIn = dsIn; 5679 PetscFunctionReturn(PETSC_SUCCESS); 5680 } 5681 } 5682 PetscCall(DMDSEnlarge_Static(dm, Nds + 1)); 5683 PetscCall(PetscObjectReference((PetscObject)label)); 5684 PetscCall(PetscObjectReference((PetscObject)fields)); 5685 PetscCall(PetscObjectReference((PetscObject)ds)); 5686 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5687 if (!label) { 5688 /* Put the NULL label at the front, so it is returned as the default */ 5689 for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s]; 5690 Nds = 0; 5691 } 5692 dm->probs[Nds].label = label; 5693 dm->probs[Nds].fields = fields; 5694 dm->probs[Nds].ds = ds; 5695 dm->probs[Nds].dsIn = dsIn; 5696 PetscFunctionReturn(PETSC_SUCCESS); 5697 } 5698 5699 /*@ 5700 DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number 5701 5702 Not Collective 5703 5704 Input Parameters: 5705 + dm - The `DM` 5706 - num - The region number, in [0, Nds) 5707 5708 Output Parameters: 5709 + label - The region label, or `NULL` 5710 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5711 . ds - The `PetscDS` defined on the given region, or `NULL` 5712 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5713 5714 Level: advanced 5715 5716 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5717 @*/ 5718 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5719 { 5720 PetscInt Nds; 5721 5722 PetscFunctionBegin; 5723 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5724 PetscCall(DMGetNumDS(dm, &Nds)); 5725 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5726 if (label) { 5727 PetscAssertPointer(label, 3); 5728 *label = dm->probs[num].label; 5729 } 5730 if (fields) { 5731 PetscAssertPointer(fields, 4); 5732 *fields = dm->probs[num].fields; 5733 } 5734 if (ds) { 5735 PetscAssertPointer(ds, 5); 5736 *ds = dm->probs[num].ds; 5737 } 5738 if (dsIn) { 5739 PetscAssertPointer(dsIn, 6); 5740 *dsIn = dm->probs[num].dsIn; 5741 } 5742 PetscFunctionReturn(PETSC_SUCCESS); 5743 } 5744 5745 /*@ 5746 DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number 5747 5748 Not Collective 5749 5750 Input Parameters: 5751 + dm - The `DM` 5752 . num - The region number, in [0, Nds) 5753 . label - The region label, or `NULL` 5754 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting 5755 . ds - The `PetscDS` defined on the given region, or `NULL` to prevent setting 5756 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5757 5758 Level: advanced 5759 5760 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5761 @*/ 5762 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5763 { 5764 PetscInt Nds; 5765 5766 PetscFunctionBegin; 5767 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5768 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5769 PetscCall(DMGetNumDS(dm, &Nds)); 5770 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5771 PetscCall(PetscObjectReference((PetscObject)label)); 5772 PetscCall(DMLabelDestroy(&dm->probs[num].label)); 5773 dm->probs[num].label = label; 5774 if (fields) { 5775 PetscValidHeaderSpecific(fields, IS_CLASSID, 4); 5776 PetscCall(PetscObjectReference((PetscObject)fields)); 5777 PetscCall(ISDestroy(&dm->probs[num].fields)); 5778 dm->probs[num].fields = fields; 5779 } 5780 if (ds) { 5781 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5); 5782 PetscCall(PetscObjectReference((PetscObject)ds)); 5783 PetscCall(PetscDSDestroy(&dm->probs[num].ds)); 5784 dm->probs[num].ds = ds; 5785 } 5786 if (dsIn) { 5787 PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6); 5788 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5789 PetscCall(PetscDSDestroy(&dm->probs[num].dsIn)); 5790 dm->probs[num].dsIn = dsIn; 5791 } 5792 PetscFunctionReturn(PETSC_SUCCESS); 5793 } 5794 5795 /*@ 5796 DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found. 5797 5798 Not Collective 5799 5800 Input Parameters: 5801 + dm - The `DM` 5802 - ds - The `PetscDS` defined on the given region 5803 5804 Output Parameter: 5805 . num - The region number, in [0, Nds), or -1 if not found 5806 5807 Level: advanced 5808 5809 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5810 @*/ 5811 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num) 5812 { 5813 PetscInt Nds, n; 5814 5815 PetscFunctionBegin; 5816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5817 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2); 5818 PetscAssertPointer(num, 3); 5819 PetscCall(DMGetNumDS(dm, &Nds)); 5820 for (n = 0; n < Nds; ++n) 5821 if (ds == dm->probs[n].ds) break; 5822 if (n >= Nds) *num = -1; 5823 else *num = n; 5824 PetscFunctionReturn(PETSC_SUCCESS); 5825 } 5826 5827 /*@ 5828 DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh 5829 5830 Not Collective 5831 5832 Input Parameters: 5833 + dm - The `DM` 5834 . Nc - The number of components for the field 5835 . prefix - The options prefix for the output `PetscFE`, or `NULL` 5836 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree 5837 5838 Output Parameter: 5839 . fem - The `PetscFE` 5840 5841 Level: intermediate 5842 5843 Note: 5844 This is a convenience method that just calls `PetscFECreateByCell()` underneath. 5845 5846 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()` 5847 @*/ 5848 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem) 5849 { 5850 DMPolytopeType ct; 5851 PetscInt dim, cStart; 5852 5853 PetscFunctionBegin; 5854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5855 PetscValidLogicalCollectiveInt(dm, Nc, 2); 5856 if (prefix) PetscAssertPointer(prefix, 3); 5857 PetscValidLogicalCollectiveInt(dm, qorder, 4); 5858 PetscAssertPointer(fem, 5); 5859 PetscCall(DMGetDimension(dm, &dim)); 5860 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 5861 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 5862 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem)); 5863 PetscFunctionReturn(PETSC_SUCCESS); 5864 } 5865 5866 /*@ 5867 DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM` 5868 5869 Collective 5870 5871 Input Parameter: 5872 . dm - The `DM` 5873 5874 Options Database Key: 5875 . -dm_petscds_view - View all the `PetscDS` objects in this `DM` 5876 5877 Level: intermediate 5878 5879 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 5880 @*/ 5881 PetscErrorCode DMCreateDS(DM dm) 5882 { 5883 MPI_Comm comm; 5884 PetscDS dsDef; 5885 DMLabel *labelSet; 5886 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k; 5887 PetscBool doSetup = PETSC_TRUE, flg; 5888 5889 PetscFunctionBegin; 5890 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5891 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); 5892 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5893 PetscCall(DMGetCoordinateDim(dm, &dE)); 5894 /* Determine how many regions we have */ 5895 PetscCall(PetscMalloc1(Nf, &labelSet)); 5896 Nl = 0; 5897 Ndef = 0; 5898 for (f = 0; f < Nf; ++f) { 5899 DMLabel label = dm->fields[f].label; 5900 PetscInt l; 5901 5902 #ifdef PETSC_HAVE_LIBCEED 5903 /* Move CEED context to discretizations */ 5904 { 5905 PetscClassId id; 5906 5907 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id)); 5908 if (id == PETSCFE_CLASSID) { 5909 Ceed ceed; 5910 5911 PetscCall(DMGetCeed(dm, &ceed)); 5912 PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed)); 5913 } 5914 } 5915 #endif 5916 if (!label) { 5917 ++Ndef; 5918 continue; 5919 } 5920 for (l = 0; l < Nl; ++l) 5921 if (label == labelSet[l]) break; 5922 if (l < Nl) continue; 5923 labelSet[Nl++] = label; 5924 } 5925 /* Create default DS if there are no labels to intersect with */ 5926 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5927 if (!dsDef && Ndef && !Nl) { 5928 IS fields; 5929 PetscInt *fld, nf; 5930 5931 for (f = 0, nf = 0; f < Nf; ++f) 5932 if (!dm->fields[f].label) ++nf; 5933 PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS"); 5934 PetscCall(PetscMalloc1(nf, &fld)); 5935 for (f = 0, nf = 0; f < Nf; ++f) 5936 if (!dm->fields[f].label) fld[nf++] = f; 5937 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5938 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5939 PetscCall(ISSetType(fields, ISGENERAL)); 5940 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5941 5942 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5943 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL)); 5944 PetscCall(PetscDSDestroy(&dsDef)); 5945 PetscCall(ISDestroy(&fields)); 5946 } 5947 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5948 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5949 /* Intersect labels with default fields */ 5950 if (Ndef && Nl) { 5951 DM plex; 5952 DMLabel cellLabel; 5953 IS fieldIS, allcellIS, defcellIS = NULL; 5954 PetscInt *fields; 5955 const PetscInt *cells; 5956 PetscInt depth, nf = 0, n, c; 5957 5958 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5959 PetscCall(DMPlexGetDepth(plex, &depth)); 5960 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS)); 5961 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS)); 5962 /* TODO This looks like it only works for one label */ 5963 for (l = 0; l < Nl; ++l) { 5964 DMLabel label = labelSet[l]; 5965 IS pointIS; 5966 5967 PetscCall(ISDestroy(&defcellIS)); 5968 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 5969 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS)); 5970 PetscCall(ISDestroy(&pointIS)); 5971 } 5972 PetscCall(ISDestroy(&allcellIS)); 5973 5974 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel)); 5975 PetscCall(ISGetLocalSize(defcellIS, &n)); 5976 PetscCall(ISGetIndices(defcellIS, &cells)); 5977 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1)); 5978 PetscCall(ISRestoreIndices(defcellIS, &cells)); 5979 PetscCall(ISDestroy(&defcellIS)); 5980 PetscCall(DMPlexLabelComplete(plex, cellLabel)); 5981 5982 PetscCall(PetscMalloc1(Ndef, &fields)); 5983 for (f = 0; f < Nf; ++f) 5984 if (!dm->fields[f].label) fields[nf++] = f; 5985 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS)); 5986 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_")); 5987 PetscCall(ISSetType(fieldIS, ISGENERAL)); 5988 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER)); 5989 5990 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5991 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL)); 5992 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5993 PetscCall(DMLabelDestroy(&cellLabel)); 5994 PetscCall(PetscDSDestroy(&dsDef)); 5995 PetscCall(ISDestroy(&fieldIS)); 5996 PetscCall(DMDestroy(&plex)); 5997 } 5998 /* Create label DSes 5999 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS 6000 */ 6001 /* TODO Should check that labels are disjoint */ 6002 for (l = 0; l < Nl; ++l) { 6003 DMLabel label = labelSet[l]; 6004 PetscDS ds, dsIn = NULL; 6005 IS fields; 6006 PetscInt *fld, nf; 6007 6008 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 6009 for (f = 0, nf = 0; f < Nf; ++f) 6010 if (label == dm->fields[f].label || !dm->fields[f].label) ++nf; 6011 PetscCall(PetscMalloc1(nf, &fld)); 6012 for (f = 0, nf = 0; f < Nf; ++f) 6013 if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f; 6014 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 6015 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 6016 PetscCall(ISSetType(fields, ISGENERAL)); 6017 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 6018 PetscCall(PetscDSSetCoordinateDimension(ds, dE)); 6019 { 6020 DMPolytopeType ct; 6021 PetscInt lStart, lEnd; 6022 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive; 6023 6024 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd)); 6025 if (lStart >= 0) { 6026 PetscCall(DMPlexGetCellType(dm, lStart, &ct)); 6027 switch (ct) { 6028 case DM_POLYTOPE_POINT_PRISM_TENSOR: 6029 case DM_POLYTOPE_SEG_PRISM_TENSOR: 6030 case DM_POLYTOPE_TRI_PRISM_TENSOR: 6031 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 6032 isCohesiveLocal = PETSC_TRUE; 6033 break; 6034 default: 6035 break; 6036 } 6037 } 6038 PetscCall(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm)); 6039 if (isCohesive) { 6040 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn)); 6041 PetscCall(PetscDSSetCoordinateDimension(dsIn, dE)); 6042 } 6043 for (f = 0, nf = 0; f < Nf; ++f) { 6044 if (label == dm->fields[f].label || !dm->fields[f].label) { 6045 if (label == dm->fields[f].label) { 6046 PetscCall(PetscDSSetDiscretization(ds, nf, NULL)); 6047 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive)); 6048 if (dsIn) { 6049 PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL)); 6050 PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive)); 6051 } 6052 } 6053 ++nf; 6054 } 6055 } 6056 } 6057 PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn)); 6058 PetscCall(ISDestroy(&fields)); 6059 PetscCall(PetscDSDestroy(&ds)); 6060 PetscCall(PetscDSDestroy(&dsIn)); 6061 } 6062 PetscCall(PetscFree(labelSet)); 6063 /* Set fields in DSes */ 6064 for (s = 0; s < dm->Nds; ++s) { 6065 PetscDS ds = dm->probs[s].ds; 6066 PetscDS dsIn = dm->probs[s].dsIn; 6067 IS fields = dm->probs[s].fields; 6068 const PetscInt *fld; 6069 PetscInt nf, dsnf; 6070 PetscBool isCohesive; 6071 6072 PetscCall(PetscDSGetNumFields(ds, &dsnf)); 6073 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 6074 PetscCall(ISGetLocalSize(fields, &nf)); 6075 PetscCall(ISGetIndices(fields, &fld)); 6076 for (f = 0; f < nf; ++f) { 6077 PetscObject disc = dm->fields[fld[f]].disc; 6078 PetscBool isCohesiveField; 6079 PetscClassId id; 6080 6081 /* Handle DS with no fields */ 6082 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 6083 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */ 6084 if (isCohesive) { 6085 if (!isCohesiveField) { 6086 PetscObject bdDisc; 6087 6088 PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc)); 6089 PetscCall(PetscDSSetDiscretization(ds, f, bdDisc)); 6090 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6091 } else { 6092 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6093 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6094 } 6095 } else { 6096 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6097 } 6098 /* We allow people to have placeholder fields and construct the Section by hand */ 6099 PetscCall(PetscObjectGetClassId(disc, &id)); 6100 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE; 6101 } 6102 PetscCall(ISRestoreIndices(fields, &fld)); 6103 } 6104 /* Allow k-jet tabulation */ 6105 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg)); 6106 if (flg) { 6107 for (s = 0; s < dm->Nds; ++s) { 6108 PetscDS ds = dm->probs[s].ds; 6109 PetscDS dsIn = dm->probs[s].dsIn; 6110 PetscInt Nf, f; 6111 6112 PetscCall(PetscDSGetNumFields(ds, &Nf)); 6113 for (f = 0; f < Nf; ++f) { 6114 PetscCall(PetscDSSetJetDegree(ds, f, k)); 6115 if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k)); 6116 } 6117 } 6118 } 6119 /* Setup DSes */ 6120 if (doSetup) { 6121 for (s = 0; s < dm->Nds; ++s) { 6122 if (dm->setfromoptionscalled) { 6123 PetscCall(PetscDSSetFromOptions(dm->probs[s].ds)); 6124 if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn)); 6125 } 6126 PetscCall(PetscDSSetUp(dm->probs[s].ds)); 6127 if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn)); 6128 } 6129 } 6130 PetscFunctionReturn(PETSC_SUCCESS); 6131 } 6132 6133 /*@ 6134 DMUseTensorOrder - Use a tensor product closure ordering for the default section 6135 6136 Input Parameters: 6137 + dm - The DM 6138 - tensor - Flag for tensor order 6139 6140 Level: developer 6141 6142 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()` 6143 @*/ 6144 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor) 6145 { 6146 PetscInt Nf; 6147 PetscBool reorder = PETSC_TRUE, isPlex; 6148 6149 PetscFunctionBegin; 6150 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 6151 PetscCall(DMGetNumFields(dm, &Nf)); 6152 for (PetscInt f = 0; f < Nf; ++f) { 6153 PetscObject obj; 6154 PetscClassId id; 6155 6156 PetscCall(DMGetField(dm, f, NULL, &obj)); 6157 PetscCall(PetscObjectGetClassId(obj, &id)); 6158 if (id == PETSCFE_CLASSID) { 6159 PetscSpace sp; 6160 PetscBool tensor; 6161 6162 PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp)); 6163 PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor)); 6164 reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE; 6165 } else reorder = PETSC_FALSE; 6166 } 6167 if (tensor) { 6168 if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 6169 } else { 6170 PetscSection s; 6171 6172 PetscCall(DMGetLocalSection(dm, &s)); 6173 if (s) PetscCall(PetscSectionResetClosurePermutation(s)); 6174 } 6175 PetscFunctionReturn(PETSC_SUCCESS); 6176 } 6177 6178 /*@ 6179 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information. 6180 6181 Collective 6182 6183 Input Parameters: 6184 + dm - The `DM` 6185 - time - The time 6186 6187 Output Parameters: 6188 + u - The vector will be filled with exact solution values, or `NULL` 6189 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL` 6190 6191 Level: developer 6192 6193 Note: 6194 The user must call `PetscDSSetExactSolution()` before using this routine 6195 6196 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()` 6197 @*/ 6198 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 6199 { 6200 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 6201 void **ectxs; 6202 Vec locu, locu_t; 6203 PetscInt Nf, Nds, s; 6204 6205 PetscFunctionBegin; 6206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6207 if (u) { 6208 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 6209 PetscCall(DMGetLocalVector(dm, &locu)); 6210 PetscCall(VecSet(locu, 0.)); 6211 } 6212 if (u_t) { 6213 PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 6214 PetscCall(DMGetLocalVector(dm, &locu_t)); 6215 PetscCall(VecSet(locu_t, 0.)); 6216 } 6217 PetscCall(DMGetNumFields(dm, &Nf)); 6218 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 6219 PetscCall(DMGetNumDS(dm, &Nds)); 6220 for (s = 0; s < Nds; ++s) { 6221 PetscDS ds; 6222 DMLabel label; 6223 IS fieldIS; 6224 const PetscInt *fields, id = 1; 6225 PetscInt dsNf, f; 6226 6227 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 6228 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 6229 PetscCall(ISGetIndices(fieldIS, &fields)); 6230 PetscCall(PetscArrayzero(exacts, Nf)); 6231 PetscCall(PetscArrayzero(ectxs, Nf)); 6232 if (u) { 6233 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6234 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6235 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6236 } 6237 if (u_t) { 6238 PetscCall(PetscArrayzero(exacts, Nf)); 6239 PetscCall(PetscArrayzero(ectxs, Nf)); 6240 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6241 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6242 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6243 } 6244 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6245 } 6246 if (u) { 6247 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution")); 6248 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_")); 6249 } 6250 if (u_t) { 6251 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative")); 6252 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_")); 6253 } 6254 PetscCall(PetscFree2(exacts, ectxs)); 6255 if (u) { 6256 PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u)); 6257 PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u)); 6258 PetscCall(DMRestoreLocalVector(dm, &locu)); 6259 } 6260 if (u_t) { 6261 PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6262 PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6263 PetscCall(DMRestoreLocalVector(dm, &locu_t)); 6264 } 6265 PetscFunctionReturn(PETSC_SUCCESS); 6266 } 6267 6268 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 6269 { 6270 PetscDS dsNew, dsInNew = NULL; 6271 6272 PetscFunctionBegin; 6273 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew)); 6274 PetscCall(PetscDSCopy(ds, dm, dsNew)); 6275 if (dsIn) { 6276 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew)); 6277 PetscCall(PetscDSCopy(dsIn, dm, dsInNew)); 6278 } 6279 PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew)); 6280 PetscCall(PetscDSDestroy(&dsNew)); 6281 PetscCall(PetscDSDestroy(&dsInNew)); 6282 PetscFunctionReturn(PETSC_SUCCESS); 6283 } 6284 6285 /*@ 6286 DMCopyDS - Copy the discrete systems for the `DM` into another `DM` 6287 6288 Collective 6289 6290 Input Parameter: 6291 . dm - The `DM` 6292 6293 Output Parameter: 6294 . newdm - The `DM` 6295 6296 Level: advanced 6297 6298 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 6299 @*/ 6300 PetscErrorCode DMCopyDS(DM dm, DM newdm) 6301 { 6302 PetscInt Nds, s; 6303 6304 PetscFunctionBegin; 6305 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 6306 PetscCall(DMGetNumDS(dm, &Nds)); 6307 PetscCall(DMClearDS(newdm)); 6308 for (s = 0; s < Nds; ++s) { 6309 DMLabel label; 6310 IS fields; 6311 PetscDS ds, dsIn, newds; 6312 PetscInt Nbd, bd; 6313 6314 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn)); 6315 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 6316 PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn)); 6317 /* Complete new labels in the new DS */ 6318 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL)); 6319 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 6320 for (bd = 0; bd < Nbd; ++bd) { 6321 PetscWeakForm wf; 6322 DMLabel label; 6323 PetscInt field; 6324 6325 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 6326 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 6327 } 6328 } 6329 PetscCall(DMCompleteBCLabels_Internal(newdm)); 6330 PetscFunctionReturn(PETSC_SUCCESS); 6331 } 6332 6333 /*@ 6334 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM` 6335 6336 Collective 6337 6338 Input Parameter: 6339 . dm - The `DM` 6340 6341 Output Parameter: 6342 . newdm - The `DM` 6343 6344 Level: advanced 6345 6346 Developer Note: 6347 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation 6348 6349 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()` 6350 @*/ 6351 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6352 { 6353 PetscFunctionBegin; 6354 PetscCall(DMCopyFields(dm, newdm)); 6355 PetscCall(DMCopyDS(dm, newdm)); 6356 PetscFunctionReturn(PETSC_SUCCESS); 6357 } 6358 6359 /*@ 6360 DMGetDimension - Return the topological dimension of the `DM` 6361 6362 Not Collective 6363 6364 Input Parameter: 6365 . dm - The `DM` 6366 6367 Output Parameter: 6368 . dim - The topological dimension 6369 6370 Level: beginner 6371 6372 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()` 6373 @*/ 6374 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6375 { 6376 PetscFunctionBegin; 6377 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6378 PetscAssertPointer(dim, 2); 6379 *dim = dm->dim; 6380 PetscFunctionReturn(PETSC_SUCCESS); 6381 } 6382 6383 /*@ 6384 DMSetDimension - Set the topological dimension of the `DM` 6385 6386 Collective 6387 6388 Input Parameters: 6389 + dm - The `DM` 6390 - dim - The topological dimension 6391 6392 Level: beginner 6393 6394 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()` 6395 @*/ 6396 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6397 { 6398 PetscDS ds; 6399 PetscInt Nds, n; 6400 6401 PetscFunctionBegin; 6402 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6403 PetscValidLogicalCollectiveInt(dm, dim, 2); 6404 dm->dim = dim; 6405 if (dm->dim >= 0) { 6406 PetscCall(DMGetNumDS(dm, &Nds)); 6407 for (n = 0; n < Nds; ++n) { 6408 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL)); 6409 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6410 } 6411 } 6412 PetscFunctionReturn(PETSC_SUCCESS); 6413 } 6414 6415 /*@ 6416 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6417 6418 Collective 6419 6420 Input Parameters: 6421 + dm - the `DM` 6422 - dim - the dimension 6423 6424 Output Parameters: 6425 + pStart - The first point of the given dimension 6426 - pEnd - The first point following points of the given dimension 6427 6428 Level: intermediate 6429 6430 Note: 6431 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6432 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6433 then the interval is empty. 6434 6435 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 6436 @*/ 6437 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6438 { 6439 PetscInt d; 6440 6441 PetscFunctionBegin; 6442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6443 PetscCall(DMGetDimension(dm, &d)); 6444 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6445 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd); 6446 PetscFunctionReturn(PETSC_SUCCESS); 6447 } 6448 6449 /*@ 6450 DMGetOutputDM - Retrieve the `DM` associated with the layout for output 6451 6452 Collective 6453 6454 Input Parameter: 6455 . dm - The original `DM` 6456 6457 Output Parameter: 6458 . odm - The `DM` which provides the layout for output 6459 6460 Level: intermediate 6461 6462 Note: 6463 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary 6464 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the 6465 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof. 6466 6467 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()` 6468 @*/ 6469 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 6470 { 6471 PetscSection section; 6472 IS perm; 6473 PetscBool hasConstraints, newDM, gnewDM; 6474 6475 PetscFunctionBegin; 6476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6477 PetscAssertPointer(odm, 2); 6478 PetscCall(DMGetLocalSection(dm, §ion)); 6479 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 6480 PetscCall(PetscSectionGetPermutation(section, &perm)); 6481 newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE; 6482 PetscCall(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 6483 if (!gnewDM) { 6484 *odm = dm; 6485 PetscFunctionReturn(PETSC_SUCCESS); 6486 } 6487 if (!dm->dmBC) { 6488 PetscSection newSection, gsection; 6489 PetscSF sf; 6490 PetscBool usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE; 6491 6492 PetscCall(DMClone(dm, &dm->dmBC)); 6493 PetscCall(DMCopyDisc(dm, dm->dmBC)); 6494 PetscCall(PetscSectionClone(section, &newSection)); 6495 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 6496 PetscCall(PetscSectionDestroy(&newSection)); 6497 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 6498 PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection)); 6499 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 6500 PetscCall(PetscSectionDestroy(&gsection)); 6501 } 6502 *odm = dm->dmBC; 6503 PetscFunctionReturn(PETSC_SUCCESS); 6504 } 6505 6506 /*@ 6507 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 6508 6509 Input Parameter: 6510 . dm - The original `DM` 6511 6512 Output Parameters: 6513 + num - The output sequence number 6514 - val - The output sequence value 6515 6516 Level: intermediate 6517 6518 Note: 6519 This is intended for output that should appear in sequence, for instance 6520 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6521 6522 Developer Note: 6523 The `DM` serves as a convenient place to store the current iteration value. The iteration is not 6524 not directly related to the `DM`. 6525 6526 .seealso: [](ch_dmbase), `DM`, `VecView()` 6527 @*/ 6528 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 6529 { 6530 PetscFunctionBegin; 6531 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6532 if (num) { 6533 PetscAssertPointer(num, 2); 6534 *num = dm->outputSequenceNum; 6535 } 6536 if (val) { 6537 PetscAssertPointer(val, 3); 6538 *val = dm->outputSequenceVal; 6539 } 6540 PetscFunctionReturn(PETSC_SUCCESS); 6541 } 6542 6543 /*@ 6544 DMSetOutputSequenceNumber - Set the sequence number/value for output 6545 6546 Input Parameters: 6547 + dm - The original `DM` 6548 . num - The output sequence number 6549 - val - The output sequence value 6550 6551 Level: intermediate 6552 6553 Note: 6554 This is intended for output that should appear in sequence, for instance 6555 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6556 6557 .seealso: [](ch_dmbase), `DM`, `VecView()` 6558 @*/ 6559 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 6560 { 6561 PetscFunctionBegin; 6562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6563 dm->outputSequenceNum = num; 6564 dm->outputSequenceVal = val; 6565 PetscFunctionReturn(PETSC_SUCCESS); 6566 } 6567 6568 /*@ 6569 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer` 6570 6571 Input Parameters: 6572 + dm - The original `DM` 6573 . viewer - The `PetscViewer` to get it from 6574 . name - The sequence name 6575 - num - The output sequence number 6576 6577 Output Parameter: 6578 . val - The output sequence value 6579 6580 Level: intermediate 6581 6582 Note: 6583 This is intended for output that should appear in sequence, for instance 6584 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6585 6586 Developer Note: 6587 It is unclear at the user API level why a `DM` is needed as input 6588 6589 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6590 @*/ 6591 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val) 6592 { 6593 PetscBool ishdf5; 6594 6595 PetscFunctionBegin; 6596 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6597 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6598 PetscAssertPointer(name, 3); 6599 PetscAssertPointer(val, 5); 6600 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6601 if (ishdf5) { 6602 #if defined(PETSC_HAVE_HDF5) 6603 PetscScalar value; 6604 6605 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 6606 *val = PetscRealPart(value); 6607 #endif 6608 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6609 PetscFunctionReturn(PETSC_SUCCESS); 6610 } 6611 6612 /*@ 6613 DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer` 6614 6615 Input Parameters: 6616 + dm - The original `DM` 6617 . viewer - The `PetscViewer` to get it from 6618 - name - The sequence name 6619 6620 Output Parameter: 6621 . len - The length of the output sequence 6622 6623 Level: intermediate 6624 6625 Note: 6626 This is intended for output that should appear in sequence, for instance 6627 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6628 6629 Developer Note: 6630 It is unclear at the user API level why a `DM` is needed as input 6631 6632 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6633 @*/ 6634 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len) 6635 { 6636 PetscBool ishdf5; 6637 6638 PetscFunctionBegin; 6639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6640 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6641 PetscAssertPointer(name, 3); 6642 PetscAssertPointer(len, 4); 6643 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6644 if (ishdf5) { 6645 #if defined(PETSC_HAVE_HDF5) 6646 PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer)); 6647 #endif 6648 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6649 PetscFunctionReturn(PETSC_SUCCESS); 6650 } 6651 6652 /*@ 6653 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6654 6655 Not Collective 6656 6657 Input Parameter: 6658 . dm - The `DM` 6659 6660 Output Parameter: 6661 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6662 6663 Level: beginner 6664 6665 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()` 6666 @*/ 6667 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6668 { 6669 PetscFunctionBegin; 6670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6671 PetscAssertPointer(useNatural, 2); 6672 *useNatural = dm->useNatural; 6673 PetscFunctionReturn(PETSC_SUCCESS); 6674 } 6675 6676 /*@ 6677 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6678 6679 Collective 6680 6681 Input Parameters: 6682 + dm - The `DM` 6683 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6684 6685 Level: beginner 6686 6687 Note: 6688 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6689 6690 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6691 @*/ 6692 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6693 { 6694 PetscFunctionBegin; 6695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6696 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6697 dm->useNatural = useNatural; 6698 PetscFunctionReturn(PETSC_SUCCESS); 6699 } 6700 6701 /*@ 6702 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6703 6704 Not Collective 6705 6706 Input Parameters: 6707 + dm - The `DM` object 6708 - name - The label name 6709 6710 Level: intermediate 6711 6712 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6713 @*/ 6714 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6715 { 6716 PetscBool flg; 6717 DMLabel label; 6718 6719 PetscFunctionBegin; 6720 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6721 PetscAssertPointer(name, 2); 6722 PetscCall(DMHasLabel(dm, name, &flg)); 6723 if (!flg) { 6724 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6725 PetscCall(DMAddLabel(dm, label)); 6726 PetscCall(DMLabelDestroy(&label)); 6727 } 6728 PetscFunctionReturn(PETSC_SUCCESS); 6729 } 6730 6731 /*@ 6732 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6733 6734 Not Collective 6735 6736 Input Parameters: 6737 + dm - The `DM` object 6738 . l - The index for the label 6739 - name - The label name 6740 6741 Level: intermediate 6742 6743 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6744 @*/ 6745 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6746 { 6747 DMLabelLink orig, prev = NULL; 6748 DMLabel label; 6749 PetscInt Nl, m; 6750 PetscBool flg, match; 6751 const char *lname; 6752 6753 PetscFunctionBegin; 6754 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6755 PetscAssertPointer(name, 3); 6756 PetscCall(DMHasLabel(dm, name, &flg)); 6757 if (!flg) { 6758 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6759 PetscCall(DMAddLabel(dm, label)); 6760 PetscCall(DMLabelDestroy(&label)); 6761 } 6762 PetscCall(DMGetNumLabels(dm, &Nl)); 6763 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6764 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6765 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6766 PetscCall(PetscStrcmp(name, lname, &match)); 6767 if (match) break; 6768 } 6769 if (m == l) PetscFunctionReturn(PETSC_SUCCESS); 6770 if (!m) dm->labels = orig->next; 6771 else prev->next = orig->next; 6772 if (!l) { 6773 orig->next = dm->labels; 6774 dm->labels = orig; 6775 } else { 6776 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next); 6777 orig->next = prev->next; 6778 prev->next = orig; 6779 } 6780 PetscFunctionReturn(PETSC_SUCCESS); 6781 } 6782 6783 /*@ 6784 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6785 6786 Not Collective 6787 6788 Input Parameters: 6789 + dm - The `DM` object 6790 . name - The label name 6791 - point - The mesh point 6792 6793 Output Parameter: 6794 . value - The label value for this point, or -1 if the point is not in the label 6795 6796 Level: beginner 6797 6798 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6799 @*/ 6800 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6801 { 6802 DMLabel label; 6803 6804 PetscFunctionBegin; 6805 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6806 PetscAssertPointer(name, 2); 6807 PetscCall(DMGetLabel(dm, name, &label)); 6808 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6809 PetscCall(DMLabelGetValue(label, point, value)); 6810 PetscFunctionReturn(PETSC_SUCCESS); 6811 } 6812 6813 /*@ 6814 DMSetLabelValue - Add a point to a `DMLabel` with given value 6815 6816 Not Collective 6817 6818 Input Parameters: 6819 + dm - The `DM` object 6820 . name - The label name 6821 . point - The mesh point 6822 - value - The label value for this point 6823 6824 Output Parameter: 6825 6826 Level: beginner 6827 6828 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6829 @*/ 6830 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6831 { 6832 DMLabel label; 6833 6834 PetscFunctionBegin; 6835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6836 PetscAssertPointer(name, 2); 6837 PetscCall(DMGetLabel(dm, name, &label)); 6838 if (!label) { 6839 PetscCall(DMCreateLabel(dm, name)); 6840 PetscCall(DMGetLabel(dm, name, &label)); 6841 } 6842 PetscCall(DMLabelSetValue(label, point, value)); 6843 PetscFunctionReturn(PETSC_SUCCESS); 6844 } 6845 6846 /*@ 6847 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6848 6849 Not Collective 6850 6851 Input Parameters: 6852 + dm - The `DM` object 6853 . name - The label name 6854 . point - The mesh point 6855 - value - The label value for this point 6856 6857 Level: beginner 6858 6859 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6860 @*/ 6861 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6862 { 6863 DMLabel label; 6864 6865 PetscFunctionBegin; 6866 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6867 PetscAssertPointer(name, 2); 6868 PetscCall(DMGetLabel(dm, name, &label)); 6869 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6870 PetscCall(DMLabelClearValue(label, point, value)); 6871 PetscFunctionReturn(PETSC_SUCCESS); 6872 } 6873 6874 /*@ 6875 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6876 6877 Not Collective 6878 6879 Input Parameters: 6880 + dm - The `DM` object 6881 - name - The label name 6882 6883 Output Parameter: 6884 . size - The number of different integer ids, or 0 if the label does not exist 6885 6886 Level: beginner 6887 6888 Developer Note: 6889 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6890 6891 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6892 @*/ 6893 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6894 { 6895 DMLabel label; 6896 6897 PetscFunctionBegin; 6898 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6899 PetscAssertPointer(name, 2); 6900 PetscAssertPointer(size, 3); 6901 PetscCall(DMGetLabel(dm, name, &label)); 6902 *size = 0; 6903 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6904 PetscCall(DMLabelGetNumValues(label, size)); 6905 PetscFunctionReturn(PETSC_SUCCESS); 6906 } 6907 6908 /*@ 6909 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6910 6911 Not Collective 6912 6913 Input Parameters: 6914 + dm - The `DM` object 6915 - name - The label name 6916 6917 Output Parameter: 6918 . ids - The integer ids, or `NULL` if the label does not exist 6919 6920 Level: beginner 6921 6922 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()` 6923 @*/ 6924 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6925 { 6926 DMLabel label; 6927 6928 PetscFunctionBegin; 6929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6930 PetscAssertPointer(name, 2); 6931 PetscAssertPointer(ids, 3); 6932 PetscCall(DMGetLabel(dm, name, &label)); 6933 *ids = NULL; 6934 if (label) { 6935 PetscCall(DMLabelGetValueIS(label, ids)); 6936 } else { 6937 /* returning an empty IS */ 6938 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 6939 } 6940 PetscFunctionReturn(PETSC_SUCCESS); 6941 } 6942 6943 /*@ 6944 DMGetStratumSize - Get the number of points in a label stratum 6945 6946 Not Collective 6947 6948 Input Parameters: 6949 + dm - The `DM` object 6950 . name - The label name of the stratum 6951 - value - The stratum value 6952 6953 Output Parameter: 6954 . size - The number of points, also called the stratum size 6955 6956 Level: beginner 6957 6958 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 6959 @*/ 6960 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 6961 { 6962 DMLabel label; 6963 6964 PetscFunctionBegin; 6965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6966 PetscAssertPointer(name, 2); 6967 PetscAssertPointer(size, 4); 6968 PetscCall(DMGetLabel(dm, name, &label)); 6969 *size = 0; 6970 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6971 PetscCall(DMLabelGetStratumSize(label, value, size)); 6972 PetscFunctionReturn(PETSC_SUCCESS); 6973 } 6974 6975 /*@ 6976 DMGetStratumIS - Get the points in a label stratum 6977 6978 Not Collective 6979 6980 Input Parameters: 6981 + dm - The `DM` object 6982 . name - The label name 6983 - value - The stratum value 6984 6985 Output Parameter: 6986 . points - The stratum points, or `NULL` if the label does not exist or does not have that value 6987 6988 Level: beginner 6989 6990 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()` 6991 @*/ 6992 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 6993 { 6994 DMLabel label; 6995 6996 PetscFunctionBegin; 6997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6998 PetscAssertPointer(name, 2); 6999 PetscAssertPointer(points, 4); 7000 PetscCall(DMGetLabel(dm, name, &label)); 7001 *points = NULL; 7002 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7003 PetscCall(DMLabelGetStratumIS(label, value, points)); 7004 PetscFunctionReturn(PETSC_SUCCESS); 7005 } 7006 7007 /*@ 7008 DMSetStratumIS - Set the points in a label stratum 7009 7010 Not Collective 7011 7012 Input Parameters: 7013 + dm - The `DM` object 7014 . name - The label name 7015 . value - The stratum value 7016 - points - The stratum points 7017 7018 Level: beginner 7019 7020 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 7021 @*/ 7022 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 7023 { 7024 DMLabel label; 7025 7026 PetscFunctionBegin; 7027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7028 PetscAssertPointer(name, 2); 7029 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 7030 PetscCall(DMGetLabel(dm, name, &label)); 7031 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7032 PetscCall(DMLabelSetStratumIS(label, value, points)); 7033 PetscFunctionReturn(PETSC_SUCCESS); 7034 } 7035 7036 /*@ 7037 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 7038 7039 Not Collective 7040 7041 Input Parameters: 7042 + dm - The `DM` object 7043 . name - The label name 7044 - value - The label value for this point 7045 7046 Output Parameter: 7047 7048 Level: beginner 7049 7050 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 7051 @*/ 7052 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 7053 { 7054 DMLabel label; 7055 7056 PetscFunctionBegin; 7057 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7058 PetscAssertPointer(name, 2); 7059 PetscCall(DMGetLabel(dm, name, &label)); 7060 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7061 PetscCall(DMLabelClearStratum(label, value)); 7062 PetscFunctionReturn(PETSC_SUCCESS); 7063 } 7064 7065 /*@ 7066 DMGetNumLabels - Return the number of labels defined by on the `DM` 7067 7068 Not Collective 7069 7070 Input Parameter: 7071 . dm - The `DM` object 7072 7073 Output Parameter: 7074 . numLabels - the number of Labels 7075 7076 Level: intermediate 7077 7078 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7079 @*/ 7080 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 7081 { 7082 DMLabelLink next = dm->labels; 7083 PetscInt n = 0; 7084 7085 PetscFunctionBegin; 7086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7087 PetscAssertPointer(numLabels, 2); 7088 while (next) { 7089 ++n; 7090 next = next->next; 7091 } 7092 *numLabels = n; 7093 PetscFunctionReturn(PETSC_SUCCESS); 7094 } 7095 7096 /*@ 7097 DMGetLabelName - Return the name of nth label 7098 7099 Not Collective 7100 7101 Input Parameters: 7102 + dm - The `DM` object 7103 - n - the label number 7104 7105 Output Parameter: 7106 . name - the label name 7107 7108 Level: intermediate 7109 7110 Developer Note: 7111 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 7112 7113 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7114 @*/ 7115 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[]) 7116 { 7117 DMLabelLink next = dm->labels; 7118 PetscInt l = 0; 7119 7120 PetscFunctionBegin; 7121 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7122 PetscAssertPointer(name, 3); 7123 while (next) { 7124 if (l == n) { 7125 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 7126 PetscFunctionReturn(PETSC_SUCCESS); 7127 } 7128 ++l; 7129 next = next->next; 7130 } 7131 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7132 } 7133 7134 /*@ 7135 DMHasLabel - Determine whether the `DM` has a label of a given name 7136 7137 Not Collective 7138 7139 Input Parameters: 7140 + dm - The `DM` object 7141 - name - The label name 7142 7143 Output Parameter: 7144 . hasLabel - `PETSC_TRUE` if the label is present 7145 7146 Level: intermediate 7147 7148 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7149 @*/ 7150 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7151 { 7152 DMLabelLink next = dm->labels; 7153 const char *lname; 7154 7155 PetscFunctionBegin; 7156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7157 PetscAssertPointer(name, 2); 7158 PetscAssertPointer(hasLabel, 3); 7159 *hasLabel = PETSC_FALSE; 7160 while (next) { 7161 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7162 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7163 if (*hasLabel) break; 7164 next = next->next; 7165 } 7166 PetscFunctionReturn(PETSC_SUCCESS); 7167 } 7168 7169 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7170 /*@ 7171 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM` 7172 7173 Not Collective 7174 7175 Input Parameters: 7176 + dm - The `DM` object 7177 - name - The label name 7178 7179 Output Parameter: 7180 . label - The `DMLabel`, or `NULL` if the label is absent 7181 7182 Default labels in a `DMPLEX`: 7183 + "depth" - Holds the depth (co-dimension) of each mesh point 7184 . "celltype" - Holds the topological type of each cell 7185 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7186 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7187 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7188 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7189 7190 Level: intermediate 7191 7192 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7193 @*/ 7194 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7195 { 7196 DMLabelLink next = dm->labels; 7197 PetscBool hasLabel; 7198 const char *lname; 7199 7200 PetscFunctionBegin; 7201 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7202 PetscAssertPointer(name, 2); 7203 PetscAssertPointer(label, 3); 7204 *label = NULL; 7205 while (next) { 7206 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7207 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7208 if (hasLabel) { 7209 *label = next->label; 7210 break; 7211 } 7212 next = next->next; 7213 } 7214 PetscFunctionReturn(PETSC_SUCCESS); 7215 } 7216 7217 /*@ 7218 DMGetLabelByNum - Return the nth label on a `DM` 7219 7220 Not Collective 7221 7222 Input Parameters: 7223 + dm - The `DM` object 7224 - n - the label number 7225 7226 Output Parameter: 7227 . label - the label 7228 7229 Level: intermediate 7230 7231 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7232 @*/ 7233 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7234 { 7235 DMLabelLink next = dm->labels; 7236 PetscInt l = 0; 7237 7238 PetscFunctionBegin; 7239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7240 PetscAssertPointer(label, 3); 7241 while (next) { 7242 if (l == n) { 7243 *label = next->label; 7244 PetscFunctionReturn(PETSC_SUCCESS); 7245 } 7246 ++l; 7247 next = next->next; 7248 } 7249 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7250 } 7251 7252 /*@ 7253 DMAddLabel - Add the label to this `DM` 7254 7255 Not Collective 7256 7257 Input Parameters: 7258 + dm - The `DM` object 7259 - label - The `DMLabel` 7260 7261 Level: developer 7262 7263 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7264 @*/ 7265 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7266 { 7267 DMLabelLink l, *p, tmpLabel; 7268 PetscBool hasLabel; 7269 const char *lname; 7270 PetscBool flg; 7271 7272 PetscFunctionBegin; 7273 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7274 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7275 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7276 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7277 PetscCall(PetscCalloc1(1, &tmpLabel)); 7278 tmpLabel->label = label; 7279 tmpLabel->output = PETSC_TRUE; 7280 for (p = &dm->labels; (l = *p); p = &l->next) { } 7281 *p = tmpLabel; 7282 PetscCall(PetscObjectReference((PetscObject)label)); 7283 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7284 if (flg) dm->depthLabel = label; 7285 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7286 if (flg) dm->celltypeLabel = label; 7287 PetscFunctionReturn(PETSC_SUCCESS); 7288 } 7289 7290 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7291 /*@ 7292 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7293 7294 Not Collective 7295 7296 Input Parameters: 7297 + dm - The `DM` object 7298 - label - The `DMLabel`, having the same name, to substitute 7299 7300 Default labels in a `DMPLEX`: 7301 + "depth" - Holds the depth (co-dimension) of each mesh point 7302 . "celltype" - Holds the topological type of each cell 7303 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7304 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7305 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7306 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7307 7308 Level: intermediate 7309 7310 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7311 @*/ 7312 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7313 { 7314 DMLabelLink next = dm->labels; 7315 PetscBool hasLabel, flg; 7316 const char *name, *lname; 7317 7318 PetscFunctionBegin; 7319 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7320 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7321 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7322 while (next) { 7323 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7324 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7325 if (hasLabel) { 7326 PetscCall(PetscObjectReference((PetscObject)label)); 7327 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7328 if (flg) dm->depthLabel = label; 7329 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7330 if (flg) dm->celltypeLabel = label; 7331 PetscCall(DMLabelDestroy(&next->label)); 7332 next->label = label; 7333 break; 7334 } 7335 next = next->next; 7336 } 7337 PetscFunctionReturn(PETSC_SUCCESS); 7338 } 7339 7340 /*@ 7341 DMRemoveLabel - Remove the label given by name from this `DM` 7342 7343 Not Collective 7344 7345 Input Parameters: 7346 + dm - The `DM` object 7347 - name - The label name 7348 7349 Output Parameter: 7350 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the 7351 caller is responsible for calling `DMLabelDestroy()`. 7352 7353 Level: developer 7354 7355 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7356 @*/ 7357 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7358 { 7359 DMLabelLink link, *pnext; 7360 PetscBool hasLabel; 7361 const char *lname; 7362 7363 PetscFunctionBegin; 7364 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7365 PetscAssertPointer(name, 2); 7366 if (label) { 7367 PetscAssertPointer(label, 3); 7368 *label = NULL; 7369 } 7370 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7371 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7372 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7373 if (hasLabel) { 7374 *pnext = link->next; /* Remove from list */ 7375 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7376 if (hasLabel) dm->depthLabel = NULL; 7377 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7378 if (hasLabel) dm->celltypeLabel = NULL; 7379 if (label) *label = link->label; 7380 else PetscCall(DMLabelDestroy(&link->label)); 7381 PetscCall(PetscFree(link)); 7382 break; 7383 } 7384 } 7385 PetscFunctionReturn(PETSC_SUCCESS); 7386 } 7387 7388 /*@ 7389 DMRemoveLabelBySelf - Remove the label from this `DM` 7390 7391 Not Collective 7392 7393 Input Parameters: 7394 + dm - The `DM` object 7395 . label - The `DMLabel` to be removed from the `DM` 7396 - failNotFound - Should it fail if the label is not found in the `DM`? 7397 7398 Level: developer 7399 7400 Note: 7401 Only exactly the same instance is removed if found, name match is ignored. 7402 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7403 *label nullified. 7404 7405 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7406 @*/ 7407 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7408 { 7409 DMLabelLink link, *pnext; 7410 PetscBool hasLabel = PETSC_FALSE; 7411 7412 PetscFunctionBegin; 7413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7414 PetscAssertPointer(label, 2); 7415 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS); 7416 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7417 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7418 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7419 if (*label == link->label) { 7420 hasLabel = PETSC_TRUE; 7421 *pnext = link->next; /* Remove from list */ 7422 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7423 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7424 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7425 PetscCall(DMLabelDestroy(&link->label)); 7426 PetscCall(PetscFree(link)); 7427 break; 7428 } 7429 } 7430 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7431 PetscFunctionReturn(PETSC_SUCCESS); 7432 } 7433 7434 /*@ 7435 DMGetLabelOutput - Get the output flag for a given label 7436 7437 Not Collective 7438 7439 Input Parameters: 7440 + dm - The `DM` object 7441 - name - The label name 7442 7443 Output Parameter: 7444 . output - The flag for output 7445 7446 Level: developer 7447 7448 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7449 @*/ 7450 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7451 { 7452 DMLabelLink next = dm->labels; 7453 const char *lname; 7454 7455 PetscFunctionBegin; 7456 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7457 PetscAssertPointer(name, 2); 7458 PetscAssertPointer(output, 3); 7459 while (next) { 7460 PetscBool flg; 7461 7462 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7463 PetscCall(PetscStrcmp(name, lname, &flg)); 7464 if (flg) { 7465 *output = next->output; 7466 PetscFunctionReturn(PETSC_SUCCESS); 7467 } 7468 next = next->next; 7469 } 7470 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7471 } 7472 7473 /*@ 7474 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7475 7476 Not Collective 7477 7478 Input Parameters: 7479 + dm - The `DM` object 7480 . name - The label name 7481 - output - `PETSC_TRUE` to save the label to the viewer 7482 7483 Level: developer 7484 7485 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7486 @*/ 7487 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7488 { 7489 DMLabelLink next = dm->labels; 7490 const char *lname; 7491 7492 PetscFunctionBegin; 7493 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7494 PetscAssertPointer(name, 2); 7495 while (next) { 7496 PetscBool flg; 7497 7498 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7499 PetscCall(PetscStrcmp(name, lname, &flg)); 7500 if (flg) { 7501 next->output = output; 7502 PetscFunctionReturn(PETSC_SUCCESS); 7503 } 7504 next = next->next; 7505 } 7506 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7507 } 7508 7509 /*@ 7510 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7511 7512 Collective 7513 7514 Input Parameters: 7515 + dmA - The `DM` object with initial labels 7516 . dmB - The `DM` object to which labels are copied 7517 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7518 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7519 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7520 7521 Level: intermediate 7522 7523 Note: 7524 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7525 7526 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7527 @*/ 7528 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7529 { 7530 DMLabel label, labelNew, labelOld; 7531 const char *name; 7532 PetscBool flg; 7533 DMLabelLink link; 7534 7535 PetscFunctionBegin; 7536 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7537 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7538 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7539 PetscValidLogicalCollectiveBool(dmA, all, 4); 7540 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7541 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 7542 for (link = dmA->labels; link; link = link->next) { 7543 label = link->label; 7544 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7545 if (!all) { 7546 PetscCall(PetscStrcmp(name, "depth", &flg)); 7547 if (flg) continue; 7548 PetscCall(PetscStrcmp(name, "dim", &flg)); 7549 if (flg) continue; 7550 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7551 if (flg) continue; 7552 } 7553 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7554 if (labelOld) { 7555 switch (emode) { 7556 case DM_COPY_LABELS_KEEP: 7557 continue; 7558 case DM_COPY_LABELS_REPLACE: 7559 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7560 break; 7561 case DM_COPY_LABELS_FAIL: 7562 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7563 default: 7564 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7565 } 7566 } 7567 if (mode == PETSC_COPY_VALUES) { 7568 PetscCall(DMLabelDuplicate(label, &labelNew)); 7569 } else { 7570 labelNew = label; 7571 } 7572 PetscCall(DMAddLabel(dmB, labelNew)); 7573 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7574 } 7575 PetscFunctionReturn(PETSC_SUCCESS); 7576 } 7577 7578 /*@C 7579 DMCompareLabels - Compare labels between two `DM` objects 7580 7581 Collective; No Fortran Support 7582 7583 Input Parameters: 7584 + dm0 - First `DM` object 7585 - dm1 - Second `DM` object 7586 7587 Output Parameters: 7588 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 7589 - message - (Optional) Message describing the difference, or `NULL` if there is no difference 7590 7591 Level: intermediate 7592 7593 Notes: 7594 The output flag equal will be the same on all processes. 7595 7596 If equal is passed as `NULL` and difference is found, an error is thrown on all processes. 7597 7598 Make sure to pass equal is `NULL` on all processes or none of them. 7599 7600 The output message is set independently on each rank. 7601 7602 message must be freed with `PetscFree()` 7603 7604 If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner. 7605 7606 Make sure to pass message as `NULL` on all processes or no processes. 7607 7608 Labels are matched by name. If the number of labels and their names are equal, 7609 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7610 7611 Developer Note: 7612 Can automatically generate the Fortran stub because `message` must be freed with `PetscFree()` 7613 7614 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7615 @*/ 7616 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 7617 { 7618 PetscInt n, i; 7619 char msg[PETSC_MAX_PATH_LEN] = ""; 7620 PetscBool eq; 7621 MPI_Comm comm; 7622 PetscMPIInt rank; 7623 7624 PetscFunctionBegin; 7625 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7626 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7627 PetscCheckSameComm(dm0, 1, dm1, 2); 7628 if (equal) PetscAssertPointer(equal, 3); 7629 if (message) PetscAssertPointer(message, 4); 7630 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7631 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7632 { 7633 PetscInt n1; 7634 7635 PetscCall(DMGetNumLabels(dm0, &n)); 7636 PetscCall(DMGetNumLabels(dm1, &n1)); 7637 eq = (PetscBool)(n == n1); 7638 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7639 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7640 if (!eq) goto finish; 7641 } 7642 for (i = 0; i < n; i++) { 7643 DMLabel l0, l1; 7644 const char *name; 7645 char *msgInner; 7646 7647 /* Ignore label order */ 7648 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7649 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7650 PetscCall(DMGetLabel(dm1, name, &l1)); 7651 if (!l1) { 7652 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7653 eq = PETSC_FALSE; 7654 break; 7655 } 7656 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7657 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7658 PetscCall(PetscFree(msgInner)); 7659 if (!eq) break; 7660 } 7661 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7662 finish: 7663 /* If message output arg not set, print to stderr */ 7664 if (message) { 7665 *message = NULL; 7666 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7667 } else { 7668 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7669 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7670 } 7671 /* If same output arg not ser and labels are not equal, throw error */ 7672 if (equal) *equal = eq; 7673 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7674 PetscFunctionReturn(PETSC_SUCCESS); 7675 } 7676 7677 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7678 { 7679 PetscFunctionBegin; 7680 PetscAssertPointer(label, 2); 7681 if (!*label) { 7682 PetscCall(DMCreateLabel(dm, name)); 7683 PetscCall(DMGetLabel(dm, name, label)); 7684 } 7685 PetscCall(DMLabelSetValue(*label, point, value)); 7686 PetscFunctionReturn(PETSC_SUCCESS); 7687 } 7688 7689 /* 7690 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7691 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7692 (label, id) pair in the DM. 7693 7694 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7695 each label. 7696 */ 7697 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7698 { 7699 DMUniversalLabel ul; 7700 PetscBool *active; 7701 PetscInt pStart, pEnd, p, Nl, l, m; 7702 7703 PetscFunctionBegin; 7704 PetscCall(PetscMalloc1(1, &ul)); 7705 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7706 PetscCall(DMGetNumLabels(dm, &Nl)); 7707 PetscCall(PetscCalloc1(Nl, &active)); 7708 ul->Nl = 0; 7709 for (l = 0; l < Nl; ++l) { 7710 PetscBool isdepth, iscelltype; 7711 const char *name; 7712 7713 PetscCall(DMGetLabelName(dm, l, &name)); 7714 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7715 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7716 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7717 if (active[l]) ++ul->Nl; 7718 } 7719 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7720 ul->Nv = 0; 7721 for (l = 0, m = 0; l < Nl; ++l) { 7722 DMLabel label; 7723 PetscInt nv; 7724 const char *name; 7725 7726 if (!active[l]) continue; 7727 PetscCall(DMGetLabelName(dm, l, &name)); 7728 PetscCall(DMGetLabelByNum(dm, l, &label)); 7729 PetscCall(DMLabelGetNumValues(label, &nv)); 7730 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7731 ul->indices[m] = l; 7732 ul->Nv += nv; 7733 ul->offsets[m + 1] = nv; 7734 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7735 ++m; 7736 } 7737 for (l = 1; l <= ul->Nl; ++l) { 7738 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7739 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7740 } 7741 for (l = 0; l < ul->Nl; ++l) { 7742 PetscInt b; 7743 7744 ul->masks[l] = 0; 7745 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7746 } 7747 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7748 for (l = 0, m = 0; l < Nl; ++l) { 7749 DMLabel label; 7750 IS valueIS; 7751 const PetscInt *varr; 7752 PetscInt nv, v; 7753 7754 if (!active[l]) continue; 7755 PetscCall(DMGetLabelByNum(dm, l, &label)); 7756 PetscCall(DMLabelGetNumValues(label, &nv)); 7757 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7758 PetscCall(ISGetIndices(valueIS, &varr)); 7759 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7760 PetscCall(ISRestoreIndices(valueIS, &varr)); 7761 PetscCall(ISDestroy(&valueIS)); 7762 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7763 ++m; 7764 } 7765 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7766 for (p = pStart; p < pEnd; ++p) { 7767 PetscInt uval = 0; 7768 PetscBool marked = PETSC_FALSE; 7769 7770 for (l = 0, m = 0; l < Nl; ++l) { 7771 DMLabel label; 7772 PetscInt val, defval, loc, nv; 7773 7774 if (!active[l]) continue; 7775 PetscCall(DMGetLabelByNum(dm, l, &label)); 7776 PetscCall(DMLabelGetValue(label, p, &val)); 7777 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7778 if (val == defval) { 7779 ++m; 7780 continue; 7781 } 7782 nv = ul->offsets[m + 1] - ul->offsets[m]; 7783 marked = PETSC_TRUE; 7784 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7785 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7786 uval += (loc + 1) << ul->bits[m]; 7787 ++m; 7788 } 7789 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7790 } 7791 PetscCall(PetscFree(active)); 7792 *universal = ul; 7793 PetscFunctionReturn(PETSC_SUCCESS); 7794 } 7795 7796 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7797 { 7798 PetscInt l; 7799 7800 PetscFunctionBegin; 7801 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7802 PetscCall(DMLabelDestroy(&(*universal)->label)); 7803 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7804 PetscCall(PetscFree((*universal)->values)); 7805 PetscCall(PetscFree(*universal)); 7806 *universal = NULL; 7807 PetscFunctionReturn(PETSC_SUCCESS); 7808 } 7809 7810 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7811 { 7812 PetscFunctionBegin; 7813 PetscAssertPointer(ulabel, 2); 7814 *ulabel = ul->label; 7815 PetscFunctionReturn(PETSC_SUCCESS); 7816 } 7817 7818 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7819 { 7820 PetscInt Nl = ul->Nl, l; 7821 7822 PetscFunctionBegin; 7823 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7824 for (l = 0; l < Nl; ++l) { 7825 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7826 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7827 } 7828 if (preserveOrder) { 7829 for (l = 0; l < ul->Nl; ++l) { 7830 const char *name; 7831 PetscBool match; 7832 7833 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7834 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7835 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]); 7836 } 7837 } 7838 PetscFunctionReturn(PETSC_SUCCESS); 7839 } 7840 7841 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7842 { 7843 PetscInt l; 7844 7845 PetscFunctionBegin; 7846 for (l = 0; l < ul->Nl; ++l) { 7847 DMLabel label; 7848 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7849 7850 if (lval) { 7851 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7852 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7853 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7854 } 7855 } 7856 PetscFunctionReturn(PETSC_SUCCESS); 7857 } 7858 7859 /*@ 7860 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7861 7862 Not Collective 7863 7864 Input Parameter: 7865 . dm - The `DM` object 7866 7867 Output Parameter: 7868 . cdm - The coarse `DM` 7869 7870 Level: intermediate 7871 7872 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7873 @*/ 7874 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7875 { 7876 PetscFunctionBegin; 7877 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7878 PetscAssertPointer(cdm, 2); 7879 *cdm = dm->coarseMesh; 7880 PetscFunctionReturn(PETSC_SUCCESS); 7881 } 7882 7883 /*@ 7884 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7885 7886 Input Parameters: 7887 + dm - The `DM` object 7888 - cdm - The coarse `DM` 7889 7890 Level: intermediate 7891 7892 Note: 7893 Normally this is set automatically by `DMRefine()` 7894 7895 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7896 @*/ 7897 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7898 { 7899 PetscFunctionBegin; 7900 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7901 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7902 if (dm == cdm) cdm = NULL; 7903 PetscCall(PetscObjectReference((PetscObject)cdm)); 7904 PetscCall(DMDestroy(&dm->coarseMesh)); 7905 dm->coarseMesh = cdm; 7906 PetscFunctionReturn(PETSC_SUCCESS); 7907 } 7908 7909 /*@ 7910 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7911 7912 Input Parameter: 7913 . dm - The `DM` object 7914 7915 Output Parameter: 7916 . fdm - The fine `DM` 7917 7918 Level: intermediate 7919 7920 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7921 @*/ 7922 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7923 { 7924 PetscFunctionBegin; 7925 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7926 PetscAssertPointer(fdm, 2); 7927 *fdm = dm->fineMesh; 7928 PetscFunctionReturn(PETSC_SUCCESS); 7929 } 7930 7931 /*@ 7932 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7933 7934 Input Parameters: 7935 + dm - The `DM` object 7936 - fdm - The fine `DM` 7937 7938 Level: developer 7939 7940 Note: 7941 Normally this is set automatically by `DMCoarsen()` 7942 7943 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 7944 @*/ 7945 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 7946 { 7947 PetscFunctionBegin; 7948 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7949 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 7950 if (dm == fdm) fdm = NULL; 7951 PetscCall(PetscObjectReference((PetscObject)fdm)); 7952 PetscCall(DMDestroy(&dm->fineMesh)); 7953 dm->fineMesh = fdm; 7954 PetscFunctionReturn(PETSC_SUCCESS); 7955 } 7956 7957 /*@C 7958 DMAddBoundary - Add a boundary condition to a model represented by a `DM` 7959 7960 Collective 7961 7962 Input Parameters: 7963 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 7964 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 7965 . name - The BC name 7966 . label - The label defining constrained points 7967 . Nv - The number of `DMLabel` values for constrained points 7968 . values - An array of values for constrained points 7969 . field - The field to constrain 7970 . Nc - The number of constrained field components (0 will constrain all fields) 7971 . comps - An array of constrained component numbers 7972 . bcFunc - A pointwise function giving boundary values 7973 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 7974 - ctx - An optional user context for bcFunc 7975 7976 Output Parameter: 7977 . bd - (Optional) Boundary number 7978 7979 Options Database Keys: 7980 + -bc_<boundary name> <num> - Overrides the boundary ids 7981 - -bc_<boundary name>_comp <num> - Overrides the boundary components 7982 7983 Level: intermediate 7984 7985 Notes: 7986 Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 7987 .vb 7988 void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 7989 .ve 7990 7991 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 7992 7993 .vb 7994 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 7995 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 7996 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 7997 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 7998 .ve 7999 + dim - the spatial dimension 8000 . Nf - the number of fields 8001 . uOff - the offset into u[] and u_t[] for each field 8002 . uOff_x - the offset into u_x[] for each field 8003 . u - each field evaluated at the current point 8004 . u_t - the time derivative of each field evaluated at the current point 8005 . u_x - the gradient of each field evaluated at the current point 8006 . aOff - the offset into a[] and a_t[] for each auxiliary field 8007 . aOff_x - the offset into a_x[] for each auxiliary field 8008 . a - each auxiliary field evaluated at the current point 8009 . a_t - the time derivative of each auxiliary field evaluated at the current point 8010 . a_x - the gradient of auxiliary each field evaluated at the current point 8011 . t - current time 8012 . x - coordinates of the current point 8013 . numConstants - number of constant parameters 8014 . constants - constant parameters 8015 - bcval - output values at the current point 8016 8017 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 8018 @*/ 8019 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) 8020 { 8021 PetscDS ds; 8022 8023 PetscFunctionBegin; 8024 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8025 PetscValidLogicalCollectiveEnum(dm, type, 2); 8026 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 8027 PetscValidLogicalCollectiveInt(dm, Nv, 5); 8028 PetscValidLogicalCollectiveInt(dm, field, 7); 8029 PetscValidLogicalCollectiveInt(dm, Nc, 8); 8030 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 8031 PetscCall(DMGetDS(dm, &ds)); 8032 /* Complete label */ 8033 if (label) { 8034 PetscObject obj; 8035 PetscClassId id; 8036 8037 PetscCall(DMGetField(dm, field, NULL, &obj)); 8038 PetscCall(PetscObjectGetClassId(obj, &id)); 8039 if (id == PETSCFE_CLASSID) { 8040 DM plex; 8041 8042 PetscCall(DMConvert(dm, DMPLEX, &plex)); 8043 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 8044 PetscCall(DMDestroy(&plex)); 8045 } 8046 } 8047 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 8048 PetscFunctionReturn(PETSC_SUCCESS); 8049 } 8050 8051 /* TODO Remove this since now the structures are the same */ 8052 static PetscErrorCode DMPopulateBoundary(DM dm) 8053 { 8054 PetscDS ds; 8055 DMBoundary *lastnext; 8056 DSBoundary dsbound; 8057 8058 PetscFunctionBegin; 8059 PetscCall(DMGetDS(dm, &ds)); 8060 dsbound = ds->boundary; 8061 if (dm->boundary) { 8062 DMBoundary next = dm->boundary; 8063 8064 /* quick check to see if the PetscDS has changed */ 8065 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 8066 /* the PetscDS has changed: tear down and rebuild */ 8067 while (next) { 8068 DMBoundary b = next; 8069 8070 next = b->next; 8071 PetscCall(PetscFree(b)); 8072 } 8073 dm->boundary = NULL; 8074 } 8075 8076 lastnext = &dm->boundary; 8077 while (dsbound) { 8078 DMBoundary dmbound; 8079 8080 PetscCall(PetscNew(&dmbound)); 8081 dmbound->dsboundary = dsbound; 8082 dmbound->label = dsbound->label; 8083 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8084 *lastnext = dmbound; 8085 lastnext = &dmbound->next; 8086 dsbound = dsbound->next; 8087 } 8088 PetscFunctionReturn(PETSC_SUCCESS); 8089 } 8090 8091 /* TODO: missing manual page */ 8092 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8093 { 8094 DMBoundary b; 8095 8096 PetscFunctionBegin; 8097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8098 PetscAssertPointer(isBd, 3); 8099 *isBd = PETSC_FALSE; 8100 PetscCall(DMPopulateBoundary(dm)); 8101 b = dm->boundary; 8102 while (b && !(*isBd)) { 8103 DMLabel label = b->label; 8104 DSBoundary dsb = b->dsboundary; 8105 PetscInt i; 8106 8107 if (label) { 8108 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8109 } 8110 b = b->next; 8111 } 8112 PetscFunctionReturn(PETSC_SUCCESS); 8113 } 8114 8115 /*@C 8116 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 8117 8118 Collective 8119 8120 Input Parameters: 8121 + dm - The `DM` 8122 . time - The time 8123 . funcs - The coordinate functions to evaluate, one per field 8124 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8125 - mode - The insertion mode for values 8126 8127 Output Parameter: 8128 . X - vector 8129 8130 Calling sequence of `funcs`: 8131 + dim - The spatial dimension 8132 . time - The time at which to sample 8133 . x - The coordinates 8134 . Nc - The number of components 8135 . u - The output field values 8136 - ctx - optional user-defined function context 8137 8138 Level: developer 8139 8140 Developer Notes: 8141 This API is specific to only particular usage of `DM` 8142 8143 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8144 8145 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8146 @*/ 8147 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) 8148 { 8149 Vec localX; 8150 8151 PetscFunctionBegin; 8152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8153 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8154 PetscCall(DMGetLocalVector(dm, &localX)); 8155 PetscCall(VecSet(localX, 0.)); 8156 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8157 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8158 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8159 PetscCall(DMRestoreLocalVector(dm, &localX)); 8160 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8161 PetscFunctionReturn(PETSC_SUCCESS); 8162 } 8163 8164 /*@C 8165 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8166 8167 Not Collective 8168 8169 Input Parameters: 8170 + dm - The `DM` 8171 . time - The time 8172 . funcs - The coordinate functions to evaluate, one per field 8173 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8174 - mode - The insertion mode for values 8175 8176 Output Parameter: 8177 . localX - vector 8178 8179 Calling sequence of `funcs`: 8180 + dim - The spatial dimension 8181 . time - The current timestep 8182 . x - The coordinates 8183 . Nc - The number of components 8184 . u - The output field values 8185 - ctx - optional user-defined function context 8186 8187 Level: developer 8188 8189 Developer Notes: 8190 This API is specific to only particular usage of `DM` 8191 8192 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8193 8194 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8195 @*/ 8196 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) 8197 { 8198 PetscFunctionBegin; 8199 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8200 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8201 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX); 8202 PetscFunctionReturn(PETSC_SUCCESS); 8203 } 8204 8205 /*@C 8206 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. 8207 8208 Collective 8209 8210 Input Parameters: 8211 + dm - The `DM` 8212 . time - The time 8213 . numIds - The number of ids 8214 . ids - The ids 8215 . Nc - The number of components 8216 . comps - The components 8217 . label - The `DMLabel` selecting the portion of the mesh for projection 8218 . funcs - The coordinate functions to evaluate, one per field 8219 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8220 - mode - The insertion mode for values 8221 8222 Output Parameter: 8223 . X - vector 8224 8225 Calling sequence of `funcs`: 8226 + dim - The spatial dimension 8227 . time - The current timestep 8228 . x - The coordinates 8229 . Nc - The number of components 8230 . u - The output field values 8231 - ctx - optional user-defined function context 8232 8233 Level: developer 8234 8235 Developer Notes: 8236 This API is specific to only particular usage of `DM` 8237 8238 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8239 8240 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8241 @*/ 8242 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) 8243 { 8244 Vec localX; 8245 8246 PetscFunctionBegin; 8247 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8248 PetscCall(DMGetLocalVector(dm, &localX)); 8249 PetscCall(VecSet(localX, 0.)); 8250 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8251 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8252 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8253 PetscCall(DMRestoreLocalVector(dm, &localX)); 8254 PetscFunctionReturn(PETSC_SUCCESS); 8255 } 8256 8257 /*@C 8258 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. 8259 8260 Not Collective 8261 8262 Input Parameters: 8263 + dm - The `DM` 8264 . time - The time 8265 . label - The `DMLabel` selecting the portion of the mesh for projection 8266 . numIds - The number of ids 8267 . ids - The ids 8268 . Nc - The number of components 8269 . comps - The components 8270 . funcs - The coordinate functions to evaluate, one per field 8271 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8272 - mode - The insertion mode for values 8273 8274 Output Parameter: 8275 . localX - vector 8276 8277 Calling sequence of `funcs`: 8278 + dim - The spatial dimension 8279 . time - The current time 8280 . x - The coordinates 8281 . Nc - The number of components 8282 . u - The output field values 8283 - ctx - optional user-defined function context 8284 8285 Level: developer 8286 8287 Developer Notes: 8288 This API is specific to only particular usage of `DM` 8289 8290 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8291 8292 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8293 @*/ 8294 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) 8295 { 8296 PetscFunctionBegin; 8297 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8298 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8299 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX); 8300 PetscFunctionReturn(PETSC_SUCCESS); 8301 } 8302 8303 /*@C 8304 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. 8305 8306 Not Collective 8307 8308 Input Parameters: 8309 + dm - The `DM` 8310 . time - The time 8311 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8312 . funcs - The functions to evaluate, one per field 8313 - mode - The insertion mode for values 8314 8315 Output Parameter: 8316 . localX - The output vector 8317 8318 Calling sequence of `funcs`: 8319 + dim - The spatial dimension 8320 . Nf - The number of input fields 8321 . NfAux - The number of input auxiliary fields 8322 . uOff - The offset of each field in u[] 8323 . uOff_x - The offset of each field in u_x[] 8324 . u - The field values at this point in space 8325 . u_t - The field time derivative at this point in space (or NULL) 8326 . u_x - The field derivatives at this point in space 8327 . aOff - The offset of each auxiliary field in u[] 8328 . aOff_x - The offset of each auxiliary field in u_x[] 8329 . a - The auxiliary field values at this point in space 8330 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8331 . a_x - The auxiliary field derivatives at this point in space 8332 . t - The current time 8333 . x - The coordinates of this point 8334 . numConstants - The number of constants 8335 . constants - The value of each constant 8336 - f - The value of the function at this point in space 8337 8338 Level: intermediate 8339 8340 Note: 8341 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. 8342 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 8343 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8344 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8345 8346 Developer Notes: 8347 This API is specific to only particular usage of `DM` 8348 8349 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8350 8351 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8352 `DMProjectFunction()`, `DMComputeL2Diff()` 8353 @*/ 8354 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) 8355 { 8356 PetscFunctionBegin; 8357 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8358 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8359 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8360 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX); 8361 PetscFunctionReturn(PETSC_SUCCESS); 8362 } 8363 8364 /*@C 8365 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. 8366 8367 Not Collective 8368 8369 Input Parameters: 8370 + dm - The `DM` 8371 . time - The time 8372 . label - The `DMLabel` marking the portion of the domain to output 8373 . numIds - The number of label ids to use 8374 . ids - The label ids to use for marking 8375 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8376 . comps - The components to set in the output, or `NULL` for all components 8377 . localU - The input field vector 8378 . funcs - The functions to evaluate, one per field 8379 - mode - The insertion mode for values 8380 8381 Output Parameter: 8382 . localX - The output vector 8383 8384 Calling sequence of `funcs`: 8385 + dim - The spatial dimension 8386 . Nf - The number of input fields 8387 . NfAux - The number of input auxiliary fields 8388 . uOff - The offset of each field in u[] 8389 . uOff_x - The offset of each field in u_x[] 8390 . u - The field values at this point in space 8391 . u_t - The field time derivative at this point in space (or NULL) 8392 . u_x - The field derivatives at this point in space 8393 . aOff - The offset of each auxiliary field in u[] 8394 . aOff_x - The offset of each auxiliary field in u_x[] 8395 . a - The auxiliary field values at this point in space 8396 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8397 . a_x - The auxiliary field derivatives at this point in space 8398 . t - The current time 8399 . x - The coordinates of this point 8400 . numConstants - The number of constants 8401 . constants - The value of each constant 8402 - f - The value of the function at this point in space 8403 8404 Level: intermediate 8405 8406 Note: 8407 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. 8408 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 8409 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8410 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8411 8412 Developer Notes: 8413 This API is specific to only particular usage of `DM` 8414 8415 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8416 8417 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8418 @*/ 8419 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) 8420 { 8421 PetscFunctionBegin; 8422 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8423 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8424 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8425 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8426 PetscFunctionReturn(PETSC_SUCCESS); 8427 } 8428 8429 /*@C 8430 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. 8431 8432 Not Collective 8433 8434 Input Parameters: 8435 + dm - The `DM` 8436 . time - The time 8437 . label - The `DMLabel` marking the portion of the domain to output 8438 . numIds - The number of label ids to use 8439 . ids - The label ids to use for marking 8440 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8441 . comps - The components to set in the output, or `NULL` for all components 8442 . U - The input field vector 8443 . funcs - The functions to evaluate, one per field 8444 - mode - The insertion mode for values 8445 8446 Output Parameter: 8447 . X - The output vector 8448 8449 Calling sequence of `funcs`: 8450 + dim - The spatial dimension 8451 . Nf - The number of input fields 8452 . NfAux - The number of input auxiliary fields 8453 . uOff - The offset of each field in u[] 8454 . uOff_x - The offset of each field in u_x[] 8455 . u - The field values at this point in space 8456 . u_t - The field time derivative at this point in space (or NULL) 8457 . u_x - The field derivatives at this point in space 8458 . aOff - The offset of each auxiliary field in u[] 8459 . aOff_x - The offset of each auxiliary field in u_x[] 8460 . a - The auxiliary field values at this point in space 8461 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8462 . a_x - The auxiliary field derivatives at this point in space 8463 . t - The current time 8464 . x - The coordinates of this point 8465 . numConstants - The number of constants 8466 . constants - The value of each constant 8467 - f - The value of the function at this point in space 8468 8469 Level: intermediate 8470 8471 Note: 8472 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. 8473 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 8474 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8475 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8476 8477 Developer Notes: 8478 This API is specific to only particular usage of `DM` 8479 8480 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8481 8482 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8483 @*/ 8484 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) 8485 { 8486 DM dmIn; 8487 Vec localU, localX; 8488 8489 PetscFunctionBegin; 8490 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8491 PetscCall(VecGetDM(U, &dmIn)); 8492 PetscCall(DMGetLocalVector(dmIn, &localU)); 8493 PetscCall(DMGetLocalVector(dm, &localX)); 8494 PetscCall(VecSet(localX, 0.)); 8495 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8496 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8497 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8498 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8499 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8500 PetscCall(DMRestoreLocalVector(dm, &localX)); 8501 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8502 PetscFunctionReturn(PETSC_SUCCESS); 8503 } 8504 8505 /*@C 8506 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. 8507 8508 Not Collective 8509 8510 Input Parameters: 8511 + dm - The `DM` 8512 . time - The time 8513 . label - The `DMLabel` marking the portion of the domain boundary to output 8514 . numIds - The number of label ids to use 8515 . ids - The label ids to use for marking 8516 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8517 . comps - The components to set in the output, or `NULL` for all components 8518 . localU - The input field vector 8519 . funcs - The functions to evaluate, one per field 8520 - mode - The insertion mode for values 8521 8522 Output Parameter: 8523 . localX - The output vector 8524 8525 Calling sequence of `funcs`: 8526 + dim - The spatial dimension 8527 . Nf - The number of input fields 8528 . NfAux - The number of input auxiliary fields 8529 . uOff - The offset of each field in u[] 8530 . uOff_x - The offset of each field in u_x[] 8531 . u - The field values at this point in space 8532 . u_t - The field time derivative at this point in space (or NULL) 8533 . u_x - The field derivatives at this point in space 8534 . aOff - The offset of each auxiliary field in u[] 8535 . aOff_x - The offset of each auxiliary field in u_x[] 8536 . a - The auxiliary field values at this point in space 8537 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8538 . a_x - The auxiliary field derivatives at this point in space 8539 . t - The current time 8540 . x - The coordinates of this point 8541 . n - The face normal 8542 . numConstants - The number of constants 8543 . constants - The value of each constant 8544 - f - The value of the function at this point in space 8545 8546 Level: intermediate 8547 8548 Note: 8549 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. 8550 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 8551 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8552 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8553 8554 Developer Notes: 8555 This API is specific to only particular usage of `DM` 8556 8557 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8558 8559 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8560 @*/ 8561 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) 8562 { 8563 PetscFunctionBegin; 8564 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8565 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8566 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8567 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8568 PetscFunctionReturn(PETSC_SUCCESS); 8569 } 8570 8571 /*@C 8572 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8573 8574 Collective 8575 8576 Input Parameters: 8577 + dm - The `DM` 8578 . time - The time 8579 . funcs - The functions to evaluate for each field component 8580 . ctxs - Optional array of contexts to pass to each function, or NULL. 8581 - X - The coefficient vector u_h, a global vector 8582 8583 Output Parameter: 8584 . diff - The diff ||u - u_h||_2 8585 8586 Level: developer 8587 8588 Developer Notes: 8589 This API is specific to only particular usage of `DM` 8590 8591 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8592 8593 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8594 @*/ 8595 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8596 { 8597 PetscFunctionBegin; 8598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8599 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8600 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff); 8601 PetscFunctionReturn(PETSC_SUCCESS); 8602 } 8603 8604 /*@C 8605 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8606 8607 Collective 8608 8609 Input Parameters: 8610 + dm - The `DM` 8611 . time - The time 8612 . funcs - The gradient functions to evaluate for each field component 8613 . ctxs - Optional array of contexts to pass to each function, or NULL. 8614 . X - The coefficient vector u_h, a global vector 8615 - n - The vector to project along 8616 8617 Output Parameter: 8618 . diff - The diff ||(grad u - grad u_h) . n||_2 8619 8620 Level: developer 8621 8622 Developer Notes: 8623 This API is specific to only particular usage of `DM` 8624 8625 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8626 8627 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8628 @*/ 8629 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) 8630 { 8631 PetscFunctionBegin; 8632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8633 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8634 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff); 8635 PetscFunctionReturn(PETSC_SUCCESS); 8636 } 8637 8638 /*@C 8639 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8640 8641 Collective 8642 8643 Input Parameters: 8644 + dm - The `DM` 8645 . time - The time 8646 . funcs - The functions to evaluate for each field component 8647 . ctxs - Optional array of contexts to pass to each function, or NULL. 8648 - X - The coefficient vector u_h, a global vector 8649 8650 Output Parameter: 8651 . diff - The array of differences, ||u^f - u^f_h||_2 8652 8653 Level: developer 8654 8655 Developer Notes: 8656 This API is specific to only particular usage of `DM` 8657 8658 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8659 8660 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8661 @*/ 8662 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8663 { 8664 PetscFunctionBegin; 8665 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8666 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8667 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff); 8668 PetscFunctionReturn(PETSC_SUCCESS); 8669 } 8670 8671 /*@C 8672 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8673 8674 Not Collective 8675 8676 Input Parameter: 8677 . dm - The `DM` 8678 8679 Output Parameters: 8680 + nranks - the number of neighbours 8681 - ranks - the neighbors ranks 8682 8683 Level: beginner 8684 8685 Note: 8686 Do not free the array, it is freed when the `DM` is destroyed. 8687 8688 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8689 @*/ 8690 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8691 { 8692 PetscFunctionBegin; 8693 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8694 PetscUseTypeMethod(dm, getneighbors, nranks, ranks); 8695 PetscFunctionReturn(PETSC_SUCCESS); 8696 } 8697 8698 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8699 8700 /* 8701 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8702 This must be a different function because it requires DM which is not defined in the Mat library 8703 */ 8704 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8705 { 8706 PetscFunctionBegin; 8707 if (coloring->ctype == IS_COLORING_LOCAL) { 8708 Vec x1local; 8709 DM dm; 8710 PetscCall(MatGetDM(J, &dm)); 8711 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8712 PetscCall(DMGetLocalVector(dm, &x1local)); 8713 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8714 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8715 x1 = x1local; 8716 } 8717 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8718 if (coloring->ctype == IS_COLORING_LOCAL) { 8719 DM dm; 8720 PetscCall(MatGetDM(J, &dm)); 8721 PetscCall(DMRestoreLocalVector(dm, &x1)); 8722 } 8723 PetscFunctionReturn(PETSC_SUCCESS); 8724 } 8725 8726 /*@ 8727 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8728 8729 Input Parameters: 8730 + coloring - The matrix to get the `DM` from 8731 - fdcoloring - the `MatFDColoring` object 8732 8733 Level: advanced 8734 8735 Developer Note: 8736 This routine exists because the PETSc `Mat` library does not know about the `DM` objects 8737 8738 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8739 @*/ 8740 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8741 { 8742 PetscFunctionBegin; 8743 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8744 PetscFunctionReturn(PETSC_SUCCESS); 8745 } 8746 8747 /*@ 8748 DMGetCompatibility - determine if two `DM`s are compatible 8749 8750 Collective 8751 8752 Input Parameters: 8753 + dm1 - the first `DM` 8754 - dm2 - the second `DM` 8755 8756 Output Parameters: 8757 + compatible - whether or not the two `DM`s are compatible 8758 - set - whether or not the compatible value was actually determined and set 8759 8760 Level: advanced 8761 8762 Notes: 8763 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8764 of the same topology. This implies that the section (field data) on one 8765 "makes sense" with respect to the topology and parallel decomposition of the other. 8766 Loosely speaking, compatible `DM`s represent the same domain and parallel 8767 decomposition, but hold different data. 8768 8769 Typically, one would confirm compatibility if intending to simultaneously iterate 8770 over a pair of vectors obtained from different `DM`s. 8771 8772 For example, two `DMDA` objects are compatible if they have the same local 8773 and global sizes and the same stencil width. They can have different numbers 8774 of degrees of freedom per node. Thus, one could use the node numbering from 8775 either `DM` in bounds for a loop over vectors derived from either `DM`. 8776 8777 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8778 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8779 .vb 8780 ... 8781 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8782 if (set && compatible) { 8783 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8784 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8785 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8786 for (j=y; j<y+n; ++j) { 8787 for (i=x; i<x+m, ++i) { 8788 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8789 } 8790 } 8791 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8792 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8793 } else { 8794 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8795 } 8796 ... 8797 .ve 8798 8799 Checking compatibility might be expensive for a given implementation of `DM`, 8800 or might be impossible to unambiguously confirm or deny. For this reason, 8801 this function may decline to determine compatibility, and hence users should 8802 always check the "set" output parameter. 8803 8804 A `DM` is always compatible with itself. 8805 8806 In the current implementation, `DM`s which live on "unequal" communicators 8807 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8808 incompatible. 8809 8810 This function is labeled "Collective," as information about all subdomains 8811 is required on each rank. However, in `DM` implementations which store all this 8812 information locally, this function may be merely "Logically Collective". 8813 8814 Developer Note: 8815 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8816 iff B is compatible with A. Thus, this function checks the implementations 8817 of both dm and dmc (if they are of different types), attempting to determine 8818 compatibility. It is left to `DM` implementers to ensure that symmetry is 8819 preserved. The simplest way to do this is, when implementing type-specific 8820 logic for this function, is to check for existing logic in the implementation 8821 of other `DM` types and let *set = PETSC_FALSE if found. 8822 8823 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8824 @*/ 8825 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8826 { 8827 PetscMPIInt compareResult; 8828 DMType type, type2; 8829 PetscBool sameType; 8830 8831 PetscFunctionBegin; 8832 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8833 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8834 8835 /* Declare a DM compatible with itself */ 8836 if (dm1 == dm2) { 8837 *set = PETSC_TRUE; 8838 *compatible = PETSC_TRUE; 8839 PetscFunctionReturn(PETSC_SUCCESS); 8840 } 8841 8842 /* Declare a DM incompatible with a DM that lives on an "unequal" 8843 communicator. Note that this does not preclude compatibility with 8844 DMs living on "congruent" or "similar" communicators, but this must be 8845 determined by the implementation-specific logic */ 8846 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8847 if (compareResult == MPI_UNEQUAL) { 8848 *set = PETSC_TRUE; 8849 *compatible = PETSC_FALSE; 8850 PetscFunctionReturn(PETSC_SUCCESS); 8851 } 8852 8853 /* Pass to the implementation-specific routine, if one exists. */ 8854 if (dm1->ops->getcompatibility) { 8855 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8856 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8857 } 8858 8859 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8860 with an implementation of this function from dm2 */ 8861 PetscCall(DMGetType(dm1, &type)); 8862 PetscCall(DMGetType(dm2, &type2)); 8863 PetscCall(PetscStrcmp(type, type2, &sameType)); 8864 if (!sameType && dm2->ops->getcompatibility) { 8865 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8866 } else { 8867 *set = PETSC_FALSE; 8868 } 8869 PetscFunctionReturn(PETSC_SUCCESS); 8870 } 8871 8872 /*@C 8873 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8874 8875 Logically Collective 8876 8877 Input Parameters: 8878 + dm - the `DM` 8879 . f - the monitor function 8880 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8881 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`) 8882 8883 Options Database Key: 8884 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8885 does not cancel those set via the options database. 8886 8887 Level: intermediate 8888 8889 Note: 8890 Several different monitoring routines may be set by calling 8891 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 8892 order in which they were set. 8893 8894 Fortran Note: 8895 Only a single monitor function can be set for each `DM` object 8896 8897 Developer Note: 8898 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 8899 8900 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8901 @*/ 8902 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) 8903 { 8904 PetscInt m; 8905 8906 PetscFunctionBegin; 8907 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8908 for (m = 0; m < dm->numbermonitors; ++m) { 8909 PetscBool identical; 8910 8911 PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 8912 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 8913 } 8914 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 8915 dm->monitor[dm->numbermonitors] = f; 8916 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 8917 dm->monitorcontext[dm->numbermonitors++] = (void *)mctx; 8918 PetscFunctionReturn(PETSC_SUCCESS); 8919 } 8920 8921 /*@ 8922 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 8923 8924 Logically Collective 8925 8926 Input Parameter: 8927 . dm - the DM 8928 8929 Options Database Key: 8930 . -dm_monitor_cancel - cancels all monitors that have been hardwired 8931 into a code by calls to `DMonitorSet()`, but does not cancel those 8932 set via the options database 8933 8934 Level: intermediate 8935 8936 Note: 8937 There is no way to clear one specific monitor from a `DM` object. 8938 8939 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8940 @*/ 8941 PetscErrorCode DMMonitorCancel(DM dm) 8942 { 8943 PetscInt m; 8944 8945 PetscFunctionBegin; 8946 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8947 for (m = 0; m < dm->numbermonitors; ++m) { 8948 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 8949 } 8950 dm->numbermonitors = 0; 8951 PetscFunctionReturn(PETSC_SUCCESS); 8952 } 8953 8954 /*@C 8955 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 8956 8957 Collective 8958 8959 Input Parameters: 8960 + dm - `DM` object you wish to monitor 8961 . name - the monitor type one is seeking 8962 . help - message indicating what monitoring is done 8963 . manual - manual page for the monitor 8964 . monitor - the monitor function 8965 - 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 8966 8967 Output Parameter: 8968 . flg - Flag set if the monitor was created 8969 8970 Level: developer 8971 8972 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 8973 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 8974 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 8975 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 8976 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 8977 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 8978 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 8979 @*/ 8980 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 8981 { 8982 PetscViewer viewer; 8983 PetscViewerFormat format; 8984 8985 PetscFunctionBegin; 8986 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8987 PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 8988 if (*flg) { 8989 PetscViewerAndFormat *vf; 8990 8991 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 8992 PetscCall(PetscViewerDestroy(&viewer)); 8993 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 8994 PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy)); 8995 } 8996 PetscFunctionReturn(PETSC_SUCCESS); 8997 } 8998 8999 /*@ 9000 DMMonitor - runs the user provided monitor routines, if they exist 9001 9002 Collective 9003 9004 Input Parameter: 9005 . dm - The `DM` 9006 9007 Level: developer 9008 9009 Developer Note: 9010 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 9011 related to the discretization process seems rather specialized since some `DM` have no 9012 concept of discretization. 9013 9014 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 9015 @*/ 9016 PetscErrorCode DMMonitor(DM dm) 9017 { 9018 PetscInt m; 9019 9020 PetscFunctionBegin; 9021 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 9022 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9023 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 9024 PetscFunctionReturn(PETSC_SUCCESS); 9025 } 9026 9027 /*@ 9028 DMComputeError - Computes the error assuming the user has provided the exact solution functions 9029 9030 Collective 9031 9032 Input Parameters: 9033 + dm - The `DM` 9034 - sol - The solution vector 9035 9036 Input/Output Parameter: 9037 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 9038 contains the error in each field 9039 9040 Output Parameter: 9041 . errorVec - A vector to hold the cellwise error (may be `NULL`) 9042 9043 Level: developer 9044 9045 Note: 9046 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 9047 9048 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 9049 @*/ 9050 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 9051 { 9052 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 9053 void **ctxs; 9054 PetscReal time; 9055 PetscInt Nf, f, Nds, s; 9056 9057 PetscFunctionBegin; 9058 PetscCall(DMGetNumFields(dm, &Nf)); 9059 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 9060 PetscCall(DMGetNumDS(dm, &Nds)); 9061 for (s = 0; s < Nds; ++s) { 9062 PetscDS ds; 9063 DMLabel label; 9064 IS fieldIS; 9065 const PetscInt *fields; 9066 PetscInt dsNf; 9067 9068 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 9069 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9070 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9071 for (f = 0; f < dsNf; ++f) { 9072 const PetscInt field = fields[f]; 9073 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9074 } 9075 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9076 } 9077 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); 9078 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9079 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9080 if (errorVec) { 9081 DM edm; 9082 DMPolytopeType ct; 9083 PetscBool simplex; 9084 PetscInt dim, cStart, Nf; 9085 9086 PetscCall(DMClone(dm, &edm)); 9087 PetscCall(DMGetDimension(edm, &dim)); 9088 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9089 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9090 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9091 PetscCall(DMGetNumFields(dm, &Nf)); 9092 for (f = 0; f < Nf; ++f) { 9093 PetscFE fe, efe; 9094 PetscQuadrature q; 9095 const char *name; 9096 9097 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 9098 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9099 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 9100 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 9101 PetscCall(PetscFEGetQuadrature(fe, &q)); 9102 PetscCall(PetscFESetQuadrature(efe, q)); 9103 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 9104 PetscCall(PetscFEDestroy(&efe)); 9105 } 9106 PetscCall(DMCreateDS(edm)); 9107 9108 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9109 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 9110 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9111 PetscCall(DMDestroy(&edm)); 9112 } 9113 PetscCall(PetscFree2(exactSol, ctxs)); 9114 PetscFunctionReturn(PETSC_SUCCESS); 9115 } 9116 9117 /*@ 9118 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 9119 9120 Not Collective 9121 9122 Input Parameter: 9123 . dm - The `DM` 9124 9125 Output Parameter: 9126 . numAux - The number of auxiliary data vectors 9127 9128 Level: advanced 9129 9130 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 9131 @*/ 9132 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9133 { 9134 PetscFunctionBegin; 9135 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9136 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9137 PetscFunctionReturn(PETSC_SUCCESS); 9138 } 9139 9140 /*@ 9141 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9142 9143 Not Collective 9144 9145 Input Parameters: 9146 + dm - The `DM` 9147 . label - The `DMLabel` 9148 . value - The label value indicating the region 9149 - part - The equation part, or 0 if unused 9150 9151 Output Parameter: 9152 . aux - The `Vec` holding auxiliary field data 9153 9154 Level: advanced 9155 9156 Note: 9157 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9158 9159 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9160 @*/ 9161 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9162 { 9163 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9164 PetscBool has; 9165 9166 PetscFunctionBegin; 9167 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9168 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9169 key.label = label; 9170 key.value = value; 9171 key.part = part; 9172 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9173 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9174 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9175 PetscFunctionReturn(PETSC_SUCCESS); 9176 } 9177 9178 /*@ 9179 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9180 9181 Not Collective because auxiliary vectors are not parallel 9182 9183 Input Parameters: 9184 + dm - The `DM` 9185 . label - The `DMLabel` 9186 . value - The label value indicating the region 9187 . part - The equation part, or 0 if unused 9188 - aux - The `Vec` holding auxiliary field data 9189 9190 Level: advanced 9191 9192 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9193 @*/ 9194 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9195 { 9196 Vec old; 9197 PetscHashAuxKey key; 9198 9199 PetscFunctionBegin; 9200 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9201 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9202 key.label = label; 9203 key.value = value; 9204 key.part = part; 9205 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9206 PetscCall(PetscObjectReference((PetscObject)aux)); 9207 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9208 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9209 PetscCall(VecDestroy(&old)); 9210 PetscFunctionReturn(PETSC_SUCCESS); 9211 } 9212 9213 /*@ 9214 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9215 9216 Not Collective 9217 9218 Input Parameter: 9219 . dm - The `DM` 9220 9221 Output Parameters: 9222 + labels - The `DMLabel`s for each `Vec` 9223 . values - The label values for each `Vec` 9224 - parts - The equation parts for each `Vec` 9225 9226 Level: advanced 9227 9228 Note: 9229 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9230 9231 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9232 @*/ 9233 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9234 { 9235 PetscHashAuxKey *keys; 9236 PetscInt n, i, off = 0; 9237 9238 PetscFunctionBegin; 9239 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9240 PetscAssertPointer(labels, 2); 9241 PetscAssertPointer(values, 3); 9242 PetscAssertPointer(parts, 4); 9243 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9244 PetscCall(PetscMalloc1(n, &keys)); 9245 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9246 for (i = 0; i < n; ++i) { 9247 labels[i] = keys[i].label; 9248 values[i] = keys[i].value; 9249 parts[i] = keys[i].part; 9250 } 9251 PetscCall(PetscFree(keys)); 9252 PetscFunctionReturn(PETSC_SUCCESS); 9253 } 9254 9255 /*@ 9256 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9257 9258 Not Collective 9259 9260 Input Parameter: 9261 . dm - The `DM` 9262 9263 Output Parameter: 9264 . dmNew - The new `DM`, now with the same auxiliary data 9265 9266 Level: advanced 9267 9268 Note: 9269 This is a shallow copy of the auxiliary vectors 9270 9271 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9272 @*/ 9273 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9274 { 9275 PetscFunctionBegin; 9276 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9277 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2); 9278 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS); 9279 PetscCall(DMClearAuxiliaryVec(dmNew)); 9280 9281 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9282 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9283 { 9284 Vec *auxData; 9285 PetscInt n, i, off = 0; 9286 9287 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n)); 9288 PetscCall(PetscMalloc1(n, &auxData)); 9289 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData)); 9290 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i])); 9291 PetscCall(PetscFree(auxData)); 9292 } 9293 PetscFunctionReturn(PETSC_SUCCESS); 9294 } 9295 9296 /*@ 9297 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one 9298 9299 Not Collective 9300 9301 Input Parameter: 9302 . dm - The `DM` 9303 9304 Level: advanced 9305 9306 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9307 @*/ 9308 PetscErrorCode DMClearAuxiliaryVec(DM dm) 9309 { 9310 Vec *auxData; 9311 PetscInt n, i, off = 0; 9312 9313 PetscFunctionBegin; 9314 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n)); 9315 PetscCall(PetscMalloc1(n, &auxData)); 9316 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData)); 9317 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 9318 PetscCall(PetscFree(auxData)); 9319 PetscCall(PetscHMapAuxDestroy(&dm->auxData)); 9320 PetscCall(PetscHMapAuxCreate(&dm->auxData)); 9321 PetscFunctionReturn(PETSC_SUCCESS); 9322 } 9323 9324 /*@ 9325 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9326 9327 Not Collective 9328 9329 Input Parameters: 9330 + ct - The `DMPolytopeType` 9331 . sourceCone - The source arrangement of faces 9332 - targetCone - The target arrangement of faces 9333 9334 Output Parameters: 9335 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9336 - found - Flag indicating that a suitable orientation was found 9337 9338 Level: advanced 9339 9340 Note: 9341 An arrangement is a face order combined with an orientation for each face 9342 9343 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9344 that labels each arrangement (face ordering plus orientation for each face). 9345 9346 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9347 9348 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9349 @*/ 9350 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9351 { 9352 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9353 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9354 PetscInt o, c; 9355 9356 PetscFunctionBegin; 9357 if (!nO) { 9358 *ornt = 0; 9359 *found = PETSC_TRUE; 9360 PetscFunctionReturn(PETSC_SUCCESS); 9361 } 9362 for (o = -nO; o < nO; ++o) { 9363 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 9364 9365 for (c = 0; c < cS; ++c) 9366 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9367 if (c == cS) { 9368 *ornt = o; 9369 break; 9370 } 9371 } 9372 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9373 PetscFunctionReturn(PETSC_SUCCESS); 9374 } 9375 9376 /*@ 9377 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9378 9379 Not Collective 9380 9381 Input Parameters: 9382 + ct - The `DMPolytopeType` 9383 . sourceCone - The source arrangement of faces 9384 - targetCone - The target arrangement of faces 9385 9386 Output Parameter: 9387 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9388 9389 Level: advanced 9390 9391 Note: 9392 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9393 9394 Developer Note: 9395 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9396 9397 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9398 @*/ 9399 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9400 { 9401 PetscBool found; 9402 9403 PetscFunctionBegin; 9404 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9405 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9406 PetscFunctionReturn(PETSC_SUCCESS); 9407 } 9408 9409 /*@ 9410 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9411 9412 Not Collective 9413 9414 Input Parameters: 9415 + ct - The `DMPolytopeType` 9416 . sourceVert - The source arrangement of vertices 9417 - targetVert - The target arrangement of vertices 9418 9419 Output Parameters: 9420 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9421 - found - Flag indicating that a suitable orientation was found 9422 9423 Level: advanced 9424 9425 Notes: 9426 An arrangement is a vertex order 9427 9428 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9429 that labels each arrangement (vertex ordering). 9430 9431 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9432 9433 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()` 9434 @*/ 9435 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9436 { 9437 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9438 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9439 PetscInt o, c; 9440 9441 PetscFunctionBegin; 9442 if (!nO) { 9443 *ornt = 0; 9444 *found = PETSC_TRUE; 9445 PetscFunctionReturn(PETSC_SUCCESS); 9446 } 9447 for (o = -nO; o < nO; ++o) { 9448 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o); 9449 9450 for (c = 0; c < cS; ++c) 9451 if (sourceVert[arr[c]] != targetVert[c]) break; 9452 if (c == cS) { 9453 *ornt = o; 9454 break; 9455 } 9456 } 9457 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9458 PetscFunctionReturn(PETSC_SUCCESS); 9459 } 9460 9461 /*@ 9462 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9463 9464 Not Collective 9465 9466 Input Parameters: 9467 + ct - The `DMPolytopeType` 9468 . sourceCone - The source arrangement of vertices 9469 - targetCone - The target arrangement of vertices 9470 9471 Output Parameter: 9472 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9473 9474 Level: advanced 9475 9476 Note: 9477 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9478 9479 Developer Note: 9480 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9481 9482 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9483 @*/ 9484 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9485 { 9486 PetscBool found; 9487 9488 PetscFunctionBegin; 9489 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9490 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9491 PetscFunctionReturn(PETSC_SUCCESS); 9492 } 9493 9494 /*@ 9495 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9496 9497 Not Collective 9498 9499 Input Parameters: 9500 + ct - The `DMPolytopeType` 9501 - point - Coordinates of the point 9502 9503 Output Parameter: 9504 . inside - Flag indicating whether the point is inside the reference cell of given type 9505 9506 Level: advanced 9507 9508 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9509 @*/ 9510 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9511 { 9512 PetscReal sum = 0.0; 9513 PetscInt d; 9514 9515 PetscFunctionBegin; 9516 *inside = PETSC_TRUE; 9517 switch (ct) { 9518 case DM_POLYTOPE_TRIANGLE: 9519 case DM_POLYTOPE_TETRAHEDRON: 9520 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9521 if (point[d] < -1.0) { 9522 *inside = PETSC_FALSE; 9523 break; 9524 } 9525 sum += point[d]; 9526 } 9527 if (sum > PETSC_SMALL) { 9528 *inside = PETSC_FALSE; 9529 break; 9530 } 9531 break; 9532 case DM_POLYTOPE_QUADRILATERAL: 9533 case DM_POLYTOPE_HEXAHEDRON: 9534 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9535 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9536 *inside = PETSC_FALSE; 9537 break; 9538 } 9539 break; 9540 default: 9541 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9542 } 9543 PetscFunctionReturn(PETSC_SUCCESS); 9544 } 9545 9546 /*@ 9547 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default 9548 9549 Logically collective 9550 9551 Input Parameters: 9552 + dm - The DM 9553 - reorder - Flag for reordering 9554 9555 Level: intermediate 9556 9557 .seealso: `DMReorderSectionGetDefault()` 9558 @*/ 9559 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder) 9560 { 9561 PetscFunctionBegin; 9562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9563 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); 9564 PetscFunctionReturn(PETSC_SUCCESS); 9565 } 9566 9567 /*@ 9568 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default 9569 9570 Not collective 9571 9572 Input Parameter: 9573 . dm - The DM 9574 9575 Output Parameter: 9576 . reorder - Flag for reordering 9577 9578 Level: intermediate 9579 9580 .seealso: `DMReorderSetDefault()` 9581 @*/ 9582 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder) 9583 { 9584 PetscFunctionBegin; 9585 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9586 PetscAssertPointer(reorder, 2); 9587 *reorder = DM_REORDER_DEFAULT_NOTSET; 9588 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); 9589 PetscFunctionReturn(PETSC_SUCCESS); 9590 } 9591 9592 /*@ 9593 DMReorderSectionSetType - Set the type of local section reordering 9594 9595 Logically collective 9596 9597 Input Parameters: 9598 + dm - The DM 9599 - reorder - The reordering method 9600 9601 Level: intermediate 9602 9603 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()` 9604 @*/ 9605 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder) 9606 { 9607 PetscFunctionBegin; 9608 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9609 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder)); 9610 PetscFunctionReturn(PETSC_SUCCESS); 9611 } 9612 9613 /*@ 9614 DMReorderSectionGetType - Get the reordering type for the local section 9615 9616 Not collective 9617 9618 Input Parameter: 9619 . dm - The DM 9620 9621 Output Parameter: 9622 . reorder - The reordering method 9623 9624 Level: intermediate 9625 9626 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()` 9627 @*/ 9628 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder) 9629 { 9630 PetscFunctionBegin; 9631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9632 PetscAssertPointer(reorder, 2); 9633 *reorder = NULL; 9634 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder)); 9635 PetscFunctionReturn(PETSC_SUCCESS); 9636 } 9637