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 PetscCallMPI(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) PetscCallMPI(MPIU_Allreduce(lmin, gmin, count, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject) dm))); 4121 if (gmax) PetscCallMPI(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 PetscCallMPI(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 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; 6672 PetscBool simplex; 6673 6674 /* Assume linear vertex coordinates */ 6675 PetscCall(DMGetDimension(dm, &dim)); 6676 PetscCall(DMGetCoordinateDim(dm, &dE)); 6677 PetscCall(DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL)); 6678 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 6679 switch (ct) { 6680 case DM_POLYTOPE_TRI_PRISM: 6681 case DM_POLYTOPE_TRI_PRISM_TENSOR: 6682 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms"); 6683 default: break; 6684 } 6685 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 6686 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear)); 6687 PetscCall(DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear)); 6688 PetscCall(PetscFEDestroy(&feLinear)); 6689 PetscCall(DMCreateDS(cdmOld)); 6690 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld)); 6691 } else { 6692 const char *discname; 6693 6694 PetscCall(PetscObjectGetType((PetscObject)discOld, &discname)); 6695 SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname); 6696 } 6697 } 6698 if (!disc) PetscFunctionReturn(0); 6699 { // Check if the new space is the same as the old modulo quadrature 6700 PetscDualSpace dsOld, ds; 6701 PetscCall(PetscFEGetDualSpace(discOld, &dsOld)); 6702 PetscCall(PetscFEGetDualSpace(disc, &ds)); 6703 PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space)); 6704 } 6705 /* Make a fresh clone of the coordinate DM */ 6706 PetscCall(DMClone(cdmOld, &cdmNew)); 6707 PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject) disc)); 6708 PetscCall(DMCreateDS(cdmNew)); 6709 PetscCall(DMGetCoordinates(dm, &coordsOld)); 6710 if (same_space) { 6711 PetscCall(PetscObjectReference((PetscObject)coordsOld)); 6712 coordsNew = coordsOld; 6713 } else { // Project the coordinate vector from old to new space 6714 PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew)); 6715 PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL)); 6716 PetscCall(MatInterpolate(matInterp, coordsOld, coordsNew)); 6717 PetscCall(MatDestroy(&matInterp)); 6718 } 6719 /* Set new coordinate structures */ 6720 PetscCall(DMSetCoordinateField(dm, NULL)); 6721 PetscCall(DMSetCoordinateDM(dm, cdmNew)); 6722 PetscCall(DMSetCoordinates(dm, coordsNew)); 6723 PetscCall(VecDestroy(&coordsNew)); 6724 PetscCall(DMDestroy(&cdmNew)); 6725 PetscFunctionReturn(0); 6726 } 6727 6728 /*@C 6729 DMGetPeriodicity - Get the description of mesh periodicity 6730 6731 Input Parameter: 6732 . dm - The DM object 6733 6734 Output Parameters: 6735 + per - Whether the DM is periodic or not 6736 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates 6737 . L - If we assume the mesh is a torus, this is the length of each coordinate 6738 - bd - This describes the type of periodicity in each topological dimension 6739 6740 Level: developer 6741 6742 .seealso: DMGetPeriodicity() 6743 @*/ 6744 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd) 6745 { 6746 PetscFunctionBegin; 6747 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6748 if (per) *per = dm->periodic; 6749 if (L) *L = dm->L; 6750 if (maxCell) *maxCell = dm->maxCell; 6751 if (bd) *bd = dm->bdtype; 6752 PetscFunctionReturn(0); 6753 } 6754 6755 /*@C 6756 DMSetPeriodicity - Set the description of mesh periodicity 6757 6758 Input Parameters: 6759 + dm - The DM object 6760 . per - Whether the DM is periodic or not. 6761 . 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. 6762 . L - If we assume the mesh is a torus, this is the length of each coordinate 6763 - bd - This describes the type of periodicity in each topological dimension 6764 6765 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. 6766 6767 Level: developer 6768 6769 .seealso: DMGetPeriodicity() 6770 @*/ 6771 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[]) 6772 { 6773 PetscInt dim, d; 6774 6775 PetscFunctionBegin; 6776 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 6777 PetscValidLogicalCollectiveBool(dm,per,2); 6778 if (maxCell) {PetscValidRealPointer(maxCell,3);} 6779 if (L) {PetscValidRealPointer(L,4);} 6780 if (bd) {PetscValidPointer(bd,5);} 6781 PetscCall(DMGetDimension(dm, &dim)); 6782 if (maxCell) { 6783 if (!dm->maxCell) PetscCall(PetscMalloc1(dim, &dm->maxCell)); 6784 for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d]; 6785 } else { /* remove maxCell information to disable automatic computation of localized vertices */ 6786 PetscCall(PetscFree(dm->maxCell)); 6787 } 6788 6789 if (L) { 6790 if (!dm->L) PetscCall(PetscMalloc1(dim, &dm->L)); 6791 for (d = 0; d < dim; ++d) dm->L[d] = L[d]; 6792 } 6793 if (bd) { 6794 if (!dm->bdtype) PetscCall(PetscMalloc1(dim, &dm->bdtype)); 6795 for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d]; 6796 } 6797 dm->periodic = per; 6798 PetscFunctionReturn(0); 6799 } 6800 6801 /*@ 6802 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. 6803 6804 Input Parameters: 6805 + dm - The DM 6806 . in - The input coordinate point (dim numbers) 6807 - endpoint - Include the endpoint L_i 6808 6809 Output Parameter: 6810 . out - The localized coordinate point 6811 6812 Level: developer 6813 6814 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate() 6815 @*/ 6816 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[]) 6817 { 6818 PetscInt dim, d; 6819 6820 PetscFunctionBegin; 6821 PetscCall(DMGetCoordinateDim(dm, &dim)); 6822 if (!dm->maxCell) { 6823 for (d = 0; d < dim; ++d) out[d] = in[d]; 6824 } else { 6825 if (endpoint) { 6826 for (d = 0; d < dim; ++d) { 6827 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)) { 6828 out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1); 6829 } else { 6830 out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]); 6831 } 6832 } 6833 } else { 6834 for (d = 0; d < dim; ++d) { 6835 out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]); 6836 } 6837 } 6838 } 6839 PetscFunctionReturn(0); 6840 } 6841 6842 /* 6843 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. 6844 6845 Input Parameters: 6846 + dm - The DM 6847 . dim - The spatial dimension 6848 . anchor - The anchor point, the input point can be no more than maxCell away from it 6849 - in - The input coordinate point (dim numbers) 6850 6851 Output Parameter: 6852 . out - The localized coordinate point 6853 6854 Level: developer 6855 6856 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 6857 6858 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate() 6859 */ 6860 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 6861 { 6862 PetscInt d; 6863 6864 PetscFunctionBegin; 6865 if (!dm->maxCell) { 6866 for (d = 0; d < dim; ++d) out[d] = in[d]; 6867 } else { 6868 for (d = 0; d < dim; ++d) { 6869 if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) { 6870 out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 6871 } else { 6872 out[d] = in[d]; 6873 } 6874 } 6875 } 6876 PetscFunctionReturn(0); 6877 } 6878 6879 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[]) 6880 { 6881 PetscInt d; 6882 6883 PetscFunctionBegin; 6884 if (!dm->maxCell) { 6885 for (d = 0; d < dim; ++d) out[d] = in[d]; 6886 } else { 6887 for (d = 0; d < dim; ++d) { 6888 if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) { 6889 out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d]; 6890 } else { 6891 out[d] = in[d]; 6892 } 6893 } 6894 } 6895 PetscFunctionReturn(0); 6896 } 6897 6898 /* 6899 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. 6900 6901 Input Parameters: 6902 + dm - The DM 6903 . dim - The spatial dimension 6904 . anchor - The anchor point, the input point can be no more than maxCell away from it 6905 . in - The input coordinate delta (dim numbers) 6906 - out - The input coordinate point (dim numbers) 6907 6908 Output Parameter: 6909 . out - The localized coordinate in + out 6910 6911 Level: developer 6912 6913 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 6914 6915 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate() 6916 */ 6917 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[]) 6918 { 6919 PetscInt d; 6920 6921 PetscFunctionBegin; 6922 if (!dm->maxCell) { 6923 for (d = 0; d < dim; ++d) out[d] += in[d]; 6924 } else { 6925 for (d = 0; d < dim; ++d) { 6926 const PetscReal maxC = dm->maxCell[d]; 6927 6928 if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) { 6929 const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d]; 6930 6931 if (PetscAbsScalar(newCoord - anchor[d]) > maxC) 6932 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])); 6933 out[d] += newCoord; 6934 } else { 6935 out[d] += in[d]; 6936 } 6937 } 6938 } 6939 PetscFunctionReturn(0); 6940 } 6941 6942 /*@ 6943 DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process 6944 6945 Not collective 6946 6947 Input Parameter: 6948 . dm - The DM 6949 6950 Output Parameter: 6951 areLocalized - True if localized 6952 6953 Level: developer 6954 6955 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity() 6956 @*/ 6957 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized) 6958 { 6959 DM cdm; 6960 PetscSection coordSection; 6961 PetscInt depth, cStart, cEnd, sStart, sEnd, c, dof; 6962 PetscBool isPlex, alreadyLocalized; 6963 6964 PetscFunctionBegin; 6965 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6966 PetscValidBoolPointer(areLocalized, 2); 6967 *areLocalized = PETSC_FALSE; 6968 6969 /* We need some generic way of refering to cells/vertices */ 6970 PetscCall(DMGetCoordinateDM(dm, &cdm)); 6971 PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex)); 6972 if (!isPlex) PetscFunctionReturn(0); 6973 PetscCall(DMPlexGetDepth(cdm, &depth)); 6974 if (!depth) PetscFunctionReturn(0); 6975 6976 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 6977 PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd)); 6978 PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd)); 6979 alreadyLocalized = PETSC_FALSE; 6980 for (c = cStart; c < cEnd; ++c) { 6981 if (c < sStart || c >= sEnd) continue; 6982 PetscCall(PetscSectionGetDof(coordSection, c, &dof)); 6983 if (dof) { alreadyLocalized = PETSC_TRUE; break; } 6984 } 6985 *areLocalized = alreadyLocalized; 6986 PetscFunctionReturn(0); 6987 } 6988 6989 /*@ 6990 DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells 6991 6992 Collective on dm 6993 6994 Input Parameter: 6995 . dm - The DM 6996 6997 Output Parameter: 6998 areLocalized - True if localized 6999 7000 Level: developer 7001 7002 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal() 7003 @*/ 7004 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized) 7005 { 7006 PetscBool localized; 7007 7008 PetscFunctionBegin; 7009 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7010 PetscValidBoolPointer(areLocalized, 2); 7011 PetscCall(DMGetCoordinatesLocalizedLocal(dm,&localized)); 7012 PetscCallMPI(MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm))); 7013 PetscFunctionReturn(0); 7014 } 7015 7016 /*@ 7017 DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces 7018 7019 Collective on dm 7020 7021 Input Parameter: 7022 . dm - The DM 7023 7024 Level: developer 7025 7026 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate() 7027 @*/ 7028 PetscErrorCode DMLocalizeCoordinates(DM dm) 7029 { 7030 DM cdm; 7031 PetscSection coordSection, cSection; 7032 Vec coordinates, cVec; 7033 PetscScalar *coords, *coords2, *anchor, *localized; 7034 PetscInt Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize; 7035 PetscBool alreadyLocalized, alreadyLocalizedGlobal; 7036 PetscInt maxHeight = 0, h; 7037 PetscInt *pStart = NULL, *pEnd = NULL; 7038 7039 PetscFunctionBegin; 7040 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7041 if (!dm->periodic) PetscFunctionReturn(0); 7042 PetscCall(DMGetCoordinatesLocalized(dm, &alreadyLocalized)); 7043 if (alreadyLocalized) PetscFunctionReturn(0); 7044 7045 /* We need some generic way of refering to cells/vertices */ 7046 PetscCall(DMGetCoordinateDM(dm, &cdm)); 7047 { 7048 PetscBool isplex; 7049 7050 PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex)); 7051 if (isplex) { 7052 PetscCall(DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd)); 7053 PetscCall(DMPlexGetMaxProjectionHeight(cdm,&maxHeight)); 7054 PetscCall(DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart)); 7055 pEnd = &pStart[maxHeight + 1]; 7056 newStart = vStart; 7057 newEnd = vEnd; 7058 for (h = 0; h <= maxHeight; h++) { 7059 PetscCall(DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h])); 7060 newStart = PetscMin(newStart,pStart[h]); 7061 newEnd = PetscMax(newEnd,pEnd[h]); 7062 } 7063 } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM"); 7064 } 7065 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 7066 PetscCheck(coordinates,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector"); 7067 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 7068 PetscCall(VecGetBlockSize(coordinates, &bs)); 7069 PetscCall(PetscSectionGetChart(coordSection,&sStart,&sEnd)); 7070 7071 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection)); 7072 PetscCall(PetscSectionSetNumFields(cSection, 1)); 7073 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc)); 7074 PetscCall(PetscSectionSetFieldComponents(cSection, 0, Nc)); 7075 PetscCall(PetscSectionSetChart(cSection, newStart, newEnd)); 7076 7077 PetscCall(DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 7078 localized = &anchor[bs]; 7079 alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE; 7080 for (h = 0; h <= maxHeight; h++) { 7081 PetscInt cStart = pStart[h], cEnd = pEnd[h], c; 7082 7083 for (c = cStart; c < cEnd; ++c) { 7084 PetscScalar *cellCoords = NULL; 7085 PetscInt b; 7086 7087 if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE; 7088 PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7089 for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b]; 7090 for (d = 0; d < dof/bs; ++d) { 7091 PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized)); 7092 for (b = 0; b < bs; b++) { 7093 if (cellCoords[d*bs + b] != localized[b]) break; 7094 } 7095 if (b < bs) break; 7096 } 7097 if (d < dof/bs) { 7098 if (c >= sStart && c < sEnd) { 7099 PetscInt cdof; 7100 7101 PetscCall(PetscSectionGetDof(coordSection, c, &cdof)); 7102 if (cdof != dof) alreadyLocalized = PETSC_FALSE; 7103 } 7104 PetscCall(PetscSectionSetDof(cSection, c, dof)); 7105 PetscCall(PetscSectionSetFieldDof(cSection, c, 0, dof)); 7106 } 7107 PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7108 } 7109 } 7110 PetscCallMPI(MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm))); 7111 if (alreadyLocalizedGlobal) { 7112 PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 7113 PetscCall(PetscSectionDestroy(&cSection)); 7114 PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart)); 7115 PetscFunctionReturn(0); 7116 } 7117 for (v = vStart; v < vEnd; ++v) { 7118 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 7119 PetscCall(PetscSectionSetDof(cSection, v, dof)); 7120 PetscCall(PetscSectionSetFieldDof(cSection, v, 0, dof)); 7121 } 7122 PetscCall(PetscSectionSetUp(cSection)); 7123 PetscCall(PetscSectionGetStorageSize(cSection, &coordSize)); 7124 PetscCall(VecCreate(PETSC_COMM_SELF, &cVec)); 7125 PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates")); 7126 PetscCall(VecSetBlockSize(cVec, bs)); 7127 PetscCall(VecSetSizes(cVec, coordSize, PETSC_DETERMINE)); 7128 PetscCall(VecSetType(cVec, VECSTANDARD)); 7129 PetscCall(VecGetArrayRead(coordinates, (const PetscScalar**)&coords)); 7130 PetscCall(VecGetArray(cVec, &coords2)); 7131 for (v = vStart; v < vEnd; ++v) { 7132 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 7133 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 7134 PetscCall(PetscSectionGetOffset(cSection, v, &off2)); 7135 for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d]; 7136 } 7137 for (h = 0; h <= maxHeight; h++) { 7138 PetscInt cStart = pStart[h], cEnd = pEnd[h], c; 7139 7140 for (c = cStart; c < cEnd; ++c) { 7141 PetscScalar *cellCoords = NULL; 7142 PetscInt b, cdof; 7143 7144 PetscCall(PetscSectionGetDof(cSection,c,&cdof)); 7145 if (!cdof) continue; 7146 PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7147 PetscCall(PetscSectionGetOffset(cSection, c, &off2)); 7148 for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b]; 7149 for (d = 0; d < dof/bs; ++d) PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs])); 7150 PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords)); 7151 } 7152 } 7153 PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor)); 7154 PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart)); 7155 PetscCall(VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords)); 7156 PetscCall(VecRestoreArray(cVec, &coords2)); 7157 PetscCall(DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection)); 7158 PetscCall(DMSetCoordinatesLocal(dm, cVec)); 7159 PetscCall(VecDestroy(&cVec)); 7160 PetscCall(PetscSectionDestroy(&cSection)); 7161 PetscFunctionReturn(0); 7162 } 7163 7164 /*@ 7165 DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells 7166 7167 Collective on v (see explanation below) 7168 7169 Input Parameters: 7170 + dm - The DM 7171 - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST 7172 7173 Input/Output Parameters: 7174 + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used 7175 - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point; 7176 on output, the PetscSF containing the ranks and local indices of the containing points 7177 7178 Level: developer 7179 7180 Notes: 7181 To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator. 7182 To do a search of all the cells in the distributed mesh, v should have the same communicator as dm. 7183 7184 If *cellSF is NULL on input, a PetscSF will be created. 7185 If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses. 7186 7187 An array that maps each point to its containing cell can be obtained with 7188 7189 $ const PetscSFNode *cells; 7190 $ PetscInt nFound; 7191 $ const PetscInt *found; 7192 $ 7193 $ PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells); 7194 7195 Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is 7196 the index of the cell in its rank's local numbering. 7197 7198 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType 7199 @*/ 7200 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF) 7201 { 7202 PetscFunctionBegin; 7203 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7204 PetscValidHeaderSpecific(v,VEC_CLASSID,2); 7205 PetscValidPointer(cellSF,4); 7206 if (*cellSF) { 7207 PetscMPIInt result; 7208 7209 PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4); 7210 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result)); 7211 PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's"); 7212 } else { 7213 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF)); 7214 } 7215 PetscCheck(dm->ops->locatepoints,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM"); 7216 PetscCall(PetscLogEventBegin(DM_LocatePoints,dm,0,0,0)); 7217 PetscCall((*dm->ops->locatepoints)(dm,v,ltype,*cellSF)); 7218 PetscCall(PetscLogEventEnd(DM_LocatePoints,dm,0,0,0)); 7219 PetscFunctionReturn(0); 7220 } 7221 7222 /*@ 7223 DMGetOutputDM - Retrieve the DM associated with the layout for output 7224 7225 Collective on dm 7226 7227 Input Parameter: 7228 . dm - The original DM 7229 7230 Output Parameter: 7231 . odm - The DM which provides the layout for output 7232 7233 Level: intermediate 7234 7235 .seealso: VecView(), DMGetGlobalSection() 7236 @*/ 7237 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 7238 { 7239 PetscSection section; 7240 PetscBool hasConstraints, ghasConstraints; 7241 7242 PetscFunctionBegin; 7243 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7244 PetscValidPointer(odm,2); 7245 PetscCall(DMGetLocalSection(dm, §ion)); 7246 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 7247 PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm))); 7248 if (!ghasConstraints) { 7249 *odm = dm; 7250 PetscFunctionReturn(0); 7251 } 7252 if (!dm->dmBC) { 7253 PetscSection newSection, gsection; 7254 PetscSF sf; 7255 7256 PetscCall(DMClone(dm, &dm->dmBC)); 7257 PetscCall(DMCopyDisc(dm, dm->dmBC)); 7258 PetscCall(PetscSectionClone(section, &newSection)); 7259 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 7260 PetscCall(PetscSectionDestroy(&newSection)); 7261 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 7262 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 7263 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 7264 PetscCall(PetscSectionDestroy(&gsection)); 7265 } 7266 *odm = dm->dmBC; 7267 PetscFunctionReturn(0); 7268 } 7269 7270 /*@ 7271 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 7272 7273 Input Parameter: 7274 . dm - The original DM 7275 7276 Output Parameters: 7277 + num - The output sequence number 7278 - val - The output sequence value 7279 7280 Level: intermediate 7281 7282 Note: This is intended for output that should appear in sequence, for instance 7283 a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system. 7284 7285 .seealso: VecView() 7286 @*/ 7287 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 7288 { 7289 PetscFunctionBegin; 7290 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7291 if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;} 7292 if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;} 7293 PetscFunctionReturn(0); 7294 } 7295 7296 /*@ 7297 DMSetOutputSequenceNumber - Set the sequence number/value for output 7298 7299 Input Parameters: 7300 + dm - The original DM 7301 . num - The output sequence number 7302 - val - The output sequence value 7303 7304 Level: intermediate 7305 7306 Note: This is intended for output that should appear in sequence, for instance 7307 a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system. 7308 7309 .seealso: VecView() 7310 @*/ 7311 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 7312 { 7313 PetscFunctionBegin; 7314 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7315 dm->outputSequenceNum = num; 7316 dm->outputSequenceVal = val; 7317 PetscFunctionReturn(0); 7318 } 7319 7320 /*@C 7321 DMOutputSequenceLoad - Retrieve the sequence value from a Viewer 7322 7323 Input Parameters: 7324 + dm - The original DM 7325 . name - The sequence name 7326 - num - The output sequence number 7327 7328 Output Parameter: 7329 . val - The output sequence value 7330 7331 Level: intermediate 7332 7333 Note: This is intended for output that should appear in sequence, for instance 7334 a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system. 7335 7336 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView() 7337 @*/ 7338 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val) 7339 { 7340 PetscBool ishdf5; 7341 7342 PetscFunctionBegin; 7343 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 7344 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2); 7345 PetscValidRealPointer(val,5); 7346 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 7347 if (ishdf5) { 7348 #if defined(PETSC_HAVE_HDF5) 7349 PetscScalar value; 7350 7351 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 7352 *val = PetscRealPart(value); 7353 #endif 7354 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 7355 PetscFunctionReturn(0); 7356 } 7357 7358 /*@ 7359 DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution 7360 7361 Not collective 7362 7363 Input Parameter: 7364 . dm - The DM 7365 7366 Output Parameter: 7367 . useNatural - The flag to build the mapping to a natural order during distribution 7368 7369 Level: beginner 7370 7371 .seealso: DMSetUseNatural(), DMCreate() 7372 @*/ 7373 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 7374 { 7375 PetscFunctionBegin; 7376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7377 PetscValidBoolPointer(useNatural, 2); 7378 *useNatural = dm->useNatural; 7379 PetscFunctionReturn(0); 7380 } 7381 7382 /*@ 7383 DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution 7384 7385 Collective on dm 7386 7387 Input Parameters: 7388 + dm - The DM 7389 - useNatural - The flag to build the mapping to a natural order during distribution 7390 7391 Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM() 7392 7393 Level: beginner 7394 7395 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM() 7396 @*/ 7397 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 7398 { 7399 PetscFunctionBegin; 7400 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7401 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 7402 dm->useNatural = useNatural; 7403 PetscFunctionReturn(0); 7404 } 7405 7406 /*@C 7407 DMCreateLabel - Create a label of the given name if it does not already exist 7408 7409 Not Collective 7410 7411 Input Parameters: 7412 + dm - The DM object 7413 - name - The label name 7414 7415 Level: intermediate 7416 7417 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7418 @*/ 7419 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 7420 { 7421 PetscBool flg; 7422 DMLabel label; 7423 7424 PetscFunctionBegin; 7425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7426 PetscValidCharPointer(name, 2); 7427 PetscCall(DMHasLabel(dm, name, &flg)); 7428 if (!flg) { 7429 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 7430 PetscCall(DMAddLabel(dm, label)); 7431 PetscCall(DMLabelDestroy(&label)); 7432 } 7433 PetscFunctionReturn(0); 7434 } 7435 7436 /*@C 7437 DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index. 7438 7439 Not Collective 7440 7441 Input Parameters: 7442 + dm - The DM object 7443 . l - The index for the label 7444 - name - The label name 7445 7446 Level: intermediate 7447 7448 .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7449 @*/ 7450 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 7451 { 7452 DMLabelLink orig, prev = NULL; 7453 DMLabel label; 7454 PetscInt Nl, m; 7455 PetscBool flg, match; 7456 const char *lname; 7457 7458 PetscFunctionBegin; 7459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7460 PetscValidCharPointer(name, 3); 7461 PetscCall(DMHasLabel(dm, name, &flg)); 7462 if (!flg) { 7463 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 7464 PetscCall(DMAddLabel(dm, label)); 7465 PetscCall(DMLabelDestroy(&label)); 7466 } 7467 PetscCall(DMGetNumLabels(dm, &Nl)); 7468 PetscCheck(l < Nl,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl); 7469 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 7470 PetscCall(PetscObjectGetName((PetscObject) orig->label, &lname)); 7471 PetscCall(PetscStrcmp(name, lname, &match)); 7472 if (match) break; 7473 } 7474 if (m == l) PetscFunctionReturn(0); 7475 if (!m) dm->labels = orig->next; 7476 else prev->next = orig->next; 7477 if (!l) { 7478 orig->next = dm->labels; 7479 dm->labels = orig; 7480 } else { 7481 for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next); 7482 orig->next = prev->next; 7483 prev->next = orig; 7484 } 7485 PetscFunctionReturn(0); 7486 } 7487 7488 /*@C 7489 DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default 7490 7491 Not Collective 7492 7493 Input Parameters: 7494 + dm - The DM object 7495 . name - The label name 7496 - point - The mesh point 7497 7498 Output Parameter: 7499 . value - The label value for this point, or -1 if the point is not in the label 7500 7501 Level: beginner 7502 7503 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS() 7504 @*/ 7505 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 7506 { 7507 DMLabel label; 7508 7509 PetscFunctionBegin; 7510 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7511 PetscValidCharPointer(name, 2); 7512 PetscCall(DMGetLabel(dm, name, &label)); 7513 PetscCheck(label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 7514 PetscCall(DMLabelGetValue(label, point, value)); 7515 PetscFunctionReturn(0); 7516 } 7517 7518 /*@C 7519 DMSetLabelValue - Add a point to a Sieve Label with given value 7520 7521 Not Collective 7522 7523 Input Parameters: 7524 + dm - The DM object 7525 . name - The label name 7526 . point - The mesh point 7527 - value - The label value for this point 7528 7529 Output Parameter: 7530 7531 Level: beginner 7532 7533 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue() 7534 @*/ 7535 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 7536 { 7537 DMLabel label; 7538 7539 PetscFunctionBegin; 7540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7541 PetscValidCharPointer(name, 2); 7542 PetscCall(DMGetLabel(dm, name, &label)); 7543 if (!label) { 7544 PetscCall(DMCreateLabel(dm, name)); 7545 PetscCall(DMGetLabel(dm, name, &label)); 7546 } 7547 PetscCall(DMLabelSetValue(label, point, value)); 7548 PetscFunctionReturn(0); 7549 } 7550 7551 /*@C 7552 DMClearLabelValue - Remove a point from a Sieve Label with given value 7553 7554 Not Collective 7555 7556 Input Parameters: 7557 + dm - The DM object 7558 . name - The label name 7559 . point - The mesh point 7560 - value - The label value for this point 7561 7562 Output Parameter: 7563 7564 Level: beginner 7565 7566 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS() 7567 @*/ 7568 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 7569 { 7570 DMLabel label; 7571 7572 PetscFunctionBegin; 7573 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7574 PetscValidCharPointer(name, 2); 7575 PetscCall(DMGetLabel(dm, name, &label)); 7576 if (!label) PetscFunctionReturn(0); 7577 PetscCall(DMLabelClearValue(label, point, value)); 7578 PetscFunctionReturn(0); 7579 } 7580 7581 /*@C 7582 DMGetLabelSize - Get the number of different integer ids in a Label 7583 7584 Not Collective 7585 7586 Input Parameters: 7587 + dm - The DM object 7588 - name - The label name 7589 7590 Output Parameter: 7591 . size - The number of different integer ids, or 0 if the label does not exist 7592 7593 Level: beginner 7594 7595 .seealso: DMLabelGetNumValues(), DMSetLabelValue() 7596 @*/ 7597 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 7598 { 7599 DMLabel label; 7600 7601 PetscFunctionBegin; 7602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7603 PetscValidCharPointer(name, 2); 7604 PetscValidIntPointer(size, 3); 7605 PetscCall(DMGetLabel(dm, name, &label)); 7606 *size = 0; 7607 if (!label) PetscFunctionReturn(0); 7608 PetscCall(DMLabelGetNumValues(label, size)); 7609 PetscFunctionReturn(0); 7610 } 7611 7612 /*@C 7613 DMGetLabelIdIS - Get the integer ids in a label 7614 7615 Not Collective 7616 7617 Input Parameters: 7618 + mesh - The DM object 7619 - name - The label name 7620 7621 Output Parameter: 7622 . ids - The integer ids, or NULL if the label does not exist 7623 7624 Level: beginner 7625 7626 .seealso: DMLabelGetValueIS(), DMGetLabelSize() 7627 @*/ 7628 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 7629 { 7630 DMLabel label; 7631 7632 PetscFunctionBegin; 7633 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7634 PetscValidCharPointer(name, 2); 7635 PetscValidPointer(ids, 3); 7636 PetscCall(DMGetLabel(dm, name, &label)); 7637 *ids = NULL; 7638 if (label) { 7639 PetscCall(DMLabelGetValueIS(label, ids)); 7640 } else { 7641 /* returning an empty IS */ 7642 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids)); 7643 } 7644 PetscFunctionReturn(0); 7645 } 7646 7647 /*@C 7648 DMGetStratumSize - Get the number of points in a label stratum 7649 7650 Not Collective 7651 7652 Input Parameters: 7653 + dm - The DM object 7654 . name - The label name 7655 - value - The stratum value 7656 7657 Output Parameter: 7658 . size - The stratum size 7659 7660 Level: beginner 7661 7662 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds() 7663 @*/ 7664 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 7665 { 7666 DMLabel label; 7667 7668 PetscFunctionBegin; 7669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7670 PetscValidCharPointer(name, 2); 7671 PetscValidIntPointer(size, 4); 7672 PetscCall(DMGetLabel(dm, name, &label)); 7673 *size = 0; 7674 if (!label) PetscFunctionReturn(0); 7675 PetscCall(DMLabelGetStratumSize(label, value, size)); 7676 PetscFunctionReturn(0); 7677 } 7678 7679 /*@C 7680 DMGetStratumIS - Get the points in a label stratum 7681 7682 Not Collective 7683 7684 Input Parameters: 7685 + dm - The DM object 7686 . name - The label name 7687 - value - The stratum value 7688 7689 Output Parameter: 7690 . points - The stratum points, or NULL if the label does not exist or does not have that value 7691 7692 Level: beginner 7693 7694 .seealso: DMLabelGetStratumIS(), DMGetStratumSize() 7695 @*/ 7696 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 7697 { 7698 DMLabel label; 7699 7700 PetscFunctionBegin; 7701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7702 PetscValidCharPointer(name, 2); 7703 PetscValidPointer(points, 4); 7704 PetscCall(DMGetLabel(dm, name, &label)); 7705 *points = NULL; 7706 if (!label) PetscFunctionReturn(0); 7707 PetscCall(DMLabelGetStratumIS(label, value, points)); 7708 PetscFunctionReturn(0); 7709 } 7710 7711 /*@C 7712 DMSetStratumIS - Set the points in a label stratum 7713 7714 Not Collective 7715 7716 Input Parameters: 7717 + dm - The DM object 7718 . name - The label name 7719 . value - The stratum value 7720 - points - The stratum points 7721 7722 Level: beginner 7723 7724 .seealso: DMLabelSetStratumIS(), DMGetStratumSize() 7725 @*/ 7726 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 7727 { 7728 DMLabel label; 7729 7730 PetscFunctionBegin; 7731 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7732 PetscValidCharPointer(name, 2); 7733 PetscValidPointer(points, 4); 7734 PetscCall(DMGetLabel(dm, name, &label)); 7735 if (!label) PetscFunctionReturn(0); 7736 PetscCall(DMLabelSetStratumIS(label, value, points)); 7737 PetscFunctionReturn(0); 7738 } 7739 7740 /*@C 7741 DMClearLabelStratum - Remove all points from a stratum from a Sieve Label 7742 7743 Not Collective 7744 7745 Input Parameters: 7746 + dm - The DM object 7747 . name - The label name 7748 - value - The label value for this point 7749 7750 Output Parameter: 7751 7752 Level: beginner 7753 7754 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue() 7755 @*/ 7756 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 7757 { 7758 DMLabel label; 7759 7760 PetscFunctionBegin; 7761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7762 PetscValidCharPointer(name, 2); 7763 PetscCall(DMGetLabel(dm, name, &label)); 7764 if (!label) PetscFunctionReturn(0); 7765 PetscCall(DMLabelClearStratum(label, value)); 7766 PetscFunctionReturn(0); 7767 } 7768 7769 /*@ 7770 DMGetNumLabels - Return the number of labels defined by the mesh 7771 7772 Not Collective 7773 7774 Input Parameter: 7775 . dm - The DM object 7776 7777 Output Parameter: 7778 . numLabels - the number of Labels 7779 7780 Level: intermediate 7781 7782 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7783 @*/ 7784 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 7785 { 7786 DMLabelLink next = dm->labels; 7787 PetscInt n = 0; 7788 7789 PetscFunctionBegin; 7790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7791 PetscValidIntPointer(numLabels, 2); 7792 while (next) {++n; next = next->next;} 7793 *numLabels = n; 7794 PetscFunctionReturn(0); 7795 } 7796 7797 /*@C 7798 DMGetLabelName - Return the name of nth label 7799 7800 Not Collective 7801 7802 Input Parameters: 7803 + dm - The DM object 7804 - n - the label number 7805 7806 Output Parameter: 7807 . name - the label name 7808 7809 Level: intermediate 7810 7811 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7812 @*/ 7813 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name) 7814 { 7815 DMLabelLink next = dm->labels; 7816 PetscInt l = 0; 7817 7818 PetscFunctionBegin; 7819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7820 PetscValidPointer(name, 3); 7821 while (next) { 7822 if (l == n) { 7823 PetscCall(PetscObjectGetName((PetscObject) next->label, name)); 7824 PetscFunctionReturn(0); 7825 } 7826 ++l; 7827 next = next->next; 7828 } 7829 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n); 7830 } 7831 7832 /*@C 7833 DMHasLabel - Determine whether the mesh has a label of a given name 7834 7835 Not Collective 7836 7837 Input Parameters: 7838 + dm - The DM object 7839 - name - The label name 7840 7841 Output Parameter: 7842 . hasLabel - PETSC_TRUE if the label is present 7843 7844 Level: intermediate 7845 7846 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7847 @*/ 7848 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7849 { 7850 DMLabelLink next = dm->labels; 7851 const char *lname; 7852 7853 PetscFunctionBegin; 7854 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7855 PetscValidCharPointer(name, 2); 7856 PetscValidBoolPointer(hasLabel, 3); 7857 *hasLabel = PETSC_FALSE; 7858 while (next) { 7859 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 7860 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7861 if (*hasLabel) break; 7862 next = next->next; 7863 } 7864 PetscFunctionReturn(0); 7865 } 7866 7867 /*@C 7868 DMGetLabel - Return the label of a given name, or NULL 7869 7870 Not Collective 7871 7872 Input Parameters: 7873 + dm - The DM object 7874 - name - The label name 7875 7876 Output Parameter: 7877 . label - The DMLabel, or NULL if the label is absent 7878 7879 Note: Some of the default labels in a DMPlex will be 7880 $ "depth" - Holds the depth (co-dimension) of each mesh point 7881 $ "celltype" - Holds the topological type of each cell 7882 $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7883 $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7884 $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7885 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7886 7887 Level: intermediate 7888 7889 .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType() 7890 @*/ 7891 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7892 { 7893 DMLabelLink next = dm->labels; 7894 PetscBool hasLabel; 7895 const char *lname; 7896 7897 PetscFunctionBegin; 7898 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7899 PetscValidCharPointer(name, 2); 7900 PetscValidPointer(label, 3); 7901 *label = NULL; 7902 while (next) { 7903 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 7904 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7905 if (hasLabel) { 7906 *label = next->label; 7907 break; 7908 } 7909 next = next->next; 7910 } 7911 PetscFunctionReturn(0); 7912 } 7913 7914 /*@C 7915 DMGetLabelByNum - Return the nth label 7916 7917 Not Collective 7918 7919 Input Parameters: 7920 + dm - The DM object 7921 - n - the label number 7922 7923 Output Parameter: 7924 . label - the label 7925 7926 Level: intermediate 7927 7928 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7929 @*/ 7930 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7931 { 7932 DMLabelLink next = dm->labels; 7933 PetscInt l = 0; 7934 7935 PetscFunctionBegin; 7936 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7937 PetscValidPointer(label, 3); 7938 while (next) { 7939 if (l == n) { 7940 *label = next->label; 7941 PetscFunctionReturn(0); 7942 } 7943 ++l; 7944 next = next->next; 7945 } 7946 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n); 7947 } 7948 7949 /*@C 7950 DMAddLabel - Add the label to this mesh 7951 7952 Not Collective 7953 7954 Input Parameters: 7955 + dm - The DM object 7956 - label - The DMLabel 7957 7958 Level: developer 7959 7960 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 7961 @*/ 7962 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7963 { 7964 DMLabelLink l, *p, tmpLabel; 7965 PetscBool hasLabel; 7966 const char *lname; 7967 PetscBool flg; 7968 7969 PetscFunctionBegin; 7970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7971 PetscCall(PetscObjectGetName((PetscObject) label, &lname)); 7972 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7973 PetscCheck(!hasLabel,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7974 PetscCall(PetscCalloc1(1, &tmpLabel)); 7975 tmpLabel->label = label; 7976 tmpLabel->output = PETSC_TRUE; 7977 for (p=&dm->labels; (l=*p); p=&l->next) {} 7978 *p = tmpLabel; 7979 PetscCall(PetscObjectReference((PetscObject)label)); 7980 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7981 if (flg) dm->depthLabel = label; 7982 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7983 if (flg) dm->celltypeLabel = label; 7984 PetscFunctionReturn(0); 7985 } 7986 7987 /*@C 7988 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7989 7990 Not Collective 7991 7992 Input Parameters: 7993 + dm - The DM object 7994 - label - The DMLabel, having the same name, to substitute 7995 7996 Note: Some of the default labels in a DMPlex will be 7997 $ "depth" - Holds the depth (co-dimension) of each mesh point 7998 $ "celltype" - Holds the topological type of each cell 7999 $ "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 8000 $ "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 8001 $ "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 8002 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh 8003 8004 Level: intermediate 8005 8006 .seealso: DMCreateLabel(), DMHasLabel(), DMPlexGetDepthLabel(), DMPlexGetCellType() 8007 @*/ 8008 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 8009 { 8010 DMLabelLink next = dm->labels; 8011 PetscBool hasLabel, flg; 8012 const char *name, *lname; 8013 8014 PetscFunctionBegin; 8015 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8016 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 8017 PetscCall(PetscObjectGetName((PetscObject) label, &name)); 8018 while (next) { 8019 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 8020 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 8021 if (hasLabel) { 8022 PetscCall(PetscObjectReference((PetscObject) label)); 8023 PetscCall(PetscStrcmp(lname, "depth", &flg)); 8024 if (flg) dm->depthLabel = label; 8025 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 8026 if (flg) dm->celltypeLabel = label; 8027 PetscCall(DMLabelDestroy(&next->label)); 8028 next->label = label; 8029 break; 8030 } 8031 next = next->next; 8032 } 8033 PetscFunctionReturn(0); 8034 } 8035 8036 /*@C 8037 DMRemoveLabel - Remove the label given by name from this mesh 8038 8039 Not Collective 8040 8041 Input Parameters: 8042 + dm - The DM object 8043 - name - The label name 8044 8045 Output Parameter: 8046 . label - The DMLabel, or NULL if the label is absent 8047 8048 Level: developer 8049 8050 Notes: 8051 DMRemoveLabel(dm,name,NULL) removes the label from dm and calls 8052 DMLabelDestroy() on the label. 8053 8054 DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT 8055 call DMLabelDestroy(). Instead, the label is returned and the user is 8056 responsible of calling DMLabelDestroy() at some point. 8057 8058 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf() 8059 @*/ 8060 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 8061 { 8062 DMLabelLink link, *pnext; 8063 PetscBool hasLabel; 8064 const char *lname; 8065 8066 PetscFunctionBegin; 8067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8068 PetscValidCharPointer(name, 2); 8069 if (label) { 8070 PetscValidPointer(label, 3); 8071 *label = NULL; 8072 } 8073 for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) { 8074 PetscCall(PetscObjectGetName((PetscObject) link->label, &lname)); 8075 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 8076 if (hasLabel) { 8077 *pnext = link->next; /* Remove from list */ 8078 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 8079 if (hasLabel) dm->depthLabel = NULL; 8080 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 8081 if (hasLabel) dm->celltypeLabel = NULL; 8082 if (label) *label = link->label; 8083 else PetscCall(DMLabelDestroy(&link->label)); 8084 PetscCall(PetscFree(link)); 8085 break; 8086 } 8087 } 8088 PetscFunctionReturn(0); 8089 } 8090 8091 /*@ 8092 DMRemoveLabelBySelf - Remove the label from this mesh 8093 8094 Not Collective 8095 8096 Input Parameters: 8097 + dm - The DM object 8098 . label - The DMLabel to be removed from the DM 8099 - failNotFound - Should it fail if the label is not found in the DM? 8100 8101 Level: developer 8102 8103 Notes: 8104 Only exactly the same instance is removed if found, name match is ignored. 8105 If the DM has an exclusive reference to the label, it gets destroyed and 8106 *label nullified. 8107 8108 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel() 8109 @*/ 8110 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 8111 { 8112 DMLabelLink link, *pnext; 8113 PetscBool hasLabel = PETSC_FALSE; 8114 8115 PetscFunctionBegin; 8116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8117 PetscValidPointer(label, 2); 8118 if (!*label && !failNotFound) PetscFunctionReturn(0); 8119 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 8120 PetscValidLogicalCollectiveBool(dm,failNotFound,3); 8121 for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) { 8122 if (*label == link->label) { 8123 hasLabel = PETSC_TRUE; 8124 *pnext = link->next; /* Remove from list */ 8125 if (*label == dm->depthLabel) dm->depthLabel = NULL; 8126 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 8127 if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 8128 PetscCall(DMLabelDestroy(&link->label)); 8129 PetscCall(PetscFree(link)); 8130 break; 8131 } 8132 } 8133 PetscCheck(hasLabel || !failNotFound,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 8134 PetscFunctionReturn(0); 8135 } 8136 8137 /*@C 8138 DMGetLabelOutput - Get the output flag for a given label 8139 8140 Not Collective 8141 8142 Input Parameters: 8143 + dm - The DM object 8144 - name - The label name 8145 8146 Output Parameter: 8147 . output - The flag for output 8148 8149 Level: developer 8150 8151 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 8152 @*/ 8153 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 8154 { 8155 DMLabelLink next = dm->labels; 8156 const char *lname; 8157 8158 PetscFunctionBegin; 8159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8160 PetscValidCharPointer(name, 2); 8161 PetscValidBoolPointer(output, 3); 8162 while (next) { 8163 PetscBool flg; 8164 8165 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 8166 PetscCall(PetscStrcmp(name, lname, &flg)); 8167 if (flg) {*output = next->output; PetscFunctionReturn(0);} 8168 next = next->next; 8169 } 8170 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 8171 } 8172 8173 /*@C 8174 DMSetLabelOutput - Set the output flag for a given label 8175 8176 Not Collective 8177 8178 Input Parameters: 8179 + dm - The DM object 8180 . name - The label name 8181 - output - The flag for output 8182 8183 Level: developer 8184 8185 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS() 8186 @*/ 8187 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 8188 { 8189 DMLabelLink next = dm->labels; 8190 const char *lname; 8191 8192 PetscFunctionBegin; 8193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8194 PetscValidCharPointer(name, 2); 8195 while (next) { 8196 PetscBool flg; 8197 8198 PetscCall(PetscObjectGetName((PetscObject) next->label, &lname)); 8199 PetscCall(PetscStrcmp(name, lname, &flg)); 8200 if (flg) {next->output = output; PetscFunctionReturn(0);} 8201 next = next->next; 8202 } 8203 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 8204 } 8205 8206 /*@ 8207 DMCopyLabels - Copy labels from one mesh to another with a superset of the points 8208 8209 Collective on dmA 8210 8211 Input Parameters: 8212 + dmA - The DM object with initial labels 8213 . dmB - The DM object to which labels are copied 8214 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES) 8215 . all - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE) 8216 - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode) 8217 8218 Level: intermediate 8219 8220 Notes: 8221 This is typically used when interpolating or otherwise adding to a mesh, or testing. 8222 8223 .seealso: DMAddLabel(), DMCopyLabelsMode 8224 @*/ 8225 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 8226 { 8227 DMLabel label, labelNew, labelOld; 8228 const char *name; 8229 PetscBool flg; 8230 DMLabelLink link; 8231 8232 PetscFunctionBegin; 8233 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 8234 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 8235 PetscValidLogicalCollectiveEnum(dmA, mode,3); 8236 PetscValidLogicalCollectiveBool(dmA, all, 4); 8237 PetscCheck(mode != PETSC_USE_POINTER,PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 8238 if (dmA == dmB) PetscFunctionReturn(0); 8239 for (link=dmA->labels; link; link=link->next) { 8240 label=link->label; 8241 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 8242 if (!all) { 8243 PetscCall(PetscStrcmp(name, "depth", &flg)); 8244 if (flg) continue; 8245 PetscCall(PetscStrcmp(name, "dim", &flg)); 8246 if (flg) continue; 8247 PetscCall(PetscStrcmp(name, "celltype", &flg)); 8248 if (flg) continue; 8249 } 8250 PetscCall(DMGetLabel(dmB, name, &labelOld)); 8251 if (labelOld) { 8252 switch (emode) { 8253 case DM_COPY_LABELS_KEEP: 8254 continue; 8255 case DM_COPY_LABELS_REPLACE: 8256 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 8257 break; 8258 case DM_COPY_LABELS_FAIL: 8259 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 8260 default: 8261 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 8262 } 8263 } 8264 if (mode==PETSC_COPY_VALUES) { 8265 PetscCall(DMLabelDuplicate(label, &labelNew)); 8266 } else { 8267 labelNew = label; 8268 } 8269 PetscCall(DMAddLabel(dmB, labelNew)); 8270 if (mode==PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 8271 } 8272 PetscFunctionReturn(0); 8273 } 8274 8275 /*@C 8276 DMCompareLabels - Compare labels of two DMPlex meshes 8277 8278 Collective 8279 8280 Input Parameters: 8281 + dm0 - First DM object 8282 - dm1 - Second DM object 8283 8284 Output Parameters 8285 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 8286 - message - (Optional) Message describing the difference, or NULL if there is no difference 8287 8288 Level: intermediate 8289 8290 Notes: 8291 The output flag equal is the same on all processes. 8292 If it is passed as NULL and difference is found, an error is thrown on all processes. 8293 Make sure to pass NULL on all processes. 8294 8295 The output message is set independently on each rank. 8296 It is set to NULL if no difference was found on the current rank. It must be freed by user. 8297 If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner. 8298 Make sure to pass NULL on all processes. 8299 8300 Labels are matched by name. If the number of labels and their names are equal, 8301 DMLabelCompare() is used to compare each pair of labels with the same name. 8302 8303 Fortran Notes: 8304 This function is currently not available from Fortran. 8305 8306 .seealso: DMAddLabel(), DMCopyLabelsMode, DMLabelCompare() 8307 @*/ 8308 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 8309 { 8310 PetscInt n, i; 8311 char msg[PETSC_MAX_PATH_LEN] = ""; 8312 PetscBool eq; 8313 MPI_Comm comm; 8314 PetscMPIInt rank; 8315 8316 PetscFunctionBegin; 8317 PetscValidHeaderSpecific(dm0,DM_CLASSID,1); 8318 PetscValidHeaderSpecific(dm1,DM_CLASSID,2); 8319 PetscCheckSameComm(dm0,1,dm1,2); 8320 if (equal) PetscValidBoolPointer(equal,3); 8321 if (message) PetscValidPointer(message, 4); 8322 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 8323 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 8324 { 8325 PetscInt n1; 8326 8327 PetscCall(DMGetNumLabels(dm0, &n)); 8328 PetscCall(DMGetNumLabels(dm1, &n1)); 8329 eq = (PetscBool) (n == n1); 8330 if (!eq) { 8331 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %D != %D = Number of labels in dm1", n, n1)); 8332 } 8333 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 8334 if (!eq) goto finish; 8335 } 8336 for (i=0; i<n; i++) { 8337 DMLabel l0, l1; 8338 const char *name; 8339 char *msgInner; 8340 8341 /* Ignore label order */ 8342 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 8343 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 8344 PetscCall(DMGetLabel(dm1, name, &l1)); 8345 if (!l1) { 8346 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%D in dm0) not found in dm1", name, i)); 8347 eq = PETSC_FALSE; 8348 break; 8349 } 8350 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 8351 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 8352 PetscCall(PetscFree(msgInner)); 8353 if (!eq) break; 8354 } 8355 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 8356 finish: 8357 /* If message output arg not set, print to stderr */ 8358 if (message) { 8359 *message = NULL; 8360 if (msg[0]) { 8361 PetscCall(PetscStrallocpy(msg, message)); 8362 } 8363 } else { 8364 if (msg[0]) { 8365 PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 8366 } 8367 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 8368 } 8369 /* If same output arg not ser and labels are not equal, throw error */ 8370 if (equal) *equal = eq; 8371 else PetscCheck(eq,comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 8372 PetscFunctionReturn(0); 8373 } 8374 8375 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 8376 { 8377 PetscFunctionBegin; 8378 PetscValidPointer(label,2); 8379 if (!*label) { 8380 PetscCall(DMCreateLabel(dm, name)); 8381 PetscCall(DMGetLabel(dm, name, label)); 8382 } 8383 PetscCall(DMLabelSetValue(*label, point, value)); 8384 PetscFunctionReturn(0); 8385 } 8386 8387 /* 8388 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 8389 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 8390 (label, id) pair in the DM. 8391 8392 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 8393 each label. 8394 */ 8395 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 8396 { 8397 DMUniversalLabel ul; 8398 PetscBool *active; 8399 PetscInt pStart, pEnd, p, Nl, l, m; 8400 8401 PetscFunctionBegin; 8402 PetscCall(PetscMalloc1(1, &ul)); 8403 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 8404 PetscCall(DMGetNumLabels(dm, &Nl)); 8405 PetscCall(PetscCalloc1(Nl, &active)); 8406 ul->Nl = 0; 8407 for (l = 0; l < Nl; ++l) { 8408 PetscBool isdepth, iscelltype; 8409 const char *name; 8410 8411 PetscCall(DMGetLabelName(dm, l, &name)); 8412 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 8413 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 8414 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 8415 if (active[l]) ++ul->Nl; 8416 } 8417 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks)); 8418 ul->Nv = 0; 8419 for (l = 0, m = 0; l < Nl; ++l) { 8420 DMLabel label; 8421 PetscInt nv; 8422 const char *name; 8423 8424 if (!active[l]) continue; 8425 PetscCall(DMGetLabelName(dm, l, &name)); 8426 PetscCall(DMGetLabelByNum(dm, l, &label)); 8427 PetscCall(DMLabelGetNumValues(label, &nv)); 8428 PetscCall(PetscStrallocpy(name, &ul->names[m])); 8429 ul->indices[m] = l; 8430 ul->Nv += nv; 8431 ul->offsets[m+1] = nv; 8432 ul->bits[m+1] = PetscCeilReal(PetscLog2Real(nv+1)); 8433 ++m; 8434 } 8435 for (l = 1; l <= ul->Nl; ++l) { 8436 ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l]; 8437 ul->bits[l] = ul->bits[l-1] + ul->bits[l]; 8438 } 8439 for (l = 0; l < ul->Nl; ++l) { 8440 PetscInt b; 8441 8442 ul->masks[l] = 0; 8443 for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b; 8444 } 8445 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 8446 for (l = 0, m = 0; l < Nl; ++l) { 8447 DMLabel label; 8448 IS valueIS; 8449 const PetscInt *varr; 8450 PetscInt nv, v; 8451 8452 if (!active[l]) continue; 8453 PetscCall(DMGetLabelByNum(dm, l, &label)); 8454 PetscCall(DMLabelGetNumValues(label, &nv)); 8455 PetscCall(DMLabelGetValueIS(label, &valueIS)); 8456 PetscCall(ISGetIndices(valueIS, &varr)); 8457 for (v = 0; v < nv; ++v) { 8458 ul->values[ul->offsets[m]+v] = varr[v]; 8459 } 8460 PetscCall(ISRestoreIndices(valueIS, &varr)); 8461 PetscCall(ISDestroy(&valueIS)); 8462 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 8463 ++m; 8464 } 8465 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 8466 for (p = pStart; p < pEnd; ++p) { 8467 PetscInt uval = 0; 8468 PetscBool marked = PETSC_FALSE; 8469 8470 for (l = 0, m = 0; l < Nl; ++l) { 8471 DMLabel label; 8472 PetscInt val, defval, loc, nv; 8473 8474 if (!active[l]) continue; 8475 PetscCall(DMGetLabelByNum(dm, l, &label)); 8476 PetscCall(DMLabelGetValue(label, p, &val)); 8477 PetscCall(DMLabelGetDefaultValue(label, &defval)); 8478 if (val == defval) {++m; continue;} 8479 nv = ul->offsets[m+1]-ul->offsets[m]; 8480 marked = PETSC_TRUE; 8481 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 8482 PetscCheck(loc >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val); 8483 uval += (loc+1) << ul->bits[m]; 8484 ++m; 8485 } 8486 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 8487 } 8488 PetscCall(PetscFree(active)); 8489 *universal = ul; 8490 PetscFunctionReturn(0); 8491 } 8492 8493 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 8494 { 8495 PetscInt l; 8496 8497 PetscFunctionBegin; 8498 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 8499 PetscCall(DMLabelDestroy(&(*universal)->label)); 8500 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 8501 PetscCall(PetscFree((*universal)->values)); 8502 PetscCall(PetscFree(*universal)); 8503 *universal = NULL; 8504 PetscFunctionReturn(0); 8505 } 8506 8507 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 8508 { 8509 PetscFunctionBegin; 8510 PetscValidPointer(ulabel, 2); 8511 *ulabel = ul->label; 8512 PetscFunctionReturn(0); 8513 } 8514 8515 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 8516 { 8517 PetscInt Nl = ul->Nl, l; 8518 8519 PetscFunctionBegin; 8520 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 8521 for (l = 0; l < Nl; ++l) { 8522 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 8523 else PetscCall(DMCreateLabel(dm, ul->names[l])); 8524 } 8525 if (preserveOrder) { 8526 for (l = 0; l < ul->Nl; ++l) { 8527 const char *name; 8528 PetscBool match; 8529 8530 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 8531 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 8532 PetscCheck(match,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]); 8533 } 8534 } 8535 PetscFunctionReturn(0); 8536 } 8537 8538 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 8539 { 8540 PetscInt l; 8541 8542 PetscFunctionBegin; 8543 for (l = 0; l < ul->Nl; ++l) { 8544 DMLabel label; 8545 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 8546 8547 if (lval) { 8548 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 8549 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 8550 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1])); 8551 } 8552 } 8553 PetscFunctionReturn(0); 8554 } 8555 8556 /*@ 8557 DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement 8558 8559 Input Parameter: 8560 . dm - The DM object 8561 8562 Output Parameter: 8563 . cdm - The coarse DM 8564 8565 Level: intermediate 8566 8567 .seealso: DMSetCoarseDM() 8568 @*/ 8569 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 8570 { 8571 PetscFunctionBegin; 8572 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8573 PetscValidPointer(cdm, 2); 8574 *cdm = dm->coarseMesh; 8575 PetscFunctionReturn(0); 8576 } 8577 8578 /*@ 8579 DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement 8580 8581 Input Parameters: 8582 + dm - The DM object 8583 - cdm - The coarse DM 8584 8585 Level: intermediate 8586 8587 .seealso: DMGetCoarseDM() 8588 @*/ 8589 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 8590 { 8591 PetscFunctionBegin; 8592 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8593 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 8594 PetscCall(PetscObjectReference((PetscObject)cdm)); 8595 PetscCall(DMDestroy(&dm->coarseMesh)); 8596 dm->coarseMesh = cdm; 8597 PetscFunctionReturn(0); 8598 } 8599 8600 /*@ 8601 DMGetFineDM - Get the fine mesh from which this was obtained by refinement 8602 8603 Input Parameter: 8604 . dm - The DM object 8605 8606 Output Parameter: 8607 . fdm - The fine DM 8608 8609 Level: intermediate 8610 8611 .seealso: DMSetFineDM() 8612 @*/ 8613 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 8614 { 8615 PetscFunctionBegin; 8616 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8617 PetscValidPointer(fdm, 2); 8618 *fdm = dm->fineMesh; 8619 PetscFunctionReturn(0); 8620 } 8621 8622 /*@ 8623 DMSetFineDM - Set the fine mesh from which this was obtained by refinement 8624 8625 Input Parameters: 8626 + dm - The DM object 8627 - fdm - The fine DM 8628 8629 Level: intermediate 8630 8631 .seealso: DMGetFineDM() 8632 @*/ 8633 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 8634 { 8635 PetscFunctionBegin; 8636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8637 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 8638 PetscCall(PetscObjectReference((PetscObject)fdm)); 8639 PetscCall(DMDestroy(&dm->fineMesh)); 8640 dm->fineMesh = fdm; 8641 PetscFunctionReturn(0); 8642 } 8643 8644 /*=== DMBoundary code ===*/ 8645 8646 /*@C 8647 DMAddBoundary - Add a boundary condition to the model 8648 8649 Collective on dm 8650 8651 Input Parameters: 8652 + dm - The DM, with a PetscDS that matches the problem being constrained 8653 . type - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann) 8654 . name - The BC name 8655 . label - The label defining constrained points 8656 . Nv - The number of DMLabel values for constrained points 8657 . values - An array of values for constrained points 8658 . field - The field to constrain 8659 . Nc - The number of constrained field components (0 will constrain all fields) 8660 . comps - An array of constrained component numbers 8661 . bcFunc - A pointwise function giving boundary values 8662 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 8663 - ctx - An optional user context for bcFunc 8664 8665 Output Parameter: 8666 . bd - (Optional) Boundary number 8667 8668 Options Database Keys: 8669 + -bc_<boundary name> <num> - Overrides the boundary ids 8670 - -bc_<boundary name>_comp <num> - Overrides the boundary components 8671 8672 Note: 8673 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is: 8674 8675 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 8676 8677 If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is: 8678 8679 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8680 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8681 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8682 $ PetscReal time, const PetscReal x[], PetscScalar bcval[]) 8683 8684 + dim - the spatial dimension 8685 . Nf - the number of fields 8686 . uOff - the offset into u[] and u_t[] for each field 8687 . uOff_x - the offset into u_x[] for each field 8688 . u - each field evaluated at the current point 8689 . u_t - the time derivative of each field evaluated at the current point 8690 . u_x - the gradient of each field evaluated at the current point 8691 . aOff - the offset into a[] and a_t[] for each auxiliary field 8692 . aOff_x - the offset into a_x[] for each auxiliary field 8693 . a - each auxiliary field evaluated at the current point 8694 . a_t - the time derivative of each auxiliary field evaluated at the current point 8695 . a_x - the gradient of auxiliary each field evaluated at the current point 8696 . t - current time 8697 . x - coordinates of the current point 8698 . numConstants - number of constant parameters 8699 . constants - constant parameters 8700 - bcval - output values at the current point 8701 8702 Level: intermediate 8703 8704 .seealso: DSGetBoundary(), PetscDSAddBoundary() 8705 @*/ 8706 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) 8707 { 8708 PetscDS ds; 8709 8710 PetscFunctionBegin; 8711 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8712 PetscValidLogicalCollectiveEnum(dm, type, 2); 8713 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 8714 PetscValidLogicalCollectiveInt(dm, Nv, 5); 8715 PetscValidLogicalCollectiveInt(dm, field, 7); 8716 PetscValidLogicalCollectiveInt(dm, Nc, 8); 8717 PetscCall(DMGetDS(dm, &ds)); 8718 PetscCall(DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, label)); 8719 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 8720 PetscFunctionReturn(0); 8721 } 8722 8723 /* TODO Remove this since now the structures are the same */ 8724 static PetscErrorCode DMPopulateBoundary(DM dm) 8725 { 8726 PetscDS ds; 8727 DMBoundary *lastnext; 8728 DSBoundary dsbound; 8729 8730 PetscFunctionBegin; 8731 PetscCall(DMGetDS(dm, &ds)); 8732 dsbound = ds->boundary; 8733 if (dm->boundary) { 8734 DMBoundary next = dm->boundary; 8735 8736 /* quick check to see if the PetscDS has changed */ 8737 if (next->dsboundary == dsbound) PetscFunctionReturn(0); 8738 /* the PetscDS has changed: tear down and rebuild */ 8739 while (next) { 8740 DMBoundary b = next; 8741 8742 next = b->next; 8743 PetscCall(PetscFree(b)); 8744 } 8745 dm->boundary = NULL; 8746 } 8747 8748 lastnext = &(dm->boundary); 8749 while (dsbound) { 8750 DMBoundary dmbound; 8751 8752 PetscCall(PetscNew(&dmbound)); 8753 dmbound->dsboundary = dsbound; 8754 dmbound->label = dsbound->label; 8755 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8756 *lastnext = dmbound; 8757 lastnext = &(dmbound->next); 8758 dsbound = dsbound->next; 8759 } 8760 PetscFunctionReturn(0); 8761 } 8762 8763 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8764 { 8765 DMBoundary b; 8766 8767 PetscFunctionBegin; 8768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8769 PetscValidBoolPointer(isBd, 3); 8770 *isBd = PETSC_FALSE; 8771 PetscCall(DMPopulateBoundary(dm)); 8772 b = dm->boundary; 8773 while (b && !(*isBd)) { 8774 DMLabel label = b->label; 8775 DSBoundary dsb = b->dsboundary; 8776 PetscInt i; 8777 8778 if (label) { 8779 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8780 } 8781 b = b->next; 8782 } 8783 PetscFunctionReturn(0); 8784 } 8785 8786 /*@C 8787 DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector. 8788 8789 Collective on DM 8790 8791 Input Parameters: 8792 + dm - The DM 8793 . time - The time 8794 . funcs - The coordinate functions to evaluate, one per field 8795 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8796 - mode - The insertion mode for values 8797 8798 Output Parameter: 8799 . X - vector 8800 8801 Calling sequence of func: 8802 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8803 8804 + dim - The spatial dimension 8805 . time - The time at which to sample 8806 . x - The coordinates 8807 . Nc - The number of components 8808 . u - The output field values 8809 - ctx - optional user-defined function context 8810 8811 Level: developer 8812 8813 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff() 8814 @*/ 8815 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X) 8816 { 8817 Vec localX; 8818 8819 PetscFunctionBegin; 8820 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8821 PetscCall(DMGetLocalVector(dm, &localX)); 8822 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8823 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8824 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8825 PetscCall(DMRestoreLocalVector(dm, &localX)); 8826 PetscFunctionReturn(0); 8827 } 8828 8829 /*@C 8830 DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector. 8831 8832 Not collective 8833 8834 Input Parameters: 8835 + dm - The DM 8836 . time - The time 8837 . funcs - The coordinate functions to evaluate, one per field 8838 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8839 - mode - The insertion mode for values 8840 8841 Output Parameter: 8842 . localX - vector 8843 8844 Calling sequence of func: 8845 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8846 8847 + dim - The spatial dimension 8848 . x - The coordinates 8849 . Nc - The number of components 8850 . u - The output field values 8851 - ctx - optional user-defined function context 8852 8853 Level: developer 8854 8855 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff() 8856 @*/ 8857 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 8858 { 8859 PetscFunctionBegin; 8860 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 8861 PetscValidHeaderSpecific(localX,VEC_CLASSID,6); 8862 PetscCheck(dm->ops->projectfunctionlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name); 8863 PetscCall((dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX)); 8864 PetscFunctionReturn(0); 8865 } 8866 8867 /*@C 8868 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. 8869 8870 Collective on DM 8871 8872 Input Parameters: 8873 + dm - The DM 8874 . time - The time 8875 . label - The DMLabel selecting the portion of the mesh for projection 8876 . funcs - The coordinate functions to evaluate, one per field 8877 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8878 - mode - The insertion mode for values 8879 8880 Output Parameter: 8881 . X - vector 8882 8883 Calling sequence of func: 8884 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8885 8886 + dim - The spatial dimension 8887 . x - The coordinates 8888 . Nc - The number of components 8889 . u - The output field values 8890 - ctx - optional user-defined function context 8891 8892 Level: developer 8893 8894 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff() 8895 @*/ 8896 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) 8897 { 8898 Vec localX; 8899 8900 PetscFunctionBegin; 8901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8902 PetscCall(DMGetLocalVector(dm, &localX)); 8903 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8904 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8905 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8906 PetscCall(DMRestoreLocalVector(dm, &localX)); 8907 PetscFunctionReturn(0); 8908 } 8909 8910 /*@C 8911 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. 8912 8913 Not collective 8914 8915 Input Parameters: 8916 + dm - The DM 8917 . time - The time 8918 . label - The DMLabel selecting the portion of the mesh for projection 8919 . funcs - The coordinate functions to evaluate, one per field 8920 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8921 - mode - The insertion mode for values 8922 8923 Output Parameter: 8924 . localX - vector 8925 8926 Calling sequence of func: 8927 $ func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx); 8928 8929 + dim - The spatial dimension 8930 . x - The coordinates 8931 . Nc - The number of components 8932 . u - The output field values 8933 - ctx - optional user-defined function context 8934 8935 Level: developer 8936 8937 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff() 8938 @*/ 8939 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) 8940 { 8941 PetscFunctionBegin; 8942 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 8943 PetscValidHeaderSpecific(localX,VEC_CLASSID,11); 8944 PetscCheck(dm->ops->projectfunctionlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name); 8945 PetscCall((dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8946 PetscFunctionReturn(0); 8947 } 8948 8949 /*@C 8950 DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector. 8951 8952 Not collective 8953 8954 Input Parameters: 8955 + dm - The DM 8956 . time - The time 8957 . localU - The input field vector 8958 . funcs - The functions to evaluate, one per field 8959 - mode - The insertion mode for values 8960 8961 Output Parameter: 8962 . localX - The output vector 8963 8964 Calling sequence of func: 8965 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8966 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 8967 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 8968 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 8969 8970 + dim - The spatial dimension 8971 . Nf - The number of input fields 8972 . NfAux - The number of input auxiliary fields 8973 . uOff - The offset of each field in u[] 8974 . uOff_x - The offset of each field in u_x[] 8975 . u - The field values at this point in space 8976 . u_t - The field time derivative at this point in space (or NULL) 8977 . u_x - The field derivatives at this point in space 8978 . aOff - The offset of each auxiliary field in u[] 8979 . aOff_x - The offset of each auxiliary field in u_x[] 8980 . a - The auxiliary field values at this point in space 8981 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8982 . a_x - The auxiliary field derivatives at this point in space 8983 . t - The current time 8984 . x - The coordinates of this point 8985 . numConstants - The number of constants 8986 . constants - The value of each constant 8987 - f - The value of the function at this point in space 8988 8989 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. 8990 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 8991 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the 8992 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8993 8994 Level: intermediate 8995 8996 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff() 8997 @*/ 8998 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, 8999 void (**funcs)(PetscInt, PetscInt, PetscInt, 9000 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9001 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9002 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 9003 InsertMode mode, Vec localX) 9004 { 9005 PetscFunctionBegin; 9006 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9007 PetscValidHeaderSpecific(localU,VEC_CLASSID,3); 9008 PetscValidHeaderSpecific(localX,VEC_CLASSID,6); 9009 PetscCheck(dm->ops->projectfieldlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name); 9010 PetscCall((dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX)); 9011 PetscFunctionReturn(0); 9012 } 9013 9014 /*@C 9015 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. 9016 9017 Not collective 9018 9019 Input Parameters: 9020 + dm - The DM 9021 . time - The time 9022 . label - The DMLabel marking the portion of the domain to output 9023 . numIds - The number of label ids to use 9024 . ids - The label ids to use for marking 9025 . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components 9026 . comps - The components to set in the output, or NULL for all components 9027 . localU - The input field vector 9028 . funcs - The functions to evaluate, one per field 9029 - mode - The insertion mode for values 9030 9031 Output Parameter: 9032 . localX - The output vector 9033 9034 Calling sequence of func: 9035 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9036 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9037 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9038 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 9039 9040 + dim - The spatial dimension 9041 . Nf - The number of input fields 9042 . NfAux - The number of input auxiliary fields 9043 . uOff - The offset of each field in u[] 9044 . uOff_x - The offset of each field in u_x[] 9045 . u - The field values at this point in space 9046 . u_t - The field time derivative at this point in space (or NULL) 9047 . u_x - The field derivatives at this point in space 9048 . aOff - The offset of each auxiliary field in u[] 9049 . aOff_x - The offset of each auxiliary field in u_x[] 9050 . a - The auxiliary field values at this point in space 9051 . a_t - The auxiliary field time derivative at this point in space (or NULL) 9052 . a_x - The auxiliary field derivatives at this point in space 9053 . t - The current time 9054 . x - The coordinates of this point 9055 . numConstants - The number of constants 9056 . constants - The value of each constant 9057 - f - The value of the function at this point in space 9058 9059 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. 9060 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 9061 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the 9062 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 9063 9064 Level: intermediate 9065 9066 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff() 9067 @*/ 9068 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, 9069 void (**funcs)(PetscInt, PetscInt, PetscInt, 9070 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9071 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9072 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 9073 InsertMode mode, Vec localX) 9074 { 9075 PetscFunctionBegin; 9076 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9077 PetscValidHeaderSpecific(localU,VEC_CLASSID,8); 9078 PetscValidHeaderSpecific(localX,VEC_CLASSID,11); 9079 PetscCheck(dm->ops->projectfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name); 9080 PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 9081 PetscFunctionReturn(0); 9082 } 9083 9084 /*@C 9085 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. 9086 9087 Not collective 9088 9089 Input Parameters: 9090 + dm - The DM 9091 . time - The time 9092 . label - The DMLabel marking the portion of the domain boundary to output 9093 . numIds - The number of label ids to use 9094 . ids - The label ids to use for marking 9095 . Nc - The number of components to set in the output, or PETSC_DETERMINE for all components 9096 . comps - The components to set in the output, or NULL for all components 9097 . localU - The input field vector 9098 . funcs - The functions to evaluate, one per field 9099 - mode - The insertion mode for values 9100 9101 Output Parameter: 9102 . localX - The output vector 9103 9104 Calling sequence of func: 9105 $ func(PetscInt dim, PetscInt Nf, PetscInt NfAux, 9106 $ const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9107 $ const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 9108 $ PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]); 9109 9110 + dim - The spatial dimension 9111 . Nf - The number of input fields 9112 . NfAux - The number of input auxiliary fields 9113 . uOff - The offset of each field in u[] 9114 . uOff_x - The offset of each field in u_x[] 9115 . u - The field values at this point in space 9116 . u_t - The field time derivative at this point in space (or NULL) 9117 . u_x - The field derivatives at this point in space 9118 . aOff - The offset of each auxiliary field in u[] 9119 . aOff_x - The offset of each auxiliary field in u_x[] 9120 . a - The auxiliary field values at this point in space 9121 . a_t - The auxiliary field time derivative at this point in space (or NULL) 9122 . a_x - The auxiliary field derivatives at this point in space 9123 . t - The current time 9124 . x - The coordinates of this point 9125 . n - The face normal 9126 . numConstants - The number of constants 9127 . constants - The value of each constant 9128 - f - The value of the function at this point in space 9129 9130 Note: 9131 There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs. 9132 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 9133 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the 9134 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 9135 9136 Level: intermediate 9137 9138 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff() 9139 @*/ 9140 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, 9141 void (**funcs)(PetscInt, PetscInt, PetscInt, 9142 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9143 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 9144 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 9145 InsertMode mode, Vec localX) 9146 { 9147 PetscFunctionBegin; 9148 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9149 PetscValidHeaderSpecific(localU,VEC_CLASSID,8); 9150 PetscValidHeaderSpecific(localX,VEC_CLASSID,11); 9151 PetscCheck(dm->ops->projectbdfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name); 9152 PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 9153 PetscFunctionReturn(0); 9154 } 9155 9156 /*@C 9157 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 9158 9159 Input Parameters: 9160 + dm - The DM 9161 . time - The time 9162 . funcs - The functions to evaluate for each field component 9163 . ctxs - Optional array of contexts to pass to each function, or NULL. 9164 - X - The coefficient vector u_h, a global vector 9165 9166 Output Parameter: 9167 . diff - The diff ||u - u_h||_2 9168 9169 Level: developer 9170 9171 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff() 9172 @*/ 9173 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 9174 { 9175 PetscFunctionBegin; 9176 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9177 PetscValidHeaderSpecific(X,VEC_CLASSID,5); 9178 PetscCheck(dm->ops->computel2diff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name); 9179 PetscCall((dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff)); 9180 PetscFunctionReturn(0); 9181 } 9182 9183 /*@C 9184 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 9185 9186 Collective on dm 9187 9188 Input Parameters: 9189 + dm - The DM 9190 , time - The time 9191 . funcs - The gradient functions to evaluate for each field component 9192 . ctxs - Optional array of contexts to pass to each function, or NULL. 9193 . X - The coefficient vector u_h, a global vector 9194 - n - The vector to project along 9195 9196 Output Parameter: 9197 . diff - The diff ||(grad u - grad u_h) . n||_2 9198 9199 Level: developer 9200 9201 .seealso: DMProjectFunction(), DMComputeL2Diff() 9202 @*/ 9203 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) 9204 { 9205 PetscFunctionBegin; 9206 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9207 PetscValidHeaderSpecific(X,VEC_CLASSID,5); 9208 PetscCheck(dm->ops->computel2gradientdiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name); 9209 PetscCall((dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff)); 9210 PetscFunctionReturn(0); 9211 } 9212 9213 /*@C 9214 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 9215 9216 Collective on dm 9217 9218 Input Parameters: 9219 + dm - The DM 9220 . time - The time 9221 . funcs - The functions to evaluate for each field component 9222 . ctxs - Optional array of contexts to pass to each function, or NULL. 9223 - X - The coefficient vector u_h, a global vector 9224 9225 Output Parameter: 9226 . diff - The array of differences, ||u^f - u^f_h||_2 9227 9228 Level: developer 9229 9230 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff() 9231 @*/ 9232 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 9233 { 9234 PetscFunctionBegin; 9235 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9236 PetscValidHeaderSpecific(X,VEC_CLASSID,5); 9237 PetscCheck(dm->ops->computel2fielddiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name); 9238 PetscCall((dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff)); 9239 PetscFunctionReturn(0); 9240 } 9241 9242 /*@C 9243 DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors 9244 9245 Not Collective 9246 9247 Input Parameter: 9248 . dm - The DM 9249 9250 Output Parameters: 9251 + nranks - the number of neighbours 9252 - ranks - the neighbors ranks 9253 9254 Notes: 9255 Do not free the array, it is freed when the DM is destroyed. 9256 9257 Level: beginner 9258 9259 .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks() 9260 @*/ 9261 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[]) 9262 { 9263 PetscFunctionBegin; 9264 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 9265 PetscCheck(dm->ops->getneighbors,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name); 9266 PetscCall((dm->ops->getneighbors)(dm,nranks,ranks)); 9267 PetscFunctionReturn(0); 9268 } 9269 9270 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 9271 9272 /* 9273 Converts the input vector to a ghosted vector and then calls the standard coloring code. 9274 This has be a different function because it requires DM which is not defined in the Mat library 9275 */ 9276 PetscErrorCode MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx) 9277 { 9278 PetscFunctionBegin; 9279 if (coloring->ctype == IS_COLORING_LOCAL) { 9280 Vec x1local; 9281 DM dm; 9282 PetscCall(MatGetDM(J,&dm)); 9283 PetscCheck(dm,PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM"); 9284 PetscCall(DMGetLocalVector(dm,&x1local)); 9285 PetscCall(DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local)); 9286 PetscCall(DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local)); 9287 x1 = x1local; 9288 } 9289 PetscCall(MatFDColoringApply_AIJ(J,coloring,x1,sctx)); 9290 if (coloring->ctype == IS_COLORING_LOCAL) { 9291 DM dm; 9292 PetscCall(MatGetDM(J,&dm)); 9293 PetscCall(DMRestoreLocalVector(dm,&x1)); 9294 } 9295 PetscFunctionReturn(0); 9296 } 9297 9298 /*@ 9299 MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring 9300 9301 Input Parameter: 9302 . coloring - the MatFDColoring object 9303 9304 Developer Notes: 9305 this routine exists because the PETSc Mat library does not know about the DM objects 9306 9307 Level: advanced 9308 9309 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType 9310 @*/ 9311 PetscErrorCode MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring) 9312 { 9313 PetscFunctionBegin; 9314 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 9315 PetscFunctionReturn(0); 9316 } 9317 9318 /*@ 9319 DMGetCompatibility - determine if two DMs are compatible 9320 9321 Collective 9322 9323 Input Parameters: 9324 + dm1 - the first DM 9325 - dm2 - the second DM 9326 9327 Output Parameters: 9328 + compatible - whether or not the two DMs are compatible 9329 - set - whether or not the compatible value was set 9330 9331 Notes: 9332 Two DMs are deemed compatible if they represent the same parallel decomposition 9333 of the same topology. This implies that the section (field data) on one 9334 "makes sense" with respect to the topology and parallel decomposition of the other. 9335 Loosely speaking, compatible DMs represent the same domain and parallel 9336 decomposition, but hold different data. 9337 9338 Typically, one would confirm compatibility if intending to simultaneously iterate 9339 over a pair of vectors obtained from different DMs. 9340 9341 For example, two DMDA objects are compatible if they have the same local 9342 and global sizes and the same stencil width. They can have different numbers 9343 of degrees of freedom per node. Thus, one could use the node numbering from 9344 either DM in bounds for a loop over vectors derived from either DM. 9345 9346 Consider the operation of summing data living on a 2-dof DMDA to data living 9347 on a 1-dof DMDA, which should be compatible, as in the following snippet. 9348 .vb 9349 ... 9350 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 9351 if (set && compatible) { 9352 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 9353 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 9354 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 9355 for (j=y; j<y+n; ++j) { 9356 for (i=x; i<x+m, ++i) { 9357 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 9358 } 9359 } 9360 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 9361 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 9362 } else { 9363 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 9364 } 9365 ... 9366 .ve 9367 9368 Checking compatibility might be expensive for a given implementation of DM, 9369 or might be impossible to unambiguously confirm or deny. For this reason, 9370 this function may decline to determine compatibility, and hence users should 9371 always check the "set" output parameter. 9372 9373 A DM is always compatible with itself. 9374 9375 In the current implementation, DMs which live on "unequal" communicators 9376 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 9377 incompatible. 9378 9379 This function is labeled "Collective," as information about all subdomains 9380 is required on each rank. However, in DM implementations which store all this 9381 information locally, this function may be merely "Logically Collective". 9382 9383 Developer Notes: 9384 Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B 9385 iff B is compatible with A. Thus, this function checks the implementations 9386 of both dm and dmc (if they are of different types), attempting to determine 9387 compatibility. It is left to DM implementers to ensure that symmetry is 9388 preserved. The simplest way to do this is, when implementing type-specific 9389 logic for this function, is to check for existing logic in the implementation 9390 of other DM types and let *set = PETSC_FALSE if found. 9391 9392 Level: advanced 9393 9394 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag() 9395 @*/ 9396 9397 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set) 9398 { 9399 PetscMPIInt compareResult; 9400 DMType type,type2; 9401 PetscBool sameType; 9402 9403 PetscFunctionBegin; 9404 PetscValidHeaderSpecific(dm1,DM_CLASSID,1); 9405 PetscValidHeaderSpecific(dm2,DM_CLASSID,2); 9406 9407 /* Declare a DM compatible with itself */ 9408 if (dm1 == dm2) { 9409 *set = PETSC_TRUE; 9410 *compatible = PETSC_TRUE; 9411 PetscFunctionReturn(0); 9412 } 9413 9414 /* Declare a DM incompatible with a DM that lives on an "unequal" 9415 communicator. Note that this does not preclude compatibility with 9416 DMs living on "congruent" or "similar" communicators, but this must be 9417 determined by the implementation-specific logic */ 9418 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult)); 9419 if (compareResult == MPI_UNEQUAL) { 9420 *set = PETSC_TRUE; 9421 *compatible = PETSC_FALSE; 9422 PetscFunctionReturn(0); 9423 } 9424 9425 /* Pass to the implementation-specific routine, if one exists. */ 9426 if (dm1->ops->getcompatibility) { 9427 PetscCall((*dm1->ops->getcompatibility)(dm1,dm2,compatible,set)); 9428 if (*set) PetscFunctionReturn(0); 9429 } 9430 9431 /* If dm1 and dm2 are of different types, then attempt to check compatibility 9432 with an implementation of this function from dm2 */ 9433 PetscCall(DMGetType(dm1,&type)); 9434 PetscCall(DMGetType(dm2,&type2)); 9435 PetscCall(PetscStrcmp(type,type2,&sameType)); 9436 if (!sameType && dm2->ops->getcompatibility) { 9437 PetscCall((*dm2->ops->getcompatibility)(dm2,dm1,compatible,set)); /* Note argument order */ 9438 } else { 9439 *set = PETSC_FALSE; 9440 } 9441 PetscFunctionReturn(0); 9442 } 9443 9444 /*@C 9445 DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance. 9446 9447 Logically Collective on DM 9448 9449 Input Parameters: 9450 + DM - the DM 9451 . f - the monitor function 9452 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired) 9453 - monitordestroy - [optional] routine that frees monitor context (may be NULL) 9454 9455 Options Database Keys: 9456 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but 9457 does not cancel those set via the options database. 9458 9459 Notes: 9460 Several different monitoring routines may be set by calling 9461 DMMonitorSet() multiple times; all will be called in the 9462 order in which they were set. 9463 9464 Fortran Notes: 9465 Only a single monitor function can be set for each DM object 9466 9467 Level: intermediate 9468 9469 .seealso: DMMonitorCancel() 9470 @*/ 9471 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**)) 9472 { 9473 PetscInt m; 9474 9475 PetscFunctionBegin; 9476 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9477 for (m = 0; m < dm->numbermonitors; ++m) { 9478 PetscBool identical; 9479 9480 PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 9481 if (identical) PetscFunctionReturn(0); 9482 } 9483 PetscCheck(dm->numbermonitors < MAXDMMONITORS,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 9484 dm->monitor[dm->numbermonitors] = f; 9485 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 9486 dm->monitorcontext[dm->numbermonitors++] = (void *) mctx; 9487 PetscFunctionReturn(0); 9488 } 9489 9490 /*@ 9491 DMMonitorCancel - Clears all the monitor functions for a DM object. 9492 9493 Logically Collective on DM 9494 9495 Input Parameter: 9496 . dm - the DM 9497 9498 Options Database Key: 9499 . -dm_monitor_cancel - cancels all monitors that have been hardwired 9500 into a code by calls to DMonitorSet(), but does not cancel those 9501 set via the options database 9502 9503 Notes: 9504 There is no way to clear one specific monitor from a DM object. 9505 9506 Level: intermediate 9507 9508 .seealso: DMMonitorSet() 9509 @*/ 9510 PetscErrorCode DMMonitorCancel(DM dm) 9511 { 9512 PetscInt m; 9513 9514 PetscFunctionBegin; 9515 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9516 for (m = 0; m < dm->numbermonitors; ++m) { 9517 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 9518 } 9519 dm->numbermonitors = 0; 9520 PetscFunctionReturn(0); 9521 } 9522 9523 /*@C 9524 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 9525 9526 Collective on DM 9527 9528 Input Parameters: 9529 + dm - DM object you wish to monitor 9530 . name - the monitor type one is seeking 9531 . help - message indicating what monitoring is done 9532 . manual - manual page for the monitor 9533 . monitor - the monitor function 9534 - 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 9535 9536 Output Parameter: 9537 . flg - Flag set if the monitor was created 9538 9539 Level: developer 9540 9541 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(), 9542 PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool() 9543 PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(), 9544 PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(), 9545 PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(), 9546 PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(), 9547 PetscOptionsFList(), PetscOptionsEList() 9548 @*/ 9549 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 9550 { 9551 PetscViewer viewer; 9552 PetscViewerFormat format; 9553 9554 PetscFunctionBegin; 9555 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9556 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg)); 9557 if (*flg) { 9558 PetscViewerAndFormat *vf; 9559 9560 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 9561 PetscCall(PetscObjectDereference((PetscObject) viewer)); 9562 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 9563 PetscCall(DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy)); 9564 } 9565 PetscFunctionReturn(0); 9566 } 9567 9568 /*@ 9569 DMMonitor - runs the user provided monitor routines, if they exist 9570 9571 Collective on DM 9572 9573 Input Parameters: 9574 . dm - The DM 9575 9576 Level: developer 9577 9578 .seealso: DMMonitorSet() 9579 @*/ 9580 PetscErrorCode DMMonitor(DM dm) 9581 { 9582 PetscInt m; 9583 9584 PetscFunctionBegin; 9585 if (!dm) PetscFunctionReturn(0); 9586 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9587 for (m = 0; m < dm->numbermonitors; ++m) { 9588 PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 9589 } 9590 PetscFunctionReturn(0); 9591 } 9592 9593 /*@ 9594 DMComputeError - Computes the error assuming the user has given exact solution functions 9595 9596 Collective on DM 9597 9598 Input Parameters: 9599 + dm - The DM 9600 - sol - The solution vector 9601 9602 Input/Output Parameter: 9603 . errors - An array of length Nf, the number of fields, or NULL for no output; on output 9604 contains the error in each field 9605 9606 Output Parameter: 9607 . errorVec - A vector to hold the cellwise error (may be NULL) 9608 9609 Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber(). 9610 9611 Level: developer 9612 9613 .seealso: DMMonitorSet(), DMGetRegionNumDS(), PetscDSGetExactSolution(), DMGetOutputSequenceNumber() 9614 @*/ 9615 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 9616 { 9617 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 9618 void **ctxs; 9619 PetscReal time; 9620 PetscInt Nf, f, Nds, s; 9621 9622 PetscFunctionBegin; 9623 PetscCall(DMGetNumFields(dm, &Nf)); 9624 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 9625 PetscCall(DMGetNumDS(dm, &Nds)); 9626 for (s = 0; s < Nds; ++s) { 9627 PetscDS ds; 9628 DMLabel label; 9629 IS fieldIS; 9630 const PetscInt *fields; 9631 PetscInt dsNf; 9632 9633 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 9634 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9635 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9636 for (f = 0; f < dsNf; ++f) { 9637 const PetscInt field = fields[f]; 9638 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9639 } 9640 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9641 } 9642 for (f = 0; f < Nf; ++f) { 9643 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); 9644 } 9645 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9646 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9647 if (errorVec) { 9648 DM edm; 9649 DMPolytopeType ct; 9650 PetscBool simplex; 9651 PetscInt dim, cStart, Nf; 9652 9653 PetscCall(DMClone(dm, &edm)); 9654 PetscCall(DMGetDimension(edm, &dim)); 9655 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9656 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9657 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 9658 PetscCall(DMGetNumFields(dm, &Nf)); 9659 for (f = 0; f < Nf; ++f) { 9660 PetscFE fe, efe; 9661 PetscQuadrature q; 9662 const char *name; 9663 9664 PetscCall(DMGetField(dm, f, NULL, (PetscObject *) &fe)); 9665 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9666 PetscCall(PetscObjectGetName((PetscObject) fe, &name)); 9667 PetscCall(PetscObjectSetName((PetscObject) efe, name)); 9668 PetscCall(PetscFEGetQuadrature(fe, &q)); 9669 PetscCall(PetscFESetQuadrature(efe, q)); 9670 PetscCall(DMSetField(edm, f, NULL, (PetscObject) efe)); 9671 PetscCall(PetscFEDestroy(&efe)); 9672 } 9673 PetscCall(DMCreateDS(edm)); 9674 9675 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9676 PetscCall(PetscObjectSetName((PetscObject) *errorVec, "Error")); 9677 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9678 PetscCall(DMDestroy(&edm)); 9679 } 9680 PetscCall(PetscFree2(exactSol, ctxs)); 9681 PetscFunctionReturn(0); 9682 } 9683 9684 /*@ 9685 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM 9686 9687 Not collective 9688 9689 Input Parameter: 9690 . dm - The DM 9691 9692 Output Parameter: 9693 . numAux - The number of auxiliary data vectors 9694 9695 Level: advanced 9696 9697 .seealso: DMGetAuxiliaryLabels(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec() 9698 @*/ 9699 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9700 { 9701 PetscFunctionBegin; 9702 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9703 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9704 PetscFunctionReturn(0); 9705 } 9706 9707 /*@ 9708 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9709 9710 Not collective 9711 9712 Input Parameters: 9713 + dm - The DM 9714 . label - The DMLabel 9715 . value - The label value indicating the region 9716 - part - The equation part, or 0 if unused 9717 9718 Output Parameter: 9719 . aux - The Vec holding auxiliary field data 9720 9721 Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9722 9723 Level: advanced 9724 9725 .seealso: DMSetAuxiliaryVec(), DMGetNumAuxiliaryVec() 9726 @*/ 9727 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9728 { 9729 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9730 PetscBool has; 9731 9732 PetscFunctionBegin; 9733 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9734 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9735 key.label = label; 9736 key.value = value; 9737 key.part = part; 9738 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9739 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9740 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9741 PetscFunctionReturn(0); 9742 } 9743 9744 /*@ 9745 DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value, and equation part 9746 9747 Not collective 9748 9749 Input Parameters: 9750 + dm - The DM 9751 . label - The DMLabel 9752 . value - The label value indicating the region 9753 . part - The equation part, or 0 if unused 9754 - aux - The Vec holding auxiliary field data 9755 9756 Level: advanced 9757 9758 .seealso: DMGetAuxiliaryVec() 9759 @*/ 9760 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9761 { 9762 Vec old; 9763 PetscHashAuxKey key; 9764 9765 PetscFunctionBegin; 9766 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9767 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9768 key.label = label; 9769 key.value = value; 9770 key.part = part; 9771 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9772 PetscCall(PetscObjectReference((PetscObject) aux)); 9773 PetscCall(PetscObjectDereference((PetscObject) old)); 9774 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9775 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9776 PetscFunctionReturn(0); 9777 } 9778 9779 /*@C 9780 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this DM 9781 9782 Not collective 9783 9784 Input Parameter: 9785 . dm - The DM 9786 9787 Output Parameters: 9788 + labels - The DMLabels for each Vec 9789 . values - The label values for each Vec 9790 - parts - The equation parts for each Vec 9791 9792 Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec(). 9793 9794 Level: advanced 9795 9796 .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec() 9797 @*/ 9798 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9799 { 9800 PetscHashAuxKey *keys; 9801 PetscInt n, i, off = 0; 9802 9803 PetscFunctionBegin; 9804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9805 PetscValidPointer(labels, 2); 9806 PetscValidIntPointer(values, 3); 9807 PetscValidIntPointer(parts, 4); 9808 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9809 PetscCall(PetscMalloc1(n, &keys)); 9810 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9811 for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value; parts[i] = keys[i].part;} 9812 PetscCall(PetscFree(keys)); 9813 PetscFunctionReturn(0); 9814 } 9815 9816 /*@ 9817 DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM 9818 9819 Not collective 9820 9821 Input Parameter: 9822 . dm - The DM 9823 9824 Output Parameter: 9825 . dmNew - The new DM, now with the same auxiliary data 9826 9827 Level: advanced 9828 9829 .seealso: DMGetNumAuxiliaryVec(), DMGetAuxiliaryVec(), DMSetAuxiliaryVec() 9830 @*/ 9831 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9832 { 9833 PetscFunctionBegin; 9834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9835 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9836 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9837 PetscFunctionReturn(0); 9838 } 9839 9840 /*@C 9841 DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement 9842 9843 Not collective 9844 9845 Input Parameters: 9846 + ct - The DMPolytopeType 9847 . sourceCone - The source arrangement of faces 9848 - targetCone - The target arrangement of faces 9849 9850 Output Parameters: 9851 + ornt - The orientation which will take the source arrangement to the target arrangement 9852 - found - Flag indicating that a suitable orientation was found 9853 9854 Level: advanced 9855 9856 .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchVertexOrientation() 9857 @*/ 9858 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9859 { 9860 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9861 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2; 9862 PetscInt o, c; 9863 9864 PetscFunctionBegin; 9865 if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);} 9866 for (o = -nO; o < nO; ++o) { 9867 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 9868 9869 for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break; 9870 if (c == cS) {*ornt = o; break;} 9871 } 9872 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9873 PetscFunctionReturn(0); 9874 } 9875 9876 /*@C 9877 DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement 9878 9879 Not collective 9880 9881 Input Parameters: 9882 + ct - The DMPolytopeType 9883 . sourceCone - The source arrangement of faces 9884 - targetCone - The target arrangement of faces 9885 9886 Output Parameters: 9887 . ornt - The orientation which will take the source arrangement to the target arrangement 9888 9889 Note: This function will fail if no suitable orientation can be found. 9890 9891 Level: advanced 9892 9893 .seealso: DMPolytopeMatchOrientation(), DMPolytopeGetVertexOrientation() 9894 @*/ 9895 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9896 { 9897 PetscBool found; 9898 9899 PetscFunctionBegin; 9900 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9901 PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9902 PetscFunctionReturn(0); 9903 } 9904 9905 /*@C 9906 DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement 9907 9908 Not collective 9909 9910 Input Parameters: 9911 + ct - The DMPolytopeType 9912 . sourceVert - The source arrangement of vertices 9913 - targetVert - The target arrangement of vertices 9914 9915 Output Parameters: 9916 + ornt - The orientation which will take the source arrangement to the target arrangement 9917 - found - Flag indicating that a suitable orientation was found 9918 9919 Level: advanced 9920 9921 .seealso: DMPolytopeGetOrientation(), DMPolytopeMatchOrientation() 9922 @*/ 9923 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9924 { 9925 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9926 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2; 9927 PetscInt o, c; 9928 9929 PetscFunctionBegin; 9930 if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);} 9931 for (o = -nO; o < nO; ++o) { 9932 const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o); 9933 9934 for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break; 9935 if (c == cS) {*ornt = o; break;} 9936 } 9937 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9938 PetscFunctionReturn(0); 9939 } 9940 9941 /*@C 9942 DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement 9943 9944 Not collective 9945 9946 Input Parameters: 9947 + ct - The DMPolytopeType 9948 . sourceCone - The source arrangement of vertices 9949 - targetCone - The target arrangement of vertices 9950 9951 Output Parameters: 9952 . ornt - The orientation which will take the source arrangement to the target arrangement 9953 9954 Note: This function will fail if no suitable orientation can be found. 9955 9956 Level: advanced 9957 9958 .seealso: DMPolytopeMatchVertexOrientation(), DMPolytopeGetOrientation() 9959 @*/ 9960 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9961 { 9962 PetscBool found; 9963 9964 PetscFunctionBegin; 9965 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9966 PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9967 PetscFunctionReturn(0); 9968 } 9969 9970 /*@C 9971 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9972 9973 Not collective 9974 9975 Input Parameters: 9976 + ct - The DMPolytopeType 9977 - point - Coordinates of the point 9978 9979 Output Parameters: 9980 . inside - Flag indicating whether the point is inside the reference cell of given type 9981 9982 Level: advanced 9983 9984 .seealso: DMLocatePoints() 9985 @*/ 9986 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9987 { 9988 PetscReal sum = 0.0; 9989 PetscInt d; 9990 9991 PetscFunctionBegin; 9992 *inside = PETSC_TRUE; 9993 switch (ct) { 9994 case DM_POLYTOPE_TRIANGLE: 9995 case DM_POLYTOPE_TETRAHEDRON: 9996 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9997 if (point[d] < -1.0) {*inside = PETSC_FALSE; break;} 9998 sum += point[d]; 9999 } 10000 if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;} 10001 break; 10002 case DM_POLYTOPE_QUADRILATERAL: 10003 case DM_POLYTOPE_HEXAHEDRON: 10004 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 10005 if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;} 10006 break; 10007 default: 10008 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 10009 } 10010 PetscFunctionReturn(0); 10011 } 10012