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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 /*@C 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 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7552 @*/ 7553 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 7554 { 7555 PetscInt n, i; 7556 char msg[PETSC_MAX_PATH_LEN] = ""; 7557 PetscBool eq; 7558 MPI_Comm comm; 7559 PetscMPIInt rank; 7560 7561 PetscFunctionBegin; 7562 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7563 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7564 PetscCheckSameComm(dm0, 1, dm1, 2); 7565 if (equal) PetscAssertPointer(equal, 3); 7566 if (message) PetscAssertPointer(message, 4); 7567 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7568 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7569 { 7570 PetscInt n1; 7571 7572 PetscCall(DMGetNumLabels(dm0, &n)); 7573 PetscCall(DMGetNumLabels(dm1, &n1)); 7574 eq = (PetscBool)(n == n1); 7575 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7576 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7577 if (!eq) goto finish; 7578 } 7579 for (i = 0; i < n; i++) { 7580 DMLabel l0, l1; 7581 const char *name; 7582 char *msgInner; 7583 7584 /* Ignore label order */ 7585 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7586 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7587 PetscCall(DMGetLabel(dm1, name, &l1)); 7588 if (!l1) { 7589 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7590 eq = PETSC_FALSE; 7591 break; 7592 } 7593 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7594 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7595 PetscCall(PetscFree(msgInner)); 7596 if (!eq) break; 7597 } 7598 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7599 finish: 7600 /* If message output arg not set, print to stderr */ 7601 if (message) { 7602 *message = NULL; 7603 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7604 } else { 7605 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7606 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7607 } 7608 /* If same output arg not ser and labels are not equal, throw error */ 7609 if (equal) *equal = eq; 7610 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7611 PetscFunctionReturn(PETSC_SUCCESS); 7612 } 7613 7614 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7615 { 7616 PetscFunctionBegin; 7617 PetscAssertPointer(label, 2); 7618 if (!*label) { 7619 PetscCall(DMCreateLabel(dm, name)); 7620 PetscCall(DMGetLabel(dm, name, label)); 7621 } 7622 PetscCall(DMLabelSetValue(*label, point, value)); 7623 PetscFunctionReturn(PETSC_SUCCESS); 7624 } 7625 7626 /* 7627 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7628 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7629 (label, id) pair in the DM. 7630 7631 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7632 each label. 7633 */ 7634 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7635 { 7636 DMUniversalLabel ul; 7637 PetscBool *active; 7638 PetscInt pStart, pEnd, p, Nl, l, m; 7639 7640 PetscFunctionBegin; 7641 PetscCall(PetscMalloc1(1, &ul)); 7642 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7643 PetscCall(DMGetNumLabels(dm, &Nl)); 7644 PetscCall(PetscCalloc1(Nl, &active)); 7645 ul->Nl = 0; 7646 for (l = 0; l < Nl; ++l) { 7647 PetscBool isdepth, iscelltype; 7648 const char *name; 7649 7650 PetscCall(DMGetLabelName(dm, l, &name)); 7651 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7652 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7653 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7654 if (active[l]) ++ul->Nl; 7655 } 7656 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7657 ul->Nv = 0; 7658 for (l = 0, m = 0; l < Nl; ++l) { 7659 DMLabel label; 7660 PetscInt nv; 7661 const char *name; 7662 7663 if (!active[l]) continue; 7664 PetscCall(DMGetLabelName(dm, l, &name)); 7665 PetscCall(DMGetLabelByNum(dm, l, &label)); 7666 PetscCall(DMLabelGetNumValues(label, &nv)); 7667 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7668 ul->indices[m] = l; 7669 ul->Nv += nv; 7670 ul->offsets[m + 1] = nv; 7671 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7672 ++m; 7673 } 7674 for (l = 1; l <= ul->Nl; ++l) { 7675 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7676 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7677 } 7678 for (l = 0; l < ul->Nl; ++l) { 7679 PetscInt b; 7680 7681 ul->masks[l] = 0; 7682 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7683 } 7684 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7685 for (l = 0, m = 0; l < Nl; ++l) { 7686 DMLabel label; 7687 IS valueIS; 7688 const PetscInt *varr; 7689 PetscInt nv, v; 7690 7691 if (!active[l]) continue; 7692 PetscCall(DMGetLabelByNum(dm, l, &label)); 7693 PetscCall(DMLabelGetNumValues(label, &nv)); 7694 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7695 PetscCall(ISGetIndices(valueIS, &varr)); 7696 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7697 PetscCall(ISRestoreIndices(valueIS, &varr)); 7698 PetscCall(ISDestroy(&valueIS)); 7699 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7700 ++m; 7701 } 7702 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7703 for (p = pStart; p < pEnd; ++p) { 7704 PetscInt uval = 0; 7705 PetscBool marked = PETSC_FALSE; 7706 7707 for (l = 0, m = 0; l < Nl; ++l) { 7708 DMLabel label; 7709 PetscInt val, defval, loc, nv; 7710 7711 if (!active[l]) continue; 7712 PetscCall(DMGetLabelByNum(dm, l, &label)); 7713 PetscCall(DMLabelGetValue(label, p, &val)); 7714 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7715 if (val == defval) { 7716 ++m; 7717 continue; 7718 } 7719 nv = ul->offsets[m + 1] - ul->offsets[m]; 7720 marked = PETSC_TRUE; 7721 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7722 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7723 uval += (loc + 1) << ul->bits[m]; 7724 ++m; 7725 } 7726 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7727 } 7728 PetscCall(PetscFree(active)); 7729 *universal = ul; 7730 PetscFunctionReturn(PETSC_SUCCESS); 7731 } 7732 7733 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7734 { 7735 PetscInt l; 7736 7737 PetscFunctionBegin; 7738 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7739 PetscCall(DMLabelDestroy(&(*universal)->label)); 7740 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7741 PetscCall(PetscFree((*universal)->values)); 7742 PetscCall(PetscFree(*universal)); 7743 *universal = NULL; 7744 PetscFunctionReturn(PETSC_SUCCESS); 7745 } 7746 7747 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7748 { 7749 PetscFunctionBegin; 7750 PetscAssertPointer(ulabel, 2); 7751 *ulabel = ul->label; 7752 PetscFunctionReturn(PETSC_SUCCESS); 7753 } 7754 7755 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7756 { 7757 PetscInt Nl = ul->Nl, l; 7758 7759 PetscFunctionBegin; 7760 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7761 for (l = 0; l < Nl; ++l) { 7762 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7763 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7764 } 7765 if (preserveOrder) { 7766 for (l = 0; l < ul->Nl; ++l) { 7767 const char *name; 7768 PetscBool match; 7769 7770 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7771 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7772 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]); 7773 } 7774 } 7775 PetscFunctionReturn(PETSC_SUCCESS); 7776 } 7777 7778 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7779 { 7780 PetscInt l; 7781 7782 PetscFunctionBegin; 7783 for (l = 0; l < ul->Nl; ++l) { 7784 DMLabel label; 7785 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7786 7787 if (lval) { 7788 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7789 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7790 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7791 } 7792 } 7793 PetscFunctionReturn(PETSC_SUCCESS); 7794 } 7795 7796 /*@ 7797 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7798 7799 Not Collective 7800 7801 Input Parameter: 7802 . dm - The `DM` object 7803 7804 Output Parameter: 7805 . cdm - The coarse `DM` 7806 7807 Level: intermediate 7808 7809 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7810 @*/ 7811 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7812 { 7813 PetscFunctionBegin; 7814 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7815 PetscAssertPointer(cdm, 2); 7816 *cdm = dm->coarseMesh; 7817 PetscFunctionReturn(PETSC_SUCCESS); 7818 } 7819 7820 /*@ 7821 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7822 7823 Input Parameters: 7824 + dm - The `DM` object 7825 - cdm - The coarse `DM` 7826 7827 Level: intermediate 7828 7829 Note: 7830 Normally this is set automatically by `DMRefine()` 7831 7832 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7833 @*/ 7834 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7835 { 7836 PetscFunctionBegin; 7837 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7838 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7839 if (dm == cdm) cdm = NULL; 7840 PetscCall(PetscObjectReference((PetscObject)cdm)); 7841 PetscCall(DMDestroy(&dm->coarseMesh)); 7842 dm->coarseMesh = cdm; 7843 PetscFunctionReturn(PETSC_SUCCESS); 7844 } 7845 7846 /*@ 7847 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7848 7849 Input Parameter: 7850 . dm - The `DM` object 7851 7852 Output Parameter: 7853 . fdm - The fine `DM` 7854 7855 Level: intermediate 7856 7857 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7858 @*/ 7859 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7860 { 7861 PetscFunctionBegin; 7862 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7863 PetscAssertPointer(fdm, 2); 7864 *fdm = dm->fineMesh; 7865 PetscFunctionReturn(PETSC_SUCCESS); 7866 } 7867 7868 /*@ 7869 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7870 7871 Input Parameters: 7872 + dm - The `DM` object 7873 - fdm - The fine `DM` 7874 7875 Level: developer 7876 7877 Note: 7878 Normally this is set automatically by `DMCoarsen()` 7879 7880 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 7881 @*/ 7882 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 7883 { 7884 PetscFunctionBegin; 7885 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7886 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 7887 if (dm == fdm) fdm = NULL; 7888 PetscCall(PetscObjectReference((PetscObject)fdm)); 7889 PetscCall(DMDestroy(&dm->fineMesh)); 7890 dm->fineMesh = fdm; 7891 PetscFunctionReturn(PETSC_SUCCESS); 7892 } 7893 7894 /*@C 7895 DMAddBoundary - Add a boundary condition to a model represented by a `DM` 7896 7897 Collective 7898 7899 Input Parameters: 7900 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 7901 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 7902 . name - The BC name 7903 . label - The label defining constrained points 7904 . Nv - The number of `DMLabel` values for constrained points 7905 . values - An array of values for constrained points 7906 . field - The field to constrain 7907 . Nc - The number of constrained field components (0 will constrain all fields) 7908 . comps - An array of constrained component numbers 7909 . bcFunc - A pointwise function giving boundary values 7910 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 7911 - ctx - An optional user context for bcFunc 7912 7913 Output Parameter: 7914 . bd - (Optional) Boundary number 7915 7916 Options Database Keys: 7917 + -bc_<boundary name> <num> - Overrides the boundary ids 7918 - -bc_<boundary name>_comp <num> - Overrides the boundary components 7919 7920 Level: intermediate 7921 7922 Notes: 7923 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 7924 .vb 7925 void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 7926 .ve 7927 7928 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 7929 7930 .vb 7931 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 7932 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 7933 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 7934 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 7935 .ve 7936 + dim - the spatial dimension 7937 . Nf - the number of fields 7938 . uOff - the offset into u[] and u_t[] for each field 7939 . uOff_x - the offset into u_x[] for each field 7940 . u - each field evaluated at the current point 7941 . u_t - the time derivative of each field evaluated at the current point 7942 . u_x - the gradient of each field evaluated at the current point 7943 . aOff - the offset into a[] and a_t[] for each auxiliary field 7944 . aOff_x - the offset into a_x[] for each auxiliary field 7945 . a - each auxiliary field evaluated at the current point 7946 . a_t - the time derivative of each auxiliary field evaluated at the current point 7947 . a_x - the gradient of auxiliary each field evaluated at the current point 7948 . t - current time 7949 . x - coordinates of the current point 7950 . numConstants - number of constant parameters 7951 . constants - constant parameters 7952 - bcval - output values at the current point 7953 7954 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 7955 @*/ 7956 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) 7957 { 7958 PetscDS ds; 7959 7960 PetscFunctionBegin; 7961 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7962 PetscValidLogicalCollectiveEnum(dm, type, 2); 7963 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 7964 PetscValidLogicalCollectiveInt(dm, Nv, 5); 7965 PetscValidLogicalCollectiveInt(dm, field, 7); 7966 PetscValidLogicalCollectiveInt(dm, Nc, 8); 7967 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 7968 PetscCall(DMGetDS(dm, &ds)); 7969 /* Complete label */ 7970 if (label) { 7971 PetscObject obj; 7972 PetscClassId id; 7973 7974 PetscCall(DMGetField(dm, field, NULL, &obj)); 7975 PetscCall(PetscObjectGetClassId(obj, &id)); 7976 if (id == PETSCFE_CLASSID) { 7977 DM plex; 7978 7979 PetscCall(DMConvert(dm, DMPLEX, &plex)); 7980 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 7981 PetscCall(DMDestroy(&plex)); 7982 } 7983 } 7984 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 7985 PetscFunctionReturn(PETSC_SUCCESS); 7986 } 7987 7988 /* TODO Remove this since now the structures are the same */ 7989 static PetscErrorCode DMPopulateBoundary(DM dm) 7990 { 7991 PetscDS ds; 7992 DMBoundary *lastnext; 7993 DSBoundary dsbound; 7994 7995 PetscFunctionBegin; 7996 PetscCall(DMGetDS(dm, &ds)); 7997 dsbound = ds->boundary; 7998 if (dm->boundary) { 7999 DMBoundary next = dm->boundary; 8000 8001 /* quick check to see if the PetscDS has changed */ 8002 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 8003 /* the PetscDS has changed: tear down and rebuild */ 8004 while (next) { 8005 DMBoundary b = next; 8006 8007 next = b->next; 8008 PetscCall(PetscFree(b)); 8009 } 8010 dm->boundary = NULL; 8011 } 8012 8013 lastnext = &dm->boundary; 8014 while (dsbound) { 8015 DMBoundary dmbound; 8016 8017 PetscCall(PetscNew(&dmbound)); 8018 dmbound->dsboundary = dsbound; 8019 dmbound->label = dsbound->label; 8020 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8021 *lastnext = dmbound; 8022 lastnext = &dmbound->next; 8023 dsbound = dsbound->next; 8024 } 8025 PetscFunctionReturn(PETSC_SUCCESS); 8026 } 8027 8028 /* TODO: missing manual page */ 8029 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8030 { 8031 DMBoundary b; 8032 8033 PetscFunctionBegin; 8034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8035 PetscAssertPointer(isBd, 3); 8036 *isBd = PETSC_FALSE; 8037 PetscCall(DMPopulateBoundary(dm)); 8038 b = dm->boundary; 8039 while (b && !(*isBd)) { 8040 DMLabel label = b->label; 8041 DSBoundary dsb = b->dsboundary; 8042 PetscInt i; 8043 8044 if (label) { 8045 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8046 } 8047 b = b->next; 8048 } 8049 PetscFunctionReturn(PETSC_SUCCESS); 8050 } 8051 8052 /*@C 8053 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 8054 8055 Collective 8056 8057 Input Parameters: 8058 + dm - The `DM` 8059 . time - The time 8060 . funcs - The coordinate functions to evaluate, one per field 8061 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8062 - mode - The insertion mode for values 8063 8064 Output Parameter: 8065 . X - vector 8066 8067 Calling sequence of `funcs`: 8068 + dim - The spatial dimension 8069 . time - The time at which to sample 8070 . x - The coordinates 8071 . Nc - The number of components 8072 . u - The output field values 8073 - ctx - optional user-defined function context 8074 8075 Level: developer 8076 8077 Developer Notes: 8078 This API is specific to only particular usage of `DM` 8079 8080 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8081 8082 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8083 @*/ 8084 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) 8085 { 8086 Vec localX; 8087 8088 PetscFunctionBegin; 8089 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8090 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8091 PetscCall(DMGetLocalVector(dm, &localX)); 8092 PetscCall(VecSet(localX, 0.)); 8093 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8094 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8095 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8096 PetscCall(DMRestoreLocalVector(dm, &localX)); 8097 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8098 PetscFunctionReturn(PETSC_SUCCESS); 8099 } 8100 8101 /*@C 8102 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8103 8104 Not Collective 8105 8106 Input Parameters: 8107 + dm - The `DM` 8108 . time - The time 8109 . funcs - The coordinate functions to evaluate, one per field 8110 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8111 - mode - The insertion mode for values 8112 8113 Output Parameter: 8114 . localX - vector 8115 8116 Calling sequence of `funcs`: 8117 + dim - The spatial dimension 8118 . time - The current timestep 8119 . x - The coordinates 8120 . Nc - The number of components 8121 . u - The output field values 8122 - ctx - optional user-defined function context 8123 8124 Level: developer 8125 8126 Developer Notes: 8127 This API is specific to only particular usage of `DM` 8128 8129 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8130 8131 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8132 @*/ 8133 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) 8134 { 8135 PetscFunctionBegin; 8136 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8137 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8138 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX); 8139 PetscFunctionReturn(PETSC_SUCCESS); 8140 } 8141 8142 /*@C 8143 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. 8144 8145 Collective 8146 8147 Input Parameters: 8148 + dm - The `DM` 8149 . time - The time 8150 . numIds - The number of ids 8151 . ids - The ids 8152 . Nc - The number of components 8153 . comps - The components 8154 . label - The `DMLabel` selecting the portion of the mesh for projection 8155 . funcs - The coordinate functions to evaluate, one per field 8156 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8157 - mode - The insertion mode for values 8158 8159 Output Parameter: 8160 . X - vector 8161 8162 Calling sequence of `funcs`: 8163 + dim - The spatial dimension 8164 . time - The current timestep 8165 . x - The coordinates 8166 . Nc - The number of components 8167 . u - The output field values 8168 - ctx - optional user-defined function context 8169 8170 Level: developer 8171 8172 Developer Notes: 8173 This API is specific to only particular usage of `DM` 8174 8175 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8176 8177 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8178 @*/ 8179 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) 8180 { 8181 Vec localX; 8182 8183 PetscFunctionBegin; 8184 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8185 PetscCall(DMGetLocalVector(dm, &localX)); 8186 PetscCall(VecSet(localX, 0.)); 8187 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8188 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8189 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8190 PetscCall(DMRestoreLocalVector(dm, &localX)); 8191 PetscFunctionReturn(PETSC_SUCCESS); 8192 } 8193 8194 /*@C 8195 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. 8196 8197 Not Collective 8198 8199 Input Parameters: 8200 + dm - The `DM` 8201 . time - The time 8202 . label - The `DMLabel` selecting the portion of the mesh for projection 8203 . numIds - The number of ids 8204 . ids - The ids 8205 . Nc - The number of components 8206 . comps - The components 8207 . funcs - The coordinate functions to evaluate, one per field 8208 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8209 - mode - The insertion mode for values 8210 8211 Output Parameter: 8212 . localX - vector 8213 8214 Calling sequence of `funcs`: 8215 + dim - The spatial dimension 8216 . time - The current time 8217 . x - The coordinates 8218 . Nc - The number of components 8219 . u - The output field values 8220 - ctx - optional user-defined function context 8221 8222 Level: developer 8223 8224 Developer Notes: 8225 This API is specific to only particular usage of `DM` 8226 8227 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8228 8229 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8230 @*/ 8231 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) 8232 { 8233 PetscFunctionBegin; 8234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8235 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8236 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX); 8237 PetscFunctionReturn(PETSC_SUCCESS); 8238 } 8239 8240 /*@C 8241 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. 8242 8243 Not Collective 8244 8245 Input Parameters: 8246 + dm - The `DM` 8247 . time - The time 8248 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8249 . funcs - The functions to evaluate, one per field 8250 - mode - The insertion mode for values 8251 8252 Output Parameter: 8253 . localX - The output vector 8254 8255 Calling sequence of `funcs`: 8256 + dim - The spatial dimension 8257 . Nf - The number of input fields 8258 . NfAux - The number of input auxiliary fields 8259 . uOff - The offset of each field in u[] 8260 . uOff_x - The offset of each field in u_x[] 8261 . u - The field values at this point in space 8262 . u_t - The field time derivative at this point in space (or NULL) 8263 . u_x - The field derivatives at this point in space 8264 . aOff - The offset of each auxiliary field in u[] 8265 . aOff_x - The offset of each auxiliary field in u_x[] 8266 . a - The auxiliary field values at this point in space 8267 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8268 . a_x - The auxiliary field derivatives at this point in space 8269 . t - The current time 8270 . x - The coordinates of this point 8271 . numConstants - The number of constants 8272 . constants - The value of each constant 8273 - f - The value of the function at this point in space 8274 8275 Level: intermediate 8276 8277 Note: 8278 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. 8279 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 8280 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8281 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8282 8283 Developer Notes: 8284 This API is specific to only particular usage of `DM` 8285 8286 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8287 8288 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8289 `DMProjectFunction()`, `DMComputeL2Diff()` 8290 @*/ 8291 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) 8292 { 8293 PetscFunctionBegin; 8294 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8295 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8296 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8297 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX); 8298 PetscFunctionReturn(PETSC_SUCCESS); 8299 } 8300 8301 /*@C 8302 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. 8303 8304 Not Collective 8305 8306 Input Parameters: 8307 + dm - The `DM` 8308 . time - The time 8309 . label - The `DMLabel` marking the portion of the domain to output 8310 . numIds - The number of label ids to use 8311 . ids - The label ids to use for marking 8312 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8313 . comps - The components to set in the output, or `NULL` for all components 8314 . localU - The input field vector 8315 . funcs - The functions to evaluate, one per field 8316 - mode - The insertion mode for values 8317 8318 Output Parameter: 8319 . localX - The output vector 8320 8321 Calling sequence of `funcs`: 8322 + dim - The spatial dimension 8323 . Nf - The number of input fields 8324 . NfAux - The number of input auxiliary fields 8325 . uOff - The offset of each field in u[] 8326 . uOff_x - The offset of each field in u_x[] 8327 . u - The field values at this point in space 8328 . u_t - The field time derivative at this point in space (or NULL) 8329 . u_x - The field derivatives at this point in space 8330 . aOff - The offset of each auxiliary field in u[] 8331 . aOff_x - The offset of each auxiliary field in u_x[] 8332 . a - The auxiliary field values at this point in space 8333 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8334 . a_x - The auxiliary field derivatives at this point in space 8335 . t - The current time 8336 . x - The coordinates of this point 8337 . numConstants - The number of constants 8338 . constants - The value of each constant 8339 - f - The value of the function at this point in space 8340 8341 Level: intermediate 8342 8343 Note: 8344 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. 8345 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 8346 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8347 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8348 8349 Developer Notes: 8350 This API is specific to only particular usage of `DM` 8351 8352 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8353 8354 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8355 @*/ 8356 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) 8357 { 8358 PetscFunctionBegin; 8359 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8360 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8361 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8362 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8363 PetscFunctionReturn(PETSC_SUCCESS); 8364 } 8365 8366 /*@C 8367 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. 8368 8369 Not Collective 8370 8371 Input Parameters: 8372 + dm - The `DM` 8373 . time - The time 8374 . label - The `DMLabel` marking the portion of the domain to output 8375 . numIds - The number of label ids to use 8376 . ids - The label ids to use for marking 8377 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8378 . comps - The components to set in the output, or `NULL` for all components 8379 . U - The input field vector 8380 . funcs - The functions to evaluate, one per field 8381 - mode - The insertion mode for values 8382 8383 Output Parameter: 8384 . X - The output vector 8385 8386 Calling sequence of `funcs`: 8387 + dim - The spatial dimension 8388 . Nf - The number of input fields 8389 . NfAux - The number of input auxiliary fields 8390 . uOff - The offset of each field in u[] 8391 . uOff_x - The offset of each field in u_x[] 8392 . u - The field values at this point in space 8393 . u_t - The field time derivative at this point in space (or NULL) 8394 . u_x - The field derivatives at this point in space 8395 . aOff - The offset of each auxiliary field in u[] 8396 . aOff_x - The offset of each auxiliary field in u_x[] 8397 . a - The auxiliary field values at this point in space 8398 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8399 . a_x - The auxiliary field derivatives at this point in space 8400 . t - The current time 8401 . x - The coordinates of this point 8402 . numConstants - The number of constants 8403 . constants - The value of each constant 8404 - f - The value of the function at this point in space 8405 8406 Level: intermediate 8407 8408 Note: 8409 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. 8410 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 8411 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8412 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8413 8414 Developer Notes: 8415 This API is specific to only particular usage of `DM` 8416 8417 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8418 8419 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8420 @*/ 8421 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) 8422 { 8423 DM dmIn; 8424 Vec localU, localX; 8425 8426 PetscFunctionBegin; 8427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8428 PetscCall(VecGetDM(U, &dmIn)); 8429 PetscCall(DMGetLocalVector(dmIn, &localU)); 8430 PetscCall(DMGetLocalVector(dm, &localX)); 8431 PetscCall(VecSet(localX, 0.)); 8432 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8433 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8434 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8435 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8436 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8437 PetscCall(DMRestoreLocalVector(dm, &localX)); 8438 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8439 PetscFunctionReturn(PETSC_SUCCESS); 8440 } 8441 8442 /*@C 8443 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. 8444 8445 Not Collective 8446 8447 Input Parameters: 8448 + dm - The `DM` 8449 . time - The time 8450 . label - The `DMLabel` marking the portion of the domain boundary to output 8451 . numIds - The number of label ids to use 8452 . ids - The label ids to use for marking 8453 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8454 . comps - The components to set in the output, or `NULL` for all components 8455 . localU - The input field vector 8456 . funcs - The functions to evaluate, one per field 8457 - mode - The insertion mode for values 8458 8459 Output Parameter: 8460 . localX - The output vector 8461 8462 Calling sequence of `funcs`: 8463 + dim - The spatial dimension 8464 . Nf - The number of input fields 8465 . NfAux - The number of input auxiliary fields 8466 . uOff - The offset of each field in u[] 8467 . uOff_x - The offset of each field in u_x[] 8468 . u - The field values at this point in space 8469 . u_t - The field time derivative at this point in space (or NULL) 8470 . u_x - The field derivatives at this point in space 8471 . aOff - The offset of each auxiliary field in u[] 8472 . aOff_x - The offset of each auxiliary field in u_x[] 8473 . a - The auxiliary field values at this point in space 8474 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8475 . a_x - The auxiliary field derivatives at this point in space 8476 . t - The current time 8477 . x - The coordinates of this point 8478 . n - The face normal 8479 . numConstants - The number of constants 8480 . constants - The value of each constant 8481 - f - The value of the function at this point in space 8482 8483 Level: intermediate 8484 8485 Note: 8486 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. 8487 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 8488 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8489 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8490 8491 Developer Notes: 8492 This API is specific to only particular usage of `DM` 8493 8494 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8495 8496 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8497 @*/ 8498 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) 8499 { 8500 PetscFunctionBegin; 8501 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8502 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8503 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8504 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8505 PetscFunctionReturn(PETSC_SUCCESS); 8506 } 8507 8508 /*@C 8509 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8510 8511 Collective 8512 8513 Input Parameters: 8514 + dm - The `DM` 8515 . time - The time 8516 . funcs - The functions to evaluate for each field component 8517 . ctxs - Optional array of contexts to pass to each function, or NULL. 8518 - X - The coefficient vector u_h, a global vector 8519 8520 Output Parameter: 8521 . diff - The diff ||u - u_h||_2 8522 8523 Level: developer 8524 8525 Developer Notes: 8526 This API is specific to only particular usage of `DM` 8527 8528 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8529 8530 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8531 @*/ 8532 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8533 { 8534 PetscFunctionBegin; 8535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8536 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8537 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff); 8538 PetscFunctionReturn(PETSC_SUCCESS); 8539 } 8540 8541 /*@C 8542 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8543 8544 Collective 8545 8546 Input Parameters: 8547 + dm - The `DM` 8548 . time - The time 8549 . funcs - The gradient functions to evaluate for each field component 8550 . ctxs - Optional array of contexts to pass to each function, or NULL. 8551 . X - The coefficient vector u_h, a global vector 8552 - n - The vector to project along 8553 8554 Output Parameter: 8555 . diff - The diff ||(grad u - grad u_h) . n||_2 8556 8557 Level: developer 8558 8559 Developer Notes: 8560 This API is specific to only particular usage of `DM` 8561 8562 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8563 8564 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8565 @*/ 8566 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) 8567 { 8568 PetscFunctionBegin; 8569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8570 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8571 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff); 8572 PetscFunctionReturn(PETSC_SUCCESS); 8573 } 8574 8575 /*@C 8576 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8577 8578 Collective 8579 8580 Input Parameters: 8581 + dm - The `DM` 8582 . time - The time 8583 . funcs - The functions to evaluate for each field component 8584 . ctxs - Optional array of contexts to pass to each function, or NULL. 8585 - X - The coefficient vector u_h, a global vector 8586 8587 Output Parameter: 8588 . diff - The array of differences, ||u^f - u^f_h||_2 8589 8590 Level: developer 8591 8592 Developer Notes: 8593 This API is specific to only particular usage of `DM` 8594 8595 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8596 8597 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8598 @*/ 8599 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8600 { 8601 PetscFunctionBegin; 8602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8603 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8604 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff); 8605 PetscFunctionReturn(PETSC_SUCCESS); 8606 } 8607 8608 /*@C 8609 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8610 8611 Not Collective 8612 8613 Input Parameter: 8614 . dm - The `DM` 8615 8616 Output Parameters: 8617 + nranks - the number of neighbours 8618 - ranks - the neighbors ranks 8619 8620 Level: beginner 8621 8622 Note: 8623 Do not free the array, it is freed when the `DM` is destroyed. 8624 8625 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8626 @*/ 8627 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8628 { 8629 PetscFunctionBegin; 8630 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8631 PetscUseTypeMethod(dm, getneighbors, nranks, ranks); 8632 PetscFunctionReturn(PETSC_SUCCESS); 8633 } 8634 8635 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8636 8637 /* 8638 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8639 This must be a different function because it requires DM which is not defined in the Mat library 8640 */ 8641 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8642 { 8643 PetscFunctionBegin; 8644 if (coloring->ctype == IS_COLORING_LOCAL) { 8645 Vec x1local; 8646 DM dm; 8647 PetscCall(MatGetDM(J, &dm)); 8648 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8649 PetscCall(DMGetLocalVector(dm, &x1local)); 8650 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8651 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8652 x1 = x1local; 8653 } 8654 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8655 if (coloring->ctype == IS_COLORING_LOCAL) { 8656 DM dm; 8657 PetscCall(MatGetDM(J, &dm)); 8658 PetscCall(DMRestoreLocalVector(dm, &x1)); 8659 } 8660 PetscFunctionReturn(PETSC_SUCCESS); 8661 } 8662 8663 /*@ 8664 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8665 8666 Input Parameters: 8667 + coloring - The matrix to get the `DM` from 8668 - fdcoloring - the `MatFDColoring` object 8669 8670 Level: advanced 8671 8672 Developer Note: 8673 This routine exists because the PETSc `Mat` library does not know about the `DM` objects 8674 8675 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8676 @*/ 8677 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8678 { 8679 PetscFunctionBegin; 8680 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8681 PetscFunctionReturn(PETSC_SUCCESS); 8682 } 8683 8684 /*@ 8685 DMGetCompatibility - determine if two `DM`s are compatible 8686 8687 Collective 8688 8689 Input Parameters: 8690 + dm1 - the first `DM` 8691 - dm2 - the second `DM` 8692 8693 Output Parameters: 8694 + compatible - whether or not the two `DM`s are compatible 8695 - set - whether or not the compatible value was actually determined and set 8696 8697 Level: advanced 8698 8699 Notes: 8700 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8701 of the same topology. This implies that the section (field data) on one 8702 "makes sense" with respect to the topology and parallel decomposition of the other. 8703 Loosely speaking, compatible `DM`s represent the same domain and parallel 8704 decomposition, but hold different data. 8705 8706 Typically, one would confirm compatibility if intending to simultaneously iterate 8707 over a pair of vectors obtained from different `DM`s. 8708 8709 For example, two `DMDA` objects are compatible if they have the same local 8710 and global sizes and the same stencil width. They can have different numbers 8711 of degrees of freedom per node. Thus, one could use the node numbering from 8712 either `DM` in bounds for a loop over vectors derived from either `DM`. 8713 8714 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8715 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8716 .vb 8717 ... 8718 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8719 if (set && compatible) { 8720 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8721 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8722 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8723 for (j=y; j<y+n; ++j) { 8724 for (i=x; i<x+m, ++i) { 8725 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8726 } 8727 } 8728 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8729 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8730 } else { 8731 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8732 } 8733 ... 8734 .ve 8735 8736 Checking compatibility might be expensive for a given implementation of `DM`, 8737 or might be impossible to unambiguously confirm or deny. For this reason, 8738 this function may decline to determine compatibility, and hence users should 8739 always check the "set" output parameter. 8740 8741 A `DM` is always compatible with itself. 8742 8743 In the current implementation, `DM`s which live on "unequal" communicators 8744 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8745 incompatible. 8746 8747 This function is labeled "Collective," as information about all subdomains 8748 is required on each rank. However, in `DM` implementations which store all this 8749 information locally, this function may be merely "Logically Collective". 8750 8751 Developer Note: 8752 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8753 iff B is compatible with A. Thus, this function checks the implementations 8754 of both dm and dmc (if they are of different types), attempting to determine 8755 compatibility. It is left to `DM` implementers to ensure that symmetry is 8756 preserved. The simplest way to do this is, when implementing type-specific 8757 logic for this function, is to check for existing logic in the implementation 8758 of other `DM` types and let *set = PETSC_FALSE if found. 8759 8760 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8761 @*/ 8762 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8763 { 8764 PetscMPIInt compareResult; 8765 DMType type, type2; 8766 PetscBool sameType; 8767 8768 PetscFunctionBegin; 8769 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8770 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8771 8772 /* Declare a DM compatible with itself */ 8773 if (dm1 == dm2) { 8774 *set = PETSC_TRUE; 8775 *compatible = PETSC_TRUE; 8776 PetscFunctionReturn(PETSC_SUCCESS); 8777 } 8778 8779 /* Declare a DM incompatible with a DM that lives on an "unequal" 8780 communicator. Note that this does not preclude compatibility with 8781 DMs living on "congruent" or "similar" communicators, but this must be 8782 determined by the implementation-specific logic */ 8783 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8784 if (compareResult == MPI_UNEQUAL) { 8785 *set = PETSC_TRUE; 8786 *compatible = PETSC_FALSE; 8787 PetscFunctionReturn(PETSC_SUCCESS); 8788 } 8789 8790 /* Pass to the implementation-specific routine, if one exists. */ 8791 if (dm1->ops->getcompatibility) { 8792 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8793 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8794 } 8795 8796 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8797 with an implementation of this function from dm2 */ 8798 PetscCall(DMGetType(dm1, &type)); 8799 PetscCall(DMGetType(dm2, &type2)); 8800 PetscCall(PetscStrcmp(type, type2, &sameType)); 8801 if (!sameType && dm2->ops->getcompatibility) { 8802 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8803 } else { 8804 *set = PETSC_FALSE; 8805 } 8806 PetscFunctionReturn(PETSC_SUCCESS); 8807 } 8808 8809 /*@C 8810 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8811 8812 Logically Collective 8813 8814 Input Parameters: 8815 + dm - the `DM` 8816 . f - the monitor function 8817 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8818 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`) 8819 8820 Options Database Key: 8821 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8822 does not cancel those set via the options database. 8823 8824 Level: intermediate 8825 8826 Note: 8827 Several different monitoring routines may be set by calling 8828 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 8829 order in which they were set. 8830 8831 Fortran Note: 8832 Only a single monitor function can be set for each `DM` object 8833 8834 Developer Note: 8835 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 8836 8837 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8838 @*/ 8839 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) 8840 { 8841 PetscInt m; 8842 8843 PetscFunctionBegin; 8844 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8845 for (m = 0; m < dm->numbermonitors; ++m) { 8846 PetscBool identical; 8847 8848 PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 8849 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 8850 } 8851 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 8852 dm->monitor[dm->numbermonitors] = f; 8853 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 8854 dm->monitorcontext[dm->numbermonitors++] = (void *)mctx; 8855 PetscFunctionReturn(PETSC_SUCCESS); 8856 } 8857 8858 /*@ 8859 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 8860 8861 Logically Collective 8862 8863 Input Parameter: 8864 . dm - the DM 8865 8866 Options Database Key: 8867 . -dm_monitor_cancel - cancels all monitors that have been hardwired 8868 into a code by calls to `DMonitorSet()`, but does not cancel those 8869 set via the options database 8870 8871 Level: intermediate 8872 8873 Note: 8874 There is no way to clear one specific monitor from a `DM` object. 8875 8876 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8877 @*/ 8878 PetscErrorCode DMMonitorCancel(DM dm) 8879 { 8880 PetscInt m; 8881 8882 PetscFunctionBegin; 8883 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8884 for (m = 0; m < dm->numbermonitors; ++m) { 8885 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 8886 } 8887 dm->numbermonitors = 0; 8888 PetscFunctionReturn(PETSC_SUCCESS); 8889 } 8890 8891 /*@C 8892 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 8893 8894 Collective 8895 8896 Input Parameters: 8897 + dm - `DM` object you wish to monitor 8898 . name - the monitor type one is seeking 8899 . help - message indicating what monitoring is done 8900 . manual - manual page for the monitor 8901 . monitor - the monitor function 8902 - 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 8903 8904 Output Parameter: 8905 . flg - Flag set if the monitor was created 8906 8907 Level: developer 8908 8909 .seealso: [](ch_dmbase), `DM`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 8910 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 8911 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 8912 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 8913 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 8914 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 8915 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 8916 @*/ 8917 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 8918 { 8919 PetscViewer viewer; 8920 PetscViewerFormat format; 8921 8922 PetscFunctionBegin; 8923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8924 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 8925 if (*flg) { 8926 PetscViewerAndFormat *vf; 8927 8928 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 8929 PetscCall(PetscOptionsRestoreViewer(&viewer)); 8930 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 8931 PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy)); 8932 } 8933 PetscFunctionReturn(PETSC_SUCCESS); 8934 } 8935 8936 /*@ 8937 DMMonitor - runs the user provided monitor routines, if they exist 8938 8939 Collective 8940 8941 Input Parameter: 8942 . dm - The `DM` 8943 8944 Level: developer 8945 8946 Developer Note: 8947 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 8948 related to the discretization process seems rather specialized since some `DM` have no 8949 concept of discretization. 8950 8951 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 8952 @*/ 8953 PetscErrorCode DMMonitor(DM dm) 8954 { 8955 PetscInt m; 8956 8957 PetscFunctionBegin; 8958 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 8959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8960 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 8961 PetscFunctionReturn(PETSC_SUCCESS); 8962 } 8963 8964 /*@ 8965 DMComputeError - Computes the error assuming the user has provided the exact solution functions 8966 8967 Collective 8968 8969 Input Parameters: 8970 + dm - The `DM` 8971 - sol - The solution vector 8972 8973 Input/Output Parameter: 8974 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 8975 contains the error in each field 8976 8977 Output Parameter: 8978 . errorVec - A vector to hold the cellwise error (may be `NULL`) 8979 8980 Level: developer 8981 8982 Note: 8983 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 8984 8985 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 8986 @*/ 8987 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 8988 { 8989 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 8990 void **ctxs; 8991 PetscReal time; 8992 PetscInt Nf, f, Nds, s; 8993 8994 PetscFunctionBegin; 8995 PetscCall(DMGetNumFields(dm, &Nf)); 8996 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 8997 PetscCall(DMGetNumDS(dm, &Nds)); 8998 for (s = 0; s < Nds; ++s) { 8999 PetscDS ds; 9000 DMLabel label; 9001 IS fieldIS; 9002 const PetscInt *fields; 9003 PetscInt dsNf; 9004 9005 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 9006 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9007 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9008 for (f = 0; f < dsNf; ++f) { 9009 const PetscInt field = fields[f]; 9010 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9011 } 9012 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9013 } 9014 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); 9015 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9016 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9017 if (errorVec) { 9018 DM edm; 9019 DMPolytopeType ct; 9020 PetscBool simplex; 9021 PetscInt dim, cStart, Nf; 9022 9023 PetscCall(DMClone(dm, &edm)); 9024 PetscCall(DMGetDimension(edm, &dim)); 9025 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9026 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9027 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9028 PetscCall(DMGetNumFields(dm, &Nf)); 9029 for (f = 0; f < Nf; ++f) { 9030 PetscFE fe, efe; 9031 PetscQuadrature q; 9032 const char *name; 9033 9034 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 9035 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9036 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 9037 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 9038 PetscCall(PetscFEGetQuadrature(fe, &q)); 9039 PetscCall(PetscFESetQuadrature(efe, q)); 9040 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 9041 PetscCall(PetscFEDestroy(&efe)); 9042 } 9043 PetscCall(DMCreateDS(edm)); 9044 9045 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9046 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 9047 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9048 PetscCall(DMDestroy(&edm)); 9049 } 9050 PetscCall(PetscFree2(exactSol, ctxs)); 9051 PetscFunctionReturn(PETSC_SUCCESS); 9052 } 9053 9054 /*@ 9055 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 9056 9057 Not Collective 9058 9059 Input Parameter: 9060 . dm - The `DM` 9061 9062 Output Parameter: 9063 . numAux - The number of auxiliary data vectors 9064 9065 Level: advanced 9066 9067 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 9068 @*/ 9069 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9070 { 9071 PetscFunctionBegin; 9072 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9073 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9074 PetscFunctionReturn(PETSC_SUCCESS); 9075 } 9076 9077 /*@ 9078 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9079 9080 Not Collective 9081 9082 Input Parameters: 9083 + dm - The `DM` 9084 . label - The `DMLabel` 9085 . value - The label value indicating the region 9086 - part - The equation part, or 0 if unused 9087 9088 Output Parameter: 9089 . aux - The `Vec` holding auxiliary field data 9090 9091 Level: advanced 9092 9093 Note: 9094 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9095 9096 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9097 @*/ 9098 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9099 { 9100 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9101 PetscBool has; 9102 9103 PetscFunctionBegin; 9104 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9105 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9106 key.label = label; 9107 key.value = value; 9108 key.part = part; 9109 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9110 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9111 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9112 PetscFunctionReturn(PETSC_SUCCESS); 9113 } 9114 9115 /*@ 9116 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9117 9118 Not Collective because auxiliary vectors are not parallel 9119 9120 Input Parameters: 9121 + dm - The `DM` 9122 . label - The `DMLabel` 9123 . value - The label value indicating the region 9124 . part - The equation part, or 0 if unused 9125 - aux - The `Vec` holding auxiliary field data 9126 9127 Level: advanced 9128 9129 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9130 @*/ 9131 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9132 { 9133 Vec old; 9134 PetscHashAuxKey key; 9135 9136 PetscFunctionBegin; 9137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9138 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9139 key.label = label; 9140 key.value = value; 9141 key.part = part; 9142 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9143 PetscCall(PetscObjectReference((PetscObject)aux)); 9144 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9145 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9146 PetscCall(VecDestroy(&old)); 9147 PetscFunctionReturn(PETSC_SUCCESS); 9148 } 9149 9150 /*@C 9151 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9152 9153 Not Collective 9154 9155 Input Parameter: 9156 . dm - The `DM` 9157 9158 Output Parameters: 9159 + labels - The `DMLabel`s for each `Vec` 9160 . values - The label values for each `Vec` 9161 - parts - The equation parts for each `Vec` 9162 9163 Level: advanced 9164 9165 Note: 9166 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9167 9168 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9169 @*/ 9170 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9171 { 9172 PetscHashAuxKey *keys; 9173 PetscInt n, i, off = 0; 9174 9175 PetscFunctionBegin; 9176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9177 PetscAssertPointer(labels, 2); 9178 PetscAssertPointer(values, 3); 9179 PetscAssertPointer(parts, 4); 9180 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9181 PetscCall(PetscMalloc1(n, &keys)); 9182 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9183 for (i = 0; i < n; ++i) { 9184 labels[i] = keys[i].label; 9185 values[i] = keys[i].value; 9186 parts[i] = keys[i].part; 9187 } 9188 PetscCall(PetscFree(keys)); 9189 PetscFunctionReturn(PETSC_SUCCESS); 9190 } 9191 9192 /*@ 9193 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9194 9195 Not Collective 9196 9197 Input Parameter: 9198 . dm - The `DM` 9199 9200 Output Parameter: 9201 . dmNew - The new `DM`, now with the same auxiliary data 9202 9203 Level: advanced 9204 9205 Note: 9206 This is a shallow copy of the auxiliary vectors 9207 9208 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9209 @*/ 9210 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9211 { 9212 PetscFunctionBegin; 9213 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9214 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2); 9215 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS); 9216 PetscCall(DMClearAuxiliaryVec(dmNew)); 9217 9218 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9219 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9220 { 9221 Vec *auxData; 9222 PetscInt n, i, off = 0; 9223 9224 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n)); 9225 PetscCall(PetscMalloc1(n, &auxData)); 9226 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData)); 9227 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i])); 9228 PetscCall(PetscFree(auxData)); 9229 } 9230 PetscFunctionReturn(PETSC_SUCCESS); 9231 } 9232 9233 /*@ 9234 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one 9235 9236 Not Collective 9237 9238 Input Parameter: 9239 . dm - The `DM` 9240 9241 Level: advanced 9242 9243 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9244 @*/ 9245 PetscErrorCode DMClearAuxiliaryVec(DM dm) 9246 { 9247 Vec *auxData; 9248 PetscInt n, i, off = 0; 9249 9250 PetscFunctionBegin; 9251 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n)); 9252 PetscCall(PetscMalloc1(n, &auxData)); 9253 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData)); 9254 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 9255 PetscCall(PetscFree(auxData)); 9256 PetscCall(PetscHMapAuxDestroy(&dm->auxData)); 9257 PetscCall(PetscHMapAuxCreate(&dm->auxData)); 9258 PetscFunctionReturn(PETSC_SUCCESS); 9259 } 9260 9261 /*@C 9262 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9263 9264 Not Collective 9265 9266 Input Parameters: 9267 + ct - The `DMPolytopeType` 9268 . sourceCone - The source arrangement of faces 9269 - targetCone - The target arrangement of faces 9270 9271 Output Parameters: 9272 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9273 - found - Flag indicating that a suitable orientation was found 9274 9275 Level: advanced 9276 9277 Note: 9278 An arrangement is a face order combined with an orientation for each face 9279 9280 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9281 that labels each arrangement (face ordering plus orientation for each face). 9282 9283 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9284 9285 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9286 @*/ 9287 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9288 { 9289 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9290 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9291 PetscInt o, c; 9292 9293 PetscFunctionBegin; 9294 if (!nO) { 9295 *ornt = 0; 9296 *found = PETSC_TRUE; 9297 PetscFunctionReturn(PETSC_SUCCESS); 9298 } 9299 for (o = -nO; o < nO; ++o) { 9300 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 9301 9302 for (c = 0; c < cS; ++c) 9303 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9304 if (c == cS) { 9305 *ornt = o; 9306 break; 9307 } 9308 } 9309 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9310 PetscFunctionReturn(PETSC_SUCCESS); 9311 } 9312 9313 /*@C 9314 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9315 9316 Not Collective 9317 9318 Input Parameters: 9319 + ct - The `DMPolytopeType` 9320 . sourceCone - The source arrangement of faces 9321 - targetCone - The target arrangement of faces 9322 9323 Output Parameter: 9324 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9325 9326 Level: advanced 9327 9328 Note: 9329 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9330 9331 Developer Note: 9332 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9333 9334 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9335 @*/ 9336 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9337 { 9338 PetscBool found; 9339 9340 PetscFunctionBegin; 9341 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9342 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9343 PetscFunctionReturn(PETSC_SUCCESS); 9344 } 9345 9346 /*@C 9347 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9348 9349 Not Collective 9350 9351 Input Parameters: 9352 + ct - The `DMPolytopeType` 9353 . sourceVert - The source arrangement of vertices 9354 - targetVert - The target arrangement of vertices 9355 9356 Output Parameters: 9357 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9358 - found - Flag indicating that a suitable orientation was found 9359 9360 Level: advanced 9361 9362 Notes: 9363 An arrangement is a vertex order 9364 9365 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9366 that labels each arrangement (vertex ordering). 9367 9368 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9369 9370 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()` 9371 @*/ 9372 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9373 { 9374 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9375 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9376 PetscInt o, c; 9377 9378 PetscFunctionBegin; 9379 if (!nO) { 9380 *ornt = 0; 9381 *found = PETSC_TRUE; 9382 PetscFunctionReturn(PETSC_SUCCESS); 9383 } 9384 for (o = -nO; o < nO; ++o) { 9385 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o); 9386 9387 for (c = 0; c < cS; ++c) 9388 if (sourceVert[arr[c]] != targetVert[c]) break; 9389 if (c == cS) { 9390 *ornt = o; 9391 break; 9392 } 9393 } 9394 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9395 PetscFunctionReturn(PETSC_SUCCESS); 9396 } 9397 9398 /*@C 9399 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9400 9401 Not Collective 9402 9403 Input Parameters: 9404 + ct - The `DMPolytopeType` 9405 . sourceCone - The source arrangement of vertices 9406 - targetCone - The target arrangement of vertices 9407 9408 Output Parameter: 9409 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9410 9411 Level: advanced 9412 9413 Note: 9414 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9415 9416 Developer Note: 9417 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9418 9419 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9420 @*/ 9421 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9422 { 9423 PetscBool found; 9424 9425 PetscFunctionBegin; 9426 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9427 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9428 PetscFunctionReturn(PETSC_SUCCESS); 9429 } 9430 9431 /*@C 9432 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9433 9434 Not Collective 9435 9436 Input Parameters: 9437 + ct - The `DMPolytopeType` 9438 - point - Coordinates of the point 9439 9440 Output Parameter: 9441 . inside - Flag indicating whether the point is inside the reference cell of given type 9442 9443 Level: advanced 9444 9445 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9446 @*/ 9447 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9448 { 9449 PetscReal sum = 0.0; 9450 PetscInt d; 9451 9452 PetscFunctionBegin; 9453 *inside = PETSC_TRUE; 9454 switch (ct) { 9455 case DM_POLYTOPE_TRIANGLE: 9456 case DM_POLYTOPE_TETRAHEDRON: 9457 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9458 if (point[d] < -1.0) { 9459 *inside = PETSC_FALSE; 9460 break; 9461 } 9462 sum += point[d]; 9463 } 9464 if (sum > PETSC_SMALL) { 9465 *inside = PETSC_FALSE; 9466 break; 9467 } 9468 break; 9469 case DM_POLYTOPE_QUADRILATERAL: 9470 case DM_POLYTOPE_HEXAHEDRON: 9471 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9472 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9473 *inside = PETSC_FALSE; 9474 break; 9475 } 9476 break; 9477 default: 9478 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9479 } 9480 PetscFunctionReturn(PETSC_SUCCESS); 9481 } 9482 9483 /*@ 9484 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default 9485 9486 Logically collective 9487 9488 Input Parameters: 9489 + dm - The DM 9490 - reorder - Flag for reordering 9491 9492 Level: intermediate 9493 9494 .seealso: `DMReorderSectionGetDefault()` 9495 @*/ 9496 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder) 9497 { 9498 PetscFunctionBegin; 9499 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9500 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); 9501 PetscFunctionReturn(PETSC_SUCCESS); 9502 } 9503 9504 /*@ 9505 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default 9506 9507 Not collective 9508 9509 Input Parameter: 9510 . dm - The DM 9511 9512 Output Parameter: 9513 . reorder - Flag for reordering 9514 9515 Level: intermediate 9516 9517 .seealso: `DMReorderSetDefault()` 9518 @*/ 9519 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder) 9520 { 9521 PetscFunctionBegin; 9522 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9523 PetscAssertPointer(reorder, 2); 9524 *reorder = DM_REORDER_DEFAULT_NOTSET; 9525 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); 9526 PetscFunctionReturn(PETSC_SUCCESS); 9527 } 9528 9529 /*@C 9530 DMReorderSectionSetType - Set the type of local section reordering 9531 9532 Logically collective 9533 9534 Input Parameters: 9535 + dm - The DM 9536 - reorder - The reordering method 9537 9538 Level: intermediate 9539 9540 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()` 9541 @*/ 9542 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder) 9543 { 9544 PetscFunctionBegin; 9545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9546 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder)); 9547 PetscFunctionReturn(PETSC_SUCCESS); 9548 } 9549 9550 /*@C 9551 DMReorderSectionGetType - Get the reordering type for the local section 9552 9553 Not collective 9554 9555 Input Parameter: 9556 . dm - The DM 9557 9558 Output Parameter: 9559 . reorder - The reordering method 9560 9561 Level: intermediate 9562 9563 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()` 9564 @*/ 9565 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder) 9566 { 9567 PetscFunctionBegin; 9568 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9569 PetscAssertPointer(reorder, 2); 9570 *reorder = NULL; 9571 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder)); 9572 PetscFunctionReturn(PETSC_SUCCESS); 9573 } 9574