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