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