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