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