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