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