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