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