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