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