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