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