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