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