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