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