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