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