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