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