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