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_VALGRIND) 15 # include <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(PETSC_HAVE_VALGRIND) 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 /* Complete labels that are being used for FEM BC */ 5184 static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, DMLabel label) 5185 { 5186 PetscObject obj; 5187 PetscClassId id; 5188 PetscInt Nbd, bd; 5189 PetscBool isFE = PETSC_FALSE; 5190 PetscBool duplicate = PETSC_FALSE; 5191 5192 PetscFunctionBegin; 5193 PetscCall(DMGetField(dm, field, NULL, &obj)); 5194 PetscCall(PetscObjectGetClassId(obj, &id)); 5195 if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE; 5196 if (isFE && label) { 5197 /* Only want to modify label once */ 5198 PetscCall(PetscDSGetNumBoundary(ds, &Nbd)); 5199 for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) { 5200 DMLabel l; 5201 5202 PetscCall(PetscDSGetBoundary(ds, bd, NULL, NULL, NULL, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); 5203 duplicate = l == label ? PETSC_TRUE : PETSC_FALSE; 5204 if (duplicate) break; 5205 } 5206 if (!duplicate) { 5207 DM plex; 5208 5209 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5210 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 5211 PetscCall(DMDestroy(&plex)); 5212 } 5213 } 5214 PetscFunctionReturn(0); 5215 } 5216 5217 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew) 5218 { 5219 DMSpace *tmpd; 5220 PetscInt Nds = dm->Nds, s; 5221 5222 PetscFunctionBegin; 5223 if (Nds >= NdsNew) PetscFunctionReturn(0); 5224 PetscCall(PetscMalloc1(NdsNew, &tmpd)); 5225 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s]; 5226 for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;} 5227 PetscCall(PetscFree(dm->probs)); 5228 dm->Nds = NdsNew; 5229 dm->probs = tmpd; 5230 PetscFunctionReturn(0); 5231 } 5232 5233 /*@ 5234 DMGetNumDS - Get the number of discrete systems in the DM 5235 5236 Not collective 5237 5238 Input Parameter: 5239 . dm - The DM 5240 5241 Output Parameter: 5242 . Nds - The number of PetscDS objects 5243 5244 Level: intermediate 5245 5246 .seealso: DMGetDS(), DMGetCellDS() 5247 @*/ 5248 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds) 5249 { 5250 PetscFunctionBegin; 5251 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5252 PetscValidIntPointer(Nds, 2); 5253 *Nds = dm->Nds; 5254 PetscFunctionReturn(0); 5255 } 5256 5257 /*@ 5258 DMClearDS - Remove all discrete systems from the DM 5259 5260 Logically collective on dm 5261 5262 Input Parameter: 5263 . dm - The DM 5264 5265 Level: intermediate 5266 5267 .seealso: DMGetNumDS(), DMGetDS(), DMSetField() 5268 @*/ 5269 PetscErrorCode DMClearDS(DM dm) 5270 { 5271 PetscInt s; 5272 5273 PetscFunctionBegin; 5274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5275 for (s = 0; s < dm->Nds; ++s) { 5276 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5277 PetscCall(DMLabelDestroy(&dm->probs[s].label)); 5278 PetscCall(ISDestroy(&dm->probs[s].fields)); 5279 } 5280 PetscCall(PetscFree(dm->probs)); 5281 dm->probs = NULL; 5282 dm->Nds = 0; 5283 PetscFunctionReturn(0); 5284 } 5285 5286 /*@ 5287 DMGetDS - Get the default PetscDS 5288 5289 Not collective 5290 5291 Input Parameter: 5292 . dm - The DM 5293 5294 Output Parameter: 5295 . prob - The default PetscDS 5296 5297 Level: intermediate 5298 5299 .seealso: DMGetCellDS(), DMGetRegionDS() 5300 @*/ 5301 PetscErrorCode DMGetDS(DM dm, PetscDS *prob) 5302 { 5303 PetscFunctionBeginHot; 5304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5305 PetscValidPointer(prob, 2); 5306 if (dm->Nds <= 0) { 5307 PetscDS ds; 5308 5309 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 5310 PetscCall(DMSetRegionDS(dm, NULL, NULL, ds)); 5311 PetscCall(PetscDSDestroy(&ds)); 5312 } 5313 *prob = dm->probs[0].ds; 5314 PetscFunctionReturn(0); 5315 } 5316 5317 /*@ 5318 DMGetCellDS - Get the PetscDS defined on a given cell 5319 5320 Not collective 5321 5322 Input Parameters: 5323 + dm - The DM 5324 - point - Cell for the DS 5325 5326 Output Parameter: 5327 . prob - The PetscDS defined on the given cell 5328 5329 Level: developer 5330 5331 .seealso: DMGetDS(), DMSetRegionDS() 5332 @*/ 5333 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob) 5334 { 5335 PetscDS probDef = NULL; 5336 PetscInt s; 5337 5338 PetscFunctionBeginHot; 5339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5340 PetscValidPointer(prob, 3); 5341 PetscCheck(point >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point); 5342 *prob = NULL; 5343 for (s = 0; s < dm->Nds; ++s) { 5344 PetscInt val; 5345 5346 if (!dm->probs[s].label) {probDef = dm->probs[s].ds;} 5347 else { 5348 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val)); 5349 if (val >= 0) {*prob = dm->probs[s].ds; break;} 5350 } 5351 } 5352 if (!*prob) *prob = probDef; 5353 PetscFunctionReturn(0); 5354 } 5355 5356 /*@ 5357 DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel 5358 5359 Not collective 5360 5361 Input Parameters: 5362 + dm - The DM 5363 - label - The DMLabel defining the mesh region, or NULL for the entire mesh 5364 5365 Output Parameters: 5366 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL 5367 - prob - The PetscDS defined on the given region, or NULL 5368 5369 Note: 5370 If a non-NULL label is given, but there is no PetscDS on that specific label, 5371 the PetscDS for the full domain (if present) is returned. Returns with 5372 fields=NULL and prob=NULL if there is no PetscDS for the full domain. 5373 5374 Level: advanced 5375 5376 .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS() 5377 @*/ 5378 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds) 5379 { 5380 PetscInt Nds = dm->Nds, s; 5381 5382 PetscFunctionBegin; 5383 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5384 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5385 if (fields) {PetscValidPointer(fields, 3); *fields = NULL;} 5386 if (ds) {PetscValidPointer(ds, 4); *ds = NULL;} 5387 for (s = 0; s < Nds; ++s) { 5388 if (dm->probs[s].label == label || !dm->probs[s].label) { 5389 if (fields) *fields = dm->probs[s].fields; 5390 if (ds) *ds = dm->probs[s].ds; 5391 if (dm->probs[s].label) PetscFunctionReturn(0); 5392 } 5393 } 5394 PetscFunctionReturn(0); 5395 } 5396 5397 /*@ 5398 DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel 5399 5400 Collective on dm 5401 5402 Input Parameters: 5403 + dm - The DM 5404 . label - The DMLabel defining the mesh region, or NULL for the entire mesh 5405 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields 5406 - prob - The PetscDS defined on the given cell 5407 5408 Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced, 5409 the fields argument is ignored. 5410 5411 Level: advanced 5412 5413 .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS() 5414 @*/ 5415 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds) 5416 { 5417 PetscInt Nds = dm->Nds, s; 5418 5419 PetscFunctionBegin; 5420 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5421 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5422 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4); 5423 for (s = 0; s < Nds; ++s) { 5424 if (dm->probs[s].label == label) { 5425 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5426 dm->probs[s].ds = ds; 5427 PetscFunctionReturn(0); 5428 } 5429 } 5430 PetscCall(DMDSEnlarge_Static(dm, Nds+1)); 5431 PetscCall(PetscObjectReference((PetscObject) label)); 5432 PetscCall(PetscObjectReference((PetscObject) fields)); 5433 PetscCall(PetscObjectReference((PetscObject) ds)); 5434 if (!label) { 5435 /* Put the NULL label at the front, so it is returned as the default */ 5436 for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s]; 5437 Nds = 0; 5438 } 5439 dm->probs[Nds].label = label; 5440 dm->probs[Nds].fields = fields; 5441 dm->probs[Nds].ds = ds; 5442 PetscFunctionReturn(0); 5443 } 5444 5445 /*@ 5446 DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number 5447 5448 Not collective 5449 5450 Input Parameters: 5451 + dm - The DM 5452 - num - The region number, in [0, Nds) 5453 5454 Output Parameters: 5455 + label - The region label, or NULL 5456 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL 5457 - ds - The PetscDS defined on the given region, or NULL 5458 5459 Level: advanced 5460 5461 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS() 5462 @*/ 5463 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds) 5464 { 5465 PetscInt Nds; 5466 5467 PetscFunctionBegin; 5468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5469 PetscCall(DMGetNumDS(dm, &Nds)); 5470 PetscCheck((num >= 0) && (num < Nds),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5471 if (label) { 5472 PetscValidPointer(label, 3); 5473 *label = dm->probs[num].label; 5474 } 5475 if (fields) { 5476 PetscValidPointer(fields, 4); 5477 *fields = dm->probs[num].fields; 5478 } 5479 if (ds) { 5480 PetscValidPointer(ds, 5); 5481 *ds = dm->probs[num].ds; 5482 } 5483 PetscFunctionReturn(0); 5484 } 5485 5486 /*@ 5487 DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number 5488 5489 Not collective 5490 5491 Input Parameters: 5492 + dm - The DM 5493 . num - The region number, in [0, Nds) 5494 . label - The region label, or NULL 5495 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting 5496 - ds - The PetscDS defined on the given region, or NULL to prevent setting 5497 5498 Level: advanced 5499 5500 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS() 5501 @*/ 5502 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds) 5503 { 5504 PetscInt Nds; 5505 5506 PetscFunctionBegin; 5507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5508 if (label) {PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);} 5509 PetscCall(DMGetNumDS(dm, &Nds)); 5510 PetscCheck((num >= 0) && (num < Nds),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5511 PetscCall(PetscObjectReference((PetscObject) label)); 5512 PetscCall(DMLabelDestroy(&dm->probs[num].label)); 5513 dm->probs[num].label = label; 5514 if (fields) { 5515 PetscValidHeaderSpecific(fields, IS_CLASSID, 4); 5516 PetscCall(PetscObjectReference((PetscObject) fields)); 5517 PetscCall(ISDestroy(&dm->probs[num].fields)); 5518 dm->probs[num].fields = fields; 5519 } 5520 if (ds) { 5521 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5); 5522 PetscCall(PetscObjectReference((PetscObject) ds)); 5523 PetscCall(PetscDSDestroy(&dm->probs[num].ds)); 5524 dm->probs[num].ds = ds; 5525 } 5526 PetscFunctionReturn(0); 5527 } 5528 5529 /*@ 5530 DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found. 5531 5532 Not collective 5533 5534 Input Parameters: 5535 + dm - The DM 5536 - ds - The PetscDS defined on the given region 5537 5538 Output Parameter: 5539 . num - The region number, in [0, Nds), or -1 if not found 5540 5541 Level: advanced 5542 5543 .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS() 5544 @*/ 5545 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num) 5546 { 5547 PetscInt Nds, n; 5548 5549 PetscFunctionBegin; 5550 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5551 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2); 5552 PetscValidIntPointer(num, 3); 5553 PetscCall(DMGetNumDS(dm, &Nds)); 5554 for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break; 5555 if (n >= Nds) *num = -1; 5556 else *num = n; 5557 PetscFunctionReturn(0); 5558 } 5559 5560 /*@C 5561 DMCreateFEDefault - Create a PetscFE based on the celltype for the mesh 5562 5563 Not collective 5564 5565 Input Parameters: 5566 + dm - The DM 5567 . Nc - The number of components for the field 5568 . prefix - The options prefix for the output PetscFE, or NULL 5569 - qorder - The quadrature order or PETSC_DETERMINE to use PetscSpace polynomial degree 5570 5571 Output Parameter: 5572 . fem - The PetscFE 5573 5574 Note: This is a convenience method that just calls PetscFECreateByCell() underneath. 5575 5576 Level: intermediate 5577 5578 .seealso: PetscFECreateByCell(), DMAddField(), DMCreateDS(), DMGetCellDS(), DMGetRegionDS() 5579 @*/ 5580 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem) 5581 { 5582 DMPolytopeType ct; 5583 PetscInt dim, cStart; 5584 5585 PetscFunctionBegin; 5586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5587 PetscValidLogicalCollectiveInt(dm, Nc, 2); 5588 if (prefix) PetscValidCharPointer(prefix, 3); 5589 PetscValidLogicalCollectiveInt(dm, qorder, 4); 5590 PetscValidPointer(fem, 5); 5591 PetscCall(DMGetDimension(dm, &dim)); 5592 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 5593 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 5594 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem)); 5595 PetscFunctionReturn(0); 5596 } 5597 5598 /*@ 5599 DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM 5600 5601 Collective on dm 5602 5603 Input Parameter: 5604 . dm - The DM 5605 5606 Options Database Keys: 5607 . -dm_petscds_view - View all the PetscDS objects in this DM 5608 5609 Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. 5610 5611 Level: intermediate 5612 5613 .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS() 5614 @*/ 5615 PetscErrorCode DMCreateDS(DM dm) 5616 { 5617 MPI_Comm comm; 5618 PetscDS dsDef; 5619 DMLabel *labelSet; 5620 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k; 5621 PetscBool doSetup = PETSC_TRUE, flg; 5622 5623 PetscFunctionBegin; 5624 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5625 if (!dm->fields) PetscFunctionReturn(0); 5626 PetscCall(PetscObjectGetComm((PetscObject) dm, &comm)); 5627 PetscCall(DMGetCoordinateDim(dm, &dE)); 5628 /* Determine how many regions we have */ 5629 PetscCall(PetscMalloc1(Nf, &labelSet)); 5630 Nl = 0; 5631 Ndef = 0; 5632 for (f = 0; f < Nf; ++f) { 5633 DMLabel label = dm->fields[f].label; 5634 PetscInt l; 5635 5636 #ifdef PETSC_HAVE_LIBCEED 5637 /* Move CEED context to discretizations */ 5638 { 5639 PetscClassId id; 5640 5641 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id)); 5642 if (id == PETSCFE_CLASSID) { 5643 Ceed ceed; 5644 5645 PetscCall(DMGetCeed(dm, &ceed)); 5646 PetscCall(PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed)); 5647 } 5648 } 5649 #endif 5650 if (!label) {++Ndef; continue;} 5651 for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break; 5652 if (l < Nl) continue; 5653 labelSet[Nl++] = label; 5654 } 5655 /* Create default DS if there are no labels to intersect with */ 5656 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef)); 5657 if (!dsDef && Ndef && !Nl) { 5658 IS fields; 5659 PetscInt *fld, nf; 5660 5661 for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf; 5662 PetscCheck(nf,comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS"); 5663 PetscCall(PetscMalloc1(nf, &fld)); 5664 for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f; 5665 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5666 PetscCall(PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_")); 5667 PetscCall(ISSetType(fields, ISGENERAL)); 5668 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5669 5670 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5671 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef)); 5672 PetscCall(PetscDSDestroy(&dsDef)); 5673 PetscCall(ISDestroy(&fields)); 5674 } 5675 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef)); 5676 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5677 /* Intersect labels with default fields */ 5678 if (Ndef && Nl) { 5679 DM plex; 5680 DMLabel cellLabel; 5681 IS fieldIS, allcellIS, defcellIS = NULL; 5682 PetscInt *fields; 5683 const PetscInt *cells; 5684 PetscInt depth, nf = 0, n, c; 5685 5686 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5687 PetscCall(DMPlexGetDepth(plex, &depth)); 5688 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS)); 5689 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS)); 5690 /* TODO This looks like it only works for one label */ 5691 for (l = 0; l < Nl; ++l) { 5692 DMLabel label = labelSet[l]; 5693 IS pointIS; 5694 5695 PetscCall(ISDestroy(&defcellIS)); 5696 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 5697 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS)); 5698 PetscCall(ISDestroy(&pointIS)); 5699 } 5700 PetscCall(ISDestroy(&allcellIS)); 5701 5702 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel)); 5703 PetscCall(ISGetLocalSize(defcellIS, &n)); 5704 PetscCall(ISGetIndices(defcellIS, &cells)); 5705 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1)); 5706 PetscCall(ISRestoreIndices(defcellIS, &cells)); 5707 PetscCall(ISDestroy(&defcellIS)); 5708 PetscCall(DMPlexLabelComplete(plex, cellLabel)); 5709 5710 PetscCall(PetscMalloc1(Ndef, &fields)); 5711 for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f; 5712 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS)); 5713 PetscCall(PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_")); 5714 PetscCall(ISSetType(fieldIS, ISGENERAL)); 5715 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER)); 5716 5717 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5718 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef)); 5719 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5720 PetscCall(DMLabelDestroy(&cellLabel)); 5721 PetscCall(PetscDSDestroy(&dsDef)); 5722 PetscCall(ISDestroy(&fieldIS)); 5723 PetscCall(DMDestroy(&plex)); 5724 } 5725 /* Create label DSes 5726 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS 5727 */ 5728 /* TODO Should check that labels are disjoint */ 5729 for (l = 0; l < Nl; ++l) { 5730 DMLabel label = labelSet[l]; 5731 PetscDS ds; 5732 IS fields; 5733 PetscInt *fld, nf; 5734 5735 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 5736 for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf; 5737 PetscCall(PetscMalloc1(nf, &fld)); 5738 for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f; 5739 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5740 PetscCall(PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_")); 5741 PetscCall(ISSetType(fields, ISGENERAL)); 5742 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5743 PetscCall(DMSetRegionDS(dm, label, fields, ds)); 5744 PetscCall(ISDestroy(&fields)); 5745 PetscCall(PetscDSSetCoordinateDimension(ds, dE)); 5746 { 5747 DMPolytopeType ct; 5748 PetscInt lStart, lEnd; 5749 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive; 5750 5751 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd)); 5752 if (lStart >= 0) { 5753 PetscCall(DMPlexGetCellType(dm, lStart, &ct)); 5754 switch (ct) { 5755 case DM_POLYTOPE_POINT_PRISM_TENSOR: 5756 case DM_POLYTOPE_SEG_PRISM_TENSOR: 5757 case DM_POLYTOPE_TRI_PRISM_TENSOR: 5758 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 5759 isCohesiveLocal = PETSC_TRUE;break; 5760 default: break; 5761 } 5762 } 5763 PetscCallMPI(MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm)); 5764 for (f = 0, nf = 0; f < Nf; ++f) { 5765 if (label == dm->fields[f].label || !dm->fields[f].label) { 5766 if (label == dm->fields[f].label) { 5767 PetscCall(PetscDSSetDiscretization(ds, nf, NULL)); 5768 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive)); 5769 } 5770 ++nf; 5771 } 5772 } 5773 } 5774 PetscCall(PetscDSDestroy(&ds)); 5775 } 5776 PetscCall(PetscFree(labelSet)); 5777 /* Set fields in DSes */ 5778 for (s = 0; s < dm->Nds; ++s) { 5779 PetscDS ds = dm->probs[s].ds; 5780 IS fields = dm->probs[s].fields; 5781 const PetscInt *fld; 5782 PetscInt nf, dsnf; 5783 PetscBool isCohesive; 5784 5785 PetscCall(PetscDSGetNumFields(ds, &dsnf)); 5786 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 5787 PetscCall(ISGetLocalSize(fields, &nf)); 5788 PetscCall(ISGetIndices(fields, &fld)); 5789 for (f = 0; f < nf; ++f) { 5790 PetscObject disc = dm->fields[fld[f]].disc; 5791 PetscBool isCohesiveField; 5792 PetscClassId id; 5793 5794 /* Handle DS with no fields */ 5795 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 5796 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */ 5797 if (isCohesive && !isCohesiveField) PetscCall(PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc)); 5798 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 5799 /* We allow people to have placeholder fields and construct the Section by hand */ 5800 PetscCall(PetscObjectGetClassId(disc, &id)); 5801 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE; 5802 } 5803 PetscCall(ISRestoreIndices(fields, &fld)); 5804 } 5805 /* Allow k-jet tabulation */ 5806 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg)); 5807 if (flg) { 5808 for (s = 0; s < dm->Nds; ++s) { 5809 PetscDS ds = dm->probs[s].ds; 5810 PetscInt Nf, f; 5811 5812 PetscCall(PetscDSGetNumFields(ds, &Nf)); 5813 for (f = 0; f < Nf; ++f) PetscCall(PetscDSSetJetDegree(ds, f, k)); 5814 } 5815 } 5816 /* Setup DSes */ 5817 if (doSetup) { 5818 for (s = 0; s < dm->Nds; ++s) PetscCall(PetscDSSetUp(dm->probs[s].ds)); 5819 } 5820 PetscFunctionReturn(0); 5821 } 5822 5823 /*@ 5824 DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information. 5825 5826 Collective on DM 5827 5828 Input Parameters: 5829 + dm - The DM 5830 - time - The time 5831 5832 Output Parameters: 5833 + u - The vector will be filled with exact solution values, or NULL 5834 - u_t - The vector will be filled with the time derivative of exact solution values, or NULL 5835 5836 Note: The user must call PetscDSSetExactSolution() beforehand 5837 5838 Level: developer 5839 5840 .seealso: PetscDSSetExactSolution() 5841 @*/ 5842 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 5843 { 5844 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 5845 void **ectxs; 5846 PetscInt Nf, Nds, s; 5847 5848 PetscFunctionBegin; 5849 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5850 if (u) PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 5851 if (u_t) PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 5852 PetscCall(DMGetNumFields(dm, &Nf)); 5853 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 5854 PetscCall(DMGetNumDS(dm, &Nds)); 5855 for (s = 0; s < Nds; ++s) { 5856 PetscDS ds; 5857 DMLabel label; 5858 IS fieldIS; 5859 const PetscInt *fields, id = 1; 5860 PetscInt dsNf, f; 5861 5862 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 5863 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 5864 PetscCall(ISGetIndices(fieldIS, &fields)); 5865 PetscCall(PetscArrayzero(exacts, Nf)); 5866 PetscCall(PetscArrayzero(ectxs, Nf)); 5867 if (u) { 5868 for (f = 0; f < dsNf; ++f) { 5869 const PetscInt field = fields[f]; 5870 PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field])); 5871 } 5872 PetscCall(ISRestoreIndices(fieldIS, &fields)); 5873 if (label) { 5874 PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u)); 5875 } else { 5876 PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u)); 5877 } 5878 } 5879 if (u_t) { 5880 PetscCall(PetscArrayzero(exacts, Nf)); 5881 PetscCall(PetscArrayzero(ectxs, Nf)); 5882 for (f = 0; f < dsNf; ++f) { 5883 const PetscInt field = fields[f]; 5884 PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field])); 5885 } 5886 PetscCall(ISRestoreIndices(fieldIS, &fields)); 5887 if (label) { 5888 PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t)); 5889 } else { 5890 PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t)); 5891 } 5892 } 5893 } 5894 if (u) { 5895 PetscCall(PetscObjectSetName((PetscObject) u, "Exact Solution")); 5896 PetscCall(PetscObjectSetOptionsPrefix((PetscObject) u, "exact_")); 5897 } 5898 if (u_t) { 5899 PetscCall(PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative")); 5900 PetscCall(PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_")); 5901 } 5902 PetscCall(PetscFree2(exacts, ectxs)); 5903 PetscFunctionReturn(0); 5904 } 5905 5906 PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds) 5907 { 5908 PetscDS dsNew; 5909 DSBoundary b; 5910 PetscInt cdim, Nf, f; 5911 PetscBool isCohesive; 5912 void *ctx; 5913 5914 PetscFunctionBegin; 5915 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew)); 5916 PetscCall(PetscDSCopyConstants(ds, dsNew)); 5917 PetscCall(PetscDSCopyExactSolutions(ds, dsNew)); 5918 PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew)); 5919 PetscCall(PetscDSCopyEquations(ds, dsNew)); 5920 PetscCall(PetscDSGetNumFields(ds, &Nf)); 5921 for (f = 0; f < Nf; ++f) { 5922 PetscCall(PetscDSGetContext(ds, f, &ctx)); 5923 PetscCall(PetscDSSetContext(dsNew, f, ctx)); 5924 PetscCall(PetscDSGetCohesive(ds, f, &isCohesive)); 5925 PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive)); 5926 } 5927 if (Nf) { 5928 PetscCall(PetscDSGetCoordinateDimension(ds, &cdim)); 5929 PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim)); 5930 } 5931 PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew)); 5932 for (b = dsNew->boundary; b; b = b->next) { 5933 PetscCall(DMGetLabel(dm, b->lname, &b->label)); 5934 /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */ 5935 //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name); 5936 } 5937 5938 PetscCall(DMSetRegionDS(dm, label, fields, dsNew)); 5939 PetscCall(PetscDSDestroy(&dsNew)); 5940 PetscFunctionReturn(0); 5941 } 5942 5943 /*@ 5944 DMCopyDS - Copy the discrete systems for the DM into another DM 5945 5946 Collective on dm 5947 5948 Input Parameter: 5949 . dm - The DM 5950 5951 Output Parameter: 5952 . newdm - The DM 5953 5954 Level: advanced 5955 5956 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS() 5957 @*/ 5958 PetscErrorCode DMCopyDS(DM dm, DM newdm) 5959 { 5960 PetscInt Nds, s; 5961 5962 PetscFunctionBegin; 5963 if (dm == newdm) PetscFunctionReturn(0); 5964 PetscCall(DMGetNumDS(dm, &Nds)); 5965 PetscCall(DMClearDS(newdm)); 5966 for (s = 0; s < Nds; ++s) { 5967 DMLabel label; 5968 IS fields; 5969 PetscDS ds, newds; 5970 PetscInt Nbd, bd; 5971 5972 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds)); 5973 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 5974 PetscCall(DMTransferDS_Internal(newdm, label, fields, ds)); 5975 /* Commplete new labels in the new DS */ 5976 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds)); 5977 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 5978 for (bd = 0; bd < Nbd; ++bd) { 5979 PetscWeakForm wf; 5980 DMLabel label; 5981 PetscInt field; 5982 5983 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 5984 PetscCall(DMCompleteBoundaryLabel_Internal(newdm, newds, field, bd, label)); 5985 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 5986 } 5987 } 5988 PetscFunctionReturn(0); 5989 } 5990 5991 /*@ 5992 DMCopyDisc - Copy the fields and discrete systems for the DM into another DM 5993 5994 Collective on dm 5995 5996 Input Parameter: 5997 . dm - The DM 5998 5999 Output Parameter: 6000 . newdm - The DM 6001 6002 Level: advanced 6003 6004 .seealso: DMCopyFields(), DMCopyDS() 6005 @*/ 6006 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6007 { 6008 PetscFunctionBegin; 6009 PetscCall(DMCopyFields(dm, newdm)); 6010 PetscCall(DMCopyDS(dm, newdm)); 6011 PetscFunctionReturn(0); 6012 } 6013 6014 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx) 6015 { 6016 DM dm_coord,dmc_coord; 6017 Vec coords,ccoords; 6018 Mat inject; 6019 PetscFunctionBegin; 6020 PetscCall(DMGetCoordinateDM(dm,&dm_coord)); 6021 PetscCall(DMGetCoordinateDM(dmc,&dmc_coord)); 6022 PetscCall(DMGetCoordinates(dm,&coords)); 6023 PetscCall(DMGetCoordinates(dmc,&ccoords)); 6024 if (coords && !ccoords) { 6025 PetscCall(DMCreateGlobalVector(dmc_coord,&ccoords)); 6026 PetscCall(PetscObjectSetName((PetscObject)ccoords,"coordinates")); 6027 PetscCall(DMCreateInjection(dmc_coord,dm_coord,&inject)); 6028 PetscCall(MatRestrict(inject,coords,ccoords)); 6029 PetscCall(MatDestroy(&inject)); 6030 PetscCall(DMSetCoordinates(dmc,ccoords)); 6031 PetscCall(VecDestroy(&ccoords)); 6032 } 6033 PetscFunctionReturn(0); 6034 } 6035 6036 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx) 6037 { 6038 DM dm_coord,subdm_coord; 6039 Vec coords,ccoords,clcoords; 6040 VecScatter *scat_i,*scat_g; 6041 PetscFunctionBegin; 6042 PetscCall(DMGetCoordinateDM(dm,&dm_coord)); 6043 PetscCall(DMGetCoordinateDM(subdm,&subdm_coord)); 6044 PetscCall(DMGetCoordinates(dm,&coords)); 6045 PetscCall(DMGetCoordinates(subdm,&ccoords)); 6046 if (coords && !ccoords) { 6047 PetscCall(DMCreateGlobalVector(subdm_coord,&ccoords)); 6048 PetscCall(PetscObjectSetName((PetscObject)ccoords,"coordinates")); 6049 PetscCall(DMCreateLocalVector(subdm_coord,&clcoords)); 6050 PetscCall(PetscObjectSetName((PetscObject)clcoords,"coordinates")); 6051 PetscCall(DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g)); 6052 PetscCall(VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD)); 6053 PetscCall(VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD)); 6054 PetscCall(VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD)); 6055 PetscCall(VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD)); 6056 PetscCall(DMSetCoordinates(subdm,ccoords)); 6057 PetscCall(DMSetCoordinatesLocal(subdm,clcoords)); 6058 PetscCall(VecScatterDestroy(&scat_i[0])); 6059 PetscCall(VecScatterDestroy(&scat_g[0])); 6060 PetscCall(VecDestroy(&ccoords)); 6061 PetscCall(VecDestroy(&clcoords)); 6062 PetscCall(PetscFree(scat_i)); 6063 PetscCall(PetscFree(scat_g)); 6064 } 6065 PetscFunctionReturn(0); 6066 } 6067 6068 /*@ 6069 DMGetDimension - Return the topological dimension of the DM 6070 6071 Not collective 6072 6073 Input Parameter: 6074 . dm - The DM 6075 6076 Output Parameter: 6077 . dim - The topological dimension 6078 6079 Level: beginner 6080 6081 .seealso: DMSetDimension(), DMCreate() 6082 @*/ 6083 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6084 { 6085 PetscFunctionBegin; 6086 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6087 PetscValidIntPointer(dim, 2); 6088 *dim = dm->dim; 6089 PetscFunctionReturn(0); 6090 } 6091 6092 /*@ 6093 DMSetDimension - Set the topological dimension of the DM 6094 6095 Collective on dm 6096 6097 Input Parameters: 6098 + dm - The DM 6099 - dim - The topological dimension 6100 6101 Level: beginner 6102 6103 .seealso: DMGetDimension(), DMCreate() 6104 @*/ 6105 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6106 { 6107 PetscDS ds; 6108 PetscInt Nds, n; 6109 6110 PetscFunctionBegin; 6111 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6112 PetscValidLogicalCollectiveInt(dm, dim, 2); 6113 dm->dim = dim; 6114 if (dm->dim >= 0) { 6115 PetscCall(DMGetNumDS(dm, &Nds)); 6116 for (n = 0; n < Nds; ++n) { 6117 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds)); 6118 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6119 } 6120 } 6121 PetscFunctionReturn(0); 6122 } 6123 6124 /*@ 6125 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6126 6127 Collective on dm 6128 6129 Input Parameters: 6130 + dm - the DM 6131 - dim - the dimension 6132 6133 Output Parameters: 6134 + pStart - The first point of the given dimension 6135 - pEnd - The first point following points of the given dimension 6136 6137 Note: 6138 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6139 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6140 then the interval is empty. 6141 6142 Level: intermediate 6143 6144 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum() 6145 @*/ 6146 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6147 { 6148 PetscInt d; 6149 6150 PetscFunctionBegin; 6151 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6152 PetscCall(DMGetDimension(dm, &d)); 6153 PetscCheck((dim >= 0) && (dim <= d),PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6154 PetscCheck(dm->ops->getdimpoints,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name); 6155 PetscCall((*dm->ops->getdimpoints)(dm, dim, pStart, pEnd)); 6156 PetscFunctionReturn(0); 6157 } 6158 6159 /*@ 6160 DMSetCoordinates - Sets into the DM a global vector that holds the coordinates 6161 6162 Collective on dm 6163 6164 Input Parameters: 6165 + dm - the DM 6166 - c - coordinate vector 6167 6168 Notes: 6169 The coordinates do include those for ghost points, which are in the local vector. 6170 6171 The vector c should be destroyed by the caller. 6172 6173 Level: intermediate 6174 6175 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates() 6176 @*/ 6177 PetscErrorCode DMSetCoordinates(DM dm, Vec c) 6178 { 6179 PetscFunctionBegin; 6180 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6181 if (c) PetscValidHeaderSpecific(c,VEC_CLASSID,2); 6182 PetscCall(PetscObjectReference((PetscObject) c)); 6183 PetscCall(VecDestroy(&dm->coordinates)); 6184 dm->coordinates = c; 6185 PetscCall(VecDestroy(&dm->coordinatesLocal)); 6186 PetscCall(DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL)); 6187 PetscCall(DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL)); 6188 PetscFunctionReturn(0); 6189 } 6190 6191 /*@ 6192 DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates 6193 6194 Not collective 6195 6196 Input Parameters: 6197 + dm - the DM 6198 - c - coordinate vector 6199 6200 Notes: 6201 The coordinates of ghost points can be set using DMSetCoordinates() 6202 followed by DMGetCoordinatesLocal(). This is intended to enable the 6203 setting of ghost coordinates outside of the domain. 6204 6205 The vector c should be destroyed by the caller. 6206 6207 Level: intermediate 6208 6209 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM() 6210 @*/ 6211 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c) 6212 { 6213 PetscFunctionBegin; 6214 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6215 if (c) PetscValidHeaderSpecific(c,VEC_CLASSID,2); 6216 PetscCall(PetscObjectReference((PetscObject) c)); 6217 PetscCall(VecDestroy(&dm->coordinatesLocal)); 6218 6219 dm->coordinatesLocal = c; 6220 6221 PetscCall(VecDestroy(&dm->coordinates)); 6222 PetscFunctionReturn(0); 6223 } 6224 6225 /*@ 6226 DMGetCoordinates - Gets a global vector with the coordinates associated with the DM. 6227 6228 Collective on dm 6229 6230 Input Parameter: 6231 . dm - the DM 6232 6233 Output Parameter: 6234 . c - global coordinate vector 6235 6236 Note: 6237 This is a borrowed reference, so the user should NOT destroy this vector. When the DM is 6238 destroyed the array will no longer be valid. 6239 6240 Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates). 6241 6242 For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 6243 and (x_0,y_0,z_0,x_1,y_1,z_1...) 6244 6245 Level: intermediate 6246 6247 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMDASetUniformCoordinates() 6248 @*/ 6249 PetscErrorCode DMGetCoordinates(DM dm, Vec *c) 6250 { 6251 PetscFunctionBegin; 6252 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6253 PetscValidPointer(c,2); 6254 if (!dm->coordinates && dm->coordinatesLocal) { 6255 DM cdm = NULL; 6256 PetscBool localized; 6257 6258 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6259 PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates)); 6260 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 6261 /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */ 6262 if (localized) { 6263 PetscInt cdim; 6264 6265 PetscCall(DMGetCoordinateDim(dm, &cdim)); 6266 PetscCall(VecSetBlockSize(dm->coordinates, cdim)); 6267 } 6268 PetscCall(PetscObjectSetName((PetscObject) dm->coordinates, "coordinates")); 6269 PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates)); 6270 PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates)); 6271 } 6272 *c = dm->coordinates; 6273 PetscFunctionReturn(0); 6274 } 6275 6276 /*@ 6277 DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards. 6278 6279 Collective on dm 6280 6281 Input Parameter: 6282 . dm - the DM 6283 6284 Level: advanced 6285 6286 .seealso: DMGetCoordinatesLocalNoncollective() 6287 @*/ 6288 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm) 6289 { 6290 PetscFunctionBegin; 6291 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6292 if (!dm->coordinatesLocal && dm->coordinates) { 6293 DM cdm = NULL; 6294 PetscBool localized; 6295 6296 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6297 PetscCall(DMCreateLocalVector(cdm, &dm->coordinatesLocal)); 6298 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 6299 /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */ 6300 if (localized) { 6301 PetscInt cdim; 6302 6303 PetscCall(DMGetCoordinateDim(dm, &cdim)); 6304 PetscCall(VecSetBlockSize(dm->coordinates, cdim)); 6305 } 6306 PetscCall(PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates")); 6307 PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal)); 6308 PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal)); 6309 } 6310 PetscFunctionReturn(0); 6311 } 6312 6313 /*@ 6314 DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM. 6315 6316 Collective on dm 6317 6318 Input Parameter: 6319 . dm - the DM 6320 6321 Output Parameter: 6322 . c - coordinate vector 6323 6324 Note: 6325 This is a borrowed reference, so the user should NOT destroy this vector 6326 6327 Each process has the local and ghost coordinates 6328 6329 For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 6330 and (x_0,y_0,z_0,x_1,y_1,z_1...) 6331 6332 Level: intermediate 6333 6334 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective() 6335 @*/ 6336 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c) 6337 { 6338 PetscFunctionBegin; 6339 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6340 PetscValidPointer(c,2); 6341 PetscCall(DMGetCoordinatesLocalSetUp(dm)); 6342 *c = dm->coordinatesLocal; 6343 PetscFunctionReturn(0); 6344 } 6345 6346 /*@ 6347 DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called. 6348 6349 Not collective 6350 6351 Input Parameter: 6352 . dm - the DM 6353 6354 Output Parameter: 6355 . c - coordinate vector 6356 6357 Level: advanced 6358 6359 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM() 6360 @*/ 6361 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c) 6362 { 6363 PetscFunctionBegin; 6364 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6365 PetscValidPointer(c,2); 6366 PetscCheck(dm->coordinatesLocal || !dm->coordinates,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called"); 6367 *c = dm->coordinatesLocal; 6368 PetscFunctionReturn(0); 6369 } 6370 6371 /*@ 6372 DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout. 6373 6374 Not collective 6375 6376 Input Parameters: 6377 + dm - the DM 6378 - p - the IS of points whose coordinates will be returned 6379 6380 Output Parameters: 6381 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates 6382 - pCoord - the Vec with coordinates of points in p 6383 6384 Note: 6385 DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective. 6386 6387 This creates a new vector, so the user SHOULD destroy this vector 6388 6389 Each process has the local and ghost coordinates 6390 6391 For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 6392 and (x_0,y_0,z_0,x_1,y_1,z_1...) 6393 6394 Level: advanced 6395 6396 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM() 6397 @*/ 6398 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord) 6399 { 6400 PetscSection cs, newcs; 6401 Vec coords; 6402 const PetscScalar *arr; 6403 PetscScalar *newarr=NULL; 6404 PetscInt n; 6405 6406 PetscFunctionBegin; 6407 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6408 PetscValidHeaderSpecific(p, IS_CLASSID, 2); 6409 if (pCoordSection) PetscValidPointer(pCoordSection, 3); 6410 if (pCoord) PetscValidPointer(pCoord, 4); 6411 PetscCheck(dm->coordinatesLocal,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set"); 6412 PetscCheck(dm->coordinateDM && dm->coordinateDM->localSection,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported"); 6413 cs = dm->coordinateDM->localSection; 6414 coords = dm->coordinatesLocal; 6415 PetscCall(VecGetArrayRead(coords, &arr)); 6416 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL)); 6417 PetscCall(VecRestoreArrayRead(coords, &arr)); 6418 if (pCoord) { 6419 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 6420 /* set array in two steps to mimic PETSC_OWN_POINTER */ 6421 PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord)); 6422 PetscCall(VecReplaceArray(*pCoord, newarr)); 6423 } else { 6424 PetscCall(PetscFree(newarr)); 6425 } 6426 if (pCoordSection) {*pCoordSection = newcs;} 6427 else PetscCall(PetscSectionDestroy(&newcs)); 6428 PetscFunctionReturn(0); 6429 } 6430 6431 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field) 6432 { 6433 PetscFunctionBegin; 6434 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6435 PetscValidPointer(field,2); 6436 if (!dm->coordinateField) { 6437 if (dm->ops->createcoordinatefield) { 6438 PetscCall((*dm->ops->createcoordinatefield)(dm,&dm->coordinateField)); 6439 } 6440 } 6441 *field = dm->coordinateField; 6442 PetscFunctionReturn(0); 6443 } 6444 6445 PetscErrorCode DMSetCoordinateField(DM dm, DMField field) 6446 { 6447 PetscFunctionBegin; 6448 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6449 if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2); 6450 PetscCall(PetscObjectReference((PetscObject)field)); 6451 PetscCall(DMFieldDestroy(&dm->coordinateField)); 6452 dm->coordinateField = field; 6453 PetscFunctionReturn(0); 6454 } 6455 6456 /*@ 6457 DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates 6458 6459 Collective on dm 6460 6461 Input Parameter: 6462 . dm - the DM 6463 6464 Output Parameter: 6465 . cdm - coordinate DM 6466 6467 Level: intermediate 6468 6469 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal() 6470 @*/ 6471 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm) 6472 { 6473 PetscFunctionBegin; 6474 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6475 PetscValidPointer(cdm,2); 6476 if (!dm->coordinateDM) { 6477 DM cdm; 6478 6479 PetscCheck(dm->ops->createcoordinatedm,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM"); 6480 PetscCall((*dm->ops->createcoordinatedm)(dm, &cdm)); 6481 PetscCall(PetscObjectSetName((PetscObject)cdm, "coordinateDM")); 6482 /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup 6483 * until the call to CreateCoordinateDM) */ 6484 PetscCall(DMDestroy(&dm->coordinateDM)); 6485 dm->coordinateDM = cdm; 6486 } 6487 *cdm = dm->coordinateDM; 6488 PetscFunctionReturn(0); 6489 } 6490 6491 /*@ 6492 DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates 6493 6494 Logically Collective on dm 6495 6496 Input Parameters: 6497 + dm - the DM 6498 - cdm - coordinate DM 6499 6500 Level: intermediate 6501 6502 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal() 6503 @*/ 6504 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm) 6505 { 6506 PetscFunctionBegin; 6507 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6508 PetscValidHeaderSpecific(cdm,DM_CLASSID,2); 6509 PetscCall(PetscObjectReference((PetscObject)cdm)); 6510 PetscCall(DMDestroy(&dm->coordinateDM)); 6511 dm->coordinateDM = cdm; 6512 PetscFunctionReturn(0); 6513 } 6514 6515 /*@ 6516 DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values. 6517 6518 Not Collective 6519 6520 Input Parameter: 6521 . dm - The DM object 6522 6523 Output Parameter: 6524 . dim - The embedding dimension 6525 6526 Level: intermediate 6527 6528 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection() 6529 @*/ 6530 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim) 6531 { 6532 PetscFunctionBegin; 6533 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6534 PetscValidIntPointer(dim, 2); 6535 if (dm->dimEmbed == PETSC_DEFAULT) { 6536 dm->dimEmbed = dm->dim; 6537 } 6538 *dim = dm->dimEmbed; 6539 PetscFunctionReturn(0); 6540 } 6541 6542 /*@ 6543 DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values. 6544 6545 Not Collective 6546 6547 Input Parameters: 6548 + dm - The DM object 6549 - dim - The embedding dimension 6550 6551 Level: intermediate 6552 6553 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection() 6554 @*/ 6555 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim) 6556 { 6557 PetscDS ds; 6558 PetscInt Nds, n; 6559 6560 PetscFunctionBegin; 6561 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6562 dm->dimEmbed = dim; 6563 if (dm->dim >= 0) { 6564 PetscCall(DMGetNumDS(dm, &Nds)); 6565 for (n = 0; n < Nds; ++n) { 6566 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds)); 6567 PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6568 } 6569 } 6570 PetscFunctionReturn(0); 6571 } 6572 6573 /*@ 6574 DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh. 6575 6576 Collective on dm 6577 6578 Input Parameter: 6579 . dm - The DM object 6580 6581 Output Parameter: 6582 . section - The PetscSection object 6583 6584 Level: intermediate 6585 6586 .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection() 6587 @*/ 6588 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section) 6589 { 6590 DM cdm; 6591 6592 PetscFunctionBegin; 6593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6594 PetscValidPointer(section, 2); 6595 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6596 PetscCall(DMGetLocalSection(cdm, section)); 6597 PetscFunctionReturn(0); 6598 } 6599 6600 /*@ 6601 DMSetCoordinateSection - Set the layout of coordinate values over the mesh. 6602 6603 Not Collective 6604 6605 Input Parameters: 6606 + dm - The DM object 6607 . dim - The embedding dimension, or PETSC_DETERMINE 6608 - section - The PetscSection object 6609 6610 Level: intermediate 6611 6612 .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection() 6613 @*/ 6614 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section) 6615 { 6616 DM cdm; 6617 6618 PetscFunctionBegin; 6619 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6620 PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3); 6621 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6622 PetscCall(DMSetLocalSection(cdm, section)); 6623 if (dim == PETSC_DETERMINE) { 6624 PetscInt d = PETSC_DEFAULT; 6625 PetscInt pStart, pEnd, vStart, vEnd, v, dd; 6626 6627 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 6628 PetscCall(DMGetDimPoints(dm, 0, &vStart, &vEnd)); 6629 pStart = PetscMax(vStart, pStart); 6630 pEnd = PetscMin(vEnd, pEnd); 6631 for (v = pStart; v < pEnd; ++v) { 6632 PetscCall(PetscSectionGetDof(section, v, &dd)); 6633 if (dd) {d = dd; break;} 6634 } 6635 if (d >= 0) PetscCall(DMSetCoordinateDim(dm, d)); 6636 } 6637 PetscFunctionReturn(0); 6638 } 6639 6640 /*@ 6641 DMProjectCoordinates - Project coordinates to a different space 6642 6643 Input Parameters: 6644 + dm - The DM object 6645 - disc - The new coordinate discretization or NULL to ensure a coordinate discretization exists 6646 6647 Level: intermediate 6648 6649 .seealso: DMGetCoordinateField() 6650 @*/ 6651 PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc) 6652 { 6653 PetscFE discOld; 6654 PetscClassId classid; 6655 DM cdmOld,cdmNew; 6656 Vec coordsOld,coordsNew; 6657 Mat matInterp; 6658 PetscBool same_space = PETSC_TRUE; 6659 6660 PetscFunctionBegin; 6661 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6662 if (disc) PetscValidHeaderSpecific(disc,PETSCFE_CLASSID,2); 6663 6664 PetscCall(DMGetCoordinateDM(dm, &cdmOld)); 6665 /* Check current discretization is compatible */ 6666 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld)); 6667 PetscCall(PetscObjectGetClassId((PetscObject)discOld, &classid)); 6668 if (classid != PETSCFE_CLASSID) { 6669 if (classid == PETSC_CONTAINER_CLASSID) { 6670 PetscFE feLinear; 6671 DMPolytopeType ct; 6672 PetscInt dim, dE, cStart, cEnd; 6673 PetscBool simplex; 6674 6675 /* Assume linear vertex coordinates */ 6676 PetscCall(DMGetDimension(dm, &dim)); 6677 PetscCall(DMGetCoordinateDim(dm, &dE)); 6678 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 6679 if (cEnd > cStart) { 6680 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 6681 switch (ct) { 6682 case DM_POLYTOPE_TRI_PRISM: 6683 case DM_POLYTOPE_TRI_PRISM_TENSOR: 6684 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms"); 6685 default: break; 6686 } 6687 } 6688 PetscCall(DMPlexIsSimplex(dm, &simplex)); 6689 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear)); 6690 PetscCall(DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear)); 6691 PetscCall(PetscFEDestroy(&feLinear)); 6692 PetscCall(DMCreateDS(cdmOld)); 6693 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld)); 6694 } else { 6695 const char *discname; 6696 6697 PetscCall(PetscObjectGetType((PetscObject)discOld, &discname)); 6698 SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname); 6699 } 6700 } 6701 if (!disc) PetscFunctionReturn(0); 6702 { // Check if the new space is the same as the old modulo quadrature 6703 PetscDualSpace dsOld, ds; 6704 PetscCall(PetscFEGetDualSpace(discOld, &dsOld)); 6705 PetscCall(PetscFEGetDualSpace(disc, &ds)); 6706 PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space)); 6707 } 6708 /* Make a fresh clone of the coordinate DM */ 6709 PetscCall(DMClone(cdmOld, &cdmNew)); 6710 PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject) disc)); 6711 PetscCall(DMCreateDS(cdmNew)); 6712 PetscCall(DMGetCoordinates(dm, &coordsOld)); 6713 if (same_space) { 6714 PetscCall(PetscObjectReference((PetscObject)coordsOld)); 6715 coordsNew = coordsOld; 6716 } else { // Project the coordinate vector from old to new space 6717 PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew)); 6718 PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL)); 6719 PetscCall(MatInterpolate(matInterp, coordsOld, coordsNew)); 6720 PetscCall(MatDestroy(&matInterp)); 6721 } 6722 /* Set new coordinate structures */ 6723 PetscCall(DMSetCoordinateField(dm, NULL)); 6724 PetscCall(DMSetCoordinateDM(dm, cdmNew)); 6725 PetscCall(DMSetCoordinates(dm, coordsNew)); 6726 PetscCall(VecDestroy(&coordsNew)); 6727 PetscCall(DMDestroy(&cdmNew)); 6728 PetscFunctionReturn(0); 6729 } 6730 6731 /*@C 6732 DMGetPeriodicity - Get the description of mesh periodicity 6733 6734 Input Parameter: 6735 . dm - The DM object 6736 6737 Output Parameters: 6738 + per - Whether the DM is periodic or not 6739 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates 6740 . L - If we assume the mesh is a torus, this is the length of each coordinate 6741 - bd - This describes the type of periodicity in each topological dimension 6742 6743 Level: developer 6744 6745 .seealso: DMGetPeriodicity() 6746 @*/ 6747 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd) 6748 { 6749 PetscFunctionBegin; 6750 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6751 if (per) *per = dm->periodic; 6752 if (L) *L = dm->L; 6753 if (maxCell) *maxCell = dm->maxCell; 6754 if (bd) *bd = dm->bdtype; 6755 PetscFunctionReturn(0); 6756 } 6757 6758 /*@C 6759 DMSetPeriodicity - Set the description of mesh periodicity 6760 6761 Input Parameters: 6762 + dm - The DM object 6763 . per - Whether the DM is periodic or not. 6764 . 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. 6765 . L - If we assume the mesh is a torus, this is the length of each coordinate 6766 - bd - This describes the type of periodicity in each topological dimension 6767 6768 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. 6769 6770 Level: developer 6771 6772 .seealso: DMGetPeriodicity() 6773 @*/ 6774 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[]) 6775 { 6776 PetscInt dim, d; 6777 6778 PetscFunctionBegin; 6779 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6780 PetscValidLogicalCollectiveBool(dm,per,2); 6781 if (maxCell) {PetscValidRealPointer(maxCell,3);} 6782 if (L) {PetscValidRealPointer(L,4);} 6783 if (bd) {PetscValidPointer(bd,5);} 6784 PetscCall(DMGetDimension(dm, &dim)); 6785 if (maxCell) { 6786 if (!dm->maxCell) PetscCall(PetscMalloc1(dim, &dm->maxCell)); 6787 for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d]; 6788 } else { /* remove maxCell information to disable automatic computation of localized vertices */ 6789 PetscCall(PetscFree(dm->maxCell)); 6790 } 6791 6792 if (L) { 6793 if (!dm->L) PetscCall(PetscMalloc1(dim, &dm->L)); 6794 for (d = 0; d < dim; ++d) dm->L[d] = L[d]; 6795 } 6796 if (bd) { 6797 if (!dm->bdtype) PetscCall(PetscMalloc1(dim, &dm->bdtype)); 6798 for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d]; 6799 } 6800 dm->periodic = per; 6801 PetscFunctionReturn(0); 6802 } 6803 6804 /*@ 6805 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. 6806 6807 Input Parameters: 6808 + dm - The DM 6809 . in - The input coordinate point (dim numbers) 6810 - endpoint - Include the endpoint L_i 6811 6812 Output Parameter: 6813 . out - The localized coordinate point 6814 6815 Level: developer 6816 6817 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate() 6818 @*/ 6819 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[]) 6820 { 6821 PetscInt dim, d; 6822 6823 PetscFunctionBegin; 6824 PetscCall(DMGetCoordinateDim(dm, &dim)); 6825 if (!dm->maxCell) { 6826 for (d = 0; d < dim; ++d) out[d] = in[d]; 6827 } else { 6828 if (endpoint) { 6829 for (d = 0; d < dim; ++d) { 6830 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)) { 6831 out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1); 6832 } else { 6833 out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]); 6834 } 6835 } 6836 } else { 6837 for (d = 0; d < dim; ++d) { 6838 out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]); 6839 } 6840 } 6841 } 6842 PetscFunctionReturn(0); 6843 } 6844 6845 /* 6846 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. 6847 6848 Input Parameters: 6849 + dm - The DM 6850 . dim - The spatial dimension 6851 . anchor - The anchor point, the input point can be no more than maxCell away from it 6852 - in - The input coordinate point (dim numbers) 6853 6854 Output Parameter: 6855 . out - The localized coordinate point 6856 6857 Level: developer 6858 6859 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 6860 6861 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate() 6862 */ 6863 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 6864 { 6865 PetscInt d; 6866 6867 PetscFunctionBegin; 6868 if (!dm->maxCell) { 6869 for (d = 0; d < dim; ++d) out[d] = in[d]; 6870 } else { 6871 for (d = 0; d < dim; ++d) { 6872 if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) { 6873 out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 6874 } else { 6875 out[d] = in[d]; 6876 } 6877 } 6878 } 6879 PetscFunctionReturn(0); 6880 } 6881 6882 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[]) 6883 { 6884 PetscInt d; 6885 6886 PetscFunctionBegin; 6887 if (!dm->maxCell) { 6888 for (d = 0; d < dim; ++d) out[d] = in[d]; 6889 } else { 6890 for (d = 0; d < dim; ++d) { 6891 if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) { 6892 out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d]; 6893 } else { 6894 out[d] = in[d]; 6895 } 6896 } 6897 } 6898 PetscFunctionReturn(0); 6899 } 6900 6901 /* 6902 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. 6903 6904 Input Parameters: 6905 + dm - The DM 6906 . dim - The spatial dimension 6907 . anchor - The anchor point, the input point can be no more than maxCell away from it 6908 . in - The input coordinate delta (dim numbers) 6909 - out - The input coordinate point (dim numbers) 6910 6911 Output Parameter: 6912 . out - The localized coordinate in + out 6913 6914 Level: developer 6915 6916 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 6917 6918 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate() 6919 */ 6920 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 6921 { 6922 PetscInt d; 6923 6924 PetscFunctionBegin; 6925 if (!dm->maxCell) { 6926 for (d = 0; d < dim; ++d) out[d] += in[d]; 6927 } else { 6928 for (d = 0; d < dim; ++d) { 6929 const PetscReal maxC = dm->maxCell[d]; 6930 6931 if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) { 6932 const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 6933 6934 if (PetscAbsScalar(newCoord - anchor[d]) > maxC) 6935 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])); 6936 out[d] += newCoord; 6937 } else { 6938 out[d] += in[d]; 6939 } 6940 } 6941 } 6942 PetscFunctionReturn(0); 6943 } 6944 6945 /*@ 6946 DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process 6947 6948 Not collective 6949 6950 Input Parameter: 6951 . dm - The DM 6952 6953 Output Parameter: 6954 areLocalized - True if localized 6955 6956 Level: developer 6957 6958 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity() 6959 @*/ 6960 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized) 6961 { 6962 DM cdm; 6963 PetscSection coordSection; 6964 PetscInt depth, cStart, cEnd, sStart, sEnd, c, dof; 6965 PetscBool isPlex, alreadyLocalized; 6966 6967 PetscFunctionBegin; 6968 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6969 PetscValidBoolPointer(areLocalized, 2); 6970 *areLocalized = PETSC_FALSE; 6971 6972 /* We need some generic way of refering to cells/vertices */ 6973 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6974 PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex)); 6975 if (!isPlex) PetscFunctionReturn(0); 6976 PetscCall(DMPlexGetDepth(cdm, &depth)); 6977 if (!depth) PetscFunctionReturn(0); 6978 6979 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6980 PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd)); 6981 PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd)); 6982 alreadyLocalized = PETSC_FALSE; 6983 for (c = cStart; c < cEnd; ++c) { 6984 if (c < sStart || c >= sEnd) continue; 6985 PetscCall(PetscSectionGetDof(coordSection, c, &dof)); 6986 if (dof) { alreadyLocalized = PETSC_TRUE; break; } 6987 } 6988 *areLocalized = alreadyLocalized; 6989 PetscFunctionReturn(0); 6990 } 6991 6992 /*@ 6993 DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells 6994 6995 Collective on dm 6996 6997 Input Parameter: 6998 . dm - The DM 6999 7000 Output Parameter: 7001 areLocalized - True if localized 7002 7003 Level: developer 7004 7005 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal() 7006 @*/ 7007 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized) 7008 { 7009 PetscBool localized; 7010 7011 PetscFunctionBegin; 7012 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7013 PetscValidBoolPointer(areLocalized, 2); 7014 PetscCall(DMGetCoordinatesLocalizedLocal(dm,&localized)); 7015 PetscCall(MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm))); 7016 PetscFunctionReturn(0); 7017 } 7018 7019 /*@ 7020 DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces 7021 7022 Collective on dm 7023 7024 Input Parameter: 7025 . dm - The DM 7026 7027 Level: developer 7028 7029 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate() 7030 @*/ 7031 PetscErrorCode DMLocalizeCoordinates(DM dm) 7032 { 7033 DM cdm; 7034 PetscSection coordSection, cSection; 7035 Vec coordinates, cVec; 7036 PetscScalar *coords, *coords2, *anchor, *localized; 7037 PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize; 7038 PetscBool alreadyLocalized, alreadyLocalizedGlobal; 7039 PetscInt maxHeight = 0, h; 7040 PetscInt *pStart = NULL, *pEnd = NULL; 7041 7042 PetscFunctionBegin; 7043 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7044 if (!dm->periodic) PetscFunctionReturn(0); 7045 PetscCall(DMGetCoordinatesLocalized(dm, &alreadyLocalized)); 7046 if (alreadyLocalized) PetscFunctionReturn(0); 7047 7048 /* We need some generic way of refering to cells/vertices */ 7049 PetscCall(DMGetCoordinateDM(dm, &cdm)); 7050 { 7051 PetscBool isplex; 7052 7053 PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex)); 7054 if (isplex) { 7055 PetscCall(DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd)); 7056 PetscCall(DMPlexGetMaxProjectionHeight(cdm,&maxHeight)); 7057 PetscCall(DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart)); 7058 pEnd = &pStart[maxHeight + 1]; 7059 newStart = vStart; 7060 newEnd = vEnd; 7061 for (h = 0; h <= maxHeight; h++) { 7062 PetscCall(DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h])); 7063 newStart = PetscMin(newStart,pStart[h]); 7064 newEnd = PetscMax(newEnd,pEnd[h]); 7065 } 7066 } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM"); 7067 } 7068 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 7069 PetscCheck(coordinates,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector"); 7070 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 7071 PetscCall(VecGetBlockSize(coordinates, &bs)); 7072 PetscCall(PetscSectionGetChart(coordSection,&sStart,&sEnd)); 7073 7074 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection)); 7075 PetscCall(PetscSectionSetNumFields(cSection, 1)); 7076 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 7077 PetscCall(PetscSectionSetFieldComponents(cSection, 0, Nc)); 7078 PetscCall(PetscSectionSetChart(cSection, newStart, newEnd)); 7079 7080 PetscCall(DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 7081 localized = &anchor[bs]; 7082 alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE; 7083 for (h = 0; h <= maxHeight; h++) { 7084 PetscInt cStart = pStart[h], cEnd = pEnd[h], c; 7085 7086 for (c = cStart; c < cEnd; ++c) { 7087 PetscScalar *cellCoords = NULL; 7088 PetscInt b; 7089 7090 if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE; 7091 PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7092 for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b]; 7093 for (d = 0; d < dof/bs; ++d) { 7094 PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized)); 7095 for (b = 0; b < bs; b++) { 7096 if (cellCoords[d*bs + b] != localized[b]) break; 7097 } 7098 if (b < bs) break; 7099 } 7100 if (d < dof/bs) { 7101 if (c >= sStart && c < sEnd) { 7102 PetscInt cdof; 7103 7104 PetscCall(PetscSectionGetDof(coordSection, c, &cdof)); 7105 if (cdof != dof) alreadyLocalized = PETSC_FALSE; 7106 } 7107 PetscCall(PetscSectionSetDof(cSection, c, dof)); 7108 PetscCall(PetscSectionSetFieldDof(cSection, c, 0, dof)); 7109 } 7110 PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7111 } 7112 } 7113 PetscCallMPI(MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm))); 7114 if (alreadyLocalizedGlobal) { 7115 PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 7116 PetscCall(PetscSectionDestroy(&cSection)); 7117 PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart)); 7118 PetscFunctionReturn(0); 7119 } 7120 for (v = vStart; v < vEnd; ++v) { 7121 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 7122 PetscCall(PetscSectionSetDof(cSection, v, dof)); 7123 PetscCall(PetscSectionSetFieldDof(cSection, v, 0, dof)); 7124 } 7125 PetscCall(PetscSectionSetUp(cSection)); 7126 PetscCall(PetscSectionGetStorageSize(cSection, &coordSize)); 7127 PetscCall(VecCreate(PETSC_COMM_SELF, &cVec)); 7128 PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates")); 7129 PetscCall(VecSetBlockSize(cVec, bs)); 7130 PetscCall(VecSetSizes(cVec, coordSize, PETSC_DETERMINE)); 7131 PetscCall(VecSetType(cVec, VECSTANDARD)); 7132 PetscCall(VecGetArrayRead(coordinates, (const PetscScalar**)&coords)); 7133 PetscCall(VecGetArray(cVec, &coords2)); 7134 for (v = vStart; v < vEnd; ++v) { 7135 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 7136 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 7137 PetscCall(PetscSectionGetOffset(cSection, v, &off2)); 7138 for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d]; 7139 } 7140 for (h = 0; h <= maxHeight; h++) { 7141 PetscInt cStart = pStart[h], cEnd = pEnd[h], c; 7142 7143 for (c = cStart; c < cEnd; ++c) { 7144 PetscScalar *cellCoords = NULL; 7145 PetscInt b, cdof; 7146 7147 PetscCall(PetscSectionGetDof(cSection,c,&cdof)); 7148 if (!cdof) continue; 7149 PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7150 PetscCall(PetscSectionGetOffset(cSection, c, &off2)); 7151 for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b]; 7152 for (d = 0; d < dof/bs; ++d) PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs])); 7153 PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7154 } 7155 } 7156 PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 7157 PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart)); 7158 PetscCall(VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords)); 7159 PetscCall(VecRestoreArray(cVec, &coords2)); 7160 PetscCall(DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection)); 7161 PetscCall(DMSetCoordinatesLocal(dm, cVec)); 7162 PetscCall(VecDestroy(&cVec)); 7163 PetscCall(PetscSectionDestroy(&cSection)); 7164 PetscFunctionReturn(0); 7165 } 7166 7167 /*@ 7168 DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells 7169 7170 Collective on v (see explanation below) 7171 7172 Input Parameters: 7173 + dm - The DM 7174 - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST 7175 7176 Input/Output Parameters: 7177 + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used 7178 - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point; 7179 on output, the PetscSF containing the ranks and local indices of the containing points 7180 7181 Level: developer 7182 7183 Notes: 7184 To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator. 7185 To do a search of all the cells in the distributed mesh, v should have the same communicator as dm. 7186 7187 If *cellSF is NULL on input, a PetscSF will be created. 7188 If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses. 7189 7190 An array that maps each point to its containing cell can be obtained with 7191 7192 $ const PetscSFNode *cells; 7193 $ PetscInt nFound; 7194 $ const PetscInt *found; 7195 $ 7196 $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells); 7197 7198 Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is 7199 the index of the cell in its rank's local numbering. 7200 7201 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType 7202 @*/ 7203 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF) 7204 { 7205 PetscFunctionBegin; 7206 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7207 PetscValidHeaderSpecific(v,VEC_CLASSID,2); 7208 PetscValidPointer(cellSF,4); 7209 if (*cellSF) { 7210 PetscMPIInt result; 7211 7212 PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4); 7213 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result)); 7214 PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's"); 7215 } else { 7216 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF)); 7217 } 7218 PetscCheck(dm->ops->locatepoints,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM"); 7219 PetscCall(PetscLogEventBegin(DM_LocatePoints,dm,0,0,0)); 7220 PetscCall((*dm->ops->locatepoints)(dm,v,ltype,*cellSF)); 7221 PetscCall(PetscLogEventEnd(DM_LocatePoints,dm,0,0,0)); 7222 PetscFunctionReturn(0); 7223 } 7224 7225 /*@ 7226 DMGetOutputDM - Retrieve the DM associated with the layout for output 7227 7228 Collective on dm 7229 7230 Input Parameter: 7231 . dm - The original DM 7232 7233 Output Parameter: 7234 . odm - The DM which provides the layout for output 7235 7236 Level: intermediate 7237 7238 .seealso: VecView(), DMGetGlobalSection() 7239 @*/ 7240 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 7241 { 7242 PetscSection section; 7243 PetscBool hasConstraints, ghasConstraints; 7244 7245 PetscFunctionBegin; 7246 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7247 PetscValidPointer(odm,2); 7248 PetscCall(DMGetLocalSection(dm, §ion)); 7249 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 7250 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 7251 if (!ghasConstraints) { 7252 *odm = dm; 7253 PetscFunctionReturn(0); 7254 } 7255 if (!dm->dmBC) { 7256 PetscSection newSection, gsection; 7257 PetscSF sf; 7258 7259 PetscCall(DMClone(dm, &dm->dmBC)); 7260 PetscCall(DMCopyDisc(dm, dm->dmBC)); 7261 PetscCall(PetscSectionClone(section, &newSection)); 7262 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 7263 PetscCall(PetscSectionDestroy(&newSection)); 7264 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 7265 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 7266 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 7267 PetscCall(PetscSectionDestroy(&gsection)); 7268 } 7269 *odm = dm->dmBC; 7270 PetscFunctionReturn(0); 7271 } 7272 7273 /*@ 7274 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 7275 7276 Input Parameter: 7277 . dm - The original DM 7278 7279 Output Parameters: 7280 + num - The output sequence number 7281 - val - The output sequence value 7282 7283 Level: intermediate 7284 7285 Note: This is intended for output that should appear in sequence, for instance 7286 a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system. 7287 7288 .seealso: VecView() 7289 @*/ 7290 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 7291 { 7292 PetscFunctionBegin; 7293 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7294 if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;} 7295 if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;} 7296 PetscFunctionReturn(0); 7297 } 7298 7299 /*@ 7300 DMSetOutputSequenceNumber - Set the sequence number/value for output 7301 7302 Input Parameters: 7303 + dm - The original DM 7304 . num - The output sequence number 7305 - val - The output sequence value 7306 7307 Level: intermediate 7308 7309 Note: This is intended for output that should appear in sequence, for instance 7310 a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system. 7311 7312 .seealso: VecView() 7313 @*/ 7314 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 7315 { 7316 PetscFunctionBegin; 7317 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7318 dm->outputSequenceNum = num; 7319 dm->outputSequenceVal = val; 7320 PetscFunctionReturn(0); 7321 } 7322 7323 /*@C 7324 DMOutputSequenceLoad - Retrieve the sequence value from a Viewer 7325 7326 Input Parameters: 7327 + dm - The original DM 7328 . name - The sequence name 7329 - num - The output sequence number 7330 7331 Output Parameter: 7332 . val - The output sequence value 7333 7334 Level: intermediate 7335 7336 Note: This is intended for output that should appear in sequence, for instance 7337 a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system. 7338 7339 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView() 7340 @*/ 7341 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val) 7342 { 7343 PetscBool ishdf5; 7344 7345 PetscFunctionBegin; 7346 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7347 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 7348 PetscValidRealPointer(val,5); 7349 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 7350 if (ishdf5) { 7351 #if defined(PETSC_HAVE_HDF5) 7352 PetscScalar value; 7353 7354 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 7355 *val = PetscRealPart(value); 7356 #endif 7357 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 7358 PetscFunctionReturn(0); 7359 } 7360 7361 /*@ 7362 DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution 7363 7364 Not collective 7365 7366 Input Parameter: 7367 . dm - The DM 7368 7369 Output Parameter: 7370 . useNatural - The flag to build the mapping to a natural order during distribution 7371 7372 Level: beginner 7373 7374 .seealso: DMSetUseNatural(), DMCreate() 7375 @*/ 7376 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 7377 { 7378 PetscFunctionBegin; 7379 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7380 PetscValidBoolPointer(useNatural, 2); 7381 *useNatural = dm->useNatural; 7382 PetscFunctionReturn(0); 7383 } 7384 7385 /*@ 7386 DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution 7387 7388 Collective on dm 7389 7390 Input Parameters: 7391 + dm - The DM 7392 - useNatural - The flag to build the mapping to a natural order during distribution 7393 7394 Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM() 7395 7396 Level: beginner 7397 7398 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM() 7399 @*/ 7400 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 7401 { 7402 PetscFunctionBegin; 7403 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7404 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 7405 dm->useNatural = useNatural; 7406 PetscFunctionReturn(0); 7407 } 7408 7409 /*@C 7410 DMCreateLabel - Create a label of the given name if it does not already exist 7411 7412 Not Collective 7413 7414 Input Parameters: 7415 + dm - The DM object 7416 - name - The label name 7417 7418 Level: intermediate 7419 7420 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7421 @*/ 7422 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 7423 { 7424 PetscBool flg; 7425 DMLabel label; 7426 7427 PetscFunctionBegin; 7428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7429 PetscValidCharPointer(name, 2); 7430 PetscCall(DMHasLabel(dm, name, &flg)); 7431 if (!flg) { 7432 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 7433 PetscCall(DMAddLabel(dm, label)); 7434 PetscCall(DMLabelDestroy(&label)); 7435 } 7436 PetscFunctionReturn(0); 7437 } 7438 7439 /*@C 7440 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists, move it to this index. 7441 7442 Not Collective 7443 7444 Input Parameters: 7445 + dm - The DM object 7446 . l - The index for the label 7447 - name - The label name 7448 7449 Level: intermediate 7450 7451 .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7452 @*/ 7453 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 7454 { 7455 DMLabelLink orig, prev = NULL; 7456 DMLabel label; 7457 PetscInt Nl, m; 7458 PetscBool flg, match; 7459 const char *lname; 7460 7461 PetscFunctionBegin; 7462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7463 PetscValidCharPointer(name, 3); 7464 PetscCall(DMHasLabel(dm, name, &flg)); 7465 if (!flg) { 7466 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 7467 PetscCall(DMAddLabel(dm, label)); 7468 PetscCall(DMLabelDestroy(&label)); 7469 } 7470 PetscCall(DMGetNumLabels(dm, &Nl)); 7471 PetscCheck(l < Nl,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 7472 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 7473 PetscCall(PetscObjectGetName((PetscObject) orig->label, &lname)); 7474 PetscCall(PetscStrcmp(name, lname, &match)); 7475 if (match) break; 7476 } 7477 if (m == l) PetscFunctionReturn(0); 7478 if (!m) dm->labels = orig->next; 7479 else prev->next = orig->next; 7480 if (!l) { 7481 orig->next = dm->labels; 7482 dm->labels = orig; 7483 } else { 7484 for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next); 7485 orig->next = prev->next; 7486 prev->next = orig; 7487 } 7488 PetscFunctionReturn(0); 7489 } 7490 7491 /*@C 7492 DMGetLabelValue - Get the value in a DMLabel for the given point, with -1 as the default 7493 7494 Not Collective 7495 7496 Input Parameters: 7497 + dm - The DM object 7498 . name - The label name 7499 - point - The mesh point 7500 7501 Output Parameter: 7502 . value - The label value for this point, or -1 if the point is not in the label 7503 7504 Level: beginner 7505 7506 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS() 7507 @*/ 7508 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 7509 { 7510 DMLabel label; 7511 7512 PetscFunctionBegin; 7513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7514 PetscValidCharPointer(name, 2); 7515 PetscCall(DMGetLabel(dm, name, &label)); 7516 PetscCheck(label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 7517 PetscCall(DMLabelGetValue(label, point, value)); 7518 PetscFunctionReturn(0); 7519 } 7520 7521 /*@C 7522 DMSetLabelValue - Add a point to a DMLabel with given value 7523 7524 Not Collective 7525 7526 Input Parameters: 7527 + dm - The DM object 7528 . name - The label name 7529 . point - The mesh point 7530 - value - The label value for this point 7531 7532 Output Parameter: 7533 7534 Level: beginner 7535 7536 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue() 7537 @*/ 7538 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 7539 { 7540 DMLabel label; 7541 7542 PetscFunctionBegin; 7543 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7544 PetscValidCharPointer(name, 2); 7545 PetscCall(DMGetLabel(dm, name, &label)); 7546 if (!label) { 7547 PetscCall(DMCreateLabel(dm, name)); 7548 PetscCall(DMGetLabel(dm, name, &label)); 7549 } 7550 PetscCall(DMLabelSetValue(label, point, value)); 7551 PetscFunctionReturn(0); 7552 } 7553 7554 /*@C 7555 DMClearLabelValue - Remove a point from a DMLabel with given value 7556 7557 Not Collective 7558 7559 Input Parameters: 7560 + dm - The DM object 7561 . name - The label name 7562 . point - The mesh point 7563 - value - The label value for this point 7564 7565 Output Parameter: 7566 7567 Level: beginner 7568 7569 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS() 7570 @*/ 7571 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 7572 { 7573 DMLabel label; 7574 7575 PetscFunctionBegin; 7576 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7577 PetscValidCharPointer(name, 2); 7578 PetscCall(DMGetLabel(dm, name, &label)); 7579 if (!label) PetscFunctionReturn(0); 7580 PetscCall(DMLabelClearValue(label, point, value)); 7581 PetscFunctionReturn(0); 7582 } 7583 7584 /*@C 7585 DMGetLabelSize - Get the number of different integer ids in a Label 7586 7587 Not Collective 7588 7589 Input Parameters: 7590 + dm - The DM object 7591 - name - The label name 7592 7593 Output Parameter: 7594 . size - The number of different integer ids, or 0 if the label does not exist 7595 7596 Level: beginner 7597 7598 .seealso: DMLabelGetNumValues(), DMSetLabelValue() 7599 @*/ 7600 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 7601 { 7602 DMLabel label; 7603 7604 PetscFunctionBegin; 7605 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7606 PetscValidCharPointer(name, 2); 7607 PetscValidIntPointer(size, 3); 7608 PetscCall(DMGetLabel(dm, name, &label)); 7609 *size = 0; 7610 if (!label) PetscFunctionReturn(0); 7611 PetscCall(DMLabelGetNumValues(label, size)); 7612 PetscFunctionReturn(0); 7613 } 7614 7615 /*@C 7616 DMGetLabelIdIS - Get the integer ids in a label 7617 7618 Not Collective 7619 7620 Input Parameters: 7621 + mesh - The DM object 7622 - name - The label name 7623 7624 Output Parameter: 7625 . ids - The integer ids, or NULL if the label does not exist 7626 7627 Level: beginner 7628 7629 .seealso: DMLabelGetValueIS(), DMGetLabelSize() 7630 @*/ 7631 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 7632 { 7633 DMLabel label; 7634 7635 PetscFunctionBegin; 7636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7637 PetscValidCharPointer(name, 2); 7638 PetscValidPointer(ids, 3); 7639 PetscCall(DMGetLabel(dm, name, &label)); 7640 *ids = NULL; 7641 if (label) { 7642 PetscCall(DMLabelGetValueIS(label, ids)); 7643 } else { 7644 /* returning an empty IS */ 7645 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids)); 7646 } 7647 PetscFunctionReturn(0); 7648 } 7649 7650 /*@C 7651 DMGetStratumSize - Get the number of points in a label stratum 7652 7653 Not Collective 7654 7655 Input Parameters: 7656 + dm - The DM object 7657 . name - The label name 7658 - value - The stratum value 7659 7660 Output Parameter: 7661 . size - The stratum size 7662 7663 Level: beginner 7664 7665 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds() 7666 @*/ 7667 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 7668 { 7669 DMLabel label; 7670 7671 PetscFunctionBegin; 7672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7673 PetscValidCharPointer(name, 2); 7674 PetscValidIntPointer(size, 4); 7675 PetscCall(DMGetLabel(dm, name, &label)); 7676 *size = 0; 7677 if (!label) PetscFunctionReturn(0); 7678 PetscCall(DMLabelGetStratumSize(label, value, size)); 7679 PetscFunctionReturn(0); 7680 } 7681 7682 /*@C 7683 DMGetStratumIS - Get the points in a label stratum 7684 7685 Not Collective 7686 7687 Input Parameters: 7688 + dm - The DM object 7689 . name - The label name 7690 - value - The stratum value 7691 7692 Output Parameter: 7693 . points - The stratum points, or NULL if the label does not exist or does not have that value 7694 7695 Level: beginner 7696 7697 .seealso: DMLabelGetStratumIS(), DMGetStratumSize() 7698 @*/ 7699 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 7700 { 7701 DMLabel label; 7702 7703 PetscFunctionBegin; 7704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7705 PetscValidCharPointer(name, 2); 7706 PetscValidPointer(points, 4); 7707 PetscCall(DMGetLabel(dm, name, &label)); 7708 *points = NULL; 7709 if (!label) PetscFunctionReturn(0); 7710 PetscCall(DMLabelGetStratumIS(label, value, points)); 7711 PetscFunctionReturn(0); 7712 } 7713 7714 /*@C 7715 DMSetStratumIS - Set the points in a label stratum 7716 7717 Not Collective 7718 7719 Input Parameters: 7720 + dm - The DM object 7721 . name - The label name 7722 . value - The stratum value 7723 - points - The stratum points 7724 7725 Level: beginner 7726 7727 .seealso: DMLabelSetStratumIS(), DMGetStratumSize() 7728 @*/ 7729 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 7730 { 7731 DMLabel label; 7732 7733 PetscFunctionBegin; 7734 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7735 PetscValidCharPointer(name, 2); 7736 PetscValidPointer(points, 4); 7737 PetscCall(DMGetLabel(dm, name, &label)); 7738 if (!label) PetscFunctionReturn(0); 7739 PetscCall(DMLabelSetStratumIS(label, value, points)); 7740 PetscFunctionReturn(0); 7741 } 7742 7743 /*@C 7744 DMClearLabelStratum - Remove all points from a stratum from a DMLabel 7745 7746 Not Collective 7747 7748 Input Parameters: 7749 + dm - The DM object 7750 . name - The label name 7751 - value - The label value for this point 7752 7753 Output Parameter: 7754 7755 Level: beginner 7756 7757 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue() 7758 @*/ 7759 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 7760 { 7761 DMLabel label; 7762 7763 PetscFunctionBegin; 7764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7765 PetscValidCharPointer(name, 2); 7766 PetscCall(DMGetLabel(dm, name, &label)); 7767 if (!label) PetscFunctionReturn(0); 7768 PetscCall(DMLabelClearStratum(label, value)); 7769 PetscFunctionReturn(0); 7770 } 7771 7772 /*@ 7773 DMGetNumLabels - Return the number of labels defined by the mesh 7774 7775 Not Collective 7776 7777 Input Parameter: 7778 . dm - The DM object 7779 7780 Output Parameter: 7781 . numLabels - the number of Labels 7782 7783 Level: intermediate 7784 7785 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7786 @*/ 7787 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 7788 { 7789 DMLabelLink next = dm->labels; 7790 PetscInt n = 0; 7791 7792 PetscFunctionBegin; 7793 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7794 PetscValidIntPointer(numLabels, 2); 7795 while (next) {++n; next = next->next;} 7796 *numLabels = n; 7797 PetscFunctionReturn(0); 7798 } 7799 7800 /*@C 7801 DMGetLabelName - Return the name of nth label 7802 7803 Not Collective 7804 7805 Input Parameters: 7806 + dm - The DM object 7807 - n - the label number 7808 7809 Output Parameter: 7810 . name - the label name 7811 7812 Level: intermediate 7813 7814 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7815 @*/ 7816 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name) 7817 { 7818 DMLabelLink next = dm->labels; 7819 PetscInt l = 0; 7820 7821 PetscFunctionBegin; 7822 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7823 PetscValidPointer(name, 3); 7824 while (next) { 7825 if (l == n) { 7826 PetscCall(PetscObjectGetName((PetscObject) next->label, name)); 7827 PetscFunctionReturn(0); 7828 } 7829 ++l; 7830 next = next->next; 7831 } 7832 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7833 } 7834 7835 /*@C 7836 DMHasLabel - Determine whether the mesh has a label of a given name 7837 7838 Not Collective 7839 7840 Input Parameters: 7841 + dm - The DM object 7842 - name - The label name 7843 7844 Output Parameter: 7845 . hasLabel - PETSC_TRUE if the label is present 7846 7847 Level: intermediate 7848 7849 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7850 @*/ 7851 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7852 { 7853 DMLabelLink next = dm->labels; 7854 const char *lname; 7855 7856 PetscFunctionBegin; 7857 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7858 PetscValidCharPointer(name, 2); 7859 PetscValidBoolPointer(hasLabel, 3); 7860 *hasLabel = PETSC_FALSE; 7861 while (next) { 7862 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 7863 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7864 if (*hasLabel) break; 7865 next = next->next; 7866 } 7867 PetscFunctionReturn(0); 7868 } 7869 7870 /*@C 7871 DMGetLabel - Return the label of a given name, or NULL 7872 7873 Not Collective 7874 7875 Input Parameters: 7876 + dm - The DM object 7877 - name - The label name 7878 7879 Output Parameter: 7880 . label - The DMLabel, or NULL if the label is absent 7881 7882 Note: Some of the default labels in a DMPlex will be 7883 $ "depth" - Holds the depth (co-dimension) of each mesh point 7884 $ "celltype" - Holds the topological type of each cell 7885 $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7886 $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7887 $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7888 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7889 7890 Level: intermediate 7891 7892 .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType() 7893 @*/ 7894 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7895 { 7896 DMLabelLink next = dm->labels; 7897 PetscBool hasLabel; 7898 const char *lname; 7899 7900 PetscFunctionBegin; 7901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7902 PetscValidCharPointer(name, 2); 7903 PetscValidPointer(label, 3); 7904 *label = NULL; 7905 while (next) { 7906 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 7907 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7908 if (hasLabel) { 7909 *label = next->label; 7910 break; 7911 } 7912 next = next->next; 7913 } 7914 PetscFunctionReturn(0); 7915 } 7916 7917 /*@C 7918 DMGetLabelByNum - Return the nth label 7919 7920 Not Collective 7921 7922 Input Parameters: 7923 + dm - The DM object 7924 - n - the label number 7925 7926 Output Parameter: 7927 . label - the label 7928 7929 Level: intermediate 7930 7931 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7932 @*/ 7933 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7934 { 7935 DMLabelLink next = dm->labels; 7936 PetscInt l = 0; 7937 7938 PetscFunctionBegin; 7939 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7940 PetscValidPointer(label, 3); 7941 while (next) { 7942 if (l == n) { 7943 *label = next->label; 7944 PetscFunctionReturn(0); 7945 } 7946 ++l; 7947 next = next->next; 7948 } 7949 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7950 } 7951 7952 /*@C 7953 DMAddLabel - Add the label to this mesh 7954 7955 Not Collective 7956 7957 Input Parameters: 7958 + dm - The DM object 7959 - label - The DMLabel 7960 7961 Level: developer 7962 7963 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7964 @*/ 7965 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7966 { 7967 DMLabelLink l, *p, tmpLabel; 7968 PetscBool hasLabel; 7969 const char *lname; 7970 PetscBool flg; 7971 7972 PetscFunctionBegin; 7973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7974 PetscCall(PetscObjectGetName((PetscObject) label, &lname)); 7975 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7976 PetscCheck(!hasLabel,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7977 PetscCall(PetscCalloc1(1, &tmpLabel)); 7978 tmpLabel->label = label; 7979 tmpLabel->output = PETSC_TRUE; 7980 for (p=&dm->labels; (l=*p); p=&l->next) {} 7981 *p = tmpLabel; 7982 PetscCall(PetscObjectReference((PetscObject)label)); 7983 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7984 if (flg) dm->depthLabel = label; 7985 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7986 if (flg) dm->celltypeLabel = label; 7987 PetscFunctionReturn(0); 7988 } 7989 7990 /*@C 7991 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7992 7993 Not Collective 7994 7995 Input Parameters: 7996 + dm - The DM object 7997 - label - The DMLabel, having the same name, to substitute 7998 7999 Note: Some of the default labels in a DMPlex will be 8000 $ "depth" - Holds the depth (co-dimension) of each mesh point 8001 $ "celltype" - Holds the topological type of each cell 8002 $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 8003 $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 8004 $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 8005 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh 8006 8007 Level: intermediate 8008 8009 .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType() 8010 @*/ 8011 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 8012 { 8013 DMLabelLink next = dm->labels; 8014 PetscBool hasLabel, flg; 8015 const char *name, *lname; 8016 8017 PetscFunctionBegin; 8018 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8019 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 8020 PetscCall(PetscObjectGetName((PetscObject) label, &name)); 8021 while (next) { 8022 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 8023 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 8024 if (hasLabel) { 8025 PetscCall(PetscObjectReference((PetscObject) label)); 8026 PetscCall(PetscStrcmp(lname, "depth", &flg)); 8027 if (flg) dm->depthLabel = label; 8028 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 8029 if (flg) dm->celltypeLabel = label; 8030 PetscCall(DMLabelDestroy(&next->label)); 8031 next->label = label; 8032 break; 8033 } 8034 next = next->next; 8035 } 8036 PetscFunctionReturn(0); 8037 } 8038 8039 /*@C 8040 DMRemoveLabel - Remove the label given by name from this mesh 8041 8042 Not Collective 8043 8044 Input Parameters: 8045 + dm - The DM object 8046 - name - The label name 8047 8048 Output Parameter: 8049 . label - The DMLabel, or NULL if the label is absent 8050 8051 Level: developer 8052 8053 Notes: 8054 DMRemoveLabel(dm,name,NULL) removes the label from dm and calls 8055 DMLabelDestroy() on the label. 8056 8057 DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT 8058 call DMLabelDestroy(). Instead, the label is returned and the user is 8059 responsible of calling DMLabelDestroy() at some point. 8060 8061 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf() 8062 @*/ 8063 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 8064 { 8065 DMLabelLink link, *pnext; 8066 PetscBool hasLabel; 8067 const char *lname; 8068 8069 PetscFunctionBegin; 8070 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8071 PetscValidCharPointer(name, 2); 8072 if (label) { 8073 PetscValidPointer(label, 3); 8074 *label = NULL; 8075 } 8076 for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) { 8077 PetscCall(PetscObjectGetName((PetscObject) link->label, &lname)); 8078 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 8079 if (hasLabel) { 8080 *pnext = link->next; /* Remove from list */ 8081 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 8082 if (hasLabel) dm->depthLabel = NULL; 8083 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 8084 if (hasLabel) dm->celltypeLabel = NULL; 8085 if (label) *label = link->label; 8086 else PetscCall(DMLabelDestroy(&link->label)); 8087 PetscCall(PetscFree(link)); 8088 break; 8089 } 8090 } 8091 PetscFunctionReturn(0); 8092 } 8093 8094 /*@ 8095 DMRemoveLabelBySelf - Remove the label from this mesh 8096 8097 Not Collective 8098 8099 Input Parameters: 8100 + dm - The DM object 8101 . label - The DMLabel to be removed from the DM 8102 - failNotFound - Should it fail if the label is not found in the DM? 8103 8104 Level: developer 8105 8106 Notes: 8107 Only exactly the same instance is removed if found, name match is ignored. 8108 If the DM has an exclusive reference to the label, it gets destroyed and 8109 *label nullified. 8110 8111 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel() 8112 @*/ 8113 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 8114 { 8115 DMLabelLink link, *pnext; 8116 PetscBool hasLabel = PETSC_FALSE; 8117 8118 PetscFunctionBegin; 8119 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8120 PetscValidPointer(label, 2); 8121 if (!*label && !failNotFound) PetscFunctionReturn(0); 8122 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 8123 PetscValidLogicalCollectiveBool(dm,failNotFound,3); 8124 for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) { 8125 if (*label == link->label) { 8126 hasLabel = PETSC_TRUE; 8127 *pnext = link->next; /* Remove from list */ 8128 if (*label == dm->depthLabel) dm->depthLabel = NULL; 8129 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 8130 if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 8131 PetscCall(DMLabelDestroy(&link->label)); 8132 PetscCall(PetscFree(link)); 8133 break; 8134 } 8135 } 8136 PetscCheck(hasLabel || !failNotFound,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 8137 PetscFunctionReturn(0); 8138 } 8139 8140 /*@C 8141 DMGetLabelOutput - Get the output flag for a given label 8142 8143 Not Collective 8144 8145 Input Parameters: 8146 + dm - The DM object 8147 - name - The label name 8148 8149 Output Parameter: 8150 . output - The flag for output 8151 8152 Level: developer 8153 8154 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 8155 @*/ 8156 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 8157 { 8158 DMLabelLink next = dm->labels; 8159 const char *lname; 8160 8161 PetscFunctionBegin; 8162 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8163 PetscValidCharPointer(name, 2); 8164 PetscValidBoolPointer(output, 3); 8165 while (next) { 8166 PetscBool flg; 8167 8168 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 8169 PetscCall(PetscStrcmp(name, lname, &flg)); 8170 if (flg) {*output = next->output; PetscFunctionReturn(0);} 8171 next = next->next; 8172 } 8173 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 8174 } 8175 8176 /*@C 8177 DMSetLabelOutput - Set the output flag for a given label 8178 8179 Not Collective 8180 8181 Input Parameters: 8182 + dm - The DM object 8183 . name - The label name 8184 - output - The flag for output 8185 8186 Level: developer 8187 8188 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 8189 @*/ 8190 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 8191 { 8192 DMLabelLink next = dm->labels; 8193 const char *lname; 8194 8195 PetscFunctionBegin; 8196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8197 PetscValidCharPointer(name, 2); 8198 while (next) { 8199 PetscBool flg; 8200 8201 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 8202 PetscCall(PetscStrcmp(name, lname, &flg)); 8203 if (flg) {next->output = output; PetscFunctionReturn(0);} 8204 next = next->next; 8205 } 8206 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 8207 } 8208 8209 /*@ 8210 DMCopyLabels - Copy labels from one mesh to another with a superset of the points 8211 8212 Collective on dmA 8213 8214 Input Parameters: 8215 + dmA - The DM object with initial labels 8216 . dmB - The DM object to which labels are copied 8217 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES) 8218 . all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE) 8219 - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode) 8220 8221 Level: intermediate 8222 8223 Notes: 8224 This is typically used when interpolating or otherwise adding to a mesh, or testing. 8225 8226 .seealso: DMAddLabel(), DMCopyLabelsMode 8227 @*/ 8228 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 8229 { 8230 DMLabel label, labelNew, labelOld; 8231 const char *name; 8232 PetscBool flg; 8233 DMLabelLink link; 8234 8235 PetscFunctionBegin; 8236 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 8237 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 8238 PetscValidLogicalCollectiveEnum(dmA, mode,3); 8239 PetscValidLogicalCollectiveBool(dmA, all, 4); 8240 PetscCheck(mode != PETSC_USE_POINTER,PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 8241 if (dmA == dmB) PetscFunctionReturn(0); 8242 for (link=dmA->labels; link; link=link->next) { 8243 label=link->label; 8244 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 8245 if (!all) { 8246 PetscCall(PetscStrcmp(name, "depth", &flg)); 8247 if (flg) continue; 8248 PetscCall(PetscStrcmp(name, "dim", &flg)); 8249 if (flg) continue; 8250 PetscCall(PetscStrcmp(name, "celltype", &flg)); 8251 if (flg) continue; 8252 } 8253 PetscCall(DMGetLabel(dmB, name, &labelOld)); 8254 if (labelOld) { 8255 switch (emode) { 8256 case DM_COPY_LABELS_KEEP: 8257 continue; 8258 case DM_COPY_LABELS_REPLACE: 8259 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 8260 break; 8261 case DM_COPY_LABELS_FAIL: 8262 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 8263 default: 8264 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 8265 } 8266 } 8267 if (mode==PETSC_COPY_VALUES) { 8268 PetscCall(DMLabelDuplicate(label, &labelNew)); 8269 } else { 8270 labelNew = label; 8271 } 8272 PetscCall(DMAddLabel(dmB, labelNew)); 8273 if (mode==PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 8274 } 8275 PetscFunctionReturn(0); 8276 } 8277 8278 /*@C 8279 DMCompareLabels - Compare labels of two DMPlex meshes 8280 8281 Collective 8282 8283 Input Parameters: 8284 + dm0 - First DM object 8285 - dm1 - Second DM object 8286 8287 Output Parameters 8288 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 8289 - message - (Optional) Message describing the difference, or NULL if there is no difference 8290 8291 Level: intermediate 8292 8293 Notes: 8294 The output flag equal is the same on all processes. 8295 If it is passed as NULL and difference is found, an error is thrown on all processes. 8296 Make sure to pass NULL on all processes. 8297 8298 The output message is set independently on each rank. 8299 It is set to NULL if no difference was found on the current rank. It must be freed by user. 8300 If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner. 8301 Make sure to pass NULL on all processes. 8302 8303 Labels are matched by name. If the number of labels and their names are equal, 8304 DMLabelCompare() is used to compare each pair of labels with the same name. 8305 8306 Fortran Notes: 8307 This function is currently not available from Fortran. 8308 8309 .seealso: DMAddLabel(), DMCopyLabelsMode, DMLabelCompare() 8310 @*/ 8311 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 8312 { 8313 PetscInt n, i; 8314 char msg[PETSC_MAX_PATH_LEN] = ""; 8315 PetscBool eq; 8316 MPI_Comm comm; 8317 PetscMPIInt rank; 8318 8319 PetscFunctionBegin; 8320 PetscValidHeaderSpecific(dm0,DM_CLASSID,1); 8321 PetscValidHeaderSpecific(dm1,DM_CLASSID,2); 8322 PetscCheckSameComm(dm0,1,dm1,2); 8323 if (equal) PetscValidBoolPointer(equal,3); 8324 if (message) PetscValidPointer(message, 4); 8325 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 8326 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8327 { 8328 PetscInt n1; 8329 8330 PetscCall(DMGetNumLabels(dm0, &n)); 8331 PetscCall(DMGetNumLabels(dm1, &n1)); 8332 eq = (PetscBool) (n == n1); 8333 if (!eq) { 8334 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 8335 } 8336 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 8337 if (!eq) goto finish; 8338 } 8339 for (i=0; i<n; i++) { 8340 DMLabel l0, l1; 8341 const char *name; 8342 char *msgInner; 8343 8344 /* Ignore label order */ 8345 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 8346 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 8347 PetscCall(DMGetLabel(dm1, name, &l1)); 8348 if (!l1) { 8349 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 8350 eq = PETSC_FALSE; 8351 break; 8352 } 8353 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 8354 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 8355 PetscCall(PetscFree(msgInner)); 8356 if (!eq) break; 8357 } 8358 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 8359 finish: 8360 /* If message output arg not set, print to stderr */ 8361 if (message) { 8362 *message = NULL; 8363 if (msg[0]) { 8364 PetscCall(PetscStrallocpy(msg, message)); 8365 } 8366 } else { 8367 if (msg[0]) { 8368 PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 8369 } 8370 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 8371 } 8372 /* If same output arg not ser and labels are not equal, throw error */ 8373 if (equal) *equal = eq; 8374 else PetscCheck(eq,comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 8375 PetscFunctionReturn(0); 8376 } 8377 8378 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 8379 { 8380 PetscFunctionBegin; 8381 PetscValidPointer(label,2); 8382 if (!*label) { 8383 PetscCall(DMCreateLabel(dm, name)); 8384 PetscCall(DMGetLabel(dm, name, label)); 8385 } 8386 PetscCall(DMLabelSetValue(*label, point, value)); 8387 PetscFunctionReturn(0); 8388 } 8389 8390 /* 8391 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 8392 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 8393 (label, id) pair in the DM. 8394 8395 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 8396 each label. 8397 */ 8398 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 8399 { 8400 DMUniversalLabel ul; 8401 PetscBool *active; 8402 PetscInt pStart, pEnd, p, Nl, l, m; 8403 8404 PetscFunctionBegin; 8405 PetscCall(PetscMalloc1(1, &ul)); 8406 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 8407 PetscCall(DMGetNumLabels(dm, &Nl)); 8408 PetscCall(PetscCalloc1(Nl, &active)); 8409 ul->Nl = 0; 8410 for (l = 0; l < Nl; ++l) { 8411 PetscBool isdepth, iscelltype; 8412 const char *name; 8413 8414 PetscCall(DMGetLabelName(dm, l, &name)); 8415 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 8416 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 8417 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 8418 if (active[l]) ++ul->Nl; 8419 } 8420 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks)); 8421 ul->Nv = 0; 8422 for (l = 0, m = 0; l < Nl; ++l) { 8423 DMLabel label; 8424 PetscInt nv; 8425 const char *name; 8426 8427 if (!active[l]) continue; 8428 PetscCall(DMGetLabelName(dm, l, &name)); 8429 PetscCall(DMGetLabelByNum(dm, l, &label)); 8430 PetscCall(DMLabelGetNumValues(label, &nv)); 8431 PetscCall(PetscStrallocpy(name, &ul->names[m])); 8432 ul->indices[m] = l; 8433 ul->Nv += nv; 8434 ul->offsets[m+1] = nv; 8435 ul->bits[m+1] = PetscCeilReal(PetscLog2Real(nv+1)); 8436 ++m; 8437 } 8438 for (l = 1; l <= ul->Nl; ++l) { 8439 ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l]; 8440 ul->bits[l] = ul->bits[l-1] + ul->bits[l]; 8441 } 8442 for (l = 0; l < ul->Nl; ++l) { 8443 PetscInt b; 8444 8445 ul->masks[l] = 0; 8446 for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b; 8447 } 8448 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 8449 for (l = 0, m = 0; l < Nl; ++l) { 8450 DMLabel label; 8451 IS valueIS; 8452 const PetscInt *varr; 8453 PetscInt nv, v; 8454 8455 if (!active[l]) continue; 8456 PetscCall(DMGetLabelByNum(dm, l, &label)); 8457 PetscCall(DMLabelGetNumValues(label, &nv)); 8458 PetscCall(DMLabelGetValueIS(label, &valueIS)); 8459 PetscCall(ISGetIndices(valueIS, &varr)); 8460 for (v = 0; v < nv; ++v) { 8461 ul->values[ul->offsets[m]+v] = varr[v]; 8462 } 8463 PetscCall(ISRestoreIndices(valueIS, &varr)); 8464 PetscCall(ISDestroy(&valueIS)); 8465 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 8466 ++m; 8467 } 8468 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8469 for (p = pStart; p < pEnd; ++p) { 8470 PetscInt uval = 0; 8471 PetscBool marked = PETSC_FALSE; 8472 8473 for (l = 0, m = 0; l < Nl; ++l) { 8474 DMLabel label; 8475 PetscInt val, defval, loc, nv; 8476 8477 if (!active[l]) continue; 8478 PetscCall(DMGetLabelByNum(dm, l, &label)); 8479 PetscCall(DMLabelGetValue(label, p, &val)); 8480 PetscCall(DMLabelGetDefaultValue(label, &defval)); 8481 if (val == defval) {++m; continue;} 8482 nv = ul->offsets[m+1]-ul->offsets[m]; 8483 marked = PETSC_TRUE; 8484 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 8485 PetscCheck(loc >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 8486 uval += (loc+1) << ul->bits[m]; 8487 ++m; 8488 } 8489 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 8490 } 8491 PetscCall(PetscFree(active)); 8492 *universal = ul; 8493 PetscFunctionReturn(0); 8494 } 8495 8496 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 8497 { 8498 PetscInt l; 8499 8500 PetscFunctionBegin; 8501 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 8502 PetscCall(DMLabelDestroy(&(*universal)->label)); 8503 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 8504 PetscCall(PetscFree((*universal)->values)); 8505 PetscCall(PetscFree(*universal)); 8506 *universal = NULL; 8507 PetscFunctionReturn(0); 8508 } 8509 8510 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 8511 { 8512 PetscFunctionBegin; 8513 PetscValidPointer(ulabel, 2); 8514 *ulabel = ul->label; 8515 PetscFunctionReturn(0); 8516 } 8517 8518 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 8519 { 8520 PetscInt Nl = ul->Nl, l; 8521 8522 PetscFunctionBegin; 8523 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 8524 for (l = 0; l < Nl; ++l) { 8525 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 8526 else PetscCall(DMCreateLabel(dm, ul->names[l])); 8527 } 8528 if (preserveOrder) { 8529 for (l = 0; l < ul->Nl; ++l) { 8530 const char *name; 8531 PetscBool match; 8532 8533 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 8534 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 8535 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]); 8536 } 8537 } 8538 PetscFunctionReturn(0); 8539 } 8540 8541 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 8542 { 8543 PetscInt l; 8544 8545 PetscFunctionBegin; 8546 for (l = 0; l < ul->Nl; ++l) { 8547 DMLabel label; 8548 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 8549 8550 if (lval) { 8551 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 8552 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 8553 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1])); 8554 } 8555 } 8556 PetscFunctionReturn(0); 8557 } 8558 8559 /*@ 8560 DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement 8561 8562 Input Parameter: 8563 . dm - The DM object 8564 8565 Output Parameter: 8566 . cdm - The coarse DM 8567 8568 Level: intermediate 8569 8570 .seealso: DMSetCoarseDM() 8571 @*/ 8572 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 8573 { 8574 PetscFunctionBegin; 8575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8576 PetscValidPointer(cdm, 2); 8577 *cdm = dm->coarseMesh; 8578 PetscFunctionReturn(0); 8579 } 8580 8581 /*@ 8582 DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement 8583 8584 Input Parameters: 8585 + dm - The DM object 8586 - cdm - The coarse DM 8587 8588 Level: intermediate 8589 8590 .seealso: DMGetCoarseDM() 8591 @*/ 8592 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 8593 { 8594 PetscFunctionBegin; 8595 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8596 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 8597 PetscCall(PetscObjectReference((PetscObject)cdm)); 8598 PetscCall(DMDestroy(&dm->coarseMesh)); 8599 dm->coarseMesh = cdm; 8600 PetscFunctionReturn(0); 8601 } 8602 8603 /*@ 8604 DMGetFineDM - Get the fine mesh from which this was obtained by refinement 8605 8606 Input Parameter: 8607 . dm - The DM object 8608 8609 Output Parameter: 8610 . fdm - The fine DM 8611 8612 Level: intermediate 8613 8614 .seealso: DMSetFineDM() 8615 @*/ 8616 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 8617 { 8618 PetscFunctionBegin; 8619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8620 PetscValidPointer(fdm, 2); 8621 *fdm = dm->fineMesh; 8622 PetscFunctionReturn(0); 8623 } 8624 8625 /*@ 8626 DMSetFineDM - Set the fine mesh from which this was obtained by refinement 8627 8628 Input Parameters: 8629 + dm - The DM object 8630 - fdm - The fine DM 8631 8632 Level: intermediate 8633 8634 .seealso: DMGetFineDM() 8635 @*/ 8636 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 8637 { 8638 PetscFunctionBegin; 8639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8640 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 8641 PetscCall(PetscObjectReference((PetscObject)fdm)); 8642 PetscCall(DMDestroy(&dm->fineMesh)); 8643 dm->fineMesh = fdm; 8644 PetscFunctionReturn(0); 8645 } 8646 8647 /*=== DMBoundary code ===*/ 8648 8649 /*@C 8650 DMAddBoundary - Add a boundary condition to the model 8651 8652 Collective on dm 8653 8654 Input Parameters: 8655 + dm - The DM, with a PetscDS that matches the problem being constrained 8656 . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann) 8657 . name - The BC name 8658 . label - The label defining constrained points 8659 . Nv - The number of DMLabel values for constrained points 8660 . values - An array of values for constrained points 8661 . field - The field to constrain 8662 . Nc - The number of constrained field components (0 will constrain all fields) 8663 . comps - An array of constrained component numbers 8664 . bcFunc - A pointwise function giving boundary values 8665 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 8666 - ctx - An optional user context for bcFunc 8667 8668 Output Parameter: 8669 . bd - (Optional) Boundary number 8670 8671 Options Database Keys: 8672 + -bc_<boundary name> <num> - Overrides the boundary ids 8673 - -bc_<boundary name>_comp <num> - Overrides the boundary components 8674 8675 Note: 8676 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is: 8677 8678 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 8679 8680 If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is: 8681 8682 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8683 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8684 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8685 $ PetscReal time, const PetscReal x[], PetscScalar bcval[]) 8686 8687 + dim - the spatial dimension 8688 . Nf - the number of fields 8689 . uOff - the offset into u[] and u_t[] for each field 8690 . uOff_x - the offset into u_x[] for each field 8691 . u - each field evaluated at the current point 8692 . u_t - the time derivative of each field evaluated at the current point 8693 . u_x - the gradient of each field evaluated at the current point 8694 . aOff - the offset into a[] and a_t[] for each auxiliary field 8695 . aOff_x - the offset into a_x[] for each auxiliary field 8696 . a - each auxiliary field evaluated at the current point 8697 . a_t - the time derivative of each auxiliary field evaluated at the current point 8698 . a_x - the gradient of auxiliary each field evaluated at the current point 8699 . t - current time 8700 . x - coordinates of the current point 8701 . numConstants - number of constant parameters 8702 . constants - constant parameters 8703 - bcval - output values at the current point 8704 8705 Level: intermediate 8706 8707 .seealso: DSGetBoundary(), PetscDSAddBoundary() 8708 @*/ 8709 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) 8710 { 8711 PetscDS ds; 8712 8713 PetscFunctionBegin; 8714 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8715 PetscValidLogicalCollectiveEnum(dm, type, 2); 8716 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 8717 PetscValidLogicalCollectiveInt(dm, Nv, 5); 8718 PetscValidLogicalCollectiveInt(dm, field, 7); 8719 PetscValidLogicalCollectiveInt(dm, Nc, 8); 8720 PetscCall(DMGetDS(dm, &ds)); 8721 PetscCall(DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label)); 8722 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 8723 PetscFunctionReturn(0); 8724 } 8725 8726 /* TODO Remove this since now the structures are the same */ 8727 static PetscErrorCode DMPopulateBoundary(DM dm) 8728 { 8729 PetscDS ds; 8730 DMBoundary *lastnext; 8731 DSBoundary dsbound; 8732 8733 PetscFunctionBegin; 8734 PetscCall(DMGetDS(dm, &ds)); 8735 dsbound = ds->boundary; 8736 if (dm->boundary) { 8737 DMBoundary next = dm->boundary; 8738 8739 /* quick check to see if the PetscDS has changed */ 8740 if (next->dsboundary == dsbound) PetscFunctionReturn(0); 8741 /* the PetscDS has changed: tear down and rebuild */ 8742 while (next) { 8743 DMBoundary b = next; 8744 8745 next = b->next; 8746 PetscCall(PetscFree(b)); 8747 } 8748 dm->boundary = NULL; 8749 } 8750 8751 lastnext = &(dm->boundary); 8752 while (dsbound) { 8753 DMBoundary dmbound; 8754 8755 PetscCall(PetscNew(&dmbound)); 8756 dmbound->dsboundary = dsbound; 8757 dmbound->label = dsbound->label; 8758 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8759 *lastnext = dmbound; 8760 lastnext = &(dmbound->next); 8761 dsbound = dsbound->next; 8762 } 8763 PetscFunctionReturn(0); 8764 } 8765 8766 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8767 { 8768 DMBoundary b; 8769 8770 PetscFunctionBegin; 8771 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8772 PetscValidBoolPointer(isBd, 3); 8773 *isBd = PETSC_FALSE; 8774 PetscCall(DMPopulateBoundary(dm)); 8775 b = dm->boundary; 8776 while (b && !(*isBd)) { 8777 DMLabel label = b->label; 8778 DSBoundary dsb = b->dsboundary; 8779 PetscInt i; 8780 8781 if (label) { 8782 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8783 } 8784 b = b->next; 8785 } 8786 PetscFunctionReturn(0); 8787 } 8788 8789 /*@C 8790 DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector. 8791 8792 Collective on DM 8793 8794 Input Parameters: 8795 + dm - The DM 8796 . time - The time 8797 . funcs - The coordinate functions to evaluate, one per field 8798 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8799 - mode - The insertion mode for values 8800 8801 Output Parameter: 8802 . X - vector 8803 8804 Calling sequence of func: 8805 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8806 8807 + dim - The spatial dimension 8808 . time - The time at which to sample 8809 . x - The coordinates 8810 . Nc - The number of components 8811 . u - The output field values 8812 - ctx - optional user-defined function context 8813 8814 Level: developer 8815 8816 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff() 8817 @*/ 8818 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X) 8819 { 8820 Vec localX; 8821 8822 PetscFunctionBegin; 8823 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8824 PetscCall(DMGetLocalVector(dm, &localX)); 8825 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8826 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8827 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8828 PetscCall(DMRestoreLocalVector(dm, &localX)); 8829 PetscFunctionReturn(0); 8830 } 8831 8832 /*@C 8833 DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector. 8834 8835 Not collective 8836 8837 Input Parameters: 8838 + dm - The DM 8839 . time - The time 8840 . funcs - The coordinate functions to evaluate, one per field 8841 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8842 - mode - The insertion mode for values 8843 8844 Output Parameter: 8845 . localX - vector 8846 8847 Calling sequence of func: 8848 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8849 8850 + dim - The spatial dimension 8851 . x - The coordinates 8852 . Nc - The number of components 8853 . u - The output field values 8854 - ctx - optional user-defined function context 8855 8856 Level: developer 8857 8858 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff() 8859 @*/ 8860 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 8861 { 8862 PetscFunctionBegin; 8863 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 8864 PetscValidHeaderSpecific(localX,VEC_CLASSID,6); 8865 PetscCheck(dm->ops->projectfunctionlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name); 8866 PetscCall((dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX)); 8867 PetscFunctionReturn(0); 8868 } 8869 8870 /*@C 8871 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. 8872 8873 Collective on DM 8874 8875 Input Parameters: 8876 + dm - The DM 8877 . time - The time 8878 . label - The DMLabel selecting the portion of the mesh for projection 8879 . funcs - The coordinate functions to evaluate, one per field 8880 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8881 - mode - The insertion mode for values 8882 8883 Output Parameter: 8884 . X - vector 8885 8886 Calling sequence of func: 8887 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8888 8889 + dim - The spatial dimension 8890 . x - The coordinates 8891 . Nc - The number of components 8892 . u - The output field values 8893 - ctx - optional user-defined function context 8894 8895 Level: developer 8896 8897 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff() 8898 @*/ 8899 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) 8900 { 8901 Vec localX; 8902 8903 PetscFunctionBegin; 8904 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8905 PetscCall(DMGetLocalVector(dm, &localX)); 8906 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8907 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8908 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8909 PetscCall(DMRestoreLocalVector(dm, &localX)); 8910 PetscFunctionReturn(0); 8911 } 8912 8913 /*@C 8914 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. 8915 8916 Not collective 8917 8918 Input Parameters: 8919 + dm - The DM 8920 . time - The time 8921 . label - The DMLabel selecting the portion of the mesh for projection 8922 . funcs - The coordinate functions to evaluate, one per field 8923 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8924 - mode - The insertion mode for values 8925 8926 Output Parameter: 8927 . localX - vector 8928 8929 Calling sequence of func: 8930 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8931 8932 + dim - The spatial dimension 8933 . x - The coordinates 8934 . Nc - The number of components 8935 . u - The output field values 8936 - ctx - optional user-defined function context 8937 8938 Level: developer 8939 8940 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff() 8941 @*/ 8942 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) 8943 { 8944 PetscFunctionBegin; 8945 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 8946 PetscValidHeaderSpecific(localX,VEC_CLASSID,11); 8947 PetscCheck(dm->ops->projectfunctionlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name); 8948 PetscCall((dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8949 PetscFunctionReturn(0); 8950 } 8951 8952 /*@C 8953 DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector. 8954 8955 Not collective 8956 8957 Input Parameters: 8958 + dm - The DM 8959 . time - The time 8960 . localU - The input field vector 8961 . funcs - The functions to evaluate, one per field 8962 - mode - The insertion mode for values 8963 8964 Output Parameter: 8965 . localX - The output vector 8966 8967 Calling sequence of func: 8968 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8969 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8970 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8971 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 8972 8973 + dim - The spatial dimension 8974 . Nf - The number of input fields 8975 . NfAux - The number of input auxiliary fields 8976 . uOff - The offset of each field in u[] 8977 . uOff_x - The offset of each field in u_x[] 8978 . u - The field values at this point in space 8979 . u_t - The field time derivative at this point in space (or NULL) 8980 . u_x - The field derivatives at this point in space 8981 . aOff - The offset of each auxiliary field in u[] 8982 . aOff_x - The offset of each auxiliary field in u_x[] 8983 . a - The auxiliary field values at this point in space 8984 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8985 . a_x - The auxiliary field derivatives at this point in space 8986 . t - The current time 8987 . x - The coordinates of this point 8988 . numConstants - The number of constants 8989 . constants - The value of each constant 8990 - f - The value of the function at this point in space 8991 8992 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. 8993 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 8994 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the 8995 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8996 8997 Level: intermediate 8998 8999 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff() 9000 @*/ 9001 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, 9002 void (**funcs)(PetscInt, PetscInt, PetscInt, 9003 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9004 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9005 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 9006 InsertMode mode, Vec localX) 9007 { 9008 PetscFunctionBegin; 9009 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9010 PetscValidHeaderSpecific(localU,VEC_CLASSID,3); 9011 PetscValidHeaderSpecific(localX,VEC_CLASSID,6); 9012 PetscCheck(dm->ops->projectfieldlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name); 9013 PetscCall((dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX)); 9014 PetscFunctionReturn(0); 9015 } 9016 9017 /*@C 9018 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. 9019 9020 Not collective 9021 9022 Input Parameters: 9023 + dm - The DM 9024 . time - The time 9025 . label - The DMLabel marking the portion of the domain to output 9026 . numIds - The number of label ids to use 9027 . ids - The label ids to use for marking 9028 . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components 9029 . comps - The components to set in the output, or NULL for all components 9030 . localU - The input field vector 9031 . funcs - The functions to evaluate, one per field 9032 - mode - The insertion mode for values 9033 9034 Output Parameter: 9035 . localX - The output vector 9036 9037 Calling sequence of func: 9038 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9039 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9040 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9041 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 9042 9043 + dim - The spatial dimension 9044 . Nf - The number of input fields 9045 . NfAux - The number of input auxiliary fields 9046 . uOff - The offset of each field in u[] 9047 . uOff_x - The offset of each field in u_x[] 9048 . u - The field values at this point in space 9049 . u_t - The field time derivative at this point in space (or NULL) 9050 . u_x - The field derivatives at this point in space 9051 . aOff - The offset of each auxiliary field in u[] 9052 . aOff_x - The offset of each auxiliary field in u_x[] 9053 . a - The auxiliary field values at this point in space 9054 . a_t - The auxiliary field time derivative at this point in space (or NULL) 9055 . a_x - The auxiliary field derivatives at this point in space 9056 . t - The current time 9057 . x - The coordinates of this point 9058 . numConstants - The number of constants 9059 . constants - The value of each constant 9060 - f - The value of the function at this point in space 9061 9062 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. 9063 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 9064 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the 9065 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 9066 9067 Level: intermediate 9068 9069 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff() 9070 @*/ 9071 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, 9072 void (**funcs)(PetscInt, PetscInt, PetscInt, 9073 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9074 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9075 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 9076 InsertMode mode, Vec localX) 9077 { 9078 PetscFunctionBegin; 9079 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9080 PetscValidHeaderSpecific(localU,VEC_CLASSID,8); 9081 PetscValidHeaderSpecific(localX,VEC_CLASSID,11); 9082 PetscCheck(dm->ops->projectfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name); 9083 PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 9084 PetscFunctionReturn(0); 9085 } 9086 9087 /*@C 9088 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. 9089 9090 Not collective 9091 9092 Input Parameters: 9093 + dm - The DM 9094 . time - The time 9095 . label - The DMLabel marking the portion of the domain boundary to output 9096 . numIds - The number of label ids to use 9097 . ids - The label ids to use for marking 9098 . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components 9099 . comps - The components to set in the output, or NULL for all components 9100 . localU - The input field vector 9101 . funcs - The functions to evaluate, one per field 9102 - mode - The insertion mode for values 9103 9104 Output Parameter: 9105 . localX - The output vector 9106 9107 Calling sequence of func: 9108 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9109 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9110 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9111 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 9112 9113 + dim - The spatial dimension 9114 . Nf - The number of input fields 9115 . NfAux - The number of input auxiliary fields 9116 . uOff - The offset of each field in u[] 9117 . uOff_x - The offset of each field in u_x[] 9118 . u - The field values at this point in space 9119 . u_t - The field time derivative at this point in space (or NULL) 9120 . u_x - The field derivatives at this point in space 9121 . aOff - The offset of each auxiliary field in u[] 9122 . aOff_x - The offset of each auxiliary field in u_x[] 9123 . a - The auxiliary field values at this point in space 9124 . a_t - The auxiliary field time derivative at this point in space (or NULL) 9125 . a_x - The auxiliary field derivatives at this point in space 9126 . t - The current time 9127 . x - The coordinates of this point 9128 . n - The face normal 9129 . numConstants - The number of constants 9130 . constants - The value of each constant 9131 - f - The value of the function at this point in space 9132 9133 Note: 9134 There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs. 9135 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 9136 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the 9137 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 9138 9139 Level: intermediate 9140 9141 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff() 9142 @*/ 9143 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, 9144 void (**funcs)(PetscInt, PetscInt, PetscInt, 9145 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9146 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9147 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 9148 InsertMode mode, Vec localX) 9149 { 9150 PetscFunctionBegin; 9151 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9152 PetscValidHeaderSpecific(localU,VEC_CLASSID,8); 9153 PetscValidHeaderSpecific(localX,VEC_CLASSID,11); 9154 PetscCheck(dm->ops->projectbdfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name); 9155 PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 9156 PetscFunctionReturn(0); 9157 } 9158 9159 /*@C 9160 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 9161 9162 Input Parameters: 9163 + dm - The DM 9164 . time - The time 9165 . funcs - The functions to evaluate for each field component 9166 . ctxs - Optional array of contexts to pass to each function, or NULL. 9167 - X - The coefficient vector u_h, a global vector 9168 9169 Output Parameter: 9170 . diff - The diff ||u - u_h||_2 9171 9172 Level: developer 9173 9174 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff() 9175 @*/ 9176 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 9177 { 9178 PetscFunctionBegin; 9179 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9180 PetscValidHeaderSpecific(X,VEC_CLASSID,5); 9181 PetscCheck(dm->ops->computel2diff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name); 9182 PetscCall((dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff)); 9183 PetscFunctionReturn(0); 9184 } 9185 9186 /*@C 9187 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 9188 9189 Collective on dm 9190 9191 Input Parameters: 9192 + dm - The DM 9193 , time - The time 9194 . funcs - The gradient functions to evaluate for each field component 9195 . ctxs - Optional array of contexts to pass to each function, or NULL. 9196 . X - The coefficient vector u_h, a global vector 9197 - n - The vector to project along 9198 9199 Output Parameter: 9200 . diff - The diff ||(grad u - grad u_h) . n||_2 9201 9202 Level: developer 9203 9204 .seealso: DMProjectFunction(), DMComputeL2Diff() 9205 @*/ 9206 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) 9207 { 9208 PetscFunctionBegin; 9209 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9210 PetscValidHeaderSpecific(X,VEC_CLASSID,5); 9211 PetscCheck(dm->ops->computel2gradientdiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name); 9212 PetscCall((dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff)); 9213 PetscFunctionReturn(0); 9214 } 9215 9216 /*@C 9217 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 9218 9219 Collective on dm 9220 9221 Input Parameters: 9222 + dm - The DM 9223 . time - The time 9224 . funcs - The functions to evaluate for each field component 9225 . ctxs - Optional array of contexts to pass to each function, or NULL. 9226 - X - The coefficient vector u_h, a global vector 9227 9228 Output Parameter: 9229 . diff - The array of differences, ||u^f - u^f_h||_2 9230 9231 Level: developer 9232 9233 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff() 9234 @*/ 9235 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 9236 { 9237 PetscFunctionBegin; 9238 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9239 PetscValidHeaderSpecific(X,VEC_CLASSID,5); 9240 PetscCheck(dm->ops->computel2fielddiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name); 9241 PetscCall((dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff)); 9242 PetscFunctionReturn(0); 9243 } 9244 9245 /*@C 9246 DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors 9247 9248 Not Collective 9249 9250 Input Parameter: 9251 . dm - The DM 9252 9253 Output Parameters: 9254 + nranks - the number of neighbours 9255 - ranks - the neighbors ranks 9256 9257 Notes: 9258 Do not free the array, it is freed when the DM is destroyed. 9259 9260 Level: beginner 9261 9262 .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks() 9263 @*/ 9264 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[]) 9265 { 9266 PetscFunctionBegin; 9267 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9268 PetscCheck(dm->ops->getneighbors,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name); 9269 PetscCall((dm->ops->getneighbors)(dm,nranks,ranks)); 9270 PetscFunctionReturn(0); 9271 } 9272 9273 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 9274 9275 /* 9276 Converts the input vector to a ghosted vector and then calls the standard coloring code. 9277 This has be a different function because it requires DM which is not defined in the Mat library 9278 */ 9279 PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx) 9280 { 9281 PetscFunctionBegin; 9282 if (coloring->ctype == IS_COLORING_LOCAL) { 9283 Vec x1local; 9284 DM dm; 9285 PetscCall(MatGetDM(J,&dm)); 9286 PetscCheck(dm,PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM"); 9287 PetscCall(DMGetLocalVector(dm,&x1local)); 9288 PetscCall(DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local)); 9289 PetscCall(DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local)); 9290 x1 = x1local; 9291 } 9292 PetscCall(MatFDColoringApply_AIJ(J,coloring,x1,sctx)); 9293 if (coloring->ctype == IS_COLORING_LOCAL) { 9294 DM dm; 9295 PetscCall(MatGetDM(J,&dm)); 9296 PetscCall(DMRestoreLocalVector(dm,&x1)); 9297 } 9298 PetscFunctionReturn(0); 9299 } 9300 9301 /*@ 9302 MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring 9303 9304 Input Parameter: 9305 . coloring - the MatFDColoring object 9306 9307 Developer Notes: 9308 this routine exists because the PETSc Mat library does not know about the DM objects 9309 9310 Level: advanced 9311 9312 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType 9313 @*/ 9314 PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring) 9315 { 9316 PetscFunctionBegin; 9317 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 9318 PetscFunctionReturn(0); 9319 } 9320 9321 /*@ 9322 DMGetCompatibility - determine if two DMs are compatible 9323 9324 Collective 9325 9326 Input Parameters: 9327 + dm1 - the first DM 9328 - dm2 - the second DM 9329 9330 Output Parameters: 9331 + compatible - whether or not the two DMs are compatible 9332 - set - whether or not the compatible value was set 9333 9334 Notes: 9335 Two DMs are deemed compatible if they represent the same parallel decomposition 9336 of the same topology. This implies that the section (field data) on one 9337 "makes sense" with respect to the topology and parallel decomposition of the other. 9338 Loosely speaking, compatible DMs represent the same domain and parallel 9339 decomposition, but hold different data. 9340 9341 Typically, one would confirm compatibility if intending to simultaneously iterate 9342 over a pair of vectors obtained from different DMs. 9343 9344 For example, two DMDA objects are compatible if they have the same local 9345 and global sizes and the same stencil width. They can have different numbers 9346 of degrees of freedom per node. Thus, one could use the node numbering from 9347 either DM in bounds for a loop over vectors derived from either DM. 9348 9349 Consider the operation of summing data living on a 2-dof DMDA to data living 9350 on a 1-dof DMDA, which should be compatible, as in the following snippet. 9351 .vb 9352 ... 9353 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 9354 if (set && compatible) { 9355 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 9356 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 9357 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 9358 for (j=y; j<y+n; ++j) { 9359 for (i=x; i<x+m, ++i) { 9360 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 9361 } 9362 } 9363 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 9364 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 9365 } else { 9366 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 9367 } 9368 ... 9369 .ve 9370 9371 Checking compatibility might be expensive for a given implementation of DM, 9372 or might be impossible to unambiguously confirm or deny. For this reason, 9373 this function may decline to determine compatibility, and hence users should 9374 always check the "set" output parameter. 9375 9376 A DM is always compatible with itself. 9377 9378 In the current implementation, DMs which live on "unequal" communicators 9379 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 9380 incompatible. 9381 9382 This function is labeled "Collective," as information about all subdomains 9383 is required on each rank. However, in DM implementations which store all this 9384 information locally, this function may be merely "Logically Collective". 9385 9386 Developer Notes: 9387 Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B 9388 iff B is compatible with A. Thus, this function checks the implementations 9389 of both dm and dmc (if they are of different types), attempting to determine 9390 compatibility. It is left to DM implementers to ensure that symmetry is 9391 preserved. The simplest way to do this is, when implementing type-specific 9392 logic for this function, is to check for existing logic in the implementation 9393 of other DM types and let *set = PETSC_FALSE if found. 9394 9395 Level: advanced 9396 9397 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag() 9398 @*/ 9399 9400 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set) 9401 { 9402 PetscMPIInt compareResult; 9403 DMType type,type2; 9404 PetscBool sameType; 9405 9406 PetscFunctionBegin; 9407 PetscValidHeaderSpecific(dm1,DM_CLASSID,1); 9408 PetscValidHeaderSpecific(dm2,DM_CLASSID,2); 9409 9410 /* Declare a DM compatible with itself */ 9411 if (dm1 == dm2) { 9412 *set = PETSC_TRUE; 9413 *compatible = PETSC_TRUE; 9414 PetscFunctionReturn(0); 9415 } 9416 9417 /* Declare a DM incompatible with a DM that lives on an "unequal" 9418 communicator. Note that this does not preclude compatibility with 9419 DMs living on "congruent" or "similar" communicators, but this must be 9420 determined by the implementation-specific logic */ 9421 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult)); 9422 if (compareResult == MPI_UNEQUAL) { 9423 *set = PETSC_TRUE; 9424 *compatible = PETSC_FALSE; 9425 PetscFunctionReturn(0); 9426 } 9427 9428 /* Pass to the implementation-specific routine, if one exists. */ 9429 if (dm1->ops->getcompatibility) { 9430 PetscCall((*dm1->ops->getcompatibility)(dm1,dm2,compatible,set)); 9431 if (*set) PetscFunctionReturn(0); 9432 } 9433 9434 /* If dm1 and dm2 are of different types, then attempt to check compatibility 9435 with an implementation of this function from dm2 */ 9436 PetscCall(DMGetType(dm1,&type)); 9437 PetscCall(DMGetType(dm2,&type2)); 9438 PetscCall(PetscStrcmp(type,type2,&sameType)); 9439 if (!sameType && dm2->ops->getcompatibility) { 9440 PetscCall((*dm2->ops->getcompatibility)(dm2,dm1,compatible,set)); /* Note argument order */ 9441 } else { 9442 *set = PETSC_FALSE; 9443 } 9444 PetscFunctionReturn(0); 9445 } 9446 9447 /*@C 9448 DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance. 9449 9450 Logically Collective on DM 9451 9452 Input Parameters: 9453 + DM - the DM 9454 . f - the monitor function 9455 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired) 9456 - monitordestroy - [optional] routine that frees monitor context (may be NULL) 9457 9458 Options Database Keys: 9459 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but 9460 does not cancel those set via the options database. 9461 9462 Notes: 9463 Several different monitoring routines may be set by calling 9464 DMMonitorSet() multiple times; all will be called in the 9465 order in which they were set. 9466 9467 Fortran Notes: 9468 Only a single monitor function can be set for each DM object 9469 9470 Level: intermediate 9471 9472 .seealso: DMMonitorCancel() 9473 @*/ 9474 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**)) 9475 { 9476 PetscInt m; 9477 9478 PetscFunctionBegin; 9479 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9480 for (m = 0; m < dm->numbermonitors; ++m) { 9481 PetscBool identical; 9482 9483 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 9484 if (identical) PetscFunctionReturn(0); 9485 } 9486 PetscCheck(dm->numbermonitors < MAXDMMONITORS,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 9487 dm->monitor[dm->numbermonitors] = f; 9488 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 9489 dm->monitorcontext[dm->numbermonitors++] = (void *) mctx; 9490 PetscFunctionReturn(0); 9491 } 9492 9493 /*@ 9494 DMMonitorCancel - Clears all the monitor functions for a DM object. 9495 9496 Logically Collective on DM 9497 9498 Input Parameter: 9499 . dm - the DM 9500 9501 Options Database Key: 9502 . -dm_monitor_cancel - cancels all monitors that have been hardwired 9503 into a code by calls to DMonitorSet(), but does not cancel those 9504 set via the options database 9505 9506 Notes: 9507 There is no way to clear one specific monitor from a DM object. 9508 9509 Level: intermediate 9510 9511 .seealso: DMMonitorSet() 9512 @*/ 9513 PetscErrorCode DMMonitorCancel(DM dm) 9514 { 9515 PetscInt m; 9516 9517 PetscFunctionBegin; 9518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9519 for (m = 0; m < dm->numbermonitors; ++m) { 9520 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 9521 } 9522 dm->numbermonitors = 0; 9523 PetscFunctionReturn(0); 9524 } 9525 9526 /*@C 9527 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 9528 9529 Collective on DM 9530 9531 Input Parameters: 9532 + dm - DM object you wish to monitor 9533 . name - the monitor type one is seeking 9534 . help - message indicating what monitoring is done 9535 . manual - manual page for the monitor 9536 . monitor - the monitor function 9537 - 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 9538 9539 Output Parameter: 9540 . flg - Flag set if the monitor was created 9541 9542 Level: developer 9543 9544 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(), 9545 PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool() 9546 PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(), 9547 PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHeadBegin(), 9548 PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(), 9549 PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(), 9550 PetscOptionsFList(), PetscOptionsEList() 9551 @*/ 9552 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 9553 { 9554 PetscViewer viewer; 9555 PetscViewerFormat format; 9556 9557 PetscFunctionBegin; 9558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9559 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg)); 9560 if (*flg) { 9561 PetscViewerAndFormat *vf; 9562 9563 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 9564 PetscCall(PetscObjectDereference((PetscObject) viewer)); 9565 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 9566 PetscCall(DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy)); 9567 } 9568 PetscFunctionReturn(0); 9569 } 9570 9571 /*@ 9572 DMMonitor - runs the user provided monitor routines, if they exist 9573 9574 Collective on DM 9575 9576 Input Parameters: 9577 . dm - The DM 9578 9579 Level: developer 9580 9581 .seealso: DMMonitorSet() 9582 @*/ 9583 PetscErrorCode DMMonitor(DM dm) 9584 { 9585 PetscInt m; 9586 9587 PetscFunctionBegin; 9588 if (!dm) PetscFunctionReturn(0); 9589 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9590 for (m = 0; m < dm->numbermonitors; ++m) { 9591 PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 9592 } 9593 PetscFunctionReturn(0); 9594 } 9595 9596 /*@ 9597 DMComputeError - Computes the error assuming the user has given exact solution functions 9598 9599 Collective on DM 9600 9601 Input Parameters: 9602 + dm - The DM 9603 - sol - The solution vector 9604 9605 Input/Output Parameter: 9606 . errors - An array of length Nf, the number of fields, or NULL for no output; on output 9607 contains the error in each field 9608 9609 Output Parameter: 9610 . errorVec - A vector to hold the cellwise error (may be NULL) 9611 9612 Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber(). 9613 9614 Level: developer 9615 9616 .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber() 9617 @*/ 9618 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 9619 { 9620 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 9621 void **ctxs; 9622 PetscReal time; 9623 PetscInt Nf, f, Nds, s; 9624 9625 PetscFunctionBegin; 9626 PetscCall(DMGetNumFields(dm, &Nf)); 9627 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 9628 PetscCall(DMGetNumDS(dm, &Nds)); 9629 for (s = 0; s < Nds; ++s) { 9630 PetscDS ds; 9631 DMLabel label; 9632 IS fieldIS; 9633 const PetscInt *fields; 9634 PetscInt dsNf; 9635 9636 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 9637 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9638 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9639 for (f = 0; f < dsNf; ++f) { 9640 const PetscInt field = fields[f]; 9641 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9642 } 9643 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9644 } 9645 for (f = 0; f < Nf; ++f) { 9646 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); 9647 } 9648 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9649 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9650 if (errorVec) { 9651 DM edm; 9652 DMPolytopeType ct; 9653 PetscBool simplex; 9654 PetscInt dim, cStart, Nf; 9655 9656 PetscCall(DMClone(dm, &edm)); 9657 PetscCall(DMGetDimension(edm, &dim)); 9658 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9659 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9660 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 9661 PetscCall(DMGetNumFields(dm, &Nf)); 9662 for (f = 0; f < Nf; ++f) { 9663 PetscFE fe, efe; 9664 PetscQuadrature q; 9665 const char *name; 9666 9667 PetscCall(DMGetField(dm, f, NULL, (PetscObject *) &fe)); 9668 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9669 PetscCall(PetscObjectGetName((PetscObject) fe, &name)); 9670 PetscCall(PetscObjectSetName((PetscObject) efe, name)); 9671 PetscCall(PetscFEGetQuadrature(fe, &q)); 9672 PetscCall(PetscFESetQuadrature(efe, q)); 9673 PetscCall(DMSetField(edm, f, NULL, (PetscObject) efe)); 9674 PetscCall(PetscFEDestroy(&efe)); 9675 } 9676 PetscCall(DMCreateDS(edm)); 9677 9678 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9679 PetscCall(PetscObjectSetName((PetscObject) *errorVec, "Error")); 9680 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9681 PetscCall(DMDestroy(&edm)); 9682 } 9683 PetscCall(PetscFree2(exactSol, ctxs)); 9684 PetscFunctionReturn(0); 9685 } 9686 9687 /*@ 9688 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM 9689 9690 Not collective 9691 9692 Input Parameter: 9693 . dm - The DM 9694 9695 Output Parameter: 9696 . numAux - The number of auxiliary data vectors 9697 9698 Level: advanced 9699 9700 .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec() 9701 @*/ 9702 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9703 { 9704 PetscFunctionBegin; 9705 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9706 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9707 PetscFunctionReturn(0); 9708 } 9709 9710 /*@ 9711 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9712 9713 Not collective 9714 9715 Input Parameters: 9716 + dm - The DM 9717 . label - The DMLabel 9718 . value - The label value indicating the region 9719 - part - The equation part, or 0 if unused 9720 9721 Output Parameter: 9722 . aux - The Vec holding auxiliary field data 9723 9724 Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9725 9726 Level: advanced 9727 9728 .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec() 9729 @*/ 9730 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9731 { 9732 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9733 PetscBool has; 9734 9735 PetscFunctionBegin; 9736 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9737 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9738 key.label = label; 9739 key.value = value; 9740 key.part = part; 9741 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9742 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9743 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9744 PetscFunctionReturn(0); 9745 } 9746 9747 /*@ 9748 DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value, and equation part 9749 9750 Not collective 9751 9752 Input Parameters: 9753 + dm - The DM 9754 . label - The DMLabel 9755 . value - The label value indicating the region 9756 . part - The equation part, or 0 if unused 9757 - aux - The Vec holding auxiliary field data 9758 9759 Level: advanced 9760 9761 .seealso: DMGetAuxiliaryVec() 9762 @*/ 9763 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9764 { 9765 Vec old; 9766 PetscHashAuxKey key; 9767 9768 PetscFunctionBegin; 9769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9770 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9771 key.label = label; 9772 key.value = value; 9773 key.part = part; 9774 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9775 PetscCall(PetscObjectReference((PetscObject) aux)); 9776 PetscCall(PetscObjectDereference((PetscObject) old)); 9777 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9778 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9779 PetscFunctionReturn(0); 9780 } 9781 9782 /*@C 9783 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this DM 9784 9785 Not collective 9786 9787 Input Parameter: 9788 . dm - The DM 9789 9790 Output Parameters: 9791 + labels - The DMLabels for each Vec 9792 . values - The label values for each Vec 9793 - parts - The equation parts for each Vec 9794 9795 Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec(). 9796 9797 Level: advanced 9798 9799 .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec() 9800 @*/ 9801 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9802 { 9803 PetscHashAuxKey *keys; 9804 PetscInt n, i, off = 0; 9805 9806 PetscFunctionBegin; 9807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9808 PetscValidPointer(labels, 2); 9809 PetscValidIntPointer(values, 3); 9810 PetscValidIntPointer(parts, 4); 9811 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9812 PetscCall(PetscMalloc1(n, &keys)); 9813 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9814 for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value; parts[i] = keys[i].part;} 9815 PetscCall(PetscFree(keys)); 9816 PetscFunctionReturn(0); 9817 } 9818 9819 /*@ 9820 DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM 9821 9822 Not collective 9823 9824 Input Parameter: 9825 . dm - The DM 9826 9827 Output Parameter: 9828 . dmNew - The new DM, now with the same auxiliary data 9829 9830 Level: advanced 9831 9832 .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec() 9833 @*/ 9834 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9835 { 9836 PetscFunctionBegin; 9837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9838 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9839 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9840 PetscFunctionReturn(0); 9841 } 9842 9843 /*@C 9844 DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement 9845 9846 Not collective 9847 9848 Input Parameters: 9849 + ct - The DMPolytopeType 9850 . sourceCone - The source arrangement of faces 9851 - targetCone - The target arrangement of faces 9852 9853 Output Parameters: 9854 + ornt - The orientation which will take the source arrangement to the target arrangement 9855 - found - Flag indicating that a suitable orientation was found 9856 9857 Level: advanced 9858 9859 .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation() 9860 @*/ 9861 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9862 { 9863 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9864 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2; 9865 PetscInt o, c; 9866 9867 PetscFunctionBegin; 9868 if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);} 9869 for (o = -nO; o < nO; ++o) { 9870 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 9871 9872 for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break; 9873 if (c == cS) {*ornt = o; break;} 9874 } 9875 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9876 PetscFunctionReturn(0); 9877 } 9878 9879 /*@C 9880 DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement 9881 9882 Not collective 9883 9884 Input Parameters: 9885 + ct - The DMPolytopeType 9886 . sourceCone - The source arrangement of faces 9887 - targetCone - The target arrangement of faces 9888 9889 Output Parameters: 9890 . ornt - The orientation which will take the source arrangement to the target arrangement 9891 9892 Note: This function will fail if no suitable orientation can be found. 9893 9894 Level: advanced 9895 9896 .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation() 9897 @*/ 9898 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9899 { 9900 PetscBool found; 9901 9902 PetscFunctionBegin; 9903 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9904 PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9905 PetscFunctionReturn(0); 9906 } 9907 9908 /*@C 9909 DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement 9910 9911 Not collective 9912 9913 Input Parameters: 9914 + ct - The DMPolytopeType 9915 . sourceVert - The source arrangement of vertices 9916 - targetVert - The target arrangement of vertices 9917 9918 Output Parameters: 9919 + ornt - The orientation which will take the source arrangement to the target arrangement 9920 - found - Flag indicating that a suitable orientation was found 9921 9922 Level: advanced 9923 9924 .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation() 9925 @*/ 9926 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9927 { 9928 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9929 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2; 9930 PetscInt o, c; 9931 9932 PetscFunctionBegin; 9933 if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);} 9934 for (o = -nO; o < nO; ++o) { 9935 const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o); 9936 9937 for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break; 9938 if (c == cS) {*ornt = o; break;} 9939 } 9940 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9941 PetscFunctionReturn(0); 9942 } 9943 9944 /*@C 9945 DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement 9946 9947 Not collective 9948 9949 Input Parameters: 9950 + ct - The DMPolytopeType 9951 . sourceCone - The source arrangement of vertices 9952 - targetCone - The target arrangement of vertices 9953 9954 Output Parameters: 9955 . ornt - The orientation which will take the source arrangement to the target arrangement 9956 9957 Note: This function will fail if no suitable orientation can be found. 9958 9959 Level: advanced 9960 9961 .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation() 9962 @*/ 9963 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9964 { 9965 PetscBool found; 9966 9967 PetscFunctionBegin; 9968 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9969 PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9970 PetscFunctionReturn(0); 9971 } 9972 9973 /*@C 9974 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9975 9976 Not collective 9977 9978 Input Parameters: 9979 + ct - The DMPolytopeType 9980 - point - Coordinates of the point 9981 9982 Output Parameters: 9983 . inside - Flag indicating whether the point is inside the reference cell of given type 9984 9985 Level: advanced 9986 9987 .seealso: DMLocatePoints() 9988 @*/ 9989 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9990 { 9991 PetscReal sum = 0.0; 9992 PetscInt d; 9993 9994 PetscFunctionBegin; 9995 *inside = PETSC_TRUE; 9996 switch (ct) { 9997 case DM_POLYTOPE_TRIANGLE: 9998 case DM_POLYTOPE_TETRAHEDRON: 9999 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 10000 if (point[d] < -1.0) {*inside = PETSC_FALSE; break;} 10001 sum += point[d]; 10002 } 10003 if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;} 10004 break; 10005 case DM_POLYTOPE_QUADRILATERAL: 10006 case DM_POLYTOPE_HEXAHEDRON: 10007 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 10008 if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;} 10009 break; 10010 default: 10011 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 10012 } 10013 PetscFunctionReturn(0); 10014 } 10015