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