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