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