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