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