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