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