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