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