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