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