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