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